diff --git a/imgnod1.png b/imgnod1.png deleted file mode 100644 index 9d6b429..0000000 Binary files a/imgnod1.png and /dev/null differ diff --git a/serve/.env b/serve/.env new file mode 100644 index 0000000..629865d --- /dev/null +++ b/serve/.env @@ -0,0 +1,2 @@ +APP_DEBUG = FALSE +APP_TRACE = FALSE \ No newline at end of file diff --git a/serve/.htaccess b/serve/.htaccess new file mode 100644 index 0000000..69a7f04 --- /dev/null +++ b/serve/.htaccess @@ -0,0 +1,7 @@ + + Options +FollowSymlinks -Multiviews + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L] + diff --git a/serve/.travis.yml b/serve/.travis.yml new file mode 100644 index 0000000..36f7b6f --- /dev/null +++ b/serve/.travis.yml @@ -0,0 +1,42 @@ +sudo: false + +language: php + +branches: + only: + - stable + +cache: + directories: + - $HOME/.composer/cache + +before_install: + - composer self-update + +install: + - composer install --no-dev --no-interaction --ignore-platform-reqs + - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip . + - composer require --update-no-dev --no-interaction "topthink/think-image:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0" + - composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0" + - composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0" + - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip . + +script: + - php think unit + +deploy: + provider: releases + api_key: + secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw= + file: + - ThinkPHP_Core.zip + - ThinkPHP_Full.zip + skip_cleanup: true + on: + tags: true diff --git a/serve/app/.htaccess.txt.txt.txt b/serve/app/.htaccess.txt.txt.txt new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/serve/app/.htaccess.txt.txt.txt @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/serve/app/BaseController.php b/serve/app/BaseController.php new file mode 100644 index 0000000..b3bd7d3 --- /dev/null +++ b/serve/app/BaseController.php @@ -0,0 +1,94 @@ +app = $app; + $this->request = $this->app->request; + + // 控制器初始化 + $this->initialize(); + } + + // 初始化 + protected function initialize() + {} + + /** + * 验证数据 + * @access protected + * @param array $data 数据 + * @param string|array $validate 验证器名或者验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array|string|true + * @throws ValidateException + */ + protected function validate(array $data, $validate, array $message = [], bool $batch = false) + { + if (is_array($validate)) { + $v = new Validate(); + $v->rule($validate); + } else { + if (strpos($validate, '.')) { + // 支持场景 + list($validate, $scene) = explode('.', $validate); + } + $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate); + $v = new $class(); + if (!empty($scene)) { + $v->scene($scene); + } + } + + $v->message($message); + + // 是否批量验证 + if ($batch || $this->batchValidate) { + $v->batch(true); + } + + return $v->failException(true)->check($data); + } + +} diff --git a/serve/app/ExceptionHandle.php b/serve/app/ExceptionHandle.php new file mode 100644 index 0000000..453d126 --- /dev/null +++ b/serve/app/ExceptionHandle.php @@ -0,0 +1,58 @@ +header('token'); + $parm=input('get.token'); + if(empty($header) && empty($parm)){ + $token=''; + }else if(!empty($header)){ + $token=$header; + }else{ + $token=$parm; + } + return $token; +} +//获取登陆状态 +function checkLogin() { + $token=getToken(); + $cache=cache($token); + if($cache==null){ + return false; + }else{ + //重置缓存有效期 + cacheReset($token); + return true; + } +} +//重置缓存有效期 +function cacheReset($key){ + $config=config(); + if($config['cache']['default']=='file'){ + //文件缓存 + $file=cache()->getCacheKey($key); + touch($file); + + } + return true; +} +//获取当前用户ID +function getUserID(){ + $cache=cache(getToken()); + if(empty($cache)){ + die('[ ERROR ] 获取用户失败!'); + }else{ + return $cache['user']; + } +} +//判断字段存在且不为空 +function existFull($arr,$keys){ + $state=true; + foreach ($keys as $key) { + if(!isset($arr[$key]) || empty($arr[$key]) || $arr[$key] === 'null'){ + $state=false; + break; + } + } + return $state; +} +//扩展数据验证 +function verify($data,$rule,$info=false){ + $validate = \think\facade\Validate::rule($rule); + if($validate->check($data)){ + return true; + }else{ + return $info?$validate->getError():false; + } +} +//汉字转拼音 +//$type[head:首字母|all:全拼音] +function zhToPy($text,$type='head'){ + $nod=new \org\ZhToPy(); + $result=$nod::encode($text,$type); + return strtolower($result);//返回结果转小写 +} +//寻找数组多层键名 +//$source:键名数组 OR "键名1|键名2" +//如查找过程键名不存在返回空 +function arraySeek($array,$source){ + $recode=$array; + is_array($source)||($source=explode('|',$source)); + foreach ($source as $sourceVo) { + if(is_array($recode) && isset($recode[$sourceVo])){ + $recode=$recode[$sourceVo]; + }else{ + $recode=''; + break; + } + } + return $recode; +} +//数组搜索 +function search($arr){ + $search=new \org\Search($arr); + return $search; +} +//判断是否JSON数据 +function isJson($string) { + json_decode($string); + return(json_last_error()==JSON_ERROR_NONE); +} +//返回数据子元素递归数据 +function findSubData($arr,$id){ + $data=[]; + $search=search($arr,[['pid','=',$id]])->select(); + foreach ($search as $searchVo) { + $subSearch=search($arr,[['pid','=',$searchVo['id']]])->select(); + $data[]=$searchVo; + if(!empty($subSearch)){ + $data=array_merge($data,findSubData($arr,$searchVo['id']));//合并数据 + } + } + return $data; +} +//过滤XSS +function htmlpurifier($html) { + $config = HTMLPurifier_Config::createDefault(); + $config->set('CSS.AllowTricky', true); + $purifier = new \HTMLPurifier($config); + $clean_html = $purifier->purify($html); + return $clean_html; +} +//获取xlsx文件数据 +function getXlsx($file){ + $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx')->setReadDataOnly(TRUE)->load($file)->getSheet(0)->toArray (null,false,false,true); + //NULL转空白字符|拦截XSS + array_walk_recursive($reader,function(&$vo){$vo=$vo===null?'':htmlpurifier($vo);}); + return $reader; +} +//路径转换 +//$path='skin.upload.xlsx' +function pathChange($path=false){ + return $path==false?root_path():root_path().str_replace(".",DIRECTORY_SEPARATOR,$path).DIRECTORY_SEPARATOR; +} +//删除过期文件 +//$path='skin.upload.xlsx' +//默认过期时间30秒 +function delOverdueFile($path,$time=30){ + clearstatcache();//清除文件状态缓存 + $path=pathChange($path);//路径转换 + $files=scandir($path);//获取文件目录 + $nowTime=time();//当前时间 + foreach ($files as $key=>$vo){ + if(substr($vo,0,1)!='.'){ + $filePath=$path.$vo;//文件路径 + if ($nowTime-filectime($filePath)>$time){ + @unlink($filePath); + } + } + } +} +//删除目录|递归删除 +function delDir($path){ + $path=pathChange($path); + if(file_exists($path)){ + $list=listFile($path); + //删除过期缓存 + foreach ($list['files'] as $file) { + @unlink($file); + } + //删除空目录 + foreach ($list['dirs'] as $dir) { + @rmdir($dir); + } + } + +} +//删除目录|递归删除 +function delCache(){ + $cache=pathChange('runtime.cache'); + if(file_exists($cache)){ + $list=listFile($cache); + //删除过期缓存 + foreach ($list['files'] as $file) { + $content = @file_get_contents($file); + if($content!==false){ + $expire = (int)substr($content, 8, 12); + if ($expire!=0 && time() - $expire > filemtime($file)){ + @unlink($file); + } + } + } + //删除空目录 + foreach ($list['dirs'] as $dir) { + @rmdir($dir); + } + } +} + +//计算多维数组最多数组数量 +function calArrMaxCount($arr,$max=0){ + //对多维数组进行循环 + foreach ($arr as $vo) { + if(is_array($vo)){ + $count=count($vo); + //判断是否多维数组 + if ($count==count($vo,1)) { + $count > $max&&($max=$count); + }else{ + $max=CalArrMaxCount($vo,$max); + } + } + } + return $max; +} +//生成EXCEL +function buildExcel($fileName,$data,$down=true){ + $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); + $cellName=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM','AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ'];//列标识 + $shell=$spreadsheet->getActiveSheet(0);//工作簿 + $shell->setTitle('NODCLOUD.COM');//工作簿名称 + $shell->getDefaultColumnDimension()->setWidth(20);//设置默认行宽 + $shell->getDefaultRowDimension()->setRowHeight(16);//设置默认行高 + //循环加入数据 + $rowNums=1;//初始化行数 + $maxCell=calArrMaxCount($data);//获取多维数组最多数组数量 + //循环增加数据 + foreach ($data as $dataVo) { + //判断数据类型 + if($dataVo['type']=='title'){ + //标题行 + $cellNums=0;//初始化列数 + $shell->mergeCells($cellName[$cellNums].$rowNums.':'.$cellName[$maxCell-1].$rowNums);//合并单元格 + $shell->setCellValue($cellName[$cellNums].$rowNums,$dataVo['info'])->getStyle ($cellName[$cellNums].$rowNums)->applyFromArray ([ + 'font'=>['bold'=>true,'size'=>12], + 'alignment'=>['horizontal'=>\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER] + ]);//设置内容|居中|粗体|12号 + $shell->getRowDimension($rowNums)->setRowHeight(26);//设置行高 + $rowNums++;//自增行数 + }elseif($dataVo['type']=='node'){ + //节点行 + $cellNums=0;//初始化列数 + $shell->getStyle($cellName[$cellNums].$rowNums.':'.$cellName[$maxCell-1].$rowNums)->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setRGB('e7e6e6');//设置背景颜色 + foreach ($dataVo['info'] as $data_info) { + $shell->setCellValue ($cellName[$cellNums].$rowNums,$data_info); + $cellNums++;//自增列数 + } + $shell->getRowDimension($rowNums)->setRowHeight(16);//设置行高 + $rowNums++;//自增行数 + }elseif($dataVo['type']=='table'){ + //表格数据 + //处理表头数据 + $cellNums=0;//初始化列数 + foreach ($dataVo['info']['thead'] as $theadVo) { + $shell->setCellValue($cellName[$cellNums].$rowNums,$theadVo)->getStyle($cellName[$cellNums].$rowNums)->applyFromArray ([ + 'font'=>['bold'=>true], + 'alignment'=>['horizontal'=>\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER] + ]);//设置内容|居中|粗体; + $cellNums++;//自增列数 + } + $shell->getRowDimension($rowNums)->setRowHeight(16);//设置标题行高 + $rowNums++;//自增行数 + //处理表格数据 + foreach ($dataVo['info']['tbody'] as $tbodyVo) { + $cellNums=0;//初始化列数 + $RowHeight=16; + foreach ($tbodyVo as $tbodyVal) { + if(is_array($tbodyVal)){ + if($tbodyVal['type']=='img'){ + //图像 + $drawing=new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing(); + $drawing->setPath($tbodyVal['info']);//设置图像路径 + $drawing->setOffsetX(22);//设置X偏移距离 + $drawing->setOffsetY(3);//设置Y偏移距离 + $drawing->setWidth(100);//设置图像宽度 + $drawing->setCoordinates($cellName[$cellNums].$rowNums)->setWorksheet($shell);//设置内容 + $imgInfo=getimagesize($tbodyVal['info']);//读取图像信息 + $ImgHeight=($imgInfo[1]/($imgInfo[0]/100))*0.75;//计算行高|按照宽度缩放比例缩放 + $RowHeight=$ImgHeight+4.5;//增加Y偏移1.5倍关系 + } + }else{ + $shell->setCellValueExplicit($cellName[$cellNums].$rowNums,$tbodyVal,\PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);//设置内容并指定文本格式 + $shell->getStyle($cellName[$cellNums].$rowNums)->getAlignment()->setWrapText(true);//设置多行文本 + } + $cellNums++;//自增列数 + } + $shell->getRowDimension($rowNums)->setRowHeight($RowHeight);//设置数据行高 + $rowNums++;//自增行数 + } + } + } + //设置边框 + $shell->getStyle('A1:'.$cellName[$maxCell-1].($rowNums-1))->applyFromArray (['borders'=>['allBorders'=>['borderStyle'=>\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN]],'alignment'=>['vertical'=>\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER]]); + //输出文件 + ob_get_contents()&&(ob_end_clean());//清除缓冲区,避免乱码 + $writer=\PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet,'Xlsx'); + if($down){ + header('Content-type:application/vnd.ms-excel'); + header("Content-Disposition:attachment;filename=$fileName.xlsx"); + $writer->save('php://output'); + exit; + }else{ + delOverdueFile('static.file.xlsx');//删除过期文件 + $filePath=pathChange('static.file.xlsx').$fileName.'.xlsx'; + $writer->save($filePath); + return $filePath; + } +} +//生成压缩文件 +function buildZip($fileName,$files,$down=true){ + delOverdueFile('static.file.zip');//删除过期文件 + empty($files)&&(die('[ 文件数据为空 ]'));//空数据检验 + $filePath=pathChange('static.file.zip').$fileName.'.zip'; + $zip=new ZipArchive(); + if ($zip->open($filePath,ZIPARCHIVE::CREATE)!==TRUE) { + exit('创建压缩文件失败!'); + } + foreach ($files as $file) { + $zip->addFile($file,basename($file)); + } + $zip->close(); + if($down){ + header("Cache-Control: max-age=0"); + header("Content-Description: File Transfer"); + header('Content-disposition: attachment; filename='.basename($filePath)); //文件名 + header("Content-Type: application/zip"); //zip格式的 + header("Content-Transfer-Encoding: binary"); //告诉浏览器,这是二进制文件 + header('Content-Length: '.filesize($filePath)); //告诉浏览器,文件大小 + @readfile($filePath);//输出文件; + exit; + }else{ + return $filePath; + } +} +//curl请求 +function curl($url,$header,$data,$method='POST'){ + $ch=curl_init(); + if($method == 'GET'){ + $url = $url.'?'.http_build_query($data); + } + if($method == 'POST'){ + curl_setopt($ch, CURLOPT_POST,TRUE); + curl_setopt($ch, CURLOPT_POSTFIELDS,$data); + } + curl_setopt($ch, CURLOPT_URL,$url); + curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE); + curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); + curl_setopt($ch,CURLOPT_HEADER,FALSE); + if($header!=false){ + curl_setopt($ch,CURLOPT_HTTPHEADER,$header); + } + curl_setopt($ch, CURLOPT_RETURNTRANSFER,TRUE); + $result=curl_exec($ch); + curl_close($ch); + return $result; +} +//获取文件夹大小 +function getDirSize($dir){ + static $sizeResult = 0; + $handle = opendir($dir); + while (false!==($FolderOrFile = readdir($handle))) { + if($FolderOrFile != "." && $FolderOrFile != "..") { + if(is_dir("$dir/$FolderOrFile")){ + $sizeResult += getDirSize("$dir/$FolderOrFile"); + }else{ + $sizeResult += filesize("$dir/$FolderOrFile"); + } + } + } + closedir($handle); + return round(($sizeResult/1048576),2); +} +//获取数据库大小 +function getMysqlSize(){ + $dbInfo=config('database.connections.mysql'); + $tabs = think\facade\Db::query("SHOW TABLE STATUS FROM `".$dbInfo['database']."`"); + $size = 0; + foreach($tabs as $vo) { + $size += $vo["Data_length"] + $vo["Index_length"]; + } + //转换为M + return round(($size/1048576),2); +} + +//生成条形码 +//$type[true:直接输出|false:保存文件] +function txm($text,$type=true){ + delOverdueFile('static.code.txm');//删除过期文件 + $font = new BarcodeBakery\Common\BCGFontFile(pathChange('static.code.font').'Arial.ttf', 18); + $colorFront = new BarcodeBakery\Common\BCGColor(0, 0, 0); + $colorBack = new BarcodeBakery\Common\BCGColor(255, 255, 255); + $code = new BarcodeBakery\Barcode\BCGcode128(); + $code->setScale(2); + $code->setThickness(30); + $code->setForegroundColor($colorFront); + $code->setBackgroundColor($colorBack); + $code->setFont($font); + $code->setStart(null); + $code->setTilde(true); + $code->parse($text); + if ($type){ + header('Content-Type: image/png'); + $drawing = new BarcodeBakery\Common\BCGDrawing('',$colorBack); + $drawing->setBarcode($code); + $drawing->draw(); + $drawing->finish(BarcodeBakery\Common\BCGDrawing::IMG_FORMAT_PNG); + exit; + }else { + $filePath=pathChange('static.code.txm').uniqid().'.png'; + $drawing = new BarcodeBakery\Common\BCGDrawing($filePath, $colorBack); + $drawing->setBarcode($code); + $drawing->draw(); + $drawing->finish(BarcodeBakery\Common\BCGDrawing::IMG_FORMAT_PNG); + return $filePath; + } +} +//生成二维码 +//$type[true:直接输出|false:返回文件地址] +function ewm($text,$type=true){ + delOverdueFile('static.code.ewm');//删除过期文件 + $qrCode = new Endroid\QrCode\QrCode($text); + if($type){ + header('Content-Type: '.$qrCode->getContentType()); + echo $qrCode->writeString(); + exit; + }else{ + $filePath=pathChange('static.code.ewm').uniqid().'.png'; + $qrCode->writeFile($filePath); + return $filePath; + } +} + +//高精度运算 +function math($digit=6){ + $math=new \org\Math($digit); + return $math; +} +//数组求和 +function mathArraySum($arr){ + $sum=0; + foreach ($arr as $vo) { + $sum=math()->chain($sum)->add($vo)->done(); + } + return $sum; +} +//四舍五入处理位数 +function roundFloat($number,$digit){ + return floatval(round($number,$digit)); +} + +//MD5|16位 +function md5_16($str){ + return substr(md5($str),8,16); +} +//计算分页 +function PageCalc($page,$limit,$type='array'){ + $state=$limit*($page-1); + $end=$limit; + return $type=='array'?[$state,$end]:$state.','.$end; +} +//二维数组指定字段去重 +function assoc_unique($arr,$key){ + $record=[]; + foreach($arr as $k => $v) { + if(in_array($v[$key],$record)){ + unset($arr[$k]); + }else{ + $record[]=$v[$key]; + } + } + sort($arr); + return $arr; +} +//数据排序 +function arraySort(&$arr,$field,$sort=SORT_ASC){ + $fields = []; + foreach ($arr as $vo) { + $fields[] = $vo[$field]; + } + array_multisort($fields,$sort,$arr); +} +//数组包含数组 +function arrayInArray($arr1,$arr2){ + foreach ($arr1 as $vo) { + if(!in_array($vo,$arr2)){ + return false; + } + } + return true; +} +//多重提取数组列 +function arrayColumns($arr,$fields){ + foreach ($fields as $field) { + $arr=array_column($arr,$field); + } + return $arr; +} +//获取路径的文件夹和文件 +function listFile($path,$state=true){ + static $record=['dirs'=>[],'files'=>[]]; + $state&&$record=['dirs'=>[],'files'=>[]]; + foreach (new \FilesystemIterator($path) as $item) { + if ($item->isDir() && !$item->isLink()) { + $record['dirs'][]=$item->getPathname(); + listFile($item->getPathname(),false); + } else { + $record['files'][]=$item->getPathname(); + } + } + return $record; +} +//判断数组中指定键是否为数组 +function is_arrays($arr,$fields){ + foreach ($fields as $field) { + if(!isset($arr[$field]) || !is_array($arr[$field])){ + return false; + } + } + return true; +} +//获取指定天数 +function getOldDay($day=7){ + $time=strtotime(date('Y-m-d',time()));//获取今天开始时间戳 + $tmp_time_arr=[]; + for ($i = 0; $i < $day; $i++) { + array_push($tmp_time_arr,date('Y-m-d',$time-($i*86400))); + } + return array_reverse($tmp_time_arr);//返回反转的数组 +} +function uuid($prefix=''){ + $chars = md5(uniqid(mt_rand(), true)); + $uuid = substr($chars,0,8) . '-'; + $uuid .= substr($chars,8,4) . '-'; + $uuid .= substr($chars,12,4) . '-'; + $uuid .= substr($chars,16,4) . '-'; + $uuid .= substr($chars,20,12); + return $prefix . $uuid; +} +//[---------- 数据相关函数 ----------] +//DB助手函数 +function db($model){ + return think\facade\Db::name($model); +} +//获取系统配置 +//传入数组分类返回|传入字符返回内容 +function getSys($name = []) { + if(empty($name)){ + $sql=[]; + }else{ + $sql=is_array($name)?[['name','in',$name]]:[['name','=',$name]]; + } + $sys = db('sys')->where($sql)->field(['name','info'])->select()->toArray(); + //数据二次处理|JSON对象转换 + foreach ($sys as $sysKey => $sysVo) { + isJson($sysVo['info']) && ($sys[$sysKey]['info'] = json_decode($sysVo['info'],true)); + } + if (empty($sys)) { + $result = false; + } else { + if(is_array($name)){ + //分类返回 + $result = []; + foreach ($sys as $sysVo) { + $result[$sysVo['name']] = $sysVo['info']; + } + }else{ + //返回内容 + $result = $sys[0]['info']; + } + } + return $result; +} +//写入日志 +function pushLog($info,$user=false) { + db('log')->insert([ + 'time' => time(), + 'user' => empty($user)?getUserID():$user, + 'info' => $info + ]); +} +//获取结账日期 +function getPeriod(){ + $row=db('period')->order(['id'=>'desc'])->find(); + return empty($row)?0:$row['date']; +} + +//快捷获取SQL +//$arr:数组数据|$config:配置项 +//['field','Eq']|[['field','a|b|c'],'eq'] +//eq:等同查询|fullEq:不为空等于数据|noNullEq:不为NULL等同数据|fullDec1:不为空内容减1|fullTime:不为空转时间戳 +//md5:MD5加密|like:包含查询|fullLike:不为空包含查询 +//fullIn:不为空包含查询(传入数组)|fullDivisionIn:不为空分割集合包含查询 +//startTime和endTime:扩展时间字段查询 +function fastSql($arr,$config) { + $sql = []; + foreach ($config as $item){ + $key=is_array($item[0])?key($item[0]):$item[0]; + $field=is_array($item[0])?$item[0][key($item[0])]:$item[0]; + if(array_key_exists($key,$arr)){ + $val=$arr[$key]; + $val==='null'&&($val=null); + $condition=$item[1]; + //判断条件 + if ($condition == 'eq') { + //等同查询 + $sql[] = [$field,'=',$val]; + } elseif ($condition == 'fullEq') { + //不为空等于数据 + empty($val) || ($sql[] = [$field,'=',$val]); + } elseif ($condition == 'noNullEq') { + //不为NULL等于数据 + $val===null || ($sql[] = [$field,'=',$val]); + } elseif ($condition == 'fullDec1') { + //不为空内容减1 + empty($val) || ($sql[] = [$field,'=',$val-1]); + } else if ($condition == 'md5') { + //md5加密 + $sql[] = [$field,'=',md5($val)]; + } elseif ($condition == 'like') { + //包含查询 + $sql[] = [$field,'like','%'.$val.'%']; + } elseif ($condition == 'fullLike') { + //不为空包含查询 + empty($val) || ($sql[] = [$field,'like','%'.$val.'%']); + }elseif ($condition == 'fullTime') { + //不为空转时间戳 + empty($val) || ($sql[] = [$field,'=',strtotime($val)]); + }elseif ($condition == 'fullIn') { + //不为空包含查询 + empty($val) || ($sql[] = [$field,'in',$val]); + } elseif ($condition == 'fullDivisionIn') { + //不为空分割集合查询 + empty($val) || ($sql[] = [$field,'in',explode(",",$val)]); + } elseif ($condition == 'startTime') { + //开始时间 + $start=strtotime($val); + empty($start)||($sql[] = [$field,'>=',$start]); + } elseif ($condition == 'endTime') { + //结束时间 + $end=strtotime($val); + empty($end)||($sql[] = [$field,'<=',$end+86399]); + }else{ + die('[ ERROR ]未匹配条件!'); + } + } + } + return array_unique($sql,SORT_REGULAR); +} +//递归获取指定ID树状数组结构 +function findTreeArr($mode,$data,$field = false) { + $tree = []; + //判断是否初次执行 + if (!is_array($data)) { + $first = db($mode)->where([['id','=',$data]])->find(); + //查询首次数据 + $tree[] = $first; + //加入首次数据 + $data = [$first]; + //修正数据数组类型 + } + $gather = array_column($data,'id'); + //获取集合数据 + $arr = db($mode)->where([['pid','in',$gather]])->select()->toArray(); + //查询子数据 + if (!empty($arr)) { + $tree = array_merge($tree,$arr,findTreeArr($mode,$arr)); + //合并数据 + } + return $field == false?$tree:array_column($tree,$field); +} +//多表多条件find查询 +//$arr[['table'=>'plug','where'=>[['only','=',1]]]] +function moreTableFind($arr) { + $result = false; + //默认未找到 + foreach ($arr as $vo) { + $find = db($vo['table'])->where($vo['where'])->find(); + if (!empty($find)) { + $result = true; + //找到数据 + break; + } + } + return $result; +} +//SQL条件转换|数组条件转索引数组 +function parmToIndex($parm){ + $sql=[]; + foreach ($parm as $parmKey=>$parmVo) { + $sql[]=[$parmKey,'=',$parmVo]; + } + return $sql; +} +//多单位分析|转换基数 +function unitRadix($unit,$data){ + $radix=1; + $state=false; + array_unshift($data,['name'=>$data[0]['source'],'nums'=>1]); + $data=array_reverse($data); + foreach ($data as $dataVo) { + if($state || $dataVo['name']==$unit){ + $state=true; + $radix=math()->chain($radix)->mul($dataVo['nums'])->done(); + } + } + if($state){ + return $radix; + }else{ + return false; + } +} +//多单位分析|单位转换 +function unitSwitch($nums,$data){ + //1 构造数据 + $record=[]; + foreach ($data as $dataVo) { + if(abs($nums)<$dataVo['nums']){ + //1.1 小于归零 + $record[]=['name'=>$dataVo['source'],'nums'=>$nums]; + $nums=0; + }else{ + //1.2 取余 + $mod=math()->chain($nums)->mod($dataVo['nums'])->done(); + $record[]=['name'=>$dataVo['source'],'nums'=>abs($mod)]; + //1.3 递减数量 + $nums=math()->chain($nums)->sub($mod)->div($dataVo['nums'])->done(); + } + } + //2 追加数据 + $end=end($data); + $record[]=['name'=>$end['name'],'nums'=>$nums]; + //3 结构数据 + $text=''; + foreach (array_reverse($record) as $recordVo) { + if(!empty($recordVo['nums'])){ + $text.=$recordVo['nums'].$recordVo['name']; + } + } + $text==''&&$text=0; + return $text; +} +//获取用户信息 +function userInfo($id,$field = false) { + $user = db('user')->where([['id','=',$id]])->find(); + return $field == false?$user:$user[$field]; +} +//获取授权数据范围 +function getUserAuth($type){ + $user=userInfo(getUserID()); + if($user['role']==0){ + $result='all'; + }else{ + $role=db('role')->where([['id','=',$user['role']]])->find(); + $auth=json_decode($role['auth'],true); + if($type=='frame'){ + if(count($auth['frame'])==1 && $auth['frame'][0]==-2){ + $result='all'; + }else if(count($auth['frame'])==1 && $auth['frame'][0]==-1){ + $result=[$user['frame']]; + }else{ + $result=$auth['frame']; + } + }elseif($type=='customer'){ + if($auth['customer']=='all'){ + $result='all'; + }else if($auth['customer']=='userId'){ + $user=getUserAuth('user'); + if($user=='all'){ + $result='all'; + }else{ + $result=array_column(db('customer')->where([['user','in',$user]])->field(['id'])->select()->toArray(),'id'); + } + }else{ + $frame=getUserAuth('frame'); + if($frame=='all'){ + $result='all'; + }else{ + $result=array_column(db('customer')->where([['frame','in',$frame]])->field(['id'])->select()->toArray(),'id'); + } + } + }elseif($type=='supplier'){ + if($auth['supplier']=='all'){ + $result='all'; + }else if($auth['supplier']=='userId'){ + $user=getUserAuth('user'); + if($user=='all'){ + $result='all'; + }else{ + $result=array_column(db('supplier')->where([['user','in',$user]])->field(['id'])->select()->toArray(),'id'); + } + }else{ + $frame=getUserAuth('frame'); + if($frame=='all'){ + $result='all'; + }else{ + $result=array_column(db('supplier')->where([['frame','in',$frame]])->field(['id'])->select()->toArray(),'id'); + } + } + }elseif($type=='warehouse'){ + if($auth['warehouse']=='all'){ + $result='all'; + }else if($auth['warehouse']=='userFrame'){ + $result=[$user['frame']]; + }else{ + $frame=getUserAuth('frame'); + if($frame=='all'){ + $result='all'; + }else{ + $result=array_column(db('warehouse')->where([['frame','in',$frame]])->field(['id'])->select()->toArray(),'id'); + } + } + }elseif($type=='account'){ + if($auth['account']=='all'){ + $result='all'; + }else if($auth['account']=='userFrame'){ + $result=[$user['frame']]; + }else{ + $frame=getUserAuth('frame'); + if($frame=='all'){ + $result='all'; + }else{ + $result=array_column(db('account')->where([['frame','in',$frame]])->field(['id'])->select()->toArray(),'id'); + } + } + }elseif($type=='user'){ + if($auth['user']=='all'){ + $result='all'; + }else if($auth['user']=='userId'){ + $result=[getUserID()]; + }else{ + $frame=getUserAuth('frame'); + if($frame=='all'){ + $result='all'; + }else{ + $result=array_column(db('user')->where([['frame','in',$frame]])->field(['id'])->select()->toArray(),'id'); + } + } + }elseif($type=='people'){ + if($auth['people']=='all'){ + $result='all'; + }else if($auth['people']=='userFrame'){ + $result=[$user['frame']]; + }else{ + $frame=getUserAuth('frame'); + if($frame=='all'){ + $result='all'; + }else{ + $result=array_column(db('people')->where([['frame','in',$frame]])->field(['id'])->select()->toArray(),'id'); + } + } + }else{ + $result = false; + } + } + return $result; +} +//组织数据范围 +function frameScope($sql,$field='frame'){ + $cache=cache(getToken()); + if(empty($cache['frame'])){ + $frame=getUserAuth('frame'); + if($frame!='all'){ + $sql[]=[$field,'in',$frame]; + } + }else{ + $sql[]=[$field,'in',$cache['frame']]; + } + return $sql; +} +//SQL数据鉴权 +function sqlAuth($model,$sql=[]){ + $tab=[ + 'user'=>['id'=>'user','frame'=>'frame'], + 'log'=>['user'=>'user'], + 'customer'=>['id'=>'customer','frame'=>'frame','user'=>'user'], + 'supplier'=>['id'=>'supplier','frame'=>'frame','user'=>'user'], + 'warehouse'=>['id'=>'warehouse','frame'=>'frame'], + 'account'=>['id'=>'account','frame'=>'frame'], + 'people'=>['frame'=>'frame'], + 'bor'=>['frame'=>'frame','supplier'=>'supplier','people'=>'people','user'=>'user'], + 'buy'=>['frame'=>'frame','supplier'=>'supplier','people'=>'people','user'=>'user'], + 'bre'=>['frame'=>'frame','supplier'=>'supplier','people'=>'people','user'=>'user'], + 'sor'=>['frame'=>'frame','customer'=>'customer','people'=>'people','user'=>'user'], + 'sell'=>['frame'=>'frame','customer'=>'customer','people'=>'people','user'=>'user'], + 'sre'=>['frame'=>'frame','customer'=>'customer','people'=>'people','user'=>'user'], + 'swap'=>['frame'=>'frame','people'=>'people','user'=>'user'], + 'entry'=>['frame'=>'frame','people'=>'people','user'=>'user'], + 'extry'=>['frame'=>'frame','people'=>'people','user'=>'user'], + 'imy'=>['frame'=>'frame','customer'=>'customer','people'=>'people','user'=>'user'], + 'omy'=>['frame'=>'frame','supplier'=>'supplier','people'=>'people','user'=>'user'], + 'bill'=>['frame'=>'frame','people'=>'people','user'=>'user'], + 'allot'=>['frame'=>'frame','people'=>'people','user'=>'user'], + 'ice'=>['frame'=>'frame','customer'=>'customer','people'=>'people','user'=>'user'], + 'oce'=>['frame'=>'frame','supplier'=>'supplier','people'=>'people','user'=>'user'], + 'summary'=>['warehouse'=>'warehouse'], + 'room'=>['warehouse'=>'warehouse'], + 'batch'=>['warehouse'=>'warehouse'], + 'period'=>['user'=>'user'] + ]; + //扩展数据 + $extend=[ + 'entry'=>['customer'=>[0]], + 'extry'=>['supplier'=>[0]], + 'ice'=>['customer'=>[0]], + 'oce'=>['supplier'=>[0]] + ]; + $user = userInfo(getUserID()); + //排除管理员 + if($user['role']!=0){ + $role=db('role')->where([['id','=',$user['role']]])->find(); + $auth=json_decode($role['auth'],true); + foreach ($tab[$model] as $tabKey => $tabVo) { + //排除存在SQL键名 + if(!in_array($tabKey,array_column($sql,0))){ + $auth=getUserAuth($tabVo); + if($auth!='all'){ + //填入扩展 + isset($extend[$model][$tabKey])&&$auth=array_merge($auth,$extend[$model][$tabKey]); + //赋值语句 + $sql[] = [$tabKey,'in',$auth]; + } + } + } + } + return $sql; +} +//获取扩展字段配置 +function getFields() { + $data=[]; + $field = db('field')->select()->toArray(); + foreach ($field as $fieldVo) { + $data[$fieldVo['key']] = json_decode($fieldVo['fields'],true); + } + return $data; +} +//获取用户权限数据 +function getUserRoot() { + $user=userInfo(getUserID()); + if ($user['role'] == 0) { + return 'all'; + } else { + $role = db('role')->where([['id','=',$user['role']]])->find(); + $root = json_decode($role['root'],true); + //初始化权限数据 + foreach ($root as $rootVo) { + $data[$rootVo['module']] = $rootVo['data']; + } + return $data; + } +} +//获取组织零售单配置 +function getFrameDeploy(){ + $userFrame=userInfo(getUserID(),'frame'); + $frame=db('frame')->where([['id','=',$userFrame]])->find(); + $deploy=db('deploy')->where([['frame','=',$frame['id']]])->find(); + while ($frame['pid']!=-1 && empty($deploy)){ + $frame=db('frame')->where([['id','=',$frame['pid']]])->find(); + $deploy=db('deploy')->where([['frame','=',$frame['id']]])->find(); + } + return empty($deploy)?null:json_decode($deploy['source'],true); +} + +//获用户权限菜单数据 +function getRootMemu() { + $root = getUserRoot(); + if ($root == 'all') { + $menu= db('menu')->order('sort asc')->select()->toArray(); + } else { + $menu = db('menu')->where([['root','<>','admin'],['id','>',0]])->order('sort asc')->select()->toArray(); + //1.做数据标识 + foreach ($menu as $menuKey=>$menuVo) { + $voRoot=explode('|',$menuVo['root']); + //[权限为空|常规上级菜单|权限存在且为真] + $menu[$menuKey]['check']=(empty($menuVo['root']) || $menuVo['resource']=='#group' || (isset($root[$voRoot[0]][count($voRoot)==1?'see':$voRoot[1]])&&$root[$voRoot[0]][count($voRoot)==1?'see':$voRoot[1]]=='true'))?1:0; + } + //2.处理附属菜单 + foreach (search($menu)->where([['type','=',1],['check','=',1]])->select() as $menuVo) { + $pidData=search($menu)->where([['id','=',$menuVo['pid']],['check','=',false]],true)->find(); + empty($pidData)||$menu[$pidData['rowKey']]['check']=-1; + } + //3.保留可访问菜单数据 + $menu=search($menu)->where([['check','in',[1,-1]]])->select(); + //4.处理空集菜单 + $group=search($menu)->where([['resource','=','#group']],true)->select(); + foreach ($group as $menuVo) { + $tree = new \org\Tree(); + $v=$tree::vTree($menu,$menuVo['id']); + if(empty($v)){ + unset($menu[$menuVo['rowKey']]); + }else{ + $find=search($v)->where([['resource','<>','#group']])->find(); + if(empty($find)){ + unset($menu[$menuVo['rowKey']]); + } + } + } + } + return $menu; +} \ No newline at end of file diff --git a/serve/app/controller/Account.php b/serve/app/controller/Account.php new file mode 100644 index 0000000..f331752 --- /dev/null +++ b/serve/app/controller/Account.php @@ -0,0 +1,118 @@ +count();//获取总条数 + $info = Accounts::with(['frameData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //构造|验证 + try { + //排除balance字段|防止更新账户余额 + unset($input['balance']); + empty($input['id'])?$this->validate($input,'app\validate\Account'):$this->validate($input,'app\validate\Account.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Accounts::create($input); + pushLog('新增资金账户[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Accounts::update($input); + pushLog('更新资金账户[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $info=Accounts::where([['id','=',$input['id']]])->find(); + $result=['state'=>'success','info'=>$info]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //关联判断 + $exist=moreTableFind([ + ['table'=>'sell','where'=>[['account','=',$input['id']]]], + ['table'=>'sre','where'=>[['account','=',$input['id']]]], + ['table'=>'buy','where'=>[['account','=',$input['id']]]], + ['table'=>'bre','where'=>[['account','=',$input['id']]]], + ['table'=>'ice','where'=>[['account','=',$input['id']]]], + ['table'=>'oce','where'=>[['account','=',$input['id']]]], + ['table'=>'allot_info','where'=>[['account|tat','=',$input['id']]]], + ['table'=>'deploy','where'=>[['source','like','%"account":'.$input['id'].'%']]] + ]); + if(empty($exist)){ + //逻辑处理 + $find=Db::name('account')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + try { + Db::name('account')->where([['id','=',$input['id']]])->delete(); + Db::name('account_info')->where([['pid','=',$input['id']]])->delete(); + pushLog('删除资金账户[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Acl.php b/serve/app/controller/Acl.php new file mode 100644 index 0000000..8e3116d --- /dev/null +++ b/serve/app/controller/Acl.php @@ -0,0 +1,11 @@ +'error','info'=>'访问由于凭证无效被拒绝!'],401)->send()); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Ali.php b/serve/app/controller/Ali.php new file mode 100644 index 0000000..dca4570 --- /dev/null +++ b/serve/app/controller/Ali.php @@ -0,0 +1,129 @@ +protocol = 'https'; + $config->gatewayHost = 'openapi.alipay.com'; + $config->appId = $deploy['ali']['appid']; + $config->signType = 'RSA2'; + $config->alipayPublicKey = $deploy['ali']['public']; + $config->merchantPrivateKey = $deploy['ali']['private']; + Factory::setOptions($config); + //单据数据 + $result = Factory::payment()->faceToFace()->pay($deploy['ali']['title'],$input['number'],$input['money'],$input['code']); + if($result->code=='10000'){ + //支付成功 + $result=['state'=>'success','info'=>$result->tradeNo]; + }else{ + //支付失败 + if(in_array($result->code,['10003','20000'])){ + //返回等待信息 + $result=['state'=>'wait','info'=>'等待操作...']; + }else{ + //确认失败,返回错误信息 + $result=['state'=>'wrong','info'=>$result->subMsg]; + } + } + }else{ + $result=['state'=>'error','info'=>'支付参数不完整!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //查询单据 + public function query(){ + $input=input('post.'); + if(existFull($input,['number'])){ + //读取配置 + $deploy=getFrameDeploy(); + if(!empty($deploy)){ + //配置数据 + $config=new Config; + $config->protocol = 'https'; + $config->gatewayHost = 'openapi.alipay.com'; + $config->appId = $deploy['ali']['appid']; + $config->signType = 'RSA2'; + $config->alipayPublicKey = $deploy['ali']['public']; + $config->merchantPrivateKey = $deploy['ali']['private']; + Factory::setOptions($config); + //单据数据 + $result = Factory::payment()->common()->query($input['number']); + //调用结果 + if($result->code=='10000'){ + if(in_array($result->tradeStatus,['TRADE_SUCCESS','TRADE_FINISHED'])){ + //支付成功 + $result=['state'=>'success','info'=>$result->tradeNo]; + }elseif($result->tradeStatus=='WAIT_BUYER_PAY'){ + //返回等待信息 + $result=['state'=>'wait','info'=>'等待操作...']; + }else{ + $result=['state'=>'wrong','info'=>'未付款|支付超时|已撤销|已退款']; + } + }else{ + //确认失败,返回错误信息 + $result=['state'=>'wrong','info'=>$result->subMsg]; + } + }else{ + $result=['state'=>'error','info'=>'支付参数不完整!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //撤销单据 + //支付成功退款|未支付关闭单据 + public function cancel(){ + $input=input('post.'); + if(existFull($input,['number'])){ + //读取配置 + $deploy=getFrameDeploy(); + if(!empty($deploy)){ + //配置数据 + $config=new Config; + $config->protocol = 'https'; + $config->gatewayHost = 'openapi.alipay.com'; + $config->appId = $deploy['ali']['appid']; + $config->signType = 'RSA2'; + $config->alipayPublicKey = $deploy['ali']['public']; + $config->merchantPrivateKey = $deploy['ali']['private']; + Factory::setOptions($config); + //单据数据 + $result = Factory::payment()->common()->cancel($input['number']); + //调用结果 + if($result->code=='10000'){ + if(in_array($result->action,['close','refund'])){ + //撤销成功 + $result=['state'=>'success','info'=>'撤销单据成功!']; + }else{ + $result=['state'=>'wrong','info'=>'撤销单据失败,请人工处理!']; + } + }else{ + //确认失败,返回错误信息 + $result=['state'=>'wrong','info'=>$result->subMsg]; + } + }else{ + $result=['state'=>'error','info'=>'支付参数不完整!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Allot.php b/serve/app/controller/Allot.php new file mode 100644 index 0000000..64d5292 --- /dev/null +++ b/serve/app/controller/Allot.php @@ -0,0 +1,462 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['user','fullEq'], + ['examine','fullDec1'], + ['people','fullEq'], + ['data','fullLike'] + ]);//构造SQL + //转账字段扩展查询 + if(existFull($input,['account'])){ + $sql[]=['id','in',array_column(Db::name('allot_info')->where([['account|tat','=',$input['account']]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('allot',$sql);//数据鉴权 + $count = Allots::where($sql)->count();//获取总条数 + $info = Allots::with(['frameData','peopleData','userData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['examine']=0; + empty($class['id'])?$this->validate($class,'app\validate\Allot'):$this->validate($class,'app\validate\Allot.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\AllotInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'数据表格第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Allots::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'allot','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增转账单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Allots::update($class); + Db::name('record')->insert(['type'=>'allot','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新转账单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + AllotInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new AllotInfo; + $model->saveAll($input['info']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Allots::where([['id','=',$input['parm']]])->find(); + $info=AllotInfo::with(['accountData','tatData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('allot')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('allot')->where([['id','in',$input['parm']]])->delete(); + Db::name('allot_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','allot'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除转账单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('allot')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('allot_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + //3 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $outStore=['account'=>[],'accountInfo'=>[]]; + $enterStore=['account'=>[],'accountInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //1 转出账户 + $outStore['account'][]=['id'=>$infoVo['account'],'balance'=>$infoVo['money']]; + //2 转出账户详情 + $outStore['accountInfo'][]=['pid'=>$infoVo['account'],'type'=>'allotOut','class'=>$class['id'],'time'=>$class['time'],'direction'=>0,'money'=>$infoVo['money']]; + //3 转入账户 + $enterStore['account'][]=['id'=>$infoVo['tat'],'balance'=>$infoVo['money']]; + //4 转入账户详情 + $enterStore['accountInfo'][]=['pid'=>$infoVo['tat'],'type'=>'allotEnter','class'=>$class['id'],'time'=>$class['time'],'direction'=>1,'money'=>$infoVo['money']]; + } + //2 转出账户 + Db::name('account')->duplicate(['balance'=>Db::raw('balance - VALUES(`balance`)')])->insertAll($outStore['account']); + //3 转出账户详情 + Db::name('account_info')->insertAll($outStore['accountInfo']); + //4 转入账户 + Db::name('account')->duplicate(['balance'=>Db::raw('balance + VALUES(`balance`)')])->insertAll($enterStore['account']); + //5 转入账户详情 + Db::name('account_info')->insertAll($enterStore['accountInfo']); + //6 更新单据 + Db::name('allot')->where([['id','=',$class['id']]])->update(['examine'=>1]); + //7 单据记录 + Db::name('record')->insert(['type'=>'allot','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //8 记录操作 + pushLog('审核转账单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + + //--- 转出数据 --- + + //1 匹配数据 + $accountInfoList=Db::name('account_info')->where([['type','=','allotOut'],['class','=',$class['id']]])->select()->toArray(); + //2 资金账户 + $accountDuplicate=[]; + foreach ($accountInfoList as $accountInfoVo) { + $accountDuplicate[]=['id'=>$accountInfoVo['pid'],'balance'=>$accountInfoVo['money']]; + } + //2.1 更新资金 + Db::name('account')->duplicate(['balance'=>Db::raw('balance + VALUES(`balance`)')])->insertAll($accountDuplicate); + //2.2 删除资金详情 + Db::name('account_info')->where([['id','in',array_column($accountInfoList,'id')]])->delete(); + + //--- 转入数据 --- + + //3 匹配数据 + $accountInfoList=Db::name('account_info')->where([['type','=','allotEnter'],['class','=',$class['id']]])->select()->toArray(); + //4 资金账户 + $accountDuplicate=[]; + foreach ($accountInfoList as $accountInfoVo) { + $accountDuplicate[]=['id'=>$accountInfoVo['pid'],'balance'=>$accountInfoVo['money']]; + } + //5.1 更新资金 + Db::name('account')->duplicate(['balance'=>Db::raw('balance - VALUES(`balance`)')])->insertAll($accountDuplicate); + //5.2 删除资金详情 + Db::name('account_info')->where([['id','in',array_column($accountInfoList,'id')]])->delete(); + + //6 更新单据 + Db::name('allot')->where([['id','=',$class['id']]])->update(['examine'=>0]); + //7 单据记录 + Db::name('record')->insert(['type'=>'allot','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //8 记录操作 + pushLog('反审核转账单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('allot', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //关联人员匹配 + if(empty($data[3]['D'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['D']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['D'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'time'=>$data[3]['A'], + 'number'=>$data[3]['B'], + 'total'=>0, + 'people'=>$people['id'], + 'file'=>[], + 'data'=>$data[3]['E'], + 'more'=>[], + 'examine'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Allot');//数据合法性验证 + //初始化INFO + $info=[]; + $account=Db::name('account')->where([['name','in',array_column($data,'F')]])->select()->toArray(); + $tat=Db::name('account')->where([['name','in',array_column($data,'G')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'account'=>$dataVo['F'], + 'tat'=>$dataVo['G'], + 'money'=>$dataVo['H'], + 'settle'=>$dataVo['I'], + 'data'=>$dataVo['J'] + ]; + //转出账户匹配 + $accountFind=search($account)->where([['name','=',$record['account']]])->find(); + if(empty($accountFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行转出账户[ '.$record['account'].' ]未匹配!'); + }else{ + $record['account']=$accountFind['id']; + } + //转入账户匹配 + $tatFind=search($tat)->where([['name','=',$record['tat']]])->find(); + if(empty($tatFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行转入账户[ '.$record['tat'].' ]未匹配!'); + }else{ + $record['tat']=$tatFind['id']; + } + //结算金额匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['money'])){ + throw new ValidateException('模板文件第'.$dataKey.'行结算金额不正确!'); + } + try{ + $this->validate($record,'app\validate\AllotInfo');//数据合法性验证 + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['money'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + Db::startTrans(); + try { + //新增CLASS + $classData=Allots::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new AllotInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'allot','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入转账单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出转账单列表');//日志 + $source=Allots::with(['frameData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'转账单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据金额:'.mathArraySum(array_column($source,'total')) + ]]; + //导出execl + buildExcel('转账单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'转账单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'accountData|name'=>'转出账户', + 'tatData|name'=>'转入账户', + 'money'=>'结算金额', + 'settle'=>'结算号', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=AllotInfo::with(['accountData','tatData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->select()->toArray(); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + } + buildZip('转账单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Api.php b/serve/app/controller/Api.php new file mode 100644 index 0000000..a14a398 --- /dev/null +++ b/serve/app/controller/Api.php @@ -0,0 +1,49 @@ +'user|tel'],'eq'], + ['pwd','md5'] + ]); + $user=User::where($sql)->field(['id','name','tel','frame','user','img'])->find(); + if(empty($user)){ + $result=['state'=>'error','info'=>'账号|手机号或密码不正确!']; + }else{ + $token=token(); + cache($token,['user'=>$user['id'],'frame'=>[]]); + cache($input['uuid'],null); + pushLog('登录成功',$user['id']); + $result=['state'=>'success','info'=>$user,'token'=>$token]; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取验证 + public function captcha(){ + $uuid=uuid(); + $captcha=new \org\Captcha(); + $info=$captcha->entry(); + cache($uuid,$info['code']); + return json(['state'=>'success','info'=>['uuid'=>$uuid,'data'=>$info['data']]]); + } + //运行数据 + public function runData(){ + return json([ + 'state'=>'success', + 'info'=>[ + 'login'=>checkLogin(), + 'sys'=>getSys(['name','company','icp','notice']), + 'ver'=>config('soft.version') + ] + ]); + } +} \ No newline at end of file diff --git a/serve/app/controller/Attribute.php b/serve/app/controller/Attribute.php new file mode 100644 index 0000000..5b4284d --- /dev/null +++ b/serve/app/controller/Attribute.php @@ -0,0 +1,149 @@ +count();//获取总条数 + $info = Attributes::where($sql)->page($input['page'],$input['limit'])->order(['sort'=>'asc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + empty($input['id'])?$this->validate($input,'app\validate\Attribute'):$this->validate($input,'app\validate\Attribute.update'); + //关联判断 + if(!empty($input['id'])){ + $column=[array_column($input['info'],'name'),array_column(Db::name('attribute_info')->where([['pid','=',$input['id']]])->select()->toArray(),'name')]; + $diff=array_diff($column[1],$column[0]); + if(!empty($diff)){ + $whereOr=[]; + foreach($diff as $v){$whereOr[]=['name','like','%'.$v.'%'];} + $attr=Db::name('attr')->whereOr($whereOr)->select()->toArray(); + if(!empty($attr)){ + $column[]=array_column($attr,'name'); + $columns=[]; + foreach($column[2] as $v){$columns=array_merge($columns,explode("|",$v));} + foreach($column[2] as $v){ + if(in_array($v,$columns)){throw new ValidateException('[ '.$v.' ] 存在数据关联,操作已撤销!');} + } + } + } + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + $createInfo=Attributes::create($input); + $input['id']=$createInfo['id'];//转存主键 + pushLog('新增辅助属性[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Attributes::update($input); + pushLog('更新辅助属性[ '.$input['name'].' ]');//日志 + } + + //INFO数据 + Db::name('attribute_info')->where([['pid','=',$input['id']]])->delete(); + foreach ($input['info'] as $k=>$v) { + $input['info'][$k]['pid']=$input['id']; + } + Db::name('attribute_info')->insertAll($input['info']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Attributes::with(['info'])->where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $find=Db::name('attribute')->where([['id','=',$input['id']]])->find(); + $info=Db::name('attribute_info')->where([['pid','=',$input['id']]])->select()->toArray(); + + //关联判断 + $list=array_column($info,'name'); + $whereOr=[]; + foreach($list as $v){ + $whereOr[]=['name','like','%'.$v.'%']; + } + $attr=Db::name('attr')->whereOr($whereOr)->select()->toArray(); + if(!empty($attr)){ + $column=array_column($attr,'name'); + $columns=[]; + foreach($column as $v){ + $columns=array_merge($columns,explode("|",$v)); + } + foreach($list as $v){ + if(in_array($v,$columns)){ + return json(['state'=>'error','info'=>'存在数据关联,删除失败!']); + } + } + } + + Db::startTrans(); + try { + Db::name('attribute')->where([['id','=',$input['id']]])->delete(); + Db::name('attribute_info')->where([['pid','=',$input['id']]])->delete(); + pushLog('删除辅助属性[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //全部 + public function select(){ + $info = Attributes::with('info')->order(['sort'=>'asc'])->select(); + $result=['state'=>'success','info'=>$info]; + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Backup.php b/serve/app/controller/Backup.php new file mode 100644 index 0000000..8fccfa1 --- /dev/null +++ b/serve/app/controller/Backup.php @@ -0,0 +1,74 @@ +get_filelist(); + //排除配置文件 + foreach ($list as $listKey=>$listVo){ + if(substr($listVo['name'],0,1)=='.'){ + unset($list[$listKey]); + } + } + $count = count($list);//获取总条数 + $info =array_slice($list,$input['limit']*($input['page']-1),$input['limit']);//匹配分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //备份 + public function backup(){ + $dbInfo=config('database.connections.mysql'); + $backup=new \org\BakSql($dbInfo['hostname'],$dbInfo['username'],$dbInfo['password'],$dbInfo['database']); + $backup->backup(); + pushLog('备份数据'); + return json (['state'=>'success']); + } + //恢复 + public function restore(){ + $input=input('post.'); + if(existFull($input,['name'])){ + //恢复指定数据 + $dbInfo=config('database.connections.mysql'); + $backup=new \org\BakSql($dbInfo['hostname'],$dbInfo['username'],$dbInfo['password'],$dbInfo['database']); + $backup->restore($input['name']); + pushLog('恢复数据备份[ '.$input['name'].' ]');//日志信息 + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $path=pathChange('static.backup'); + foreach ($input['parm'] as $infoVo) { + //防止恶意请求 + if(strpos($infoVo,DIRECTORY_SEPARATOR)===false && strpos($infoVo,'..')===false){ + @unlink($path.$infoVo); + pushLog('删除数据备份[ '.$infoVo.' ]');//日志信息 + }else{ + return json(['state'=>'error','info'=>'传入参数错误!']); + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Batch.php b/serve/app/controller/Batch.php new file mode 100644 index 0000000..533c437 --- /dev/null +++ b/serve/app/controller/Batch.php @@ -0,0 +1,687 @@ +where(empty($input['warehouse'])?sqlAuth('warehouse',[]):[['id','in',$input['warehouse']]])->order(['id'=>'desc'])->select()->toArray(); + //构造表头|集合 + $column=[]; + foreach ($warehouse as $warehouseVo) { + $column[]=['id'=>$warehouseVo['id'],'key'=>'stock_'.$warehouseVo['id'],'name'=>$warehouseVo['name']]; + } + //匹配商品 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'], + ['spec','fullLike'], + ['brand','fullEq'], + ['code','fullLike'] + ]);//构造SQL + //商品类型 + $sql[]=['type','=',0]; + //辅助属性扩展查询 + $sqlOr=existFull($input,['code'])?[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]:[]; + //商品分类树结构查询 + existFull($input,['category'])&&$sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + //批次查询 + $batchSql=fastSql($input,[ + [['batch'=>'number'],'fullLike'], + ['time','fullTime'] + ]);//构造SQL + $batchSql[]=['warehouse','in',array_column($warehouse,'id')]; + //查询操作-批次类型 + if(empty($input['state'])){ + $batch=Db::name('batch')->where($batchSql)->select()->toArray(); + }else{ + $batchSql[]=['time','<>',0]; + $batch=Db::name('batch')->alias('a')->join('goods b','a.goods = b.id')->where($batchSql)->whereRaw('a.time + (b.validity * 86400) >= :time - (b.threshold * 86400)',['time'=>strtotime(date('Y-m-d',time()))])->field('a.*')->select()->toArray(); + } + //查询商品 + $sql[]=['id','in',array_column($batch,'goods')]; + //获取总条数 + $count = Goods::where($sql)->whereOr($sqlOr)->count(); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->order(['id'=>'desc'])->page($input['page'],$input['limit'])->append(['extension'])->select()->toArray(); + //唯一标识|属性处理 + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['key']=$infoVo['id']; + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + $info[$infoKey]['attr'][$attrKey]['key']=$infoVo['id'].'.'.$attrVo['id']; + //属性处理 + if(existFull($input,['code']) && !in_array($input['code'],[$infoVo['code'],$attrVo['code']])){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //库存集合[w:仓库|g:商品|a:属性|b:批次|t:生产日期] + $gather=['g'=>[],'wg'=>[],'ga'=>[],'wga'=>[],'gb'=>[],'wgb'=>[],'gbt'=>[],'wgbt'=>[],'gab'=>[],'wgab'=>[],'gabt'=>[],'wgabt'=>[]]; + //查询库存数据-仓储 + $room=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['goods','in',array_column($info,'id')]])->select()->toArray(); + //构造库存数据 + foreach ($room as $roomVo) { + //商品 + $g=md5_16($roomVo['goods']); + $gather['g'][$g]=math()->chain($gather['g'][$g]??0)->add($roomVo['nums'])->done(); + //仓库|商品 + $wg=md5_16($roomVo['warehouse'].'&'.$roomVo['goods']); + $gather['wg'][$wg]=math()->chain($gather['wg'][$wg]??0)->add($roomVo['nums'])->done(); + //判断属性 + if(!empty($roomVo['attr'])){ + //商品|属性 + $ga=md5_16($roomVo['goods'].'&'.$roomVo['attr']); + $gather['ga'][$ga]=math()->chain($gather['ga'][$ga]??0)->add($roomVo['nums'])->done(); + //仓库|商品|属性 + $wga=md5_16($roomVo['warehouse'].'&'.$roomVo['goods'].'&'.$roomVo['attr']); + $gather['wga'][$wga]=math()->chain($gather['wga'][$wga]??0)->add($roomVo['nums'])->done(); + } + } + + //构造库存数据-批次 + foreach ($batch as $batchKey=>$batchVo) { + //商品|批次 + $gb=md5_16($batchVo['goods'].'&'.$batchVo['number']); + $gather['gb'][$gb]=math()->chain($gather['gb'][$gb]??0)->add($batchVo['nums'])->done(); + //仓库|商品|批次 + $wgb=md5_16($batchVo['warehouse'].'&'.$batchVo['goods'].'&'.$batchVo['number']); + $gather['wgb'][$wgb]=math()->chain($gather['wgb'][$wgb]??0)->add($batchVo['nums'])->done(); + + //匹配辅助属性 + $find=search($room)->where([['id','=',$batchVo['room']]])->find(); + if(empty($find['attr'])){ + //转存数据 + $batch[$batchKey]['attr']=null; + //生产日期 + if(!empty($batchVo['time'])){ + //商品|批次|生产日期 + $gbt=md5_16($batchVo['goods'].'&'.$batchVo['id'].'&'.$batchVo['time']); + $gather['gbt'][$gbt]=math()->chain($gather['gbt'][$gbt]??0)->add($batchVo['nums'])->done(); + //仓库|商品|批次|生产日期 + $wgbt=md5_16($batchVo['warehouse'].'&'.$batchVo['goods'].'&'.$batchVo['id'].'&'.$batchVo['time']); + $gather['wgbt'][$wgbt]=math()->chain($gather['wgbt'][$wgbt]??0)->add($batchVo['nums'])->done(); + } + }else{ + //转存数据 + $batch[$batchKey]['attr']=$find['attr']; + //商品|属性|批次 + $gab=md5_16($batchVo['goods'].'&'.$find['attr'].'&'.$batchVo['number']); + $gather['gab'][$gab]=math()->chain($gather['gab'][$gab]??0)->add($batchVo['nums'])->done(); + //仓库|商品|属性|批次 + $wgab=md5_16($batchVo['warehouse'].'&'.$batchVo['goods'].'&'.$find['attr'].'&'.$batchVo['number']); + $gather['wgab'][$wgab]=math()->chain($gather['wgab'][$wgab]??0)->add($batchVo['nums'])->done(); + //生产日期 + if(!empty($batchVo['time'])){ + //商品|属性|批次|生产日期 + $gabt=md5_16($batchVo['goods'].'&'.$find['attr'].'&'.$batchVo['id'].'&'.$batchVo['time']); + $gather['gabt'][$gabt]=math()->chain($gather['gabt'][$gabt]??0)->add($batchVo['nums'])->done(); + //仓库|商品|属性|批次|生产日期 + $wgabt=md5_16($batchVo['warehouse'].'&'.$batchVo['goods'].'&'.$find['attr'].'&'.$batchVo['id'].'&'.$batchVo['time']); + $gather['wgabt'][$wgabt]=math()->chain($gather['wgabt'][$wgabt]??0)->add($batchVo['nums'])->done(); + } + } + } + //数量匹配|库存处理 + foreach ($info as $infoKey=>$infoVo) { + //商品 + $g=md5_16($infoVo['id']); + $info[$infoKey]['summary']=isset($gather['g'][$g])?($infoVo['unit']=='-1'?unitSwitch($gather['g'][$g],$infoVo['units']):$gather['g'][$g]):0; + //仓库|商品 + foreach ($column as $columnVo) { + $wg=md5_16($columnVo['id'].'&'.$infoVo['id']); + $info[$infoKey]['stock_'.$columnVo['id']]=isset($gather['wg'][$wg])?($infoVo['unit']=='-1'?unitSwitch($gather['wg'][$wg],$infoVo['units']):$gather['wg'][$wg]):0; + } + //匹配辅助属性 + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //商品|属性 + $ga=md5_16($infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['summary']=isset($gather['ga'][$ga])?($infoVo['unit']=='-1'?unitSwitch($gather['ga'][$ga],$infoVo['units']):$gather['ga'][$ga]):0; + //仓库|商品|属性 + foreach ($column as $columnVo) { + $wga=md5_16($columnVo['id'].'&'.$infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['stock_'.$columnVo['id']]=isset($gather['wga'][$wga])?($infoVo['unit']=='-1'?unitSwitch($gather['wga'][$wga],$infoVo['units']):$gather['wga'][$wga]):0; + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //数量匹配|批次处理 + foreach ($info as $infoKey=>$infoVo) { + //数组改造 + if(empty($infoVo['attr'])){ + $list=search($batch)->where([['goods','=',$infoVo['id']],['attr','=',null]])->select(); + //去重匹配 + foreach (assoc_unique($list,'number') as $listVo) { + $row=[ + 'name'=>$listVo['number'] + ]; + //商品|批次 + $gb=md5_16($infoVo['id'].'&'.$listVo['number']); + $row['summary']=isset($gather['gb'][$gb])?($infoVo['unit']=='-1'?unitSwitch($gather['gb'][$gb],$infoVo['units']):$gather['gb'][$gb]):0; + //仓库|商品|批次 + foreach ($column as $columnVo) { + $wgb=md5_16($columnVo['id'].'&'.$infoVo['id'].'&'.$listVo['number']); + $row['stock_'.$columnVo['id']]=isset($gather['wgb'][$wgb])?($infoVo['unit']=='-1'?unitSwitch($gather['wgb'][$wgb],$infoVo['units']):$gather['wgb'][$wgb]):0; + } + //生产日期处理 + if(empty($listVo['time'])){ + $row['batch']=$listVo['id']; + }else{ + $sub=search($list)->where([['number','=',$listVo['number']]])->select(); + foreach ($sub as $subVo) { + $tag=[ + 'batch'=>$subVo['id'], + 'name'=>'-', + 'protect'=>$infoVo['protect'], + 'startTime'=>date('Y-m-d',$subVo['time']), + 'endTime'=>date('Y-m-d',$subVo['time']+($infoVo['protect']*86400)) + ]; + //商品|批次|生产日期 + $gbt=md5_16($infoVo['id'].'&'.$subVo['id'].'&'.$subVo['time']); + $tag['summary']=isset($gather['gbt'][$gbt])?($infoVo['unit']=='-1'?unitSwitch($gather['gbt'][$gbt],$infoVo['units']):$gather['gbt'][$gbt]):0; + //仓库|商品|批次|生产日期 + foreach ($column as $columnVo) { + $wgbt=md5_16($columnVo['id'].'&'.$infoVo['id'].'&'.$subVo['id'].'&'.$subVo['time']); + $tag['stock_'.$columnVo['id']]=isset($gather['wgbt'][$wgbt])?($infoVo['unit']=='-1'?unitSwitch($gather['wgbt'][$wgbt],$infoVo['units']):$gather['wgbt'][$wgbt]):0; + } + $tag['key']=$gbt; + $row['attr'][]=$tag; + } + } + $row['key']=$gb; + $info[$infoKey]['attr'][]=$row; + } + }else{ + //匹配数据 + $list=search($batch)->where([['goods','=',$infoVo['id']],['attr','<>',null]])->select(); + //循环属性 + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + $select=search($list)->where([['attr','=',$attrVo['name']]])->select(); + //去重匹配 + foreach (assoc_unique($select,'number') as $selectVo) { + $row=[ + 'name'=>$selectVo['number'] + ]; + //商品|属性|批次 + $gab=md5_16($infoVo['id'].'&'.$selectVo['attr'].'&'.$selectVo['number']); + $row['summary']=isset($gather['gab'][$gab])?($infoVo['unit']=='-1'?unitSwitch($gather['gab'][$gab],$infoVo['units']):$gather['gab'][$gab]):0; + //仓库|商品|属性|批次 + foreach ($column as $columnVo) { + $wgab=md5_16($columnVo['id'].'&'.$infoVo['id'].$selectVo['attr'].'&'.$selectVo['number']); + $row['stock_'.$columnVo['id']]=isset($gather['wgab'][$wgab])?($infoVo['unit']=='-1'?unitSwitch($gather['wgab'][$wgab],$infoVo['units']):$gather['wgab'][$wgab]):0; + } + //生产日期处理 + if(empty($selectVo['time'])){ + $row['batch']=$selectVo['id']; + }else{ + $sub=search($list)->where([['number','=',$selectVo['number']]])->select(); + foreach ($sub as $subVo) { + $tag=[ + 'batch'=>$subVo['id'], + 'name'=>'-', + 'protect'=>$infoVo['protect'], + 'startTime'=>date('Y-m-d',$subVo['time']), + 'endTime'=>date('Y-m-d',$subVo['time']+($infoVo['protect']*86400)) + ]; + //商品|属性|批次|生产日期 + $gabt=md5_16($infoVo['id'].'&'.$selectVo['attr'].'&'.$subVo['id'].'&'.$subVo['time']); + $tag['summary']=isset($gather['gabt'][$gabt])?($infoVo['unit']=='-1'?unitSwitch($gather['gabt'][$gabt],$infoVo['units']):$gather['gabt'][$gabt]):0; + //仓库|商品|属性|批次|生产日期 + foreach ($column as $columnVo) { + $wgabt=md5_16($columnVo['id'].'&'.$infoVo['id'].'&'.$selectVo['attr'].'&'.$subVo['id'].'&'.$subVo['time']); + $tag['stock_'.$columnVo['id']]=isset($gather['wgabt'][$wgabt])?($infoVo['unit']=='-1'?unitSwitch($gather['wgabt'][$wgabt],$infoVo['units']):$gather['wgabt'][$wgabt]):0; + } + $tag['key']=$gabt; + $row['attr'][]=$tag; + } + } + $row['key']=$gab; + $info[$infoKey]['attr'][$attrKey]['attr'][]=$row; + } + if(empty($select))unset($info[$infoKey]['attr'][$attrKey]); + } + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info, + 'column'=>$column + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + existFull($input,['warehouse'])||$input['warehouse']=[]; + if(isset($input['warehouse']) && is_array($input['warehouse']) && isset($input['state']) && in_array($input['state'],[0,1])){ + pushLog('导出批次列表');//日志 + //匹配仓库 + $warehouse = Db::name('warehouse')->where(empty($input['warehouse'])?sqlAuth('warehouse',[]):[['id','in',explode(',',$input['warehouse'])]])->order(['id'=>'desc'])->select()->toArray(); + //构造表头 + $column=[]; + foreach ($warehouse as $warehouseVo) { + $column['stock_'.$warehouseVo['id']]=$warehouseVo['name']; + } + //匹配商品 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'], + ['spec','fullLike'], + ['brand','fullEq'], + ['code','fullLike'] + ]);//构造SQL + //商品类型 + $sql[]=['type','=',0]; + //辅助属性扩展查询 + $sqlOr=existFull($input,['code'])?[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]:[]; + //商品分类树结构查询 + existFull($input,['category'])&&$sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + //批次查询 + $batchSql=fastSql($input,[ + [['batch'=>'number'],'fullLike'], + ['time','fullTime'] + ]);//构造SQL + $batchSql[]=['warehouse','in',array_column($warehouse,'id')]; + //查询操作-批次类型 + if(empty($input['state'])){ + $batch=Db::name('batch')->where($batchSql)->select()->toArray(); + }else{ + $batchSql[]=['time','<>',0]; + $batch=Db::name('batch')->alias('a')->join('goods b','a.goods = b.id')->where($batchSql)->whereRaw('a.time + (b.threshold * 86400) < :time',['time'=>strtotime(date('Y-m-d',time()))])->field('a.*')->select()->toArray(); + } + //查询商品 + $sql[]=['id','in',array_column($batch,'goods')]; + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //属性处理 + foreach ($info as $infoKey=>$infoVo) { + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //属性处理 + if(existFull($input,['code']) && !in_array($input['code'],[$infoVo['code'],$attrVo['code']])){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + + //库存集合[w:仓库|g:商品|a:属性|b:批次|t:生产日期] + $gather=['g'=>[],'wg'=>[],'ga'=>[],'wga'=>[],'gb'=>[],'wgb'=>[],'gbt'=>[],'wgbt'=>[],'gab'=>[],'wgab'=>[],'gabt'=>[],'wgabt'=>[]]; + //查询库存数据-仓储 + $room=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['goods','in',array_column($info,'id')]])->select()->toArray(); + //构造库存数据 + foreach ($room as $roomVo) { + //商品 + $g=md5_16($roomVo['goods']); + $gather['g'][$g]=math()->chain($gather['g'][$g]??0)->add($roomVo['nums'])->done(); + //仓库|商品 + $wg=md5_16($roomVo['warehouse'].'&'.$roomVo['goods']); + $gather['wg'][$wg]=math()->chain($gather['wg'][$wg]??0)->add($roomVo['nums'])->done(); + //判断属性 + if(!empty($roomVo['attr'])){ + //商品|属性 + $ga=md5_16($roomVo['goods'].'&'.$roomVo['attr']); + $gather['ga'][$ga]=math()->chain($gather['ga'][$ga]??0)->add($roomVo['nums'])->done(); + //仓库|商品|属性 + $wga=md5_16($roomVo['warehouse'].'&'.$roomVo['goods'].'&'.$roomVo['attr']); + $gather['wga'][$wga]=math()->chain($gather['wga'][$wga]??0)->add($roomVo['nums'])->done(); + } + } + + //构造库存数据-批次 + foreach ($batch as $batchKey=>$batchVo) { + //商品|批次 + $gb=md5_16($batchVo['goods'].'&'.$batchVo['number']); + $gather['gb'][$gb]=math()->chain($gather['gb'][$gb]??0)->add($batchVo['nums'])->done(); + //仓库|商品|批次 + $wgb=md5_16($batchVo['warehouse'].'&'.$batchVo['goods'].'&'.$batchVo['number']); + $gather['wgb'][$wgb]=math()->chain($gather['wgb'][$wgb]??0)->add($batchVo['nums'])->done(); + + //匹配辅助属性 + $find=search($room)->where([['id','=',$batchVo['room']]])->find(); + if(empty($find['attr'])){ + //转存数据 + $batch[$batchKey]['attr']=null; + //生产日期 + if(!empty($batchVo['time'])){ + //商品|批次|生产日期 + $gbt=md5_16($batchVo['goods'].'&'.$batchVo['id'].'&'.$batchVo['time']); + $gather['gbt'][$gbt]=math()->chain($gather['gbt'][$gbt]??0)->add($batchVo['nums'])->done(); + //仓库|商品|批次|生产日期 + $wgbt=md5_16($batchVo['warehouse'].'&'.$batchVo['goods'].'&'.$batchVo['id'].'&'.$batchVo['time']); + $gather['wgbt'][$wgbt]=math()->chain($gather['wgbt'][$wgbt]??0)->add($batchVo['nums'])->done(); + } + }else{ + //转存数据 + $batch[$batchKey]['attr']=$find['attr']; + //商品|属性|批次 + $gab=md5_16($batchVo['goods'].'&'.$find['attr'].'&'.$batchVo['number']); + $gather['gab'][$gab]=math()->chain($gather['gab'][$gab]??0)->add($batchVo['nums'])->done(); + //仓库|商品|属性|批次 + $wgab=md5_16($batchVo['warehouse'].'&'.$batchVo['goods'].'&'.$find['attr'].'&'.$batchVo['number']); + $gather['wgab'][$wgab]=math()->chain($gather['wgab'][$wgab]??0)->add($batchVo['nums'])->done(); + //生产日期 + if(!empty($batchVo['time'])){ + //商品|属性|批次|生产日期 + $gabt=md5_16($batchVo['goods'].'&'.$find['attr'].'&'.$batchVo['id'].'&'.$batchVo['time']); + $gather['gabt'][$gabt]=math()->chain($gather['gabt'][$gabt]??0)->add($batchVo['nums'])->done(); + //仓库|商品|属性|批次|生产日期 + $wgabt=md5_16($batchVo['warehouse'].'&'.$batchVo['goods'].'&'.$find['attr'].'&'.$batchVo['id'].'&'.$batchVo['time']); + $gather['wgabt'][$wgabt]=math()->chain($gather['wgabt'][$wgabt]??0)->add($batchVo['nums'])->done(); + } + } + } + //数量匹配|库存处理 + foreach ($info as $infoKey=>$infoVo) { + //商品 + $g=md5_16($infoVo['id']); + $info[$infoKey]['summary']=isset($gather['g'][$g])?($infoVo['unit']=='-1'?unitSwitch($gather['g'][$g],$infoVo['units']):$gather['g'][$g]):0; + //仓库|商品 + foreach ($warehouse as $warehouseVo) { + $wg=md5_16($warehouseVo['id'].'&'.$infoVo['id']); + $info[$infoKey]['stock_'.$warehouseVo['id']]=isset($gather['wg'][$wg])?($infoVo['unit']=='-1'?unitSwitch($gather['wg'][$wg],$infoVo['units']):$gather['wg'][$wg]):0; + } + //匹配辅助属性 + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //商品|属性 + $ga=md5_16($infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['summary']=isset($gather['ga'][$ga])?($infoVo['unit']=='-1'?unitSwitch($gather['ga'][$ga],$infoVo['units']):$gather['ga'][$ga]):0; + //仓库|商品|属性 + foreach ($warehouse as $warehouseVo) { + $wga=md5_16($warehouseVo['id'].'&'.$infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['stock_'.$warehouseVo['id']]=isset($gather['wga'][$wga])?($infoVo['unit']=='-1'?unitSwitch($gather['wga'][$wga],$infoVo['units']):$gather['wga'][$wga]):0; + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //数量匹配|批次处理 + foreach ($info as $infoKey=>$infoVo) { + //数组改造 + if(empty($infoVo['attr'])){ + $list=search($batch)->where([['goods','=',$infoVo['id']],['attr','=',null]])->select(); + //去重匹配 + foreach (assoc_unique($list,'number') as $listVo) { + $row=[ + 'name'=>$listVo['number'] + ]; + //商品|批次 + $gb=md5_16($infoVo['id'].'&'.$listVo['number']); + $row['summary']=isset($gather['gb'][$gb])?($infoVo['unit']=='-1'?unitSwitch($gather['gb'][$gb],$infoVo['units']):$gather['gb'][$gb]):0; + //仓库|商品|批次 + foreach ($warehouse as $columnVo) { + $wgb=md5_16($warehouseVo['id'].'&'.$infoVo['id'].'&'.$listVo['number']); + $row['stock_'.$warehouseVo['id']]=isset($gather['wgb'][$wgb])?($infoVo['unit']=='-1'?unitSwitch($gather['wgb'][$wgb],$infoVo['units']):$gather['wgb'][$wgb]):0; + } + //生产日期处理 + if(!empty($listVo['time'])){ + $sub=search($list)->where([['number','=',$listVo['number']]])->select(); + foreach ($sub as $subVo) { + $tag=[ + 'name'=>'-', + 'protect'=>$infoVo['protect'], + 'startTime'=>date('Y-m-d',$subVo['time']), + 'endTime'=>date('Y-m-d',$subVo['time']+($infoVo['protect']*86400)) + ]; + //商品|批次|生产日期 + $gbt=md5_16($infoVo['id'].'&'.$subVo['id'].'&'.$subVo['time']); + $tag['summary']=isset($gather['gbt'][$gbt])?($infoVo['unit']=='-1'?unitSwitch($gather['gbt'][$gbt],$infoVo['units']):$gather['gbt'][$gbt]):0; + //仓库|商品|批次|生产日期 + foreach ($warehouse as $warehouseVo) { + $wgbt=md5_16($warehouseVo['id'].'&'.$infoVo['id'].'&'.$subVo['id'].'&'.$subVo['time']); + $tag['stock_'.$warehouseVo['id']]=isset($gather['wgbt'][$wgbt])?($infoVo['unit']=='-1'?unitSwitch($gather['wgbt'][$wgbt],$infoVo['units']):$gather['wgbt'][$wgbt]):0; + } + $tag['key']=$gbt; + $row['attr'][]=$tag; + } + } + $row['key']=$gb; + $info[$infoKey]['attr'][]=$row; + } + }else{ + //匹配数据 + $list=search($batch)->where([['goods','=',$infoVo['id']],['attr','<>',null]])->select(); + //循环属性 + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + $select=search($list)->where([['attr','=',$attrVo['name']]])->select(); + //去重匹配 + foreach (assoc_unique($select,'number') as $selectVo) { + $row=[ + 'name'=>$selectVo['number'] + ]; + //商品|属性|批次 + $gab=md5_16($infoVo['id'].'&'.$selectVo['attr'].'&'.$selectVo['number']); + $row['summary']=isset($gather['gab'][$gab])?($infoVo['unit']=='-1'?unitSwitch($gather['gab'][$gab],$infoVo['units']):$gather['gab'][$gab]):0; + //仓库|商品|属性|批次 + foreach ($warehouse as $warehouseVo) { + $wgab=md5_16($warehouseVo['id'].'&'.$infoVo['id'].$selectVo['attr'].'&'.$selectVo['number']); + $row['stock_'.$warehouseVo['id']]=isset($gather['wgab'][$wgab])?($infoVo['unit']=='-1'?unitSwitch($gather['wgab'][$wgab],$infoVo['units']):$gather['wgab'][$wgab]):0; + } + //生产日期处理 + if(!empty($selectVo['time'])){ + $sub=search($list)->where([['number','=',$selectVo['number']]])->select(); + foreach ($sub as $subVo) { + $tag=[ + 'name'=>'-', + 'protect'=>$infoVo['protect'], + 'startTime'=>date('Y-m-d',$subVo['time']), + 'endTime'=>date('Y-m-d',$subVo['time']+($infoVo['protect']*86400)) + ]; + //商品|属性|批次|生产日期 + $gabt=md5_16($infoVo['id'].'&'.$selectVo['attr'].'&'.$subVo['id'].'&'.$subVo['time']); + $tag['summary']=isset($gather['gabt'][$gabt])?($infoVo['unit']=='-1'?unitSwitch($gather['gabt'][$gabt],$infoVo['units']):$gather['gabt'][$gabt]):0; + //仓库|商品|属性|批次|生产日期 + foreach ($warehouse as $warehouseVo) { + $wgabt=md5_16($warehouseVo['id'].'&'.$infoVo['id'].'&'.$selectVo['attr'].'&'.$subVo['id'].'&'.$subVo['time']); + $tag['stock_'.$warehouseVo['id']]=isset($gather['wgabt'][$wgabt])?($infoVo['unit']=='-1'?unitSwitch($gather['wgabt'][$wgabt],$infoVo['units']):$gather['wgabt'][$wgabt]):0; + } + $tag['key']=$gabt; + $row['attr'][]=$tag; + } + } + $row['key']=$gab; + $info[$infoKey]['attr'][$attrKey]['attr'][]=$row; + } + if(empty($select))unset($info[$infoKey]['attr'][$attrKey]); + } + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + } + //结构重组 + $source=[]; + foreach ($info as $infoVo) { + $source[]=$infoVo; + if(!empty($infoVo['attr'])){ + foreach ($infoVo['attr'] as $attrVo) { + $attrVo['name']='|- '.$attrVo['name']; + $source[]=$attrVo; + if(existFull($attrVo,['attr'])){ + foreach ($attrVo['attr'] as $subVo) { + $subVo['name']='|-- '.$subVo['name']; + $source[]=$subVo; + } + } + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'批次列表']; + //表格数据 + $field=array_merge(['name'=>'商品名称','summary'=>'库存数量'],$column,['protect'=>'保质期(天)','startTime'=>'生产日期','endTime'=>'过期日期','number'=>'商品编号','spec'=>'规格型号','categoryData|name'=>'商品分类','brand'=>'商品品牌','extension|unit'=>'商品单位','code'=>'商品条码','data'=>'商品备注']); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('批次列表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } + //详情列表 + public function detailRecord(){ + $input=input('post.'); + $sheet=['buy','bre','sell','sre','swapOut','swapEnter','entry','extry']; + existFull($input,['type'])||$input['type']=$sheet; + if(existFull($input,['page','limit','batch','warehouse']) && is_arrays($input,['batch','warehouse','type']) && arrayInArray($input['type'],$sheet)){ + //构造SQL|batch + $sql=fastSql($input,[ + [['batch'=>'id'],'fullIn'], + ['warehouse','fullIn'] + ]); + //查询批次数据 + $batch=Db::name('batch')->where($sql)->field(['id','goods'])->select()->toArray(); + if(empty($batch)){ + $count=0; + $info=[]; + }else{ + //构造SQL|BATCHINFO + $infoSql=fastSql($input,[['type','fullIn']]); + $infoSql[]=['pid','in',array_column($batch,'id')]; + //子查询SQL + $existsSql=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['id','=',Db::raw('info.class')]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + //匹配类型|减少查询 + if(in_array($k,$input['type'])){ + $union[]=Db::name($v)->where([['info.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $count=BatchInfo::alias('info')->where($infoSql)->whereExists($union)->count(); + $info=BatchInfo::with(['sourceData'=>['frameData']])->alias('info')->where($infoSql)->whereExists($union)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //处理多单位 + if(!empty($info)){ + $goods=Db::name('goods')->where([['id','=',$batch[0]['goods']]])->find(); + if($goods['unit']=='-1'){ + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['nums']=unitSwitch($infoVo['nums'],json_decode($goods['units'],true)); + } + } + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //详情导出 + public function detailExports(){ + $input=input('get.'); + $sheet=['buy','bre','sell','sre','swapOut','swapEnter','entry','extry']; + existFull($input,['batch'])||$input['batch']=[]; + existFull($input,['type'])||$input['type']=$sheet; + if(existFull($input,['batch','warehouse']) && is_arrays($input,['batch','warehouse','type']) && arrayInArray($input['type'],$sheet)){ + pushLog('导出批次详情');//日志 + //构造SQL|batch + $sql=fastSql($input,[ + [['batch'=>'id'],'fullIn'], + ['warehouse','fullIn'] + ]); + //查询仓储数据 + $batch=Db::name('batch')->where($sql)->field(['id','goods','number'])->select()->toArray(); + if(empty($batch)){ + $source=[]; + }else{ + //构造SQL|BATCHINFO + $infoSql=fastSql($input,[['type','fullIn']]); + $infoSql[]=['pid','in',array_column($batch,'id')]; + //子查询SQL + $existsSql=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['id','=',Db::raw('info.class')]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + //匹配类型|减少查询 + if(in_array($k,$input['type'])){ + $union[]=Db::name($v)->where([['info.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $source=BatchInfo::with(['sourceData'=>['frameData']])->alias('info')->where($infoSql)->whereExists($union)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //处理多单位 + if(!empty($source)){ + $goods=Db::name('goods')->where([['id','=',$batch[0]['goods']]])->find(); + if($goods['unit']=='-1'){ + foreach ($source as $sourceKey=>$sourceVo) { + $source[$sourceKey]['nums']=unitSwitch($sourceVo['nums'],json_decode($goods['units'],true)); + } + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'批次详情']; + //表格数据 + $field=[ + 'sourceData|frameData|name'=>'所属组织', + 'sourceData|time'=>'操作时间', + 'extension|type'=>'单据类型', + 'sourceData|number'=>'单据编号', + 'extension|direction'=>'操作类型', + 'nums'=>'操作数量' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('批次详情',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Bill.php b/serve/app/controller/Bill.php new file mode 100644 index 0000000..ecc783d --- /dev/null +++ b/serve/app/controller/Bill.php @@ -0,0 +1,381 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['user','fullEq'], + ['examine','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('bill',$sql);//数据鉴权 + $count = Bills::where($sql)->count();//获取总条数 + $info = Bills::with(['frameData','customerData','supplierData','userData','peopleData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['examine']=0; + empty($class['id'])?$this->validate($class,'app\validate\Bill'):$this->validate($class,'app\validate\Bill.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\BillInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'单据数据第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Bills::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'bill','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增核销单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Bills::update($class); + Db::name('record')->insert(['type'=>'bill','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新核销单[ '.$class['number'].' ]');//日志 + } + //INFO数据 + BillInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new BillInfo; + $model->saveAll($input['info']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Bills::where([['id','=',$input['parm']]])->find(); + $info=BillInfo::with(['sourceData'])->where([['pid','=',$input['parm']]])->append(['extension'])->order(['id'=>'asc'])->select()->each(function($item){ + $item->sourceData->append(['extension']); + })->toArray(); + //数据处理 + foreach ($info as $key=>$vo) { + in_array($vo['mold'],['buy','bre','sell','sre','ice','oce'])&&$info[$key]['sourceData']['total']=$vo['sourceData']['actual']; + } + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //关联验证 + $data=Db::name('bill')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('bill')->where([['id','in',$input['parm']]])->delete(); + Db::name('bill_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','bill'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除核销单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('bill')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=BillInfo::with(['sourceData'])->where([['pid','=',$parmVo]])->append(['extension'])->order(['id'=>'asc'])->select()->each(function($item){ + $item->sourceData->append(['extension']); + })->toArray(); + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + //3 INFO验证 + foreach ($info as $infoKey=>$infoVo) { + //场景验证 + if(empty($class['examine'])){ + //核销金额验证 + $anwo=$infoVo['sourceData']['extension']['anwo']; + if(bccomp(abs($infoVo['money']),abs($anwo))==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行可核销金额不足!']); + exit; + } + } + } + //4 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + + //1 数据处理 + foreach ($info as $infoVo){ + $mold=$infoVo['mold']; + $money=in_array($infoVo['mold'],['bre','sre'])?abs($infoVo['money']):$infoVo['money']; + //1.1 添加核销记录 + Db::name($mold.'_bill')->insert([ + 'pid'=>$infoVo['source'], + 'type'=>'bill', + 'source'=>$class['id'], + 'time'=>$class['time'], + 'money'=>$money + ]); + //1.2 读取核销状态 + $sum=Db::name($mold.'_bill')->where(['pid'=>$infoVo['source']])->sum('money'); + $total=in_array($infoVo['mold'],['buy','bre','sell','sre','ice','oce'])?$infoVo['sourceData']['actual']:$infoVo['sourceData']['total']; + $nucleus=bccomp($sum,$total)==0?2:1; + //1.3 更新核销状态 + Db::name($mold)->where([['id','=',$infoVo['source']]])->update(['nucleus'=>$nucleus]); + } + //2 更新单据 + Db::name('bill')->where([['id','=',$class['id']]])->update(['examine'=>1]); + //3 单据记录 + Db::name('record')->insert(['type'=>'bill','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //4 记录操作 + pushLog('审核核销单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + + //1 数据处理 + foreach ($info as $infoVo){ + $mold=$infoVo['mold']; + $money=in_array($infoVo['mold'],['bre','sre'])?abs($infoVo['money']):$infoVo['money']; + //1.1 删除核销记录 + Db::name($mold.'_bill')->where([ + ['pid','=',$infoVo['source']], + ['type','=','bill'], + ['source','=',$class['id']] + ])->delete(); + //1.2 读取核销状态 + $sum=Db::name($mold.'_bill')->where(['pid'=>$infoVo['source']])->sum('money'); + $nucleus=empty($sum)?0:1; + //1.3 更新核销状态 + Db::name($mold)->where([['id','=',$infoVo['source']]])->update(['nucleus'=>$nucleus]); + } + //2 更新单据 + Db::name('bill')->where([['id','=',$class['id']]])->update(['examine'=>0]); + //3 单据记录 + Db::name('record')->insert(['type'=>'bill','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //11 记录操作 + pushLog('反审核核销单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('bill', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出核销单列表');//日志 + $source=Bills::with(['frameData','customerData','supplierData','userData','peopleData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'核销单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'supplierData|name'=>'供应商', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'extension|type'=>'核销类型', + 'pmy'=>'核销金额', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总核销金额:'.mathArraySum(array_column($source,'pmy')), + ]]; + //导出execl + buildExcel('核销单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'核销单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '客户:'.arraySeek($sourceVo,'customerData|name'), + '供应商:'.arraySeek($sourceVo,'supplierData|name'), + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'extension|bill'=>'核销类型', + 'extension|mold'=>'单据类型', + 'sourceData|time'=>'单据日期', + 'sourceData|number'=>'单据编号', + 'sourceData|total'=>'单据金额', + 'sourceData|extension|amount'=>'已核销', + 'sourceData|extension|anwo'=>'未核销', + 'money'=>'核销金额' + ]; + //构造表内数据 + $info=BillInfo::with(['sourceData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->append(['extension'])->select()->each(function($item){ + $item->sourceData->append(['extension']); + })->toArray(); + //数据处理 + foreach ($info as $key=>$vo) { + in_array($vo['mold'],['buy','bre','sell','sre','ice','oce'])&&$info[$key]['sourceData']['total']=$vo['sourceData']['actual']; + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '核销类型:'.arraySeek($sourceVo,'extension|type'), + '核销金额:'.$sourceVo['pmy'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + + } + buildZip('核销单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Bor.php b/serve/app/controller/Bor.php new file mode 100644 index 0000000..63ec638 --- /dev/null +++ b/serve/app/controller/Bor.php @@ -0,0 +1,633 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['startArrival'=>'arrival'],'startTime'], + [['endArrival'=>'arrival'],'endTime'], + ['user','fullEq'], + ['examine','fullDec1'], + ['state','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['id','in',array_column(Db::name('bor_info')->where([['goods','in',$goods]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('bor',$sql);//数据鉴权 + $count = Bors::where($sql)->count();//获取总条数 + $info = Bors::with(['frameData','supplierData','peopleData','userData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + //关联单据 + if(!empty($info)){ + $sor=Db::name('sor')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + $buy=Db::name('buy')->where([['source','in',array_column($info,'id')]])->select()->toArray(); + foreach ($info as $infoKey=>$infoVo) { + //销售订单 + $sorData=array_map(function($item){ + return ['type'=>'销售订单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'sor','id'=>$item['id']]; + },search($sor)->where([['id','=',$infoVo['source']]])->select()); + //采购单 + $buyData=array_map(function($item){ + return ['type'=>'采购单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'buy','id'=>$item['id']]; + },search($buy)->where([['source','=',$infoVo['id']]])->select()); + //合并排序 + $merge=array_merge($sorData,$buyData); + array_multisort(array_column($merge,'sort'),SORT_DESC,$merge); + $info[$infoKey]['relation']=$merge; + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['examine']=0; + empty($class['id'])?$this->validate($class,'app\validate\Bor'):$this->validate($class,'app\validate\Bor.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\BorInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'商品信息第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Bors::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'bor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增采购订单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Bors::update($class); + Db::name('record')->insert(['type'=>'bor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新采购订单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + BorInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + $input['info'][$infoKey]['handle']=0;//初始|入库数量 + } + $model = new BorInfo; + $model->saveAll($input['info']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Bors::where([['id','=',$input['parm']]])->find(); + $info=BorInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //关联验证 + $exist=moreTableFind([['table'=>'buy','where'=>[['source','in',$input['parm']]]]]); + if($exist){ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + }else{ + $data=Db::name('bor')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('bor')->where([['id','in',$input['parm']]])->delete(); + Db::name('bor_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','bor'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除采购订单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('bor')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + //2 综合处理 + foreach ($classList as $class) { + //1 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(!empty($class['examine'])){ + //采购单 + $buy=Db::name('buy')->where([['source','=',$class['id']]])->find(); + if(!empty($buy)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该订单存在关联采购单!']); + exit; + } + } + //2 数据处理 + Db::startTrans(); + try { + //场景判断 + if(empty($class['examine'])){ + //审核 + Db::name('bor')->where([['id','=',$class['id']]])->update(['examine'=>1]); + Db::name('record')->insert(['type'=>'bor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + pushLog('审核采购订单[ '.$class['number'].' ]');//日志 + }else{ + //反审核 + Db::name('bor')->where([['id','=',$class['id']]])->update(['examine'=>0]); + Db::name('record')->insert(['type'=>'bor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + pushLog('反审核采购订单[ '.$class['number'].' ]');//日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //开启|关闭 + public function update(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $period=getPeriod(); + $class=Db::name('bor')->where([['id','=',$input['id']]])->find(); + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据失败,原因:单据日期与结账日期冲突!']); + exit; + }else{ + Db::startTrans(); + try { + if($class['state']==3){ + //开启 + Db::name('bor')->where([['id','=',$class['id']]])->update(['state'=>1]); + Db::name('record')->insert(['type'=>'bor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'开启单据']); + pushLog('开启采购订单[ '.$class['number'].' ]');//日志 + }else{ + //关闭 + Db::name('bor')->where([['id','=',$class['id']]])->update(['state'=>3]); + Db::name('record')->insert(['type'=>'bor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'关闭单据']); + pushLog('关闭采购订单[ '.$class['number'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return empty($parm)?json($result):$result; + } + //生成采购单 + public function buildBuy(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //源数据 + $source=[ + 'class'=>Bors::where([['id','=',$input['id']]])->find(), + 'info'=>BorInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['id']]])->order(['id'=>'asc'])->select()->toArray() + ]; + //状态验证 + if($source['class']['state']!=2){ + //CLASS数据 + $class=[ + 'source'=>$source['class']['id'], + 'supplier'=>$source['class']['supplier'], + 'total'=>0 + ]; + //INFO数据 + $info=[]; + $fun=getSys('fun'); + foreach ($source['info'] as $infoVo) { + //判断入库状态 + if(bccomp($infoVo['nums'],$infoVo['handle'])==1){ + $infoVo['source']=$infoVo['id']; + $infoVo['serial']=[]; + $infoVo['batch']=''; + $infoVo['mfd']=''; + $infoVo['retreat']=0; + //重算价格 + $infoVo['nums']=math()->chain($infoVo['nums'])->sub($infoVo['handle'])->done(); + $storage=math()->chain($infoVo['price'])->mul($infoVo['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($infoVo['discount']==0){ + $infoVo['total']=$storage; + }else{ + $infoVo['dsc']=math()->chain($storage)->div(100)->mul($infoVo['discount'])->round($fun['digit']['money'])->done(); + $infoVo['total']=math()->chain($storage)->sub($infoVo['dsc'])->done(); + } + //税额|价税合计 + if($infoVo['tax']==0){ + $infoVo['tpt']=$infoVo['total']; + }else{ + $infoVo['tat']=math()->chain($infoVo['total'])->div(100)->mul($infoVo['tax'])->round(2)->done(); + $infoVo['tpt']=math()->chain($infoVo['total'])->add($infoVo['tat'])->done(); + } + //转存数据 + $info[]=$infoVo; + $class['total']=math()->chain($class['total'])->add($infoVo['tpt'])->done();//累加单据金额 + } + } + $result=['state'=>'success','info'=>['class'=>$class,'info'=>$info]]; + }else{ + $result=['state'=>'warning','info'=>'操作失败,订单状态为已入库!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('bor', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state'=>'error','info'=>$e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + $supplier=Db::name('supplier')->where([['name','=',$data[3]['A']]])->find(); + if(empty($supplier)){ + throw new ValidateException('供应商[ '.$data[3]['A'].' ]未匹配!'); + } + //关联人员匹配 + if(empty($data[3]['F'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['F']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['F'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'supplier'=>$supplier['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'actual'=>$data[3]['E'], + 'people'=>$people['id'], + 'arrival'=>$data[3]['G'], + 'logistics'=>["key"=>"auto","name"=>"自动识别","number"=>$data[3]['H']], + 'file'=>[], + 'data'=>$data[3]['I'], + 'more'=>[], + 'examine'=>0, + 'state'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Bor');//数据合法性验证 + //初始化INFO + $info=[]; + $goods=Goods::with(['attr'])->where([['name','in',array_column($data,'J')]])->select()->toArray(); + $warehouse=Db::name('warehouse')->where([['name','in',array_column($data,'M')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'goods'=>$dataVo['J'], + 'attr'=>$dataVo['K'], + 'unit'=>$dataVo['L'], + 'warehouse'=>$dataVo['M'], + 'price'=>$dataVo['N'], + 'nums'=>$dataVo['O'], + 'discount'=>$dataVo['P'], + 'dsc'=>0, + 'total'=>0, + 'tax'=>$dataVo['S'], + 'tat'=>0, + 'tpt'=>0, + 'data'=>$dataVo['V'], + 'handle'=>0, + ]; + //商品匹配 + $goodsFind=search($goods)->where([['name','=',$record['goods']]])->find(); + if(empty($goodsFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行商品名称[ '.$record['goods'].' ]未匹配!'); + }else{ + $record['goods']=$goodsFind['id']; + } + //辅助属性匹配 + if(empty($goodsFind['attr'])){ + $record['attr']=''; + }else{ + if(empty($record['attr'])){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性不可为空!'); + }else{ + $attrFind=search($goodsFind['attr'])->where([['name','=',$record['attr']]])->find(); + if(empty($attrFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性[ '.$record['attr'].' ]未匹配!'); + } + } + } + //单位匹配 + if($goodsFind['unit']==-1){ + if(empty($record['unit'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单位不可为空!'); + }else{ + $unitFind=search($goodsFind['units'])->where([['name','=',$record['unit']]])->find(); + if(empty($unitFind) && $goodsFind['units'][0]['source']!=$record['unit']){ + throw new ValidateException('模板文件第'.$dataKey.'行单位[ '.$record['unit'].' ]未匹配!'); + } + } + }else{ + $record['unit']=$goodsFind['unit']; + } + //仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $warehouseFind=search($warehouse)->where([['name','=',$record['warehouse']]])->find(); + if(empty($warehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行仓库[ '.$record['warehouse'].' ]未匹配!'); + }else{ + $record['warehouse']=$warehouseFind['id']; + } + }else{ + //服务产品 + $record['warehouse']=null; + } + //单价匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['price'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单价不正确!'); + } + //数量匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['nums']."})?$/",$record['nums'])){ + throw new ValidateException('模板文件第'.$dataKey.'行数量不正确!'); + } + try{ + $this->validate($record,'app\validate\BorInfo');//数据合法性验证 + $storage=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($record['discount']==0){ + $record['total']=$storage; + }else{ + $record['dsc']=math()->chain($storage)->div(100)->mul($record['discount'])->round($fun['digit']['money'])->done(); + $record['total']=math()->chain($storage)->sub($record['dsc'])->done(); + } + //税额|价税合计 + if($record['tax']==0){ + $record['tpt']=$record['total']; + }else{ + + $record['tat']=math()->chain($record['total'])->div(100)->mul($record['tax'])->round(2)->done(); + $record['tpt']=math()->chain($record['total'])->add($record['tat'])->done(); + } + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['tpt'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + //CLASS数据验证 + if(bccomp($class['total'],$class['actual'])==-1){ + throw new ValidateException('实际金额不可大于单据金额[ '.$class['total'].' ]!'); + }else{ + Db::startTrans(); + try { + //新增CLASS + $classData=Bors::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new BorInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'bor','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入采购订单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出采购订单列表');//日志 + $source=Bors::with(['frameData','supplierData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购订单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'supplierData|name'=>'供应商', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'actual'=>'实际金额', + 'arrival'=>'到货日期', + 'extension|examine'=>'审核状态', + 'extension|state'=>'入库状态', + 'peopleData|name'=>'关联人员', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>['总数:'.count($source),'总单据金额:'.mathArraySum(array_column($source,'total')),'总实际金额:'.mathArraySum(array_column($source,'actual'))]]; + //导出execl + buildExcel('采购订单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购订单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '供应商:'.$sourceVo['supplierData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'goodsData|spec'=>'规格型号', + 'attr'=>'辅助属性', + 'unit'=>'单位', + 'warehouseData|name'=>'仓库', + 'price'=>'单价', + 'nums'=>'数量', + 'handle'=>'入库数量', + 'discount'=>'折扣率', + 'dsc'=>'折扣额', + 'total'=>'金额', + 'tax'=>'税率', + 'tat'=>'税额', + 'tpt'=>'价税合计', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=BorInfo::with(['goodsData','warehouseData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->select()->toArray(); + //税金匹配 + $fun=getSys('fun'); + if(empty(search($info)->where([['tax','<>',0]])->find()) && !$fun['tax']){ + unset($field['tax']); + unset($field['tat']); + unset($field['tpt']); + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '实际金额:'.$sourceVo['actual'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '到货日期:'.$sourceVo['arrival'], + '物流信息:'.$sourceVo['extension']['logistics'], + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + } + buildZip('采购订单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} diff --git a/serve/app/controller/Bre.php b/serve/app/controller/Bre.php new file mode 100644 index 0000000..d661ee4 --- /dev/null +++ b/serve/app/controller/Bre.php @@ -0,0 +1,1225 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['examine','fullDec1'], + ['nucleus','fullDec1'], + ['cse','fullDec1'], + ['invoice','fullDec1'], + ['check','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['id','in',array_column(Db::name('bre_info')->where([['goods','in',$goods]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('bre',$sql);//数据鉴权 + $count = Bres::where($sql)->count();//获取总条数 + $info = Bres::with(['frameData','supplierData','peopleData','userData','billData','costData','invoiceData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + //关联单据 + if(!empty($info)){ + $buy=Db::name('buy')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + foreach ($info as $infoKey=>$infoVo) { + //采购单 + $relation=array_map(function($item){ + return ['type'=>'采购单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'buy','id'=>$item['id']]; + },search($buy)->where([['id','=',$infoVo['source']]])->select()); + //数据排序 + array_multisort(array_column($relation,'sort'),SORT_DESC,$relation); + $info[$infoKey]['relation']=$relation; + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id']) && isset($input['cost'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['cse']=empty($class['cost'])?3:0; + $class['invoice']=empty($class['actual'])?3:0; + $class['examine']=0; + $class['nucleus']=0; + empty($class['id'])?$this->validate($class,'app\validate\Bre'):$this->validate($class,'app\validate\Bre.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\BreInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'商品信息第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //验证Cost + foreach ($input['cost'] as $costKey=>$costVo) { + try { + $this->validate($costVo,'app\validate\Cost'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'单据费用第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Bres::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'bre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增采购退货单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Bres::update($class); + Db::name('record')->insert(['type'=>'bre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新采购退货单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + BreInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new BreInfo; + $model->saveAll($input['info']); + + //COST数据 + Cost::where([['type','=','bre'],['class','=',$class['id']]])->delete(); + foreach ($input['cost'] as $costKey=>$costVo) { + unset($input['cost'][$costKey]['id']); + $input['cost'][$costKey]['type']='bre'; + $input['cost'][$costKey]['class']=$class['id']; + $input['cost'][$costKey]['time']=$class['time']; + $input['cost'][$costKey]['settle']=0; + $input['cost'][$costKey]['state']=0; + } + $model = new Cost; + $model->saveAll($input['cost']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Bres::where([['id','=',$input['parm']]])->find(); + $info=BreInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $cost=Cost::where([['type','=','bre'],['class','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + 'cost'=>$cost, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('bre')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('bre')->where([['id','in',$input['parm']]])->delete(); + Db::name('bre_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('cost')->where([['type','=','bre'],['class','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','bre'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除采购退货单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //核对|反核对 + public function check(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $period=getPeriod(); + $classList=Db::name('bre')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + foreach ($input['parm'] as $parmVo) { + $class=search($classList)->where([['id','=',$parmVo]])->find(); + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(empty($class['check'])){ + Db::name('bre')->where([['id','=',$class['id']]])->update(['check'=>1]); + //1 单据记录 + Db::name('record')->insert(['type'=>'bre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'核对单据']); + //2 记录操作 + pushLog('核对采购退货单[ '.$class['number'].' ]');//单据日志 + }else{ + Db::name('bre')->where([['id','=',$class['id']]])->update(['check'=>0]); + //1 单据记录 + Db::name('record')->insert(['type'=>'bre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反核对单据']); + //2 记录操作 + pushLog('反核对采购退货单[ '.$class['number'].' ]');//单据日志 + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $fun=getSys('fun'); + $period=getPeriod(); + $classList=Db::name('bre')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('bre_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //1.1 商品数据 + $goodsList=Db::name('goods')->where([['id','in',array_unique(array_column($info,'goods'))]])->select()->toArray(); + //1.2 综合匹配 + if(empty($class['examine'])){ + //1 关联单据 + empty($class['source'])||$buyInfoList=Db::name('buy_info')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + //2 构造数据 + $batchGather=[]; + $serialGather=[]; + $roomWhereOrSql=[]; + foreach ($info as $infoVo) { + //1 批次号 + empty($infoVo['batch'])||$batchGather[]=$infoVo['batch']; + //2 序列号 + $serialGather=array_merge($serialGather,json_decode($infoVo['serial'])); + //3 仓储条件 + empty($infoVo['warehouse'])||$roomWhereOrSql[]=[['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]]; + } + //3 匹配数据 + empty($batchGather)||$batchList=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + empty($serialGather)||$serialList=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + if(!empty($roomWhereOrSql)){ + //1 去重转存 + $roomWhereOrSql=array_unique($roomWhereOrSql,SORT_REGULAR); + //2 仓储匹配 + $roomList=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + } + } + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(!empty($class['examine'])){ + //1 核销单 + $bill=Db::name('bill_info')->where([['mold','=','bre'],['source','=',$class['id']]])->find(); + if(!empty($bill)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联核销单!']); + exit; + } + //2 单据费用 + $cost=Db::name('cost')->alias('cost')->where([['type','=','bre'],['class','=',$class['id']]])->whereExists(function($query){ + $query->name('oce_info')->where([['source','=',Db::raw('cost.id')]])->limit(1); + })->find(); + if(!empty($cost)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联其它支出单!']); + exit; + } + //3 单据发票 + $invoice=Db::name('invoice')->where([['type','=','bre'],['class','=',$class['id']]])->find(); + if(!empty($invoice)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联单据发票!']); + exit; + } + } + //3 INFO验证|构造 + foreach ($info as $infoKey=>$infoVo) { + //1 匹配商品 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + //2 商品类型 + if(empty($goods['type'])){ + //场景验证 + if(empty($class['examine'])){ + //1 匹配数据 + $room=search($roomList)->where([['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]],true)->find(); + (empty($room)||empty($infoVo['batch']))||$batch=search($batchList)->where([['room','=',$room['id']],['number','=',$infoVo['batch']],['time','=',$infoVo['mfd']]],true)->find(); + //2 关联单据 + if(!empty($infoVo['source'])){ + $buyInfo=search($buyInfoList)->where([['id','=',$infoVo['source']]])->find(); + if(!empty($buyInfo)){ + if($buyInfo['unit']!=$infoVo['unit']){ + //单位匹配 + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行单位与采购单不匹配!']); + exit; + }elseif(bccomp(math()->chain($buyInfo['retreat'])->add($infoVo['nums'])->done(),$buyInfo['nums'])==1){ + //数量匹配 + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行超出采购单可退货数量!']); + exit; + } + } + + } + //3 多单位处理 + if($goods['unit']==-1){ + //多单位|转存 + $radix=unitRadix($infoVo['unit'],json_decode($goods['units'],true)); + $info[$infoKey]['basic']=[ + 'nums'=>math()->chain($infoVo['nums'])->mul($radix)->done(), + 'price'=>math()->chain($infoVo['price'])->div($radix)->round(4)->done() + ]; + }else{ + //常规单位|转存 + $info[$infoKey]['basic']=[ + 'nums'=>$infoVo['nums'], + 'price'=>$infoVo['price'] + ]; + } + //4 序列号 + $serialData=json_decode($infoVo['serial']); + if(empty($serialData)){ + $info[$infoKey]['serial']=[]; + }else{ + //序列号状态[不存在|未销售] + $serialCollect=search($serialList)->where([['goods','=',$infoVo['goods']],['number','in',$serialData]])->select(); + foreach ($serialCollect as $serialCollectVo) { + if($serialCollectVo['state']==0){ + if(empty($room) || $room['id']!=$serialCollectVo['room']){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]与仓库不匹配!']); + exit; + } + if((empty($infoVo['batch'])&&!empty($serialCollectVo['batch']))||(!empty($infoVo['batch'])&&(empty($batch)||$batch['id']!=$serialCollectVo['batch']))){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]与批次不匹配!']); + exit; + } + }else{ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]状态不正确!']); + exit; + } + } + $info[$infoKey]['serial']=$serialData; + } + //5 负库存验证 + if($fun['overflow']==false){ + //1 仓储验证 + if(empty($room)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行仓储信息不存在!']); + exit; + }else{ + if(bccomp($info[$infoKey]['basic']['nums'],$room['nums'])==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行仓储库存不足!']); + exit; + }else{ + $roomList[$room['rowKey']]['nums']=math()->chain($room['nums'])->sub($info[$infoKey]['basic']['nums'])->done(); + } + } + //2 批次验证 + if(!empty($infoVo['batch'])){ + if(empty($batch)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行批次信息无效!']); + exit; + }else{ + if(bccomp($info[$infoKey]['basic']['nums'],$batch['nums'])==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行批次库存不足!']); + exit; + }else{ + $batchList[$batch['rowKey']]['nums']=math()->chain($batch['nums'])->sub($info[$infoKey]['basic']['nums'])->done(); + } + } + } + //3 序列号验证 + if(!empty($serialData)){ + $serialCount=search($serialList)->where([['room','=',$room['id']],['number','in',$serialData]])->count(); + if($serialCount != count($serialData)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行存在无效序列号!']); + exit; + } + } + } + }else{ + //1 验证序列号 + $serialInfoCollect=Db::name('serial_info')->where([['type','=','bre'],['info','in',array_column($info,'id')]])->select()->toArray(); + if(!empty($serialInfoCollect)){ + //序列号状态[已退货] + $serialFind=Db::name('serial')->where([['id','in',array_column($serialInfoCollect,'pid')],['state','<>',3]])->find(); + if(!empty($serialFind)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + } + } + } + //4 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $store=['buyInfo'=>[],'room'=>[],'roomInfo'=>[],'batch'=>[],'batchInfo'=>[],'serial'=>[],'serialInfo'=>[],'serve'=>[],'serveInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //1 关联单据 + empty($infoVo['source'])||$store['buyInfo'][]=['id'=>$infoVo['source'],'retreat'=>$infoVo['nums']]; + //2 判断商品类型 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + if(empty($goods['type'])){ + //常规商品 + //1 仓储 + $store['room'][]=['warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['basic']['nums']]; + //2 仓储详情 + $store['roomInfo'][]=['pid'=>null,'type'=>'bre','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'direction'=>0,'price'=>$infoVo['basic']['price'],'nums'=>$infoVo['basic']['nums']]; + //3 批次号 + if(empty($infoVo['batch'])){ + $store['batch'][]=[]; + $store['batchInfo'][]=[]; + }else{ + $store['batch'][]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'number'=>$infoVo['batch'],'time'=>$infoVo['mfd'],'nums'=>$infoVo['basic']['nums']]; + $store['batchInfo'][]=['pid'=>null,'type'=>'bre','class'=>$class['id'],'info'=>$infoVo['id'],'direction'=>0,'nums'=>$infoVo['basic']['nums']]; + } + //4 序列号 + if(empty($infoVo['serial'])){ + $store['serial'][]=[]; + $store['serialInfo'][]=[]; + }else{ + $serial=[]; + $serialInfo=[]; + foreach ($infoVo['serial'] as $serialVo) { + $serial[]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'batch'=>null,'goods'=>$infoVo['goods'],'number'=>$serialVo,'state'=>3]; + $serialInfo[]=['pid'=>null,'type'=>'bre','class'=>$class['id'],'info'=>$infoVo['id']]; + } + $store['serial'][]=$serial; + $store['serialInfo'][]=$serialInfo; + } + }else{ + //5 服务商品 + $store['serve'][]=['goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['nums']]; + $store['serveInfo'][]=['pid'=>null,'type'=>'bre','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'price'=>$infoVo['price'],'nums'=>$infoVo['nums']]; + } + } + //2 关联单据 + if(!empty($store['buyInfo'])){ + //更新详情 + Db::name('buy_info')->duplicate(['retreat'=>Db::raw('retreat + VALUES(`retreat`)')])->insertAll($store['buyInfo']); + $buyInfo=Db::name('buy_info')->where([['id','in',array_column($store['buyInfo'],'id')]])->select()->toArray(); + $borInfoDuplicate=[]; + foreach ($buyInfo as $buyVo){ + empty($buyVo['source'])||$borInfoDuplicate[]=['id'=>$buyVo['source'],'handle'=>$buyVo['retreat']]; + } + if(!empty($borInfoDuplicate)){ + //更新详情 + Db::name('bor_info')->duplicate(['handle'=>Db::raw('handle - VALUES(`handle`)')])->insertAll($borInfoDuplicate); + //2 更新销售订单CLASS + $borInfo=Db::name('bor_info')->where([['id','in',array_column($buyInfo,'source')]])->select()->toArray(); + if(array_sum(array_column($borInfo,'handle'))==0){ + $state=0; + }else{ + $state=mathArraySum(array_column($borInfo,'nums'))==mathArraySum(array_column($borInfo,'handle'))?2:1; + } + Db::name('bor')->where([['id','=',$borInfo[0]['pid']]])->update(['state'=>$state]); + } + + + } + //3 仓储 + if(!empty($store['room'])){ + //1 构造数据 + $roomInsert=[]; + foreach ($store['room'] as $roomVo) { + $roomFind=search($roomList)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + if(empty($roomFind)){ + $roomVo['nums']=0; + $roomInsert[]=$roomVo; + } + } + //2 创建数据|去重 + empty($roomInsert)||Db::name('room')->insertAll(array_unique($roomInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $roomDuplicate=[]; + $room=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + foreach ($store['room'] as $roomKey=>$roomVo) { + $roomFind=search($room)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + $store['room'][$roomKey]['id']=$roomFind['id']; + $roomDuplicate[]=['id'=>$roomFind['id'],'nums'=>$roomVo['nums']]; + } + //4 更新数据 + Db::name('room')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($roomDuplicate); + } + //4 仓储详情 + if(!empty($store['roomInfo'])){ + //1 填充数据 + foreach ($store['roomInfo'] as $roomInfoKey=>$roomInfoVo) { + $store['roomInfo'][$roomInfoKey]['pid']=$store['room'][$roomInfoKey]['id']; + } + //2 创建数据 + Db::name('room_info')->insertAll($store['roomInfo']); + } + //5 批次号 + if(!empty($store['batch'])){ + //1 构造数据 + $batchData=[]; + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $store['batch'][$batchKey]['room']=$store['room'][$batchKey]['id']; + $batchData[]=$store['batch'][$batchKey]; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchData)){ + //1 构造数据 + $batchInsert=[]; + foreach ($batchData as $batchDataKey=>$batchDataVo) { + $batchFind=search($batchList)->where([['room','=',$batchDataVo['room']],['number','=',$batchDataVo['number']],['time','=',$batchDataVo['time']]])->find(); + if(empty($batchFind)){ + $batchDataVo['nums']=0; + $batchInsert[]=$batchDataVo; + } + } + //2 创建数据|去重 + empty($batchInsert)||Db::name('batch')->insertAll(array_unique($batchInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $batchDuplicate=[]; + $batch=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $batchFind=search($batch)->where([['room','=',$batchVo['room']],['number','=',$batchVo['number']],['time','=',$batchVo['time']]])->find(); + $store['batch'][$batchKey]['id']=$batchFind['id']; + $batchDuplicate[]=['id'=>$batchFind['id'],'nums'=>$batchVo['nums']]; + } + } + //4 更新数据 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($batchDuplicate); + } + } + //6 批次号详情 + if(!empty($store['batchInfo'])){ + //1 构造数据 + $batchInfoInstall=[]; + foreach ($store['batchInfo'] as $batchInfoKey=>$batchInfoVo) { + if(!empty($batchInfoVo)){ + $batchInfoVo['pid']=$store['batch'][$batchInfoKey]['id']; + $batchInfoInstall[]=$batchInfoVo; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchInfoInstall)){ + //创建数据 + Db::name('batch_info')->insertAll($batchInfoInstall); + } + } + //7 序列号 + if(!empty($store['serial'])){ + //1 构造数据 + $serialData=[]; + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $store['serial'][$serialKey][$itemKey]['room']=$store['room'][$serialKey]['id']; + $store['serial'][$serialKey][$itemKey]['batch']=empty($store['batch'][$serialKey])?0:$store['batch'][$serialKey]['id']; + $serialData[]=$store['serial'][$serialKey][$itemKey]; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialData)){ + //1 构造数据 + $serialInsert=[]; + foreach ($serialData as $serialDataKey=>$serialDataVo) { + $serialFind=search($serialList)->where([['room','=',$serialDataVo['room']],['batch','=',$serialDataVo['batch']],['number','=',$serialDataVo['number']]])->find(); + if(empty($serialFind)){ + $serialInsert[]=$serialDataVo; + } + } + //2 创建数据 + empty($serialInsert)||Db::name('serial')->insertAll($serialInsert); + //3 匹配主键|构造更新 + $serialDuplicate=[]; + $serial=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $serialFind=search($serial)->where([['room','=',$itemVo['room']],['batch','=',$itemVo['batch']],['number','=',$itemVo['number']]])->find(); + $store['serial'][$serialKey][$itemKey]['id']=$serialFind['id']; + $serialFind['state']==0&&$serialDuplicate[]=$serialFind['id']; + } + } + } + //4 更新数据|状态变更 + empty($serialDuplicate)||Db::name('serial')->where([['id','in',$serialDuplicate]])->update(['state'=>3]); + } + } + //8 序列号详情 + if(!empty($store['serialInfo'])){ + //1 构造数据 + $serialInfoInstall=[]; + foreach ($store['serialInfo'] as $serialInfoKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $itemVo['pid']=$store['serial'][$serialInfoKey][$itemKey]['id']; + $serialInfoInstall[]=$itemVo; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialInfoInstall)){ + //创建数据 + Db::name('serial_info')->insertAll($serialInfoInstall); + } + } + //9 服务商品 + if(!empty($store['serve'])){ + //1 匹配数据|去重 + $serveWhereOrSql=array_unique(array_map(function($item){ + return [['goods','=',$item['goods']],['attr','=',$item['attr']]]; + },$store['serve']),SORT_REGULAR); + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + //2 构造数据 + $serveInsert=[]; + foreach ($store['serve'] as $serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + if(empty($serveFind)){ + $serveVo['nums']=0; + $serveInsert[]=$serveVo; + } + } + //3 创建数据|去重 + empty($serveInsert)||Db::name('serve')->insertAll(array_unique($serveInsert,SORT_REGULAR)); + //4 匹配主键|构造更新 + $serveDuplicate=[]; + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + foreach ($store['serve'] as $serveKey=>$serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + $store['serve'][$serveKey]['id']=$serveFind['id']; + $serveDuplicate[]=['id'=>$serveFind['id'],'nums'=>$serveVo['nums']]; + } + //5 更新数据 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($serveDuplicate); + } + //10 服务商品详情 + if(!empty($store['serveInfo'])){ + //1 填充数据 + foreach ($store['serveInfo'] as $serveInfoKey=>$serveInfoVo) { + $store['serveInfo'][$serveInfoKey]['pid']=$store['serve'][$serveInfoKey]['id']; + } + //2 创建数据 + Db::name('serve_info')->insertAll($store['serveInfo']); + } + //11 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->inc('balance',$class['money'])->update(); + //2 创建资金详情 + Db::name('account_info')->insert([ + 'pid'=>$class['account'], + 'type'=>'bre', + 'class'=>$class['id'], + 'time'=>$class['time'], + 'direction'=>1, + 'money'=>$class['money'] + ]); + //3 创建核销记录 + Db::name('bre_bill')->insert([ + 'pid'=>$class['id'], + 'type'=>'bre', + 'source'=>$class['id'], + 'time'=>$class['time'], + 'money'=>$class['money'] + ]); + } + //12 供应商|应付款余额 + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('supplier')->where([['id','=',$class['supplier']]])->dec('balance',$balance)->update(); + } + //13 更新单据 + $nucleus=$class['money']==$class['actual']?2:($class['money']==0?0:1); + Db::name('bre')->where([['id','=',$class['id']]])->update(['examine'=>1,'nucleus'=>$nucleus]); + //14 单据记录 + Db::name('record')->insert(['type'=>'bre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //15 收发记录 + $summary=new Summary; + $summary->note('bre',$class['id'],true); + //16 记录操作 + pushLog('审核采购退货单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 匹配数据 + $listSql=[['type','=','bre'],['info','in',array_column($info,'id')]]; + $roomInfoList=Db::name('room_info')->where($listSql)->select()->toArray(); + $batchInfoList=Db::name('batch_info')->where($listSql)->select()->toArray(); + $serialInfoList=Db::name('serial_info')->where($listSql)->select()->toArray(); + $serveInfoList=Db::name('serve_info')->where($listSql)->select()->toArray(); + //2 关联单据 + if(!empty($class['source'])){ + //更新详情 + $buyInfoDuplicate=[]; + foreach ($info as $infoVo) { + empty($infoVo['source'])||$buyInfoDuplicate[]=['id'=>$infoVo['source'],'retreat'=>$infoVo['nums']]; + } + empty($buyInfoDuplicate)||Db::name('buy_info')->duplicate(['retreat'=>Db::raw('retreat - VALUES(`retreat`)')])->insertAll($buyInfoDuplicate); + //查询是否关联销售订单 + $buyInfo=Db::name('buy_info')->where([['id','in',array_column($buyInfoDuplicate,'id')]])->select()->toArray(); + $borInfoDuplicate=[]; + foreach ($buyInfo as $buyVo){ + empty($buyVo['source'])||$borInfoDuplicate[]=['id'=>$buyVo['source'],'handle'=>$infoVo['nums']]; + } + if(!empty($borInfoDuplicate)){ + //更新详情 + Db::name('bor_info')->duplicate(['handle'=>Db::raw('handle + VALUES(`handle`)')])->insertAll($borInfoDuplicate); + //2 更新采购订单CLASS + $borInfo=Db::name('bor_info')->where([['id','in',array_column($buyInfo,'source')]])->select()->toArray(); + $state=mathArraySum(array_column($borInfo,'nums'))==mathArraySum(array_column($borInfo,'handle'))?2:1; + Db::name('bor')->where([['id','=',$borInfo[0]['pid']]])->update(['state'=>$state]); + } + + } + //3 仓储 + $roomDuplicate=[]; + foreach ($roomInfoList as $roomInfoVo) { + $roomDuplicate[]=['id'=>$roomInfoVo['pid'],'nums'=>$roomInfoVo['nums']]; + } + //3.1 更新仓储 + Db::name('room')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($roomDuplicate); + //3.2 删除仓储详情 + Db::name('room_info')->where([['id','in',array_column($roomInfoList,'id')]])->delete(); + //3.3 仓储|冗余 + $roomPk=array_unique(array_column($roomInfoList,'pid')); + $roomInfoData=Db::name('room_info')->where([['pid','in',$roomPk]])->select()->toArray(); + $roomDiff=array_diff($roomPk,array_unique(array_column($roomInfoData,'pid'))); + empty($roomDiff)||Db::name('room')->where([['id','in',$roomDiff]])->delete(); + //4 批次号 + if(!empty($batchInfoList)){ + //1 构造数据 + $batchInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$batchInfoList); + //2 更新批次号 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($batchInfoDuplicate); + //3 删除批次号详情 + Db::name('batch_info')->where([['id','in',array_column($batchInfoList,'id')]])->delete(); + //4 批次号|冗余 + $batchPk=array_unique(array_column($batchInfoList,'pid')); + $batchInfoData=Db::name('batch_info')->where([['pid','in',$batchPk]])->select()->toArray(); + $batchDiff=array_diff($batchPk,array_unique(array_column($batchInfoData,'pid'))); + empty($batchDiff)||Db::name('batch')->where([['id','in',$batchDiff]])->delete(); + } + //5 序列号 + if(!empty($serialInfoList)){ + //1 更新序列号 + Db::name('serial')->where([['id','in',array_column($serialInfoList,'pid')]])->update(['state'=>0]); + //2 删除序列号详情 + Db::name('serial_info')->where([['id','in',array_column($serialInfoList,'id')]])->delete(); + //3 序列号|冗余 + $serialPk=array_unique(array_column($serialInfoList,'pid')); + $serialInfoData=Db::name('serial_info')->where([['pid','in',$serialPk]])->select()->toArray(); + $serialDiff=array_diff($serialPk,array_unique(array_column($serialInfoData,'pid'))); + empty($serialDiff)||Db::name('serial')->where([['id','in',$serialDiff]])->delete(); + } + //6 服务 + if(!empty($serveInfoList)){ + //1 构造数据 + $serveInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$serveInfoList); + //2 更新服务 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($serveInfoDuplicate); + //3 删除服务详情 + Db::name('serve_info')->where([['id','in',array_column($serveInfoList,'id')]])->delete(); + //4 服务|冗余 + $servePk=array_unique(array_column($serveInfoList,'pid')); + $serveInfoData=Db::name('serve_info')->where([['pid','in',$servePk]])->select()->toArray(); + $serveDiff=array_diff($servePk,array_unique(array_column($serveInfoData,'pid'))); + empty($serveDiff)||Db::name('serve')->where([['id','in',$serveDiff]])->delete(); + } + //7 资金|核销 + if(!empty($class['money'])){ + //6.1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->dec('balance',$class['money'])->update(); + //6.2 删除资金详情 + Db::name('account_info')->where([['type','=','bre'],['class','=',$class['id']]])->delete(); + //6.3 删除核销记录 + Db::name('bre_bill')->where([['pid','=',$class['id']]])->delete(); + } + //8 供应商|应付款余额 + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('supplier')->where([['id','=',$class['supplier']]])->inc('balance',$balance)->update(); + } + //9 更新单据 + Db::name('bre')->where([['id','=',$class['id']]])->update(['examine'=>0,'nucleus'=>0]); + //10 单据记录 + Db::name('record')->insert(['type'=>'bre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //11 收发记录 + $summary=new Summary; + $summary->note('bre',$class['id'],false); + //12 记录操作 + pushLog('反审核采购退货单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('bre', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + $supplier=Db::name('supplier')->where([['name','=',$data[3]['A']]])->find(); + if(empty($supplier)){ + throw new ValidateException('供应商[ '.$data[3]['A'].' ]未匹配!'); + } + //结算账户匹配 + if(empty($data[3]['F'])){ + $account=['id'=>0]; + }else{ + $account=Db::name('account')->where([['name','=',$data[3]['G']]])->find(); + if(empty($account)){ + throw new ValidateException('结算账户[ '.$data[3]['G'].' ]不正确!'); + } + } + //关联人员匹配 + if(empty($data[3]['H'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['H']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['H'].' ]未匹配!'); + } + } + $class=[ + 'source'=>0, + 'frame'=>userInfo(getUserID(),'frame'), + 'supplier'=>$supplier['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'actual'=>$data[3]['E'], + 'money'=>$data[3]['F'], + 'account'=>$account['id'], + 'people'=>$people['id'], + 'logistics'=>["key"=>"auto","name"=>"自动识别","number"=>$data[3]['I']], + 'file'=>[], + 'data'=>$data[3]['J'], + 'more'=>[], + 'examine'=>0, + 'nucleus'=>0, + 'cse'=>0, + 'invoice'=>0, + 'check'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Bre');//数据合法性验证 + //初始化INFO + $info=[]; + $goods=Goods::with(['attr'])->where([['name','in',array_column($data,'K')]])->select()->toArray(); + $warehouse=Db::name('warehouse')->where([['name','in',array_column($data,'N')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'source'=>0, + 'goods'=>$dataVo['K'], + 'attr'=>$dataVo['L'], + 'unit'=>$dataVo['M'], + 'warehouse'=>$dataVo['N'], + 'batch'=>$dataVo['O'], + 'mfd'=>$dataVo['P'], + 'price'=>$dataVo['Q'], + 'nums'=>$dataVo['R'], + 'serial'=>explode(',',$dataVo['S']), + 'discount'=>$dataVo['T'], + 'dsc'=>0, + 'total'=>0, + 'tax'=>$dataVo['W'], + 'tat'=>0, + 'tpt'=>0, + 'data'=>$dataVo['Z'], + ]; + //商品匹配 + $goodsFind=search($goods)->where([['name','=',$record['goods']]])->find(); + if(empty($goodsFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行商品名称[ '.$record['goods'].' ]未匹配!'); + }else{ + $record['goods']=$goodsFind['id']; + } + //辅助属性匹配 + if(empty($goodsFind['attr'])){ + $record['attr']=''; + }else{ + if(empty($record['attr'])){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性不可为空!'); + }else{ + $attrFind=search($goodsFind['attr'])->where([['name','=',$record['attr']]])->find(); + if(empty($attrFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性[ '.$record['attr'].' ]未匹配!'); + } + } + } + //单位匹配 + if($goodsFind['unit']==-1){ + if(empty($record['unit'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单位不可为空!'); + }else{ + $unitFind=search($goodsFind['units'])->where([['name','=',$record['unit']]])->find(); + if(empty($unitFind) && $goodsFind['units'][0]['source']!=$record['unit']){ + throw new ValidateException('模板文件第'.$dataKey.'行单位[ '.$record['unit'].' ]未匹配!'); + } + } + }else{ + $record['unit']=$goodsFind['unit']; + } + //仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $warehouseFind=search($warehouse)->where([['name','=',$record['warehouse']]])->find(); + if(empty($warehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行仓库[ '.$record['warehouse'].' ]未匹配!'); + }else{ + $record['warehouse']=$warehouseFind['id']; + } + }else{ + //服务产品 + $record['warehouse']=null; + } + //批次号匹配 + if(empty($goodsFind['batch'])){ + $record['batch']=''; + }else{ + if(empty($record['batch'])){ + throw new ValidateException('模板文件第'.$dataKey.'行批次号不可为空!'); + } + } + //生产日期匹配 + if(empty($goodsFind['validity'])){ + $record['mfd']=''; + }else{ + if(empty($record['mfd'])){ + throw new ValidateException('模板文件第'.$dataKey.'行生产日期不可为空!'); + } + } + //单价匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['price'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单价不正确!'); + } + //数量匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['nums']."})?$/",$record['nums'])){ + throw new ValidateException('模板文件第'.$dataKey.'行数量不正确!'); + } + //序列号匹配 + if(empty($goodsFind['serial'])){ + $record['serial']=[]; + }else{ + if(count($record['serial'])==1 && empty($record['serial'][0])){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号不可为空!'); + }else{ + if(count($record['serial'])!=$record['nums']){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号个数与数量不符!'); + } + } + } + try{ + $this->validate($record,'app\validate\BreInfo');//数据合法性验证 + $storage=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($record['discount']==0){ + $record['total']=$storage; + }else{ + $record['dsc']=math()->chain($storage)->div(100)->mul($record['discount'])->round($fun['digit']['money'])->done(); + $record['total']=math()->chain($storage)->sub($record['dsc'])->done(); + } + //税额|价税合计 + if($record['tax']==0){ + $record['tpt']=$record['total']; + }else{ + $record['tat']=math()->chain($record['total'])->div(100)->mul($record['tax'])->round(2)->done(); + $record['tpt']=math()->chain($record['total'])->add($record['tat'])->done(); + } + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['tpt'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + //序列号重复验证 + $serials=[]; + foreach ($info as $infoVo) { + $serials = array_merge($serials,$infoVo['serial']); + } + if(count($serials)!=count(array_unique($serials))){ + throw new ValidateException('商品信息中存在重复序列号!'); + } + //CLASS数据验证 + if(bccomp($class['total'],$class['actual'])==-1){ + throw new ValidateException('实际金额不可大于单据金额[ '.$class['total'].' ]!'); + }else if(bccomp($class['actual'],$class['money'])==-1){ + throw new ValidateException('实收金额不可大于实际金额[ '.floatval($class['actual']).' ]!'); + }else{ + Db::startTrans(); + try { + //新增CLASS + $classData=Bres::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new BreInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'bre','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入采购退货单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出采购退货单列表');//日志 + $source=Bres::with(['frameData','supplierData','accountData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购退货单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'supplierData|name'=>'供应商', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'actual'=>'实际金额', + 'money'=>'单据收款', + 'extension|amount'=>'核销金额', + 'cost'=>'单据费用', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|nucleus'=>'核销状态', + 'extension|cse'=>'费用状态', + 'extension|invoice'=>'发票状态', + 'extension|check'=>'核对状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据金额:'.mathArraySum(array_column($source,'total')), + '总实际金额:'.mathArraySum(array_column($source,'actual')), + '总单据收款:'.mathArraySum(array_column($source,'money')), + '总核销金额:'.mathArraySum(arrayColumns($source,['extension','amount'])), + '总单据费用:'.mathArraySum(array_column($source,'cost')) + ]]; + //导出execl + buildExcel('采购退货单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购退货单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '供应商:'.$sourceVo['supplierData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'goodsData|spec'=>'规格型号', + 'attr'=>'辅助属性', + 'unit'=>'单位', + 'warehouseData|name'=>'仓库', + 'batch'=>'批次号', + 'mfd'=>'生产日期', + 'price'=>'单价', + 'nums'=>'数量', + 'extension|serial'=>'序列号', + 'discount'=>'折扣率', + 'dsc'=>'折扣额', + 'total'=>'金额', + 'tax'=>'税率', + 'tat'=>'税额', + 'tpt'=>'价税合计', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=BreInfo::with(['goodsData','warehouseData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->append(['extension'])->select()->toArray(); + //批次号匹配 + if(empty(search($info)->where([['goodsData|batch','=',true]])->find())){ + unset($field['batch']); + } + //生产日期匹配 + if(empty(search($info)->where([['goodsData|validity','=',true]])->find())){ + unset($field['mfd']); + } + //序列号匹配 + if(empty(search($info)->where([['goodsData|serial','=',true]])->find())){ + unset($field['extension|serial']); + } + //税金匹配 + $fun=getSys('fun'); + if(empty(search($info)->where([['tax','<>',0]])->find()) && !$fun['tax']){ + unset($field['tax']); + unset($field['tat']); + unset($field['tpt']); + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '单据费用:'.$sourceVo['cost'], + '实际金额:'.$sourceVo['actual'], + '核销金额:'.$sourceVo['extension']['amount'], + '结算账户:'.arraySeek($sourceVo,'accountData|name'), + '发票信息:'.$sourceVo['invoice'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '物流信息:'.$sourceVo['extension']['logistics'], + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + + } + buildZip('采购退货单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Brt.php b/serve/app/controller/Brt.php new file mode 100644 index 0000000..2dac79c --- /dev/null +++ b/serve/app/controller/Brt.php @@ -0,0 +1,1154 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['startArrival'=>'arrival'],'startTime'], + [['endArrival'=>'arrival'],'endTime'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + $sql['class']=sqlAuth('bor',$sql['class']);//数据鉴权 + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + $sql['or']=[]; + //状态匹配 + if(existFull($input,['state'])){ + foreach ($input['state'] as $stateVo) { + $sql['or'][]=[['handle','=',0],Db::raw('handle > 0 AND handle < nums'),['handle','=',Db::raw('nums')]][$stateVo]; + } + } + //判断排序 + if(empty($input['type'])){ + //单据排序 + $record=Db::name('bor')->alias('class')->join(['is_bor_info'=>'info'],'class.id=info.pid')->where($sql['class'])->where($sql['info'])->where(function($query)use($sql){$query->whereOr($sql['or']);})->fieldRaw('class.id as class,group_concat(info.id) as info')->group('class.id')->order('class.id', 'desc')->select()->toArray(); + $data=[]; + $count=count($record); + if(!empty($record)){ + $classList = \app\model\Bor::with(['frameData','supplierData'])->where([['id','in',array_column($record,'class')]])->append(['extension'])->page($input['page'],$input['limit'])->select()->toArray(); + $infoList = \app\model\BorInfo::with(['goodsData','warehouseData'])->where([['pid','in',array_column($classList,'id')],['id','in',array_unique(explode(',',implode(',',array_column($record,'info'))))]])->select()->toArray(); + foreach ($classList as $class) { + $class['key']=$class['id']; + $class['money']=$class['actual']; + $class['nmy']=0; + $info=search($infoList)->where([['pid','=',$class['id']]])->select(); + foreach ($info as $key=>$vo) { + $info[$key]['key']=$class['id'].'_'.$vo['id']; + $info[$key]['price']=math()->chain($vo['tpt'])->div($vo['nums'])->round(2)->done(); + $info[$key]['money']=$vo['tpt']; + $info[$key]['extension']['state']=$vo['handle']==0?'未入库':($vo['handle']==$vo['nums']?'已入库':'部分入库'); + $info[$key]['nns']=math()->chain($vo['nums'])->sub($vo['handle'])->done(); + $info[$key]['nmy']=math()->chain($info[$key]['price'])->mul($info[$key]['nns'])->done(); + //汇总数据 + $class['nmy']=math()->chain($class['nmy'])->add($info[$key]['nmy'])->done(); + } + $class['node']=$info; + $data[]=$class; + } + } + }else{ + //商品排序 + $record=Db::name('bor_info')->alias('info')->join(['is_bor'=>'class'],'info.pid=class.id')->where($sql['class'])->where($sql['info'])->where(function($query)use($sql){$query->whereOr($sql['or']);})->fieldRaw('info.id as row,group_concat(info.id) as info')->group('info.goods,info.attr,info.warehouse')->order('info.id', 'desc')->select()->toArray(); + $data=[]; + $count=count($record); + if(!empty($record)){ + $record = array_slice($record,$input['limit']*($input['page']-1),$input['limit']); + $infoList = \app\model\BorInfo::with(['goodsData','warehouseData'])->where([['id','in',array_unique(explode(',',implode(',',array_column($record,'info'))))]])->select()->toArray(); + $classList = \app\model\Bor::with(['frameData','supplierData'])->where([['id','in',array_unique(array_column($infoList,'pid'))]])->append(['extension'])->select()->toArray(); + foreach ($record as $recordVo) { + $info=search($infoList)->where([['id','in',explode(',',$recordVo['info'])]])->select(); + $row=$info[0]; + $row['key']=$row['id']; + $row['unit']=''; + $row['price']=''; + $row['nums']=0; + $row['money']=0; + $row['nns']=0; + $row['nmy']=0; + foreach ($info as $vo) { + $class=search($classList)->where([['id','=',$vo['pid']]])->find(); + $class['key']=$vo['id'].'_'.$class['id']; + $class['unit']=$vo['unit']; + $class['price']=math()->chain($vo['tpt'])->div($vo['nums'])->round(2)->done(); + $class['nums']=$vo['nums']; + $class['money']=$vo['tpt']; + $class['extension']['state']=$vo['handle']==0?'未入库':($vo['handle']==$vo['nums']?'已入库':'部分入库'); + $class['nns']=math()->chain($vo['nums'])->sub($vo['handle'])->done(); + $class['nmy']=math()->chain($class['price'])->mul($class['nns'])->done(); + $class['data']=$vo['data']; + $class['basic']=['nums'=>$vo['nums'],'nns'=>$class['nns']]; + //汇总数据 + $row['money']=math()->chain($row['money'])->add($vo['tpt'])->done(); + $row['nmy']=math()->chain($row['nmy'])->add($class['nmy'])->done(); + //单位转换 + if($vo['goodsData']['unit']=='-1'){ + $radix=unitRadix($vo['unit'],$vo['goodsData']['units']); + $row['nums']=math()->chain($class['nums'])->mul($radix)->add($row['nums'])->done(); + $row['nns']=math()->chain($class['nns'])->mul($radix)->add($row['nns'])->done(); + }else{ + $row['nums']=math()->chain($class['nums'])->add($row['nums'])->done(); + $row['nns']=math()->chain($class['nns'])->add($row['nns'])->done(); + } + $row['node'][]=$class; + } + $row['extension']['state']=$row['nns']==0?'已入库':($row['nns']==$row['nums']?'未入库':'部分入库'); + //单位处理 + if($row['goodsData']['unit']=='-1'){ + $row['nums']=unitSwitch($row['nums'],$row['goodsData']['units']); + $row['nns']=unitSwitch($row['nns'],$row['goodsData']['units']); + } + $data[]=$row; + } + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //采购订单跟踪表-导出 + public function bttExports(){ + $input=input('get.'); + existFull($input,['state'])||$input['state']=[]; + existFull($input,['warehouse'])||$input['warehouse']=[]; + if(is_arrays($input,['state','warehouse']) && isset($input['type'])){ + pushLog('导出采购订单跟踪表');//日志 + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['supplier','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['startArrival'=>'arrival'],'startTime'], + [['endArrival'=>'arrival'],'endTime'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + $sql['class']=sqlAuth('bor',$sql['class']);//数据鉴权 + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + $sql['or']=[]; + //状态匹配 + if(existFull($input,['state'])){ + foreach ($input['state'] as $stateVo) { + $sql['or'][]=[['handle','=',0],Db::raw('handle > 0 AND handle < nums'),['handle','=',Db::raw('nums')]][$stateVo]; + } + } + //判断排序 + if(empty($input['type'])){ + //单据排序 + $record=Db::name('bor')->alias('class')->join(['is_bor_info'=>'info'],'class.id=info.pid')->where($sql['class'])->where($sql['info'])->where(function($query)use($sql){$query->whereOr($sql['or']);})->fieldRaw('class.id as class,group_concat(info.id) as info')->group('class.id')->order('class.id', 'desc')->select()->toArray(); + $data=[]; + $count=count($record); + if(!empty($record)){ + $classList = \app\model\Bor::with(['frameData','supplierData'])->where([['id','in',array_column($record,'class')]])->append(['extension'])->select()->toArray(); + $infoList = \app\model\BorInfo::with(['goodsData','warehouseData'])->where([['pid','in',array_column($classList,'id')],['id','in',array_unique(explode(',',implode(',',array_column($record,'info'))))]])->select()->toArray(); + foreach ($classList as $class) { + $class['key']=$class['id']; + $class['money']=$class['actual']; + $class['nmy']=0; + $info=search($infoList)->where([['pid','=',$class['id']]])->select(); + foreach ($info as $key=>$vo) { + $info[$key]['key']=$class['id'].'_'.$vo['id']; + $info[$key]['price']=math()->chain($vo['tpt'])->div($vo['nums'])->round(2)->done(); + $info[$key]['money']=$vo['tpt']; + $info[$key]['extension']['state']=$vo['handle']==0?'未入库':($vo['handle']==$vo['nums']?'已入库':'部分入库'); + $info[$key]['nns']=math()->chain($vo['nums'])->sub($vo['handle'])->done(); + $info[$key]['nmy']=math()->chain($info[$key]['price'])->mul($info[$key]['nns'])->done(); + //汇总数据 + $class['nmy']=math()->chain($class['nmy'])->add($info[$key]['nmy'])->done(); + } + $class['node']=$info; + $data[]=$class; + } + } + }else{ + //商品排序 + $record=Db::name('bor_info')->alias('info')->join(['is_bor'=>'class'],'info.pid=class.id')->where($sql['class'])->where($sql['info'])->where(function($query)use($sql){$query->whereOr($sql['or']);})->fieldRaw('info.id as row,group_concat(info.id) as info')->group('info.goods,info.attr,info.warehouse')->order('info.id', 'desc')->select()->toArray(); + $data=[]; + $count=count($record); + if(!empty($record)){ + $infoList = \app\model\BorInfo::with(['goodsData','warehouseData'])->where([['id','in',array_unique(explode(',',implode(',',array_column($record,'info'))))]])->select()->toArray(); + $classList = \app\model\Bor::with(['frameData','supplierData'])->where([['id','in',array_unique(array_column($infoList,'pid'))]])->append(['extension'])->select()->toArray(); + foreach ($record as $recordVo) { + $info=search($infoList)->where([['id','in',explode(',',$recordVo['info'])]])->select(); + $row=$info[0]; + $row['key']=$row['id']; + $row['unit']=''; + $row['price']=''; + $row['nums']=0; + $row['money']=0; + $row['nns']=0; + $row['nmy']=0; + foreach ($info as $vo) { + $class=search($classList)->where([['id','=',$vo['pid']]])->find(); + $class['key']=$vo['id'].'_'.$class['id']; + $class['unit']=$vo['unit']; + $class['price']=math()->chain($vo['tpt'])->div($vo['nums'])->round(2)->done(); + $class['nums']=$vo['nums']; + $class['money']=$vo['tpt']; + $class['extension']['state']=$vo['handle']==0?'未入库':($vo['handle']==$vo['nums']?'已入库':'部分入库'); + $class['nns']=math()->chain($vo['nums'])->sub($vo['handle'])->done(); + $class['nmy']=math()->chain($class['price'])->mul($class['nns'])->done(); + $class['data']=$vo['data']; + $class['basic']=['nums'=>$vo['nums'],'nns'=>$class['nns']]; + //汇总数据 + $row['money']=math()->chain($row['money'])->add($vo['tpt'])->done(); + $row['nmy']=math()->chain($row['nmy'])->add($class['nmy'])->done(); + //单位转换 + if($vo['goodsData']['unit']=='-1'){ + $radix=unitRadix($vo['unit'],$vo['goodsData']['units']); + $row['nums']=math()->chain($class['nums'])->mul($radix)->add($row['nums'])->done(); + $row['nns']=math()->chain($class['nns'])->mul($radix)->add($row['nns'])->done(); + }else{ + $row['nums']=math()->chain($class['nums'])->add($row['nums'])->done(); + $row['nns']=math()->chain($class['nns'])->add($row['nns'])->done(); + } + $row['node'][]=$class; + } + $row['extension']['state']=$row['nns']==0?'已入库':($row['nns']==$row['nums']?'未入库':'部分入库'); + //单位处理 + if($row['goodsData']['unit']=='-1'){ + $row['nums']=unitSwitch($row['nums'],$row['goodsData']['units']); + $row['nns']=unitSwitch($row['nns'],$row['goodsData']['units']); + } + $data[]=$row; + } + } + } + //结构重组 + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购订单跟踪表']; + //表格数据 + $field=[ + [ + 'frameData|name'=>'所属组织', + 'supplierData|name'=>'供应商', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'goodsData|name'=>'商品名称', + 'attr'=>'辅助属性', + 'warehouseData|name'=>'仓库', + ],[ + 'goodsData|name'=>'商品名称', + 'attr'=>'辅助属性', + 'warehouseData|name'=>'仓库', + 'frameData|name'=>'所属组织', + 'supplierData|name'=>'供应商', + 'time'=>'单据时间', + 'number'=>'单据编号' + ],[ + 'unit'=>'单位', + 'price'=>'单价', + 'nums'=>'数量', + 'money'=>'金额', + 'extension|state'=>'入库状态', + 'nns'=>'未入库数量', + 'nmy'=>'未入库金额', + 'arrival'=>'到货日期', + 'data'=>'备注信息' + ] + ]; + $field=array_merge(empty($input['type'])?$field[0]:$field[1],$field[2]); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('采购订单跟踪表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //采购明细表 + public function blt(){ + $input=input('post.'); + $sheet=['buy','bre']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(existFull($input,['page','limit']) && is_arrays($input,['warehouse','mold']) && arrayInArray($input['mold'],$sheet)){ + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['supplier','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['data'=>'class.data'],'fullLike'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + //数据鉴权[结构一致] + $sql['class']=sqlAuth('buy',$sql['class']); + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + //组装查询语句 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold.'_info')->alias('info')->join(['is_'.$mold=>'class'],'info.pid=class.id')->where($sql['info'])->where($sql['class'])->fieldRaw('info.id as info,class.id as class,time,"'.$mold.'" as mold')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $count=DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $table=[ + "class"=>"app\\model\\".ucfirst($mold), + 'info'=>"app\\model\\".ucfirst($mold).'Info', + ]; + $list[$mold]['info']=$table['info']::with(['goodsData','warehouseData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + $list[$mold]['class']=$table['class']::with(['frameData','supplierData'])->where([['id','in',array_column($list[$mold]['info'],'pid')]])->append(['extension'])->select()->toArray(); + } + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $data[]=[ + 'mold'=>$mold, + 'name'=>['buy'=>'采购单','bre'=>'采购退货单'][$mold], + 'class'=>search($list[$mold]['class'])->where([['id','=',$recordVo['class']]])->find(), + 'info'=>search($list[$mold]['info'])->where([['id','=',$recordVo['info']]])->find() + ]; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //采购明细表-导出 + public function bltExports(){ + $input=input('get.'); + $sheet=['buy','bre']; + existFull($input,['warehouse'])||$input['warehouse']=[]; + existFull($input,['mold'])||$input['mold']=$sheet; + if(is_arrays($input,['warehouse','mold']) && arrayInArray($input['mold'],$sheet)){ + pushLog('导出采购明细表');//日志 + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['supplier','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['data'=>'class.data'],'fullLike'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + //数据鉴权[结构一致] + $sql['class']=sqlAuth('buy',$sql['class']); + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + //组装查询语句 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold.'_info')->alias('info')->join(['is_'.$mold=>'class'],'info.pid=class.id')->where($sql['info'])->where($sql['class'])->fieldRaw('info.id as info,class.id as class,time,"'.$mold.'" as mold')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC'); + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $table=[ + "class"=>"app\\model\\".ucfirst($mold), + 'info'=>"app\\model\\".ucfirst($mold).'Info', + ]; + $list[$mold]['info']=$table['info']::with(['goodsData','warehouseData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + $list[$mold]['class']=$table['class']::with(['frameData','supplierData'])->where([['id','in',array_column($list[$mold]['info'],'pid')]])->append(['extension'])->select()->toArray(); + } + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $data[]=[ + 'mold'=>$mold, + 'name'=>['buy'=>'采购单','bre'=>'采购退货单'][$mold], + 'class'=>search($list[$mold]['class'])->where([['id','=',$recordVo['class']]])->find(), + 'info'=>search($list[$mold]['info'])->where([['id','=',$recordVo['info']]])->find() + ]; + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购明细表']; + //表格数据 + $field=[ + 'name'=>'单据类型', + 'class|frameData|name'=>'所属组织', + 'class|supplierData|name'=>'供应商', + 'class|time'=>'单据时间', + 'class|number'=>'单据编号', + 'info|goodsData|name'=>'商品名称', + 'info|attr'=>'辅助属性', + 'info|warehouseData|name'=>'仓库', + 'info|unit'=>'单位', + 'info|price'=>'单价', + 'info|nums'=>'数量', + 'info|dsc'=>'折扣额', + 'info|total'=>'金额', + 'info|tat'=>'税额', + 'info|tpt'=>'价税合计', + 'class|data'=>'备注信息', + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $math=['buy'=>[],'bre'=>[]]; + foreach ($source as $sourceVo) { + $math[$sourceVo['mold']][]=$sourceVo['info']['tpt']; + } + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '采购总金额:'.mathArraySum($math['buy']), + '采购退货总金额:'.mathArraySum($math['bre']) + ]]; + //导出execl + buildExcel('采购明细表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //采购汇总表 + public function bsy(){ + $input=input('post.'); + if(existFull($input,['page','limit']) && is_array($input['warehouse']) && isset($input['type'])){ + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['supplier','fullEq'], + ['user','fullEq'], + ['people','fullEq'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + $sql['class']=sqlAuth('buy',$sql['class']);//数据鉴权[结构一致] + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + //构造语句 + $union=[]; + $tab=['buy','bre']; + foreach ($tab as $t) { + $union[]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($sql['class'])->where($sql['info'])->fieldRaw('"'.$t.'" as mold,class.supplier as supplier,class.user as user,class.people as people,info.id as info,goods,attr,warehouse,unit,nums,tpt')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //判断类型 + if($input['type']==0){ + //按商品 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by goods,attr,warehouse ORDER BY `goods` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + }else if($input['type']==1){ + //按供应商 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by supplier,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,supplier,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by supplier,goods,attr,warehouse ORDER BY `supplier` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + }else if($input['type']==2){ + //按用户 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by user,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,user,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by user,goods,attr,warehouse ORDER BY `user` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + }else{ + //按人员 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by people,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,people,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by people,goods,attr,warehouse ORDER BY `people` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + } + //构造数据 + $group = []; + foreach($record as $vo){ + $moldList = explode(",", $vo['mold']); + $infoList = explode(",", $vo['info']); + $unitList = explode(",", $vo['unit']); + $numsList = explode(",", $vo['nums']); + $tptList = explode(",", $vo['tpt']); + $row=['mold'=>$moldList[0],'info'=>$infoList[0]]; + foreach ($moldList as $key => $mold) { + $row[$mold]['unit'][]=$unitList[$key]; + $row[$mold]['nums'][]=$numsList[$key]??0; + $row[$mold]['tpt'][]=$tptList[$key]??0; + } + $input['type']==1&&$row['supplier']=$vo['supplier'];//供应商转存 + $input['type']==2&&$row['user']=$vo['user'];//用户转存 + $input['type']==3&&$row['people']=$vo['people'];//人员转存 + $group[]=$row; + } + //数据匹配 + $infoList=[]; + foreach ($tab as $t) { + $mold="app\\model\\".ucfirst($t).'Info'; + $gather=search($group)->where([['mold','=',$t]])->select(); + $infoList[$t]=$mold::with(['goodsData','warehouseData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + } + //查询类型-匹配供应商 + $input['type']==1&&$supplierList=db::name('supplier')->where([['id','in',array_column($group,'supplier')]])->select()->toArray(); + //查询类型-匹配用户 + $input['type']==2&&$userList=db::name('user')->where([['id','in',array_column($group,'user')]])->select()->toArray(); + //查询类型-匹配人员 + $input['type']==3&&$peopleList=db::name('people')->where([['id','in',array_column($group,'people')]])->select()->toArray(); + //数据处理 + $data=[]; + foreach ($group as $groupVo) { + $row=search($infoList[$groupVo['mold']])->where([['id','=',$groupVo['info']]])->find(); + $row['unit']=$row['goodsData']['unit']==-1?'多单位':$row['unit']; + foreach ($tab as $t) { + if(isset($groupVo[$t])){ + if($row['goodsData']['unit']==-1){ + $base=0; + foreach ($groupVo[$t]['unit'] as $key=> $unit) { + $radix=unitRadix($unit,$row['goodsData']['units']); + $base=math()->chain($groupVo[$t]['nums'][$key])->mul($radix)->add($base)->done(); + } + $row[$t]=['base'=>$base,'nums'=>unitSwitch($base,$row['goodsData']['units']),'money'=>mathArraySum($groupVo[$t]['tpt'])]; + $row[$t]['price']=math()->chain($row[$t]['money'])->div($base)->round(2)->done(); + }else{ + $row[$t]=['nums'=>mathArraySum($groupVo[$t]['nums']),'money'=>mathArraySum($groupVo[$t]['tpt'])]; + $row[$t]['price']=math()->chain($row[$t]['money'])->div($row[$t]['nums'])->round(2)->done(); + $row[$t]['base']=$row[$t]['nums']; + } + }else{ + $row[$t]=['base'=>0,'price'=>0,'nums'=>0,'money'=>0]; + } + } + $row['summary']['nums']=math()->chain($row['buy']['base'])->sub($row['bre']['base'])->done(); + $row['goodsData']['unit']==-1&&$row['summary']['nums']=unitSwitch($row['summary']['nums'],$row['goodsData']['units']); + $row['summary']['money']=math()->chain($row['buy']['money'])->sub($row['bre']['money'])->done(); + //类型匹配 + $input['type']==1&&$row['supplier']=search($supplierList)->where([['id','=',$groupVo['supplier']]])->find();//匹配供应商 + $input['type']==2&&$row['user']=search($userList)->where([['id','=',$groupVo['user']]])->find();//匹配用户 + $input['type']==3&&$row['people']=search($peopleList)->where([['id','=',$groupVo['people']]])->find();//匹配人员 + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //采购汇总表-导出 + public function bsyExports(){ + $input=input('get.'); + existFull($input,['warehouse'])||$input['warehouse']=[]; + if(is_array($input['warehouse']) && isset($input['type'])){ + pushLog('导出采购汇总表');//日志 + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['supplier','fullEq'], + ['user','fullEq'], + ['people','fullEq'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + $sql['class']=sqlAuth('buy',$sql['class']);//数据鉴权[结构一致] + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + //构造语句 + $union=[]; + $tab=['buy','bre']; + foreach ($tab as $t) { + $union[]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($sql['class'])->where($sql['info'])->fieldRaw('"'.$t.'" as mold,class.supplier as supplier,class.user as user,class.people as people,info.id as info,goods,attr,warehouse,unit,nums,tpt')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //判断类型 + if($input['type']==0){ + //按商品 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by goods,attr,warehouse ORDER BY `goods` DESC'); + }else if($input['type']==1){ + //按供应商 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by supplier,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,supplier,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by supplier,goods,attr,warehouse ORDER BY `supplier` DESC'); + }else if($input['type']==2){ + //按用户 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by user,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,user,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by user,goods,attr,warehouse ORDER BY `user` DESC'); + }else{ + //按人员 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by people,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,people,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by people,goods,attr,warehouse ORDER BY `people` DESC'); + } + //构造数据 + $group = []; + foreach($record as $vo){ + $moldList = explode(",", $vo['mold']); + $infoList = explode(",", $vo['info']); + $unitList = explode(",", $vo['unit']); + $numsList = explode(",", $vo['nums']); + $tptList = explode(",", $vo['tpt']); + $row=['mold'=>$moldList[0],'info'=>$infoList[0]]; + foreach ($moldList as $key => $mold) { + $row[$mold]['unit'][]=$unitList[$key]; + $row[$mold]['nums'][]=$numsList[$key]??0; + $row[$mold]['tpt'][]=$tptList[$key]??0; + } + $input['type']==1&&$row['supplier']=$vo['supplier'];//供应商转存 + $input['type']==2&&$row['user']=$vo['user'];//用户转存 + $input['type']==3&&$row['people']=$vo['people'];//人员转存 + $group[]=$row; + } + //数据匹配 + $infoList=[]; + foreach ($tab as $t) { + $mold="app\\model\\".ucfirst($t).'Info'; + $gather=search($group)->where([['mold','=',$t]])->select(); + $infoList[$t]=$mold::with(['goodsData','warehouseData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + } + //查询类型-匹配供应商 + $input['type']==1&&$supplierList=db::name('supplier')->where([['id','in',array_column($group,'supplier')]])->select()->toArray(); + //查询类型-匹配用户 + $input['type']==2&&$userList=db::name('user')->where([['id','in',array_column($group,'user')]])->select()->toArray(); + //查询类型-匹配人员 + $input['type']==3&&$peopleList=db::name('people')->where([['id','in',array_column($group,'people')]])->select()->toArray(); + //数据处理 + $data=[]; + foreach ($group as $groupVo) { + $row=search($infoList[$groupVo['mold']])->where([['id','=',$groupVo['info']]])->find(); + $row['unit']=$row['goodsData']['unit']==-1?'多单位':$row['unit']; + foreach ($tab as $t) { + if(isset($groupVo[$t])){ + if($row['goodsData']['unit']==-1){ + $base=0; + foreach ($groupVo[$t]['unit'] as $key=> $unit) { + $radix=unitRadix($unit,$row['goodsData']['units']); + $base=math()->chain($groupVo[$t]['nums'][$key])->mul($radix)->add($base)->done(); + } + $row[$t]=['base'=>$base,'nums'=>unitSwitch($base,$row['goodsData']['units']),'money'=>mathArraySum($groupVo[$t]['tpt'])]; + $row[$t]['price']=math()->chain($row[$t]['money'])->div($base)->round(2)->done(); + }else{ + $row[$t]=['nums'=>mathArraySum($groupVo[$t]['nums']),'money'=>mathArraySum($groupVo[$t]['tpt'])]; + $row[$t]['price']=math()->chain($row[$t]['money'])->div($row[$t]['nums'])->round(2)->done(); + $row[$t]['base']=$row[$t]['nums']; + } + }else{ + $row[$t]=['base'=>0,'price'=>0,'nums'=>0,'money'=>0]; + } + } + $row['summary']['nums']=math()->chain($row['buy']['base'])->sub($row['bre']['base'])->done(); + $row['goodsData']['unit']==-1&&$row['summary']['nums']=unitSwitch($row['summary']['nums'],$row['goodsData']['units']); + $row['summary']['money']=math()->chain($row['buy']['money'])->sub($row['bre']['money'])->done(); + //类型匹配 + $input['type']==1&&$row['supplier']=search($supplierList)->where([['id','=',$groupVo['supplier']]])->find();//匹配供应商 + $input['type']==2&&$row['user']=search($userList)->where([['id','=',$groupVo['user']]])->find();//匹配用户 + $input['type']==3&&$row['people']=search($peopleList)->where([['id','=',$groupVo['people']]])->find();//匹配人员 + $data[]=$row; + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购汇总表']; + //表格数据 + $field=[ + [ + "supplier|name"=>"供应商" + ], + [ + "user|name"=>"用户" + ], + [ + "people|name"=>"关联人员" + ], + [ + "goodsData|name"=>"商品名称", + "attr"=>"辅助属性", + "warehouseData|name"=>"仓库", + "unit"=>"单位", + "buy|price"=>"采购单价", + "buy|nums"=>"采购数量", + "buy|money"=>"采购金额", + "bre|price"=>"购退单价", + "bre|nums"=>"购退数量", + "bre|money"=>"购退金额", + "summary|nums"=>"汇总数量", + "summary|money"=>"汇总金额" + ] + ]; + $field=[$field[3],array_merge($field[0],$field[3]),array_merge($field[1],$field[3]),array_merge($field[2],$field[3]),][$input['type']]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '采购总金额:'.mathArraySum(arrayColumns($source,['buy','money'])), + '采购退货总金额:'.mathArraySum(arrayColumns($source,['bre','money'])), + '汇总金额:'.mathArraySum(arrayColumns($source,['summary','money'])) + ]]; + //导出execl + buildExcel('采购汇总表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //采购付款表 + public function bbt(){ + $input=input('post.'); + $sheet=['buy','bre']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(existFull($input,['page','limit']) && is_arrays($input,['nucleus','mold']) && arrayInArray($input['mold'],$sheet)){ + $sql=[]; + //CLASS语句 + $sql=fastSql($input,[ + ['supplier','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['nucleus','fullIn'] + ]); + $sql[]=['examine','=',1]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('buy',$sql);//数据鉴权[结构一致] + //组装语句 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->where($sql)->fieldRaw('"'.$mold.'" as mold,id,time')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $count=DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + //匹配数据 + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $db="app\\model\\".ucfirst($mold); + $list[$mold]=$db::with(['frameData','supplierData','billData'])->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray(); + } + //构造数据 + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $row=search($list[$mold])->where([['id','=',$recordVo['id']]])->find(); + $row['key']=$mold.'_'.$recordVo['id']; + $row['name']=['buy'=>'采购单','bre'=>'采购退货单'][$mold]; + $row['balance']=$row['extension']['anwo']; + $row['rate']=in_array($row['nucleus'],['0','2'])?['0%','','100%'][$row['nucleus']]:math()->chain($row['extension']['amount'])->div($row['actual'])->mul(100)->round(2)->done().'%'; + $row['node']=[]; + $bill=search($row['billData'])->where([['type','=','bill']])->select(); + foreach ($bill as $billVo) { + $node=[ + 'key'=>$row['key'].'_'.$billVo['id'], + 'name'=>'核销单', + 'time'=>$billVo['time'], + 'number'=>$billVo['sourceData']['number'], + 'money'=>$billVo['money'], + ]; + //反转金额 + in_array($mold,['bre'])&&$node['money']*=-1; + $row['node'][]=$node; + } + //反转金额 + if(in_array($mold,['bre'])){ + $row['total']*=-1; + $row['actual']*=-1; + $row['money']*=-1; + $row['balance']*=-1; + } + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //采购付款表-导出 + public function bbtExports(){ + $input=input('get.'); + $sheet=['buy','bre']; + existFull($input,['nucleus'])||$input['nucleus']=[]; + existFull($input,['mold'])||$input['mold']=$sheet; + if(is_arrays($input,['nucleus','mold']) && arrayInArray($input['mold'],$sheet)){ + pushLog('导出采购付款表');//日志 + $sql=[]; + //CLASS语句 + $sql=fastSql($input,[ + ['supplier','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['nucleus','fullIn'] + ]); + $sql[]=['examine','=',1]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('buy',$sql);//数据鉴权[结构一致] + //组装语句 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->where($sql)->fieldRaw('"'.$mold.'" as mold,id,time')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC'); + //匹配数据 + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $db="app\\model\\".ucfirst($mold); + $list[$mold]=$db::with(['frameData','supplierData','billData'])->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray(); + } + //构造数据 + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $row=search($list[$mold])->where([['id','=',$recordVo['id']]])->find(); + $row['key']=$mold.'_'.$recordVo['id']; + $row['name']=['buy'=>'采购单','bre'=>'采购退货单'][$mold]; + $row['balance']=$row['extension']['anwo']; + $row['rate']=in_array($row['nucleus'],['0','2'])?['0%','','100%'][$row['nucleus']]:math()->chain($row['extension']['amount'])->div($row['actual'])->mul(100)->round(2)->done().'%'; + $row['node']=[]; + $bill=search($row['billData'])->where([['type','=','bill']])->select(); + foreach ($bill as $billVo) { + $node=[ + 'key'=>$row['key'].'_'.$billVo['id'], + 'name'=>'核销单', + 'time'=>$billVo['time'], + 'number'=>$billVo['sourceData']['number'], + 'money'=>$billVo['money'], + ]; + //反转金额 + in_array($mold,['bre'])&&$node['money']*=-1; + $row['node'][]=$node; + } + //反转金额 + if(in_array($mold,['bre'])){ + $row['total']*=-1; + $row['actual']*=-1; + $row['money']*=-1; + $row['balance']*=-1; + } + $data[]=$row; + } + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购付款表']; + //表格数据 + $field=[ + "name"=>"单据类型", + "frameData|name"=>"所属组织", + "supplierData|name"=>"供应商", + "time"=>"单据时间", + "number"=>"单据编号", + "total"=>"单据金额", + "actual"=>"实际金额", + "money"=>"单据付款", + "balance"=>"应付款余额", + "rate"=>"付款率", + "extension|nucleus"=>"核销状态", + "data"=>"备注信息" + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '应付款总余额:'.mathArraySum(array_column($source,'balance')) + ]]; + //导出execl + buildExcel('采购付款表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //采购排行表 + public function bot(){ + $input=input('post.'); + if(existFull($input,['page','limit'])){ + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'] + ]); + $goods=Db::name('goods')->where($sql)->select()->toArray(); + //数据匹配 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['goods','in',array_column($goods,'id')]; + $existsSql[]=['examine','=',1]; + $existsSql=frameScope($existsSql); + $existsSql=sqlAuth('buy',$existsSql);//结构一致 + //多源匹配 + $union=[]; + $tab=['buy','bre']; + foreach ($tab as $t) { + $union[0][]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($existsSql)->fieldRaw('goods,attr,sum(nums) as nums')->group(['goods,attr'])->buildSql(); + } + $union_0=implode(' UNION ALL ',$union[0]); + $count=DB::query('select count(*) as count from ( SELECT count(*) FROM ('.$union_0.') as f GROUP BY goods,attr ) as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union_0.') as nodcloud GROUP BY goods,attr ORDER BY `nums` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + //构造条件|减少查询 + foreach ($existsSql as $k=>$v) { + if($v[0]=='goods'){ + $existsSql[$k][2]=array_column($record,'goods'); + break; + } + } + foreach ($tab as $t) { + $union[1][]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($existsSql)->fieldRaw('"'.$t.'" as mold,goods,attr,group_concat(info.id) as id,sum(dsc) as dsc,sum(tat) as tat,sum(tpt) as tpt')->group(['goods,attr'])->buildSql(); + } + $union_1=implode(' UNION ALL ',$union[1]); + $list=DB::query('SELECT * FROM ('.$union_1.') as nodcloud'); + //获取数据 + $summary=[]; + foreach ($tab as $t) { + $gather=explode(',',implode(',',array_column(search($list)->where([['mold','=',$t]])->select(),'id'))); + $summary[$t]=Db::name('summary')->where([['type','=',$t],['info','in',$gather]])->select()->toArray(); + } + $data=[]; + //统计数据 + foreach ($record as $vo) { + $row=[]; + $g=search($goods)->where([['id','=',$vo['goods']]])->find(); + $row['goodsData']=$g; + $row['attr']=$vo['attr']; + $row['unit']=$g['unit']==-1?'多单位':$g['unit']; + $base=[['goods','=',$vo['goods']],['attr','=',$vo['attr']]]; + $gather=[]; + foreach ($tab as $t) { + $b=search($list)->where(array_merge($base,[['mold','=',$t]]))->find(); + $s=search($summary[$t])->where(array_merge($base,[['type','=',$t]]))->select(); + $gather['nums'][$t]=mathArraySum(array_column($s,'nums')); + $gather['dsc'][$t]=empty($b)?0:$b['dsc']; + $gather['tat'][$t]=empty($b)?0:$b['tat']; + $gather['tpt'][$t]=empty($b)?0:$b['tpt']; + $gather['bct'][$t]=mathArraySum(array_column($s,'bct')); + } + $nums=math()->chain($gather['nums']['buy'])->sub($gather['nums']['bre'])->done(); + $row['nums']=$g['unit']==-1?unitSwitch($nums,json_decode($g['units'],true)):$nums; + $row['dsc']=math()->chain($gather['dsc']['buy'])->sub($gather['dsc']['bre'])->done(); + $row['tat']=math()->chain($gather['tat']['buy'])->sub($gather['tat']['bre'])->done(); + $row['tpt']=math()->chain($gather['tpt']['buy'])->sub($gather['tpt']['bre'])->done(); + $row['bct']=math()->chain($gather['bct']['buy'])->sub($gather['bct']['bre'])->done(); + $row['uct']=empty($nums)?0:math()->chain($row['bct'])->div($nums)->round(2)->abs()->done(); + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //采购排行表-导出 + public function botExports(){ + $input=input('get.'); + pushLog('导出采购排行表');//日志 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'] + ]); + $goods=Db::name('goods')->where($sql)->select()->toArray(); + //数据匹配 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['goods','in',array_column($goods,'id')]; + $existsSql[]=['examine','=',1]; + $existsSql=frameScope($existsSql); + $existsSql=sqlAuth('buy',$existsSql);//结构一致 + //多源匹配 + $union=[]; + $tab=['buy','bre']; + foreach ($tab as $t) { + $union[0][]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($existsSql)->fieldRaw('goods,attr,sum(nums) as nums')->group(['goods,attr'])->buildSql(); + } + $union_0=implode(' UNION ALL ',$union[0]); + $record=DB::query('SELECT * FROM ('.$union_0.') as nodcloud GROUP BY goods,attr ORDER BY `nums` DESC'); + //匹配数据 + foreach ($tab as $t) { + $union[1][]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($existsSql)->fieldRaw('"'.$t.'" as mold,goods,attr,group_concat(info.id) as id,sum(dsc) as dsc,sum(tat) as tat,sum(tpt) as tpt')->group(['goods,attr'])->buildSql(); + } + $union_1=implode(' UNION ALL ',$union[1]); + $list=DB::query('SELECT * FROM ('.$union_1.') as nodcloud'); + //获取数据 + $summary=[]; + foreach ($tab as $t) { + $gather=explode(',',implode(',',array_column(search($list)->where([['mold','=',$t]])->select(),'id'))); + $summary[$t]=Db::name('summary')->where([['type','=',$t],['info','in',$gather]])->select()->toArray(); + } + $data=[]; + //统计数据 + foreach ($record as $vo) { + $row=[]; + $g=search($goods)->where([['id','=',$vo['goods']]])->find(); + $row['goodsData']=$g; + $row['attr']=$vo['attr']; + $row['unit']=$g['unit']==-1?'多单位':$g['unit']; + $base=[['goods','=',$vo['goods']],['attr','=',$vo['attr']]]; + $gather=[]; + foreach ($tab as $t) { + $b=search($list)->where(array_merge($base,[['mold','=',$t]]))->find(); + $s=search($summary[$t])->where(array_merge($base,[['type','=',$t]]))->select(); + $gather['nums'][$t]=mathArraySum(array_column($s,'nums')); + $gather['dsc'][$t]=empty($b)?0:$b['dsc']; + $gather['tat'][$t]=empty($b)?0:$b['tat']; + $gather['tpt'][$t]=empty($b)?0:$b['tpt']; + $gather['bct'][$t]=mathArraySum(array_column($s,'bct')); + } + $nums=math()->chain($gather['nums']['buy'])->sub($gather['nums']['bre'])->done(); + $row['nums']=$g['unit']==-1?unitSwitch($nums,json_decode($g['units'],true)):$nums; + $row['dsc']=math()->chain($gather['dsc']['buy'])->sub($gather['dsc']['bre'])->done(); + $row['tat']=math()->chain($gather['tat']['buy'])->sub($gather['tat']['bre'])->done(); + $row['tpt']=math()->chain($gather['tpt']['buy'])->sub($gather['tpt']['bre'])->done(); + $row['bct']=math()->chain($gather['bct']['buy'])->sub($gather['bct']['bre'])->done(); + $row['uct']=empty($nums)?0:math()->chain($row['bct'])->div($nums)->round(2)->abs()->done(); + $data[]=$row; + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购排行表']; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'attr'=>'辅助属性', + 'goodsData|number'=>'商品编号', + 'goodsData|spec'=>'规格型号', + 'unit'=>'单位', + 'nums'=>'数量', + 'dsc'=>'折扣额', + 'tat'=>'税额', + 'tpt'=>'价税合计', + 'uct'=>'成本', + 'bct'=>'总成本' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source) + ]]; + //导出execl + buildExcel('采购排行表',$excel); + } +} diff --git a/serve/app/controller/Buy.php b/serve/app/controller/Buy.php new file mode 100644 index 0000000..d70e745 --- /dev/null +++ b/serve/app/controller/Buy.php @@ -0,0 +1,1246 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['examine','fullDec1'], + ['nucleus','fullDec1'], + ['cse','fullDec1'], + ['invoice','fullDec1'], + ['check','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['id','in',array_column(Db::name('buy_info')->where([['goods','in',$goods]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('buy',$sql);//数据鉴权 + $count = Buys::where($sql)->count();//获取总条数 + $info = Buys::with(['frameData','supplierData','peopleData','userData','billData','costData','invoiceData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + //关联单据 + if(!empty($info)){ + $bor=Db::name('bor')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + $bre=Db::name('bre')->where([['source','in',array_column($info,'id')]])->select()->toArray(); + foreach ($info as $infoKey=>$infoVo) { + //采购订单 + $borData=array_map(function($item){ + return ['type'=>'采购订单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'bor','id'=>$item['id']]; + },search($bor)->where([['id','=',$infoVo['source']]])->select()); + //采购退货单 + $breData=array_map(function($item){ + return ['type'=>'采购退货单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'bre','id'=>$item['id']]; + },search($bre)->where([['source','=',$infoVo['id']]])->select()); + $merge=array_merge($borData,$breData); + //合并排序 + array_multisort(array_column($merge,'sort'),SORT_DESC,$merge); + $info[$infoKey]['relation']=$merge; + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id']) && isset($input['cost'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['cse']=empty($class['cost'])?3:0; + $class['invoice']=empty($class['actual'])?3:0; + $class['examine']=0; + $class['nucleus']=0; + empty($class['id'])?$this->validate($class,'app\validate\Buy'):$this->validate($class,'app\validate\Buy.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\BuyInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'商品信息第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //验证Cost + foreach ($input['cost'] as $costKey=>$costVo) { + try { + $this->validate($costVo,'app\validate\Cost'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'单据费用第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Buys::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'buy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增采购单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Buys::update($class); + Db::name('record')->insert(['type'=>'buy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新采购单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + BuyInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + $input['info'][$infoKey]['retreat']=0;//初始|退货数量 + } + $model = new BuyInfo; + $model->saveAll($input['info']); + + //COST数据 + Cost::where([['type','=','buy'],['class','=',$class['id']]])->delete(); + foreach ($input['cost'] as $costKey=>$costVo) { + unset($input['cost'][$costKey]['id']); + $input['cost'][$costKey]['type']='buy'; + $input['cost'][$costKey]['class']=$class['id']; + $input['cost'][$costKey]['time']=$class['time']; + $input['cost'][$costKey]['settle']=0; + $input['cost'][$costKey]['state']=0; + } + $model = new Cost; + $model->saveAll($input['cost']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Buys::where([['id','=',$input['parm']]])->find(); + $info=BuyInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $cost=Cost::where([['type','=','buy'],['class','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + 'cost'=>$cost + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //关联验证 + $exist=moreTableFind([['table'=>'bre','where'=>[['source','in',$input['parm']]]]]); + if($exist){ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + }else{ + $data=Db::name('buy')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('buy')->where([['id','in',$input['parm']]])->delete(); + Db::name('buy_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('cost')->where([['type','=','buy'],['class','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','buy'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除采购单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //核对|反核对 + public function check(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $period=getPeriod(); + $classList=Db::name('buy')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + foreach ($input['parm'] as $parmVo) { + $class=search($classList)->where([['id','=',$parmVo]])->find(); + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(empty($class['check'])){ + Db::name('buy')->where([['id','=',$class['id']]])->update(['check'=>1]); + //1 单据记录 + Db::name('record')->insert(['type'=>'buy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'核对单据']); + //2 记录操作 + pushLog('核对采购单[ '.$class['number'].' ]');//单据日志 + }else{ + Db::name('buy')->where([['id','=',$class['id']]])->update(['check'=>0]); + //1 单据记录 + Db::name('record')->insert(['type'=>'buy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反核对单据']); + //2 记录操作 + pushLog('反核对采购单[ '.$class['number'].' ]');//单据日志 + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('buy')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('buy_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //1.1 商品数据 + $goodsList=Db::name('goods')->where([['id','in',array_unique(array_column($info,'goods'))]])->select()->toArray(); + //1.2 综合匹配 + if(empty($class['examine'])){ + //1 关联单据 + empty($class['source'])||$borInfoList=Db::name('bor_info')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + //2 构造数据 + $batchGather=[]; + $serialGather=[]; + $roomWhereOrSql=[]; + foreach ($info as $infoVo) { + //1 批次号 + empty($infoVo['batch'])||$batchGather[]=$infoVo['batch']; + //2 序列号 + $serialGather=array_merge($serialGather,json_decode($infoVo['serial'])); + //3 仓储条件 + empty($infoVo['warehouse'])||$roomWhereOrSql[]=[['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]]; + } + //3 匹配数据 + empty($batchGather)||$batchList=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + empty($serialGather)||$serialList=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + if(!empty($roomWhereOrSql)){ + //1 去重转存 + $roomWhereOrSql=array_unique($roomWhereOrSql,SORT_REGULAR); + //2 仓储匹配 + $roomList=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + } + } + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(empty($class['examine'])){ + //采购订单 + if(!empty($class['source'])){ + $bor=Db::name('bor')->where([['id','=',$class['source']]])->find(); + if(in_array($bor['state'],[2,3])){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:关联订单状态不正确!']); + exit; + } + } + }else{ + //1 采购订单 + if(!empty($class['source'])){ + $bor=Db::name('bor')->where([['id','=',$class['source']]])->find(); + if(in_array($bor['state'],[0,3])){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:关联订单状态不正确!']); + exit; + } + } + //2 采购退货单 + $bre=Db::name('bre')->where([['source','=',$class['id']]])->find(); + if(!empty($bre)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联采购退货单!']); + exit; + } + //3 核销单 + $bill=Db::name('bill_info')->where([['mold','=','buy'],['source','=',$class['id']]])->find(); + if(!empty($bill)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联核销单!']); + exit; + } + //4 单据费用 + $cost=Db::name('cost')->alias('cost')->where([['type','=','buy'],['class','=',$class['id']]])->whereExists(function($query){ + $query->name('oce_info')->where([['source','=',Db::raw('cost.id')]])->limit(1); + })->find(); + if(!empty($cost)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联其它支出单!']); + exit; + } + //5 单据发票 + $invoice=Db::name('invoice')->where([['type','=','buy'],['class','=',$class['id']]])->find(); + if(!empty($invoice)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联单据发票!']); + exit; + } + } + //3 INFO验证|构造 + foreach ($info as $infoKey=>$infoVo) { + //1 匹配商品 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + //2 商品类型 + if(empty($goods['type'])){ + //场景验证 + if(empty($class['examine'])){ + //1 关联单据 + if(!empty($infoVo['source'])){ + $borInfo=search($borInfoList)->where([['id','=',$infoVo['source']]])->find(); + if(!empty($borInfo)){ + if($borInfo['unit']!=$infoVo['unit']){ + //单位匹配 + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行单位与采购订单不匹配!']); + exit; + }elseif(bccomp(math()->chain($borInfo['handle'])->add($infoVo['nums'])->done(),$borInfo['nums'])==1){ + //数量匹配 + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行超出采购订单可入库数量!']); + exit; + } + } + } + //2 多单位处理 + if($goods['unit']==-1){ + //多单位|转存 + $radix=unitRadix($infoVo['unit'],json_decode($goods['units'],true)); + $info[$infoKey]['basic']=[ + 'nums'=>math()->chain($infoVo['nums'])->mul($radix)->done(), + 'price'=>math()->chain($infoVo['price'])->div($radix)->round(4)->done() + ]; + }else{ + //常规单位|转存 + $info[$infoKey]['basic']=[ + 'nums'=>$infoVo['nums'], + 'price'=>$infoVo['price'] + ]; + } + //3 序列号 + $serialData=json_decode($infoVo['serial']); + if(empty($serialData)){ + $info[$infoKey]['serial']=[]; + }else{ + //序列号状态[不存在|已退货] + $serialFind=search($serialList)->where([['goods','=',$infoVo['goods']],['number','in',$serialData],['state','<>',3]])->find(); + if(empty($serialFind)){ + $info[$infoKey]['serial']=$serialData; + }else{ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + }else{ + //1 验证序列号 + $serialInfoCollect=Db::name('serial_info')->where([['type','=','buy'],['info','in',array_column($info,'id')]])->select()->toArray(); + if(!empty($serialInfoCollect)){ + //序列号状态[未销售] + $serialFind=Db::name('serial')->where([['id','in',array_column($serialInfoCollect,'pid')],['state','<>',0]])->find(); + if(!empty($serialFind)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + } + } + } + //4 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $store=['borInfo'=>[],'room'=>[],'roomInfo'=>[],'batch'=>[],'batchInfo'=>[],'serial'=>[],'serialInfo'=>[],'serve'=>[],'serveInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //1 关联单据 + empty($infoVo['source'])||$store['borInfo'][]=['id'=>$infoVo['source'],'handle'=>$infoVo['nums']]; + //2 判断商品类型 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + if(empty($goods['type'])){ + //常规商品 + //1 仓储 + $store['room'][]=['warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['basic']['nums']]; + //2 仓储详情 + $store['roomInfo'][]=['pid'=>null,'type'=>'buy','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'direction'=>1,'price'=>$infoVo['basic']['price'],'nums'=>$infoVo['basic']['nums']]; + //3 批次号 + if(empty($infoVo['batch'])){ + $store['batch'][]=[]; + $store['batchInfo'][]=[]; + }else{ + $store['batch'][]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'number'=>$infoVo['batch'],'time'=>$infoVo['mfd'],'nums'=>$infoVo['basic']['nums']]; + $store['batchInfo'][]=['pid'=>null,'type'=>'buy','class'=>$class['id'],'info'=>$infoVo['id'],'direction'=>1,'nums'=>$infoVo['basic']['nums']]; + } + //4 序列号 + if(empty($infoVo['serial'])){ + $store['serial'][]=[]; + $store['serialInfo'][]=[]; + }else{ + $serial=[]; + $serialInfo=[]; + foreach ($infoVo['serial'] as $serialVo) { + $serial[]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'batch'=>null,'goods'=>$infoVo['goods'],'number'=>$serialVo,'state'=>0]; + $serialInfo[]=['pid'=>null,'type'=>'buy','class'=>$class['id'],'info'=>$infoVo['id']]; + } + $store['serial'][]=$serial; + $store['serialInfo'][]=$serialInfo; + } + }else{ + //5 服务商品 + $store['serve'][]=['goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['nums']]; + $store['serveInfo'][]=['pid'=>null,'type'=>'buy','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'price'=>$infoVo['price'],'nums'=>$infoVo['nums']]; + } + } + //2 关联单据 + if(!empty($store['borInfo'])){ + //1 更新详情 + Db::name('bor_info')->duplicate(['handle'=>Db::raw('handle + VALUES(`handle`)')])->insertAll($store['borInfo']); + //2 更新CLASS + $borInfo=Db::name('bor_info')->where([['pid','=',$class['source']]])->select()->toArray(); + $state=mathArraySum(array_column($borInfo,'nums'))==mathArraySum(array_column($borInfo,'handle'))?2:1; + Db::name('bor')->where([['id','=',$class['source']]])->update(['state'=>$state]); + } + //3 仓储 + if(!empty($store['room'])){ + //1 构造数据 + $roomInsert=[]; + foreach ($store['room'] as $roomVo) { + $roomFind=search($roomList)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + if(empty($roomFind)){ + $roomVo['nums']=0; + $roomInsert[]=$roomVo; + } + } + //2 创建数据|去重 + empty($roomInsert)||Db::name('room')->insertAll(array_unique($roomInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $roomDuplicate=[]; + $room=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + foreach ($store['room'] as $roomKey=>$roomVo) { + $roomFind=search($room)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + $store['room'][$roomKey]['id']=$roomFind['id']; + $roomDuplicate[]=['id'=>$roomFind['id'],'nums'=>$roomVo['nums']]; + } + //4 更新数据 + Db::name('room')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($roomDuplicate); + } + //4 仓储详情 + if(!empty($store['roomInfo'])){ + //1 填充数据 + foreach ($store['roomInfo'] as $roomInfoKey=>$roomInfoVo) { + $store['roomInfo'][$roomInfoKey]['pid']=$store['room'][$roomInfoKey]['id']; + } + //2 创建数据 + Db::name('room_info')->insertAll($store['roomInfo']); + } + //5 批次号 + if(!empty($store['batch'])){ + //1 构造数据 + $batchData=[]; + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $store['batch'][$batchKey]['room']=$store['room'][$batchKey]['id']; + $batchData[]=$store['batch'][$batchKey]; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchData)){ + //1 构造数据 + $batchInsert=[]; + foreach ($batchData as $batchDataKey=>$batchDataVo) { + $batchFind=search($batchList)->where([['room','=',$batchDataVo['room']],['number','=',$batchDataVo['number']],['time','=',$batchDataVo['time']]])->find(); + if(empty($batchFind)){ + $batchDataVo['nums']=0; + $batchInsert[]=$batchDataVo; + } + } + //2 创建数据|去重 + empty($batchInsert)||Db::name('batch')->insertAll(array_unique($batchInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $batchDuplicate=[]; + $batch=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $batchFind=search($batch)->where([['room','=',$batchVo['room']],['number','=',$batchVo['number']],['time','=',$batchVo['time']]])->find(); + $store['batch'][$batchKey]['id']=$batchFind['id']; + $batchDuplicate[]=['id'=>$batchFind['id'],'nums'=>$batchVo['nums']]; + } + } + //4 更新数据 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($batchDuplicate); + } + } + //6 批次号详情 + if(!empty($store['batchInfo'])){ + //1 构造数据 + $batchInfoInstall=[]; + foreach ($store['batchInfo'] as $batchInfoKey=>$batchInfoVo) { + if(!empty($batchInfoVo)){ + $batchInfoVo['pid']=$store['batch'][$batchInfoKey]['id']; + $batchInfoInstall[]=$batchInfoVo; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchInfoInstall)){ + //创建数据 + Db::name('batch_info')->insertAll($batchInfoInstall); + } + } + //7 序列号 + if(!empty($store['serial'])){ + //1 构造数据 + $serialData=[]; + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $store['serial'][$serialKey][$itemKey]['room']=$store['room'][$serialKey]['id']; + $store['serial'][$serialKey][$itemKey]['batch']=empty($store['batch'][$serialKey])?0:$store['batch'][$serialKey]['id']; + $serialData[]=$store['serial'][$serialKey][$itemKey]; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialData)){ + //1 构造数据 + $serialInsert=[]; + foreach ($serialData as $serialDataKey=>$serialDataVo) { + $serialFind=search($serialList)->where([['room','=',$serialDataVo['room']],['batch','=',$serialDataVo['batch']],['number','=',$serialDataVo['number']]])->find(); + if(empty($serialFind)){ + $serialInsert[]=$serialDataVo; + } + } + //2 创建数据 + empty($serialInsert)||Db::name('serial')->insertAll($serialInsert); + //3 匹配主键|构造更新 + $serialDuplicate=[]; + $serial=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $serialFind=search($serial)->where([['room','=',$itemVo['room']],['batch','=',$itemVo['batch']],['number','=',$itemVo['number']]])->find(); + $store['serial'][$serialKey][$itemKey]['id']=$serialFind['id']; + $serialFind['state']==3&&$serialDuplicate[]=$serialFind['id']; + } + } + } + //4 更新数据|状态变更 + empty($serialDuplicate)||Db::name('serial')->where([['id','in',$serialDuplicate]])->update(['state'=>0]); + } + } + //8 序列号详情 + if(!empty($store['serialInfo'])){ + //1 构造数据 + $serialInfoInstall=[]; + foreach ($store['serialInfo'] as $serialInfoKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $itemVo['pid']=$store['serial'][$serialInfoKey][$itemKey]['id']; + $serialInfoInstall[]=$itemVo; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialInfoInstall)){ + //创建数据 + Db::name('serial_info')->insertAll($serialInfoInstall); + } + } + //9 服务商品 + if(!empty($store['serve'])){ + //1 匹配数据|去重 + $serveWhereOrSql=array_unique(array_map(function($item){ + return [['goods','=',$item['goods']],['attr','=',$item['attr']]]; + },$store['serve']),SORT_REGULAR); + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + //2 构造数据 + $serveInsert=[]; + foreach ($store['serve'] as $serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + if(empty($serveFind)){ + $serveVo['nums']=0; + $serveInsert[]=$serveVo; + } + } + //3 创建数据|去重 + empty($serveInsert)||Db::name('serve')->insertAll(array_unique($serveInsert,SORT_REGULAR)); + //4 匹配主键|构造更新 + $serveDuplicate=[]; + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + foreach ($store['serve'] as $serveKey=>$serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + $store['serve'][$serveKey]['id']=$serveFind['id']; + $serveDuplicate[]=['id'=>$serveFind['id'],'nums'=>$serveVo['nums']]; + } + //5 更新数据 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($serveDuplicate); + } + //10 服务商品详情 + if(!empty($store['serveInfo'])){ + //1 填充数据 + foreach ($store['serveInfo'] as $serveInfoKey=>$serveInfoVo) { + $store['serveInfo'][$serveInfoKey]['pid']=$store['serve'][$serveInfoKey]['id']; + } + //2 创建数据 + Db::name('serve_info')->insertAll($store['serveInfo']); + } + //11 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->dec('balance',$class['money'])->update(); + //2 创建资金详情 + Db::name('account_info')->insert([ + 'pid'=>$class['account'], + 'type'=>'buy', + 'class'=>$class['id'], + 'time'=>$class['time'], + 'direction'=>0, + 'money'=>$class['money'] + ]); + //3 创建核销记录 + Db::name('buy_bill')->insert([ + 'pid'=>$class['id'], + 'type'=>'buy', + 'source'=>$class['id'], + 'time'=>$class['time'], + 'money'=>$class['money'] + ]); + } + //12 供应商|应付款余额 + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('supplier')->where([['id','=',$class['supplier']]])->inc('balance',$balance)->update(); + } + //13 更新单据 + $nucleus=$class['money']==$class['actual']?2:($class['money']==0?0:1); + Db::name('buy')->where([['id','=',$class['id']]])->update(['examine'=>1,'nucleus'=>$nucleus]); + //14 单据记录 + Db::name('record')->insert(['type'=>'buy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //15 收发记录 + $summary=new Summary; + $summary->note('buy',$class['id'],true); + //16 记录操作 + pushLog('审核采购单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 匹配数据 + $listSql=[['type','=','buy'],['info','in',array_column($info,'id')]]; + $roomInfoList=Db::name('room_info')->where($listSql)->select()->toArray(); + $batchInfoList=Db::name('batch_info')->where($listSql)->select()->toArray(); + $serialInfoList=Db::name('serial_info')->where($listSql)->select()->toArray(); + $serveInfoList=Db::name('serve_info')->where($listSql)->select()->toArray(); + //2 关联单据 + if(!empty($class['source'])){ + //1 更新详情 + $borInfoDuplicate=[]; + foreach ($info as $infoVo) { + empty($infoVo['source'])||$borInfoDuplicate[]=['id'=>$infoVo['source'],'handle'=>$infoVo['nums']]; + } + empty($borInfoDuplicate)||Db::name('bor_info')->duplicate(['handle'=>Db::raw('handle - VALUES(`handle`)')])->insertAll($borInfoDuplicate); + //2 更新CALSS + $borInfo=Db::name('bor_info')->where([['pid','=',$class['source']]])->select()->toArray(); + $state=empty(mathArraySum(array_column($borInfo,'handle')))?0:1; + Db::name('bor')->where([['id','=',$class['source']]])->update(['state'=>$state]); + } + //3 仓储 + $roomDuplicate=[]; + foreach ($roomInfoList as $roomInfoVo) { + $roomDuplicate[]=['id'=>$roomInfoVo['pid'],'nums'=>$roomInfoVo['nums']]; + } + //3.1 更新仓储 + Db::name('room')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($roomDuplicate); + //3.2 删除仓储详情 + Db::name('room_info')->where([['id','in',array_column($roomInfoList,'id')]])->delete(); + //3.3 仓储|冗余 + $roomPk=array_unique(array_column($roomInfoList,'pid')); + $roomInfoData=Db::name('room_info')->where([['pid','in',$roomPk]])->select()->toArray(); + $roomDiff=array_diff($roomPk,array_unique(array_column($roomInfoData,'pid'))); + empty($roomDiff)||Db::name('room')->where([['id','in',$roomDiff]])->delete(); + //4 批次号 + if(!empty($batchInfoList)){ + //1 构造数据 + $batchInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$batchInfoList); + //2 更新批次号 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($batchInfoDuplicate); + //3 删除批次号详情 + Db::name('batch_info')->where([['id','in',array_column($batchInfoList,'id')]])->delete(); + //4 批次号|冗余 + $batchPk=array_unique(array_column($batchInfoList,'pid')); + $batchInfoData=Db::name('batch_info')->where([['pid','in',$batchPk]])->select()->toArray(); + $batchDiff=array_diff($batchPk,array_unique(array_column($batchInfoData,'pid'))); + empty($batchDiff)||Db::name('batch')->where([['id','in',$batchDiff]])->delete(); + } + //5 序列号 + if(!empty($serialInfoList)){ + //1 更新序列号 + Db::name('serial')->where([['id','in',array_column($serialInfoList,'pid')]])->update(['state'=>3]); + //2 删除序列号详情 + Db::name('serial_info')->where([['id','in',array_column($serialInfoList,'id')]])->delete(); + //3 序列号|冗余 + $serialPk=array_unique(array_column($serialInfoList,'pid')); + $serialInfoData=Db::name('serial_info')->where([['pid','in',$serialPk]])->select()->toArray(); + $serialDiff=array_diff($serialPk,array_unique(array_column($serialInfoData,'pid'))); + empty($serialDiff)||Db::name('serial')->where([['id','in',$serialDiff]])->delete(); + } + //6 服务 + if(!empty($serveInfoList)){ + //1 构造数据 + $serveInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$serveInfoList); + //2 更新服务 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($serveInfoDuplicate); + //3 删除服务详情 + Db::name('serve_info')->where([['id','in',array_column($serveInfoList,'id')]])->delete(); + //4 服务|冗余 + $servePk=array_unique(array_column($serveInfoList,'pid')); + $serveInfoData=Db::name('serve_info')->where([['pid','in',$servePk]])->select()->toArray(); + $serveDiff=array_diff($servePk,array_unique(array_column($serveInfoData,'pid'))); + empty($serveDiff)||Db::name('serve')->where([['id','in',$serveDiff]])->delete(); + } + //7 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->inc('balance',$class['money'])->update(); + //2 删除资金详情 + Db::name('account_info')->where([['type','=','buy'],['class','=',$class['id']]])->delete(); + //3 删除核销记录 + Db::name('buy_bill')->where([['pid','=',$class['id']]])->delete(); + } + //8 供应商|应付款余额 + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('supplier')->where([['id','=',$class['supplier']]])->dec('balance',$balance)->update(); + } + //9 更新单据 + Db::name('buy')->where([['id','=',$class['id']]])->update(['examine'=>0,'nucleus'=>0]); + //10 单据记录 + Db::name('record')->insert(['type'=>'buy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //11 收发记录 + $summary=new Summary; + $summary->note('buy',$class['id'],false); + //12 记录操作 + pushLog('反审核采购单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('buy', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //生成采购退货单 + public function buildBre(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //源数据 + $source=[ + 'class'=>Buys::where([['id','=',$input['id']]])->find(), + 'info'=>BuyInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['id']]])->order(['id'=>'asc'])->select()->toArray() + ]; + //状态验证 + if(mathArraySum(array_column($source['info'],'nums'))==mathArraySum(array_column($source['info'],'retreat'))){ + $result=['state'=>'warning','info'=>'操作失败,无可生成的数据!']; + }else{ + //CLASS数据 + $class=[ + 'source'=>$source['class']['id'], + 'supplier'=>$source['class']['supplier'], + 'total'=>0 + ]; + //INFO数据 + $info=[]; + $fun=getSys('fun'); + foreach ($source['info'] as $infoVo) { + //判断入库状态 + if(bccomp($infoVo['nums'],$infoVo['retreat'])==1){ + $infoVo['source']=$infoVo['id']; + $infoVo['serial']=[]; + //重算价格 + $infoVo['nums']=math()->chain($infoVo['nums'])->sub($infoVo['retreat'])->done(); + $storage=math()->chain($infoVo['price'])->mul($infoVo['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($infoVo['discount']==0){ + $infoVo['total']=$storage; + }else{ + $infoVo['dsc']=math()->chain($storage)->div(100)->mul($infoVo['discount'])->round($fun['digit']['money'])->done(); + $infoVo['total']=math()->chain($storage)->sub($infoVo['dsc'])->done(); + } + //税额|价税合计 + if($infoVo['tax']==0){ + $infoVo['tpt']=$infoVo['total']; + }else{ + $infoVo['tat']=math()->chain($infoVo['total'])->div(100)->mul($infoVo['tax'])->round(2)->done(); + $infoVo['tpt']=math()->chain($infoVo['total'])->add($infoVo['tat'])->done(); + } + //转存数据 + $info[]=$infoVo; + $class['total']=math()->chain($class['total'])->add($infoVo['tpt'])->done();//累加单据金额 + } + } + $result=['state'=>'success','info'=>['class'=>$class,'info'=>$info]]; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //供应商匹配 + $supplier=Db::name('supplier')->where([['name','=',$data[3]['A']]])->find(); + if(empty($supplier)){ + throw new ValidateException('供应商[ '.$data[3]['A'].' ]未匹配!'); + } + //结算账户匹配 + if(empty($data[3]['F'])){ + $account=['id'=>0]; + }else{ + $account=Db::name('account')->where([['name','=',$data[3]['G']]])->find(); + if(empty($account)){ + throw new ValidateException('结算账户[ '.$data[3]['G'].' ]不正确!'); + } + } + //关联人员匹配 + if(empty($data[3]['H'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['H']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['H'].' ]未匹配!'); + } + } + $class=[ + 'source'=>0, + 'frame'=>userInfo(getUserID(),'frame'), + 'supplier'=>$supplier['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'actual'=>$data[3]['E'], + 'money'=>$data[3]['F'], + 'account'=>$account['id'], + 'people'=>$people['id'], + 'logistics'=>["key"=>"auto","name"=>"自动识别","number"=>$data[3]['I']], + 'file'=>[], + 'data'=>$data[3]['J'], + 'more'=>[], + 'examine'=>0, + 'nucleus'=>0, + 'cse'=>0, + 'invoice'=>0, + 'check'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Buy');//数据合法性验证 + //初始化INFO + $info=[]; + $goods=Goods::with(['attr'])->where([['name','in',array_column($data,'K')]])->select()->toArray(); + $warehouse=Db::name('warehouse')->where([['name','in',array_column($data,'N')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'source'=>0, + 'goods'=>$dataVo['K'], + 'attr'=>$dataVo['L'], + 'unit'=>$dataVo['M'], + 'warehouse'=>$dataVo['N'], + 'batch'=>$dataVo['O'], + 'mfd'=>$dataVo['P'], + 'price'=>$dataVo['Q'], + 'nums'=>$dataVo['R'], + 'serial'=>explode(',',$dataVo['S']), + 'discount'=>$dataVo['T'], + 'dsc'=>0, + 'total'=>0, + 'tax'=>$dataVo['W'], + 'tat'=>0, + 'tpt'=>0, + 'data'=>$dataVo['Z'], + 'retreat'=>0, + ]; + //商品匹配 + $goodsFind=search($goods)->where([['name','=',$record['goods']]])->find(); + if(empty($goodsFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行商品名称[ '.$record['goods'].' ]未匹配!'); + }else{ + $record['goods']=$goodsFind['id']; + } + //辅助属性匹配 + if(empty($goodsFind['attr'])){ + $record['attr']=''; + }else{ + if(empty($record['attr'])){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性不可为空!'); + }else{ + $attrFind=search($goodsFind['attr'])->where([['name','=',$record['attr']]])->find(); + if(empty($attrFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性[ '.$record['attr'].' ]未匹配!'); + } + } + } + //单位匹配 + if($goodsFind['unit']==-1){ + if(empty($record['unit'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单位不可为空!'); + }else{ + $unitFind=search($goodsFind['units'])->where([['name','=',$record['unit']]])->find(); + if(empty($unitFind) && $goodsFind['units'][0]['source']!=$record['unit']){ + throw new ValidateException('模板文件第'.$dataKey.'行单位[ '.$record['unit'].' ]未匹配!'); + } + } + }else{ + $record['unit']=$goodsFind['unit']; + } + //仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $warehouseFind=search($warehouse)->where([['name','=',$record['warehouse']]])->find(); + if(empty($warehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行仓库[ '.$record['warehouse'].' ]未匹配!'); + }else{ + $record['warehouse']=$warehouseFind['id']; + } + }else{ + //服务产品 + $record['warehouse']=null; + } + //批次号匹配 + if(empty($goodsFind['batch'])){ + $record['batch']=''; + }else{ + if(empty($record['batch'])){ + throw new ValidateException('模板文件第'.$dataKey.'行批次号不可为空!'); + } + } + //生产日期匹配 + if(empty($goodsFind['validity'])){ + $record['mfd']=''; + }else{ + if(empty($record['mfd'])){ + throw new ValidateException('模板文件第'.$dataKey.'行生产日期不可为空!'); + } + } + //单价匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['price'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单价不正确!'); + } + //数量匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['nums']."})?$/",$record['nums'])){ + throw new ValidateException('模板文件第'.$dataKey.'行数量不正确!'); + } + //序列号匹配 + if(empty($goodsFind['serial'])){ + $record['serial']=[]; + }else{ + if(count($record['serial'])==1 && empty($record['serial'][0])){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号不可为空!'); + }else{ + if(count($record['serial'])!=$record['nums']){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号个数与数量不符!'); + } + } + } + try{ + $this->validate($record,'app\validate\BuyInfo');//数据合法性验证 + $storage=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($record['discount']==0){ + $record['total']=$storage; + }else{ + $record['dsc']=math()->chain($storage)->div(100)->mul($record['discount'])->round($fun['digit']['money'])->done(); + $record['total']=math()->chain($storage)->sub($record['dsc'])->done(); + } + //税额|价税合计 + if($record['tax']==0){ + $record['tpt']=$record['total']; + }else{ + $record['tat']=math()->chain($record['total'])->div(100)->mul($record['tax'])->round(2)->done(); + $record['tpt']=math()->chain($record['total'])->add($record['tat'])->done(); + } + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['tpt'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + //序列号重复验证 + $serials=[]; + foreach ($info as $infoVo) { + $serials = array_merge($serials,$infoVo['serial']); + } + if(count($serials)!=count(array_unique($serials))){ + throw new ValidateException('商品信息中存在重复序列号!'); + } + //CLASS数据验证 + if(bccomp($class['total'],$class['actual'])==-1){ + throw new ValidateException('实际金额不可大于单据金额[ '.$class['total'].' ]!'); + }else if(bccomp($class['actual'],$class['money'])==-1){ + throw new ValidateException('实付金额不可大于实际金额[ '.floatval($class['actual']).' ]!'); + }else{ + Db::startTrans(); + try { + //新增CLASS + $classData=Buys::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new BuyInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'buy','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入采购单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出采购单列表');//日志 + $source=Buys::with(['frameData','supplierData','accountData','userData','peopleData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'supplierData|name'=>'供应商', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'actual'=>'实际金额', + 'money'=>'单据付款', + 'extension|amount'=>'核销金额', + 'cost'=>'单据费用', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|nucleus'=>'核销状态', + 'extension|cse'=>'费用状态', + 'extension|invoice'=>'发票状态', + 'extension|check'=>'核对状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据金额:'.mathArraySum(array_column($source,'total')), + '总实际金额:'.mathArraySum(array_column($source,'actual')), + '总单据付款:'.mathArraySum(array_column($source,'money')), + '总核销金额:'.mathArraySum(arrayColumns($source,['extension','amount'])), + '总单据费用:'.mathArraySum(array_column($source,'cost')) + ]]; + //导出execl + buildExcel('采购单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'采购单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '供应商:'.$sourceVo['supplierData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'goodsData|spec'=>'规格型号', + 'attr'=>'辅助属性', + 'unit'=>'单位', + 'warehouseData|name'=>'仓库', + 'batch'=>'批次号', + 'mfd'=>'生产日期', + 'price'=>'单价', + 'nums'=>'数量', + 'extension|serial'=>'序列号', + 'retreat'=>'退货数量', + 'discount'=>'折扣率', + 'dsc'=>'折扣额', + 'total'=>'金额', + 'tax'=>'税率', + 'tat'=>'税额', + 'tpt'=>'价税合计', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=BuyInfo::with(['goodsData','warehouseData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->append(['extension'])->select()->toArray(); + //批次号匹配 + if(empty(search($info)->where([['goodsData|batch','=',true]])->find())){ + unset($field['batch']); + } + //生产日期匹配 + if(empty(search($info)->where([['goodsData|validity','=',true]])->find())){ + unset($field['mfd']); + } + //序列号匹配 + if(empty(search($info)->where([['goodsData|serial','=',true]])->find())){ + unset($field['extension|serial']); + } + //退货数量匹配 + if(empty(search($info)->where([['retreat','<>',0]])->find())){ + unset($field['retreat']); + } + //税金匹配 + $fun=getSys('fun'); + if(empty(search($info)->where([['tax','<>',0]])->find()) && !$fun['tax']){ + unset($field['tax']); + unset($field['tat']); + unset($field['tpt']); + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '单据费用:'.$sourceVo['cost'], + '实际金额:'.$sourceVo['actual'], + '核销金额:'.$sourceVo['extension']['amount'], + '结算账户:'.arraySeek($sourceVo,'accountData|name'), + '发票信息:'.$sourceVo['invoice'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '物流信息:'.$sourceVo['extension']['logistics'], + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + + } + buildZip('采购单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Category.php b/serve/app/controller/Category.php new file mode 100644 index 0000000..e517a3c --- /dev/null +++ b/serve/app/controller/Category.php @@ -0,0 +1,106 @@ +'asc'])->select()); + return json(['state'=>'success','info'=>$category]); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + if(empty($input['id'])){ + $this->validate($input,'app\validate\Category'); + }else{ + $this->validate($input,'app\validate\Category.update'); + //所属不可等于或包含当前 + if(in_array($input['pid'],findTreeArr('category',$input['id'],'id'))){ + throw new ValidateException('所属类别选择不正确!'); + } + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Categorys::create($input); + pushLog('新增商品类别[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Categorys::update($input); + pushLog('更新商品类别[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Categorys::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $subFind=Db::name('category')->where([['pid','=',$input['id']]])->find(); + if(empty($subFind)){ + //关联判断 + $exist=moreTableFind([ + ['table'=>'goods','where'=>[['category','=',$input['id']]]], + ]); + if(empty($exist)){ + //逻辑处理 + $find=Db::name('category')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + try { + Db::name('category')->where([['id','=',$input['id']]])->delete(); + pushLog('删除商品类别[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'存在子数据,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} diff --git a/serve/app/controller/Code.php b/serve/app/controller/Code.php new file mode 100644 index 0000000..80ccf70 --- /dev/null +++ b/serve/app/controller/Code.php @@ -0,0 +1,207 @@ +count();//获取总条数 + $info = Codes::where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + empty($input['id'])?$this->validate($input,'app\validate\Code'):$this->validate($input,'app\validate\Code.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Codes::create($input); + pushLog('新增条码[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Codes::update($input); + pushLog('更新条码[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Codes::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('code')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + Db::startTrans(); + try { + Db::name('code')->where([['id','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除条码信息[ '.implode(' | ',array_column($data,'name')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + $sql=[];//初始化SQL + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'name'=>$dataVo['A'], + 'info'=>$dataVo['B'], + 'type'=>$dataVo['C']=="条形码"?0:1, + 'data'=>$dataVo['D'] + ]; + //数据合法性验证 + try { + $this->validate($record,'app\validate\Code'); + $sql[]=$record;//加入SQL + } catch (ValidateException $e) { + //返回错误信息 + return json(['state'=>'error','info'=>'模板文件第[ '.$dataKey.' ]行'.$e->getError()]); + exit; + } + } + //新增数据 + $code = new Codes; + $code->saveAll($sql); + $result=['state'=>'success','info'=>'成功导入'.count($sql).'行条码数据']; + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $info=Codes::where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询数据 + //生成并关联图像信息 + foreach ($info as $infoKey=>$infoVo) { + if($infoVo['type']==0){ + $info[$infoKey]['img']=[ + 'type'=>'img', + 'info'=>txm($infoVo['info'],false) + ]; + }else if($infoVo['type']==1){ + $info[$infoKey]['img']=[ + 'type'=>'img', + 'info'=>ewm($infoVo['info'],false) + ]; + }else{ + exit("Error"); + } + } + $field=[ + 'name'=>'条码名称', + 'info'=>'条码内容', + 'extension|type'=>'条码类型', + 'img'=>'条码图像', + 'data'=>'备注信息' + ]; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'条码信息']; + //表格数据 + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>['总数:'.count($info)]]; + //导出execl + pushLog('导出条码信息');//日志 + buildExcel('条码信息',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } + //图像 + public function view(){ + $input=input('get.'); + if(existFull($input,['text','type']) && in_array($input['type'],['txm','ewm'])){ + if($input['type']=='txm'){ + //条形码 + txm($input['text']); + }else if($input['type']=='ewm'){ + //二维条 + ewm($input['text']); + }else{ + exit('error'); + } + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Cost.php b/serve/app/controller/Cost.php new file mode 100644 index 0000000..045e720 --- /dev/null +++ b/serve/app/controller/Cost.php @@ -0,0 +1,420 @@ +'type'],'fullIn'], + ['iet','fullIn'], + ['state','fullIn'] + ]); + //基础语句 + $sql['base']=fastSql($input,[ + [['number'=>'number'],'fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql['base'][]=['examine','=',1]; + $sql['base'][]=['id','=',Db::raw('cost.class')]; + $sql['base']=frameScope($sql['base']); + //场景匹配 + foreach ($input['mold'] as $mold) { + if(in_array($mold,['buy','bre','entry'])){ + //供应商 + $sql[$mold]=array_merge($sql['base'],fastSql($input,[['supplier','fullEq']])); + }else if(in_array($mold,['sell','sre','extry'])){ + //客户 + $sql[$mold]=array_merge($sql['base'],fastSql($input,[['customer','fullEq']])); + }else{ + //调拨单 + $sql[$mold]=$sql['base']; + } + $sql[$mold]=sqlAuth($mold,$sql[$mold]);//数据鉴权 + } + //构造查询 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->alias('class')->where([['cost.type','=',$mold]])->where($sql[$mold])->limit(1)->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $count=Costs::alias('cost')->where($sql['cost'])->whereExists($union)->count(); + $info=Costs::with(['sourceData'=>['frameData'],'ietData'])->alias('cost')->where($sql['cost'])->whereExists($union)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //匹配往来单位 + $currentList=['customer'=>[],'supplier'=>[]]; + //匹配客戶 + foreach (search($info)->where([['type','in',['sell','sre','extry']]])->select() as $item) { + $currentList['customer'][]=$item['sourceData']['customer']; + } + empty($currentList['customer'])||$currentList['customer']=Db::name('customer')->where([['id','in',array_unique($currentList['customer'])]])->select()->toArray(); + //匹配供应商 + foreach (search($info)->where([['type','in',['buy','bre','entry']]])->select() as $item) { + $currentList['supplier'][]=$item['sourceData']['supplier']; + } + empty($currentList['supplier'])||$currentList['supplier']=Db::name('supplier')->where([['id','in',array_unique($currentList['supplier'])]])->select()->toArray(); + foreach ($info as $key=>$vo) { + //未结算金额 + $info[$key]['uat']=math()->chain($vo['money'])->sub($vo['settle'])->done(); + //往来单位 + if(in_array($vo['type'],['buy','bre','entry'])){ + $info[$key]['current']=search($currentList['supplier'])->where([['id','=',$vo['sourceData']['supplier']]])->find(); + }else if(in_array($vo['type'],['sell','sre','extry'])){ + $info[$key]['current']=search($currentList['customer'])->where([['id','=',$vo['sourceData']['customer']]])->find(); + }else{ + $info[$key]['current']=[]; + } + $info[$key]['csa']=''; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //购销费用-导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + pushLog('导出购销费用');//日志 + $info=Costs::with(['sourceData'=>['frameData'],'ietData'])->alias('cost')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //匹配往来单位 + $currentList=['customer'=>[],'supplier'=>[]]; + //匹配客戶 + foreach (search($info)->where([['type','in',['sell','sre','extry']]])->select() as $item) { + $currentList['customer'][]=$item['sourceData']['customer']; + } + empty($currentList['customer'])||$currentList['customer']=Db::name('customer')->where([['id','in',array_unique($currentList['customer'])]])->select()->toArray(); + //匹配供应商 + foreach (search($info)->where([['type','in',['buy','bre','entry']]])->select() as $item) { + $currentList['supplier'][]=$item['sourceData']['supplier']; + } + empty($currentList['supplier'])||$currentList['supplier']=Db::name('supplier')->where([['id','in',array_unique($currentList['supplier'])]])->select()->toArray(); + foreach ($info as $key=>$vo) { + //未结算金额 + $info[$key]['uat']=math()->chain($vo['money'])->sub($vo['settle'])->done(); + //往来单位 + if(in_array($vo['type'],['buy','bre','entry'])){ + $info[$key]['current']=search($currentList['supplier'])->where([['id','=',$vo['sourceData']['supplier']]])->find(); + }else if(in_array($vo['type'],['sell','sre','extry'])){ + $info[$key]['current']=search($currentList['customer'])->where([['id','=',$vo['sourceData']['customer']]])->find(); + }else{ + $info[$key]['current']=[]; + } + } + $source=$info; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'购销费用']; + //表格数据 + $field=[ + 'extension|type'=>'单据类型', + 'sourceData|frameData|name'=>'所属组织', + 'current|name'=>'往来单位', + 'sourceData|time'=>'单据时间', + 'sourceData|number'=>'单据编号', + 'ietData|name'=>'支出类别', + 'extension|state'=>'结算状态', + 'money'=>'金额', + 'settle'=>'已结算金额', + 'uat'=>'未结算金额' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '单据总金额:'.mathArraySum(array_column($source,'money')), + '已结算总金额:'.mathArraySum(array_column($source,'settle')), + '未结算总金额:'.mathArraySum(array_column($source,'uat')) + ]]; + //导出execl + buildExcel('购销费用',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //生成其它支出单 + public function buildOce(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //源数据 + $list=Costs::with(['ietData'])->where([['id','in',array_column($input['parm'],'id')],['state','<>',2]])->order(['id'=>'asc'])->select()->toArray(); + if(empty($list)){ + $result=['state'=>'warning','info'=>'操作失败,无可结算数据!']; + }else{ + //CLASS数据 + $class=[ + 'total'=>0 + ]; + //INFO数据 + $info=[]; + foreach ($list as $vo) { + $find=search($input['parm'])->where([['id','=',$vo['id']]])->find(); + //判断结算金额 + if(bccomp($find['csa'],math()->chain($vo['money'])->sub($vo['settle'])->done())==1){ + $item=Costs::with(['sourceData'])->where([['id','=',$vo['id']]])->find(); + return json(['state'=>'warning','info'=>'单据编号[ '.$item['sourceData']['number'].' ]结算金额不可大于未结算金额!']); + exit; + }else{ + //转存数据 + $info[]=[ + 'source'=>$vo['id'], + 'iet'=>$vo['iet'], + 'ietData'=>$vo['ietData'], + 'money'=>$find['csa'], + 'data'=>'' + ]; + $class['total']=math()->chain($class['total'])->add($find['csa'])->done();//累加单据金额 + } + } + $result=['state'=>'success','info'=>['class'=>$class,'info'=>$info]]; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + + //报表数据 + public function form(){ + $input=input('post.'); + $sheet=['buy','bre','sell','sre','entry','extry']; + existFull($input,['state'])||$input['state']=[1,2]; + existFull($input,['mold'])||$input['mold']=$sheet; + if(existFull($input,['page','limit']) && is_arrays($input,['iet','state','mold']) && arrayInArray($input['state'],[1,2]) && arrayInArray($input['mold'],$sheet)){ + $sql=[]; + //查询语句 + $sql['cost']=fastSql($input,[ + [['mold'=>'type'],'fullIn'], + ['iet','fullIn'], + ['state','fullIn'] + ]); + //基础语句 + $sql['base']=fastSql($input,[ + [['number'=>'number'],'fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql['base'][]=['examine','=',1]; + $sql['base'][]=['id','=',Db::raw('cost.class')]; + $sql['base']=frameScope($sql['base']); + //场景匹配 + foreach ($input['mold'] as $mold) { + if(in_array($mold,['buy','bre','entry'])){ + $sql[$mold]=array_merge($sql['base'],fastSql($input,[['supplier','fullEq']])); + }else{ + $sql[$mold]=array_merge($sql['base'],fastSql($input,[['customer','fullEq']])); + } + $sql[$mold]=sqlAuth($mold,$sql[$mold]);//数据鉴权 + } + //构造查询 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->alias('class')->where([['cost.type','=',$mold]])->where($sql[$mold])->limit(1)->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $count=Costs::alias('cost')->where($sql['cost'])->whereExists($union)->count(); + $info=Costs::with(['sourceData'=>['frameData'],'ietData'])->alias('cost')->where($sql['cost'])->whereExists($union)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //匹配往来单位 + $currentList=['customer'=>[],'supplier'=>[]]; + //匹配客戶 + foreach (search($info)->where([['type','in',['sell','sre','extry']]])->select() as $item) { + $currentList['customer'][]=$item['sourceData']['customer']; + } + empty($currentList['customer'])||$currentList['customer']=Db::name('customer')->where([['id','in',array_unique($currentList['customer'])]])->select()->toArray(); + //匹配供应商 + foreach (search($info)->where([['type','in',['buy','bre','entry']]])->select() as $item) { + $currentList['supplier'][]=$item['sourceData']['supplier']; + } + empty($currentList['supplier'])||$currentList['supplier']=Db::name('supplier')->where([['id','in',array_unique($currentList['supplier'])]])->select()->toArray(); + //查询子节点 + if(!empty($info)){ + $gather=CostInfo::with(['oceData'=>['frameData','supplierData']])->where([['pid','in',array_column($info,'id')]])->select()->toArray(); + } + foreach ($info as $key=>$vo) { + $info[$key]['key']=$vo['id']; + //往来单位 + if(in_array($vo['type'],['buy','bre','entry'])){ + $info[$key]['current']=search($currentList['supplier'])->where([['id','=',$vo['sourceData']['supplier']]])->find(); + }else if(in_array($vo['type'],['sell','sre','extry'])){ + $info[$key]['current']=search($currentList['customer'])->where([['id','=',$vo['sourceData']['customer']]])->find(); + }else{ + $info[$key]['current']=[]; + } + $node=[]; + $costInfo=search($gather)->where([['pid','=',$vo['id']]])->select(); + foreach($costInfo as $costInfoVo){ + $node[]=[ + 'key'=>$costInfoVo['pid'].'_'.$costInfoVo['id'], + 'extension'=>['type'=>'其它支出单','state'=>'-'], + 'sourceData'=>$costInfoVo['oceData'], + 'current'=>empty($costInfoVo['oceData']['supplier'])?['name'=>'']:$costInfoVo['oceData']['supplierData'], + 'ietData'=>['name'=>'-'], + 'money'=>$costInfoVo['money'] + ]; + } + //匹配子节点 + $info[$key]['node']=$node; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //购销费用报表-导出 + public function formExports(){ + $input=input('get.'); + $sheet=['buy','bre','sell','sre','entry','extry']; + existFull($input,['iet'])||$input['iet']=[]; + existFull($input,['state'])||$input['state']=[1,2]; + existFull($input,['mold'])||$input['mold']=$sheet; + if(is_arrays($input,['iet','state','mold']) && arrayInArray($input['state'],[1,2]) && arrayInArray($input['mold'],$sheet)){ + pushLog('导出购销费用报表');//日志 + $sql=[]; + //查询语句 + $sql['cost']=fastSql($input,[ + [['mold'=>'type'],'fullIn'], + ['iet','fullIn'], + ['state','fullIn'] + ]); + //基础语句 + $sql['base']=fastSql($input,[ + [['number'=>'number'],'fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql['base'][]=['examine','=',1]; + $sql['base'][]=['id','=',Db::raw('cost.class')]; + $sql['base']=frameScope($sql['base']); + //场景匹配 + foreach ($input['mold'] as $mold) { + if(in_array($mold,['buy','bre','entry'])){ + $sql[$mold]=array_merge($sql['base'],fastSql($input,[['supplier','fullEq']])); + }else{ + $sql[$mold]=array_merge($sql['base'],fastSql($input,[['customer','fullEq']])); + } + $sql[$mold]=sqlAuth($mold,$sql[$mold]);//数据鉴权 + } + //构造查询 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->alias('class')->where([['cost.type','=',$mold]])->where($sql[$mold])->limit(1)->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $info=Costs::with(['sourceData'=>['frameData'],'ietData'])->alias('cost')->where($sql['cost'])->whereExists($union)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //匹配往来单位 + $currentList=['customer'=>[],'supplier'=>[]]; + //匹配客戶 + foreach (search($info)->where([['type','in',['sell','sre','extry']]])->select() as $item) { + $currentList['customer'][]=$item['sourceData']['customer']; + } + empty($currentList['customer'])||$currentList['customer']=Db::name('customer')->where([['id','in',array_unique($currentList['customer'])]])->select()->toArray(); + //匹配供应商 + foreach (search($info)->where([['type','in',['buy','bre','entry']]])->select() as $item) { + $currentList['supplier'][]=$item['sourceData']['supplier']; + } + empty($currentList['supplier'])||$currentList['supplier']=Db::name('supplier')->where([['id','in',array_unique($currentList['supplier'])]])->select()->toArray(); + //查询子节点 + if(!empty($info)){ + $gather=CostInfo::with(['oceData'=>['frameData','supplierData']])->where([['pid','in',array_column($info,'id')]])->select()->toArray(); + } + foreach ($info as $key=>$vo) { + $info[$key]['key']=$vo['id']; + //往来单位 + if(in_array($vo['type'],['buy','bre','entry'])){ + $info[$key]['current']=search($currentList['supplier'])->where([['id','=',$vo['sourceData']['supplier']]])->find(); + }else if(in_array($vo['type'],['sell','sre','extry'])){ + $info[$key]['current']=search($currentList['customer'])->where([['id','=',$vo['sourceData']['customer']]])->find(); + }else{ + $info[$key]['current']=[]; + } + $node=[]; + $costInfo=search($gather)->where([['pid','=',$vo['id']]])->select(); + foreach($costInfo as $costInfoVo){ + $node[]=[ + 'key'=>$costInfoVo['pid'].'_'.$costInfoVo['id'], + 'extension'=>['type'=>'其它支出单','state'=>'-'], + 'sourceData'=>$costInfoVo['oceData'], + 'current'=>empty($costInfoVo['oceData']['supplier'])?['name'=>'']:$costInfoVo['oceData']['supplierData'], + 'ietData'=>['name'=>'-'], + 'money'=>$costInfoVo['money'] + ]; + } + //匹配子节点 + $info[$key]['node']=$node; + } + //结构重组 + $source=[]; + foreach ($info as $infoVo) { + $source[]=$infoVo; + if(!empty($infoVo['node'])){ + foreach ($infoVo['node'] as $nodeVo) { + $nodeVo['extension']['type']='|- '.$nodeVo['extension']['type']; + $source[]=$nodeVo; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'购销费用报表']; + //表格数据 + $field=[ + 'extension|type'=>'单据类型', + 'sourceData|frameData|name'=>'所属组织', + 'current|name'=>'往来单位', + 'sourceData|time'=>'单据时间', + 'sourceData|number'=>'单据编号', + 'ietData|name'=>'支出类别', + 'extension|state'=>'结算状态', + 'money'=>'金额' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source) + ]]; + //导出execl + buildExcel('购销费用报表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } +} diff --git a/serve/app/controller/Crt.php b/serve/app/controller/Crt.php new file mode 100644 index 0000000..d8fb9bd --- /dev/null +++ b/serve/app/controller/Crt.php @@ -0,0 +1,1869 @@ +'id'],'fullEq'], + ]); + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('account',$sql);//数据鉴权 + //数据查询 + $count=Db::name('account')->where($sql)->count(); + $data=Db::name('account')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['user','fullEq'] + ]); + $existsSql[]=['id','=',Db::raw('info.class')]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + $where=[['pid','in',array_column($data,'id')]]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','imy'=>'imy','omy'=>'omy','allotOut'=>'allot','allotEnter'=>'allot','ice'=>'ice','oce'=>'oce']; + foreach ($table as $k=>$v) { + $unionSql=array_merge([['info.type','=',$k]],$existsSql); + if(existFull($input,['supplier','customer'])){ + //供应商-客户 + if(!in_array($v,['allot'])){ + in_array($v,['buy','bre','omy','oce'])&&$unionSql=array_merge($unionSql,fastSql($input,[['supplier','fullEq']])); + in_array($v,['sell','sre','imy','ice'])&&$unionSql=array_merge($unionSql,fastSql($input,[['customer','fullEq']])); + $unionSql=sqlAuth($v,$unionSql); + $union[]=Db::name($v)->where($unionSql)->limit(1)->buildSql(); + } + count($where)==1&&$where[]=['type','in',['buy','bre','omy','oce','sell','sre','imy','ice']]; + }else{ + if(existFull($input,['supplier'])){ + //供应商 + if(in_array($v,['buy','bre','omy','oce'])){ + $unionSql=array_merge($unionSql,fastSql($input,[['supplier','fullEq']])); + $unionSql=sqlAuth($v,$unionSql); + $union[]=Db::name($v)->where($unionSql)->limit(1)->buildSql(); + } + count($where)==1&&$where[]=['type','in',['buy','bre','omy','oce']]; + }elseif(existFull($input,['customer'])){ + //客户 + if(in_array($v,['sell','sre','imy','ice'])){ + $unionSql=array_merge($unionSql,fastSql($input,[['customer','fullEq']])); + $unionSql=sqlAuth($v,$unionSql); + $union[]=Db::name($v)->where($unionSql)->limit(1)->buildSql(); + } + count($where)==1&&$where[]=['type','in',['sell','sre','imy','ice']]; + }else{ + //空 + $unionSql=sqlAuth($v,$unionSql); + $union[]=Db::name($v)->where($unionSql)->limit(1)->buildSql(); + } + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $infoList=AccountInfo::with(['sourceData'=>['frameData','userData']])->alias('info')->where($where)->whereExists($union)->append(['extension'])->order('time asc')->select()->toArray(); + //匹配往来单位 + $currentList=['customer'=>[],'supplier'=>[]]; + //匹配客戶 + foreach (search($infoList)->where([['type','in',['sell','sre','imy','ice']]])->select() as $item) { + $currentList['customer'][]=$item['sourceData']['customer']; + } + empty($currentList['customer'])||$currentList['customer']=Db::name('customer')->where([['id','in',array_unique($currentList['customer'])]])->select()->toArray(); + //匹配供应商 + foreach (search($infoList)->where([['type','in',['buy','bre','omy','oce']]])->select() as $item) { + $currentList['supplier'][]=$item['sourceData']['supplier']; + } + empty($currentList['supplier'])||$currentList['supplier']=Db::name('supplier')->where([['id','in',array_unique($currentList['supplier'])]])->select()->toArray(); + //匹配节点 + foreach($data as $key => $vo){ + $data[$key]['key'] = $vo['id']; + $data[$key]['number'] = ''; + $data[$key]['time'] = ''; + $node = search($infoList)->where([['pid', '=', $vo['id']]])->select(); + //计算期初 + $stats=Db::name('account_info')->where([['pid','=',$vo['id']],['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0]])->group('direction')->fieldRaw('direction,sum(money) as money')->order('direction desc')->select()->toArray(); + if(empty($stats)){ + $balance=floatval($vo['initial']); + }else if(count($stats)==1){ + if(empty($stats[0]['direction'])){ + //纯出 + $balance=math()->chain($stats[0]['money'])->mul(-1)->add($vo['initial'])->done(); + }else{ + //纯入 + $balance=math()->chain($stats[0]['money'])->add($vo['initial'])->done(); + } + }else{ + $balance=math()->chain($stats[0]['money'])->sub($stats[1]['money'])->add($vo['initial'])->done(); + } + //赋值期初 + array_unshift($node,['key'=>$vo['id'].'_'.'0','extension'=>['type'=>'期初余额'],'balance'=>$balance]); + //节点赋值 + foreach($node as $nodeKey => $nodeVo){ + //排除期初 + if(!empty($nodeKey)){ + $node[$nodeKey]['key'] = $nodeVo['pid']."_".$nodeVo['id']; + //类型判断 + if(empty($nodeVo['direction'])){ + $node[$nodeKey]['in'] = 0; + $node[$nodeKey]['out'] = $nodeVo['money']; + $node[$nodeKey]['balance'] = math()->chain($node[$nodeKey-1]['balance'])->sub($nodeVo['money'])->done(); + }else{ + $node[$nodeKey]['in'] = $nodeVo['money']; + $node[$nodeKey]['out'] = 0; + $node[$nodeKey]['balance'] = math()->chain($node[$nodeKey-1]['balance'])->add($nodeVo['money'])->done(); + } + //往来单位 + if(in_array($nodeVo['type'],['buy','bre','omy','oce'])){ + $node[$nodeKey]['current']=search($currentList['supplier'])->where([['id','=',$nodeVo['sourceData']['supplier']]])->find(); + }else if(in_array($nodeVo['type'],['sell','sre','imy','ice'])){ + $node[$nodeKey]['current']=search($currentList['customer'])->where([['id','=',$nodeVo['sourceData']['customer']]])->find(); + }else{ + $node[$nodeKey]['current']=[]; + } + } + } + //汇总数据 + $data[$key]['in']=mathArraySum(array_column($node,'in')); + $data[$key]['out']=mathArraySum(array_column($node,'out')); + $data[$key]['balance']=$node[count($node)-1]['balance']; + $data[$key]['node'] = $node; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //现金银行报表-导出 + public function cbfExports(){ + $input=input('get.'); + $sql=[]; + //CLASS语句 + $sql=fastSql($input,[ + [['account'=>'id'],'fullEq'], + ]); + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('account',$sql);//数据鉴权 + //数据查询 + $data=Db::name('account')->where($sql)->order(['id'=>'desc'])->select()->toArray(); + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['user','fullEq'] + ]); + $existsSql[]=['id','=',Db::raw('info.class')]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + $where=[['pid','in',array_column($data,'id')]]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','imy'=>'imy','omy'=>'omy','allotOut'=>'allot','allotEnter'=>'allot','ice'=>'ice','oce'=>'oce']; + foreach ($table as $k=>$v) { + $unionSql=array_merge([['info.type','=',$k]],$existsSql); + if(existFull($input,['supplier','customer'])){ + //供应商-客户 + if(!in_array($v,['allot'])){ + in_array($v,['buy','bre','omy','oce'])&&$unionSql=array_merge($unionSql,fastSql($input,[['supplier','fullEq']])); + in_array($v,['sell','sre','imy','ice'])&&$unionSql=array_merge($unionSql,fastSql($input,[['customer','fullEq']])); + $unionSql=sqlAuth($v,$unionSql); + $union[]=Db::name($v)->where($unionSql)->limit(1)->buildSql(); + } + count($where)==1&&$where[]=['type','in',['buy','bre','omy','oce','sell','sre','imy','ice']]; + }else{ + if(existFull($input,['supplier'])){ + //供应商 + if(in_array($v,['buy','bre','omy','oce'])){ + $unionSql=array_merge($unionSql,fastSql($input,[['supplier','fullEq']])); + $unionSql=sqlAuth($v,$unionSql); + $union[]=Db::name($v)->where($unionSql)->limit(1)->buildSql(); + } + count($where)==1&&$where[]=['type','in',['buy','bre','omy','oce']]; + }elseif(existFull($input,['customer'])){ + //客户 + if(in_array($v,['sell','sre','imy','ice'])){ + $unionSql=array_merge($unionSql,fastSql($input,[['customer','fullEq']])); + $unionSql=sqlAuth($v,$unionSql); + $union[]=Db::name($v)->where($unionSql)->limit(1)->buildSql(); + } + count($where)==1&&$where[]=['type','in',['sell','sre','imy','ice']]; + }else{ + //空 + $unionSql=sqlAuth($v,$unionSql); + $union[]=Db::name($v)->where($unionSql)->limit(1)->buildSql(); + } + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $infoList=AccountInfo::with(['sourceData'=>['frameData','userData']])->alias('info')->where($where)->whereExists($union)->append(['extension'])->order('time asc')->select()->toArray(); + //匹配往来单位 + $currentList=['customer'=>[],'supplier'=>[]]; + //匹配客戶 + foreach (search($infoList)->where([['type','in',['sell','sre','imy','ice']]])->select() as $item) { + $currentList['customer'][]=$item['sourceData']['customer']; + } + empty($currentList['customer'])||$currentList['customer']=Db::name('customer')->where([['id','in',array_unique($currentList['customer'])]])->select()->toArray(); + //匹配供应商 + foreach (search($infoList)->where([['type','in',['buy','bre','omy','oce']]])->select() as $item) { + $currentList['supplier'][]=$item['sourceData']['supplier']; + } + empty($currentList['supplier'])||$currentList['supplier']=Db::name('supplier')->where([['id','in',array_unique($currentList['supplier'])]])->select()->toArray(); + //匹配节点 + foreach($data as $key => $vo){ + $data[$key]['key'] = $vo['id']; + $data[$key]['number'] = ''; + $data[$key]['time'] = ''; + $node = search($infoList)->where([['pid', '=', $vo['id']]])->select(); + //计算期初 + $stats=Db::name('account_info')->where([['pid','=',$vo['id']],['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0]])->group('direction')->fieldRaw('direction,sum(money) as money')->order('direction desc')->select()->toArray(); + if(empty($stats)){ + $balance=floatval($vo['initial']); + }else if(count($stats)==1){ + if(empty($stats[0]['direction'])){ + //纯出 + $balance=math()->chain($stats[0]['money'])->mul(-1)->add($vo['initial'])->done(); + }else{ + //纯入 + $balance=math()->chain($stats[0]['money'])->add($vo['initial'])->done(); + } + }else{ + $balance=math()->chain($stats[0]['money'])->sub($stats[1]['money'])->add($vo['initial'])->done(); + } + //赋值期初 + array_unshift($node,['key'=>$vo['id'].'_'.'0','extension'=>['type'=>'期初余额'],'balance'=>$balance]); + //节点赋值 + foreach($node as $nodeKey => $nodeVo){ + //排除期初 + if(!empty($nodeKey)){ + $node[$nodeKey]['key'] = $nodeVo['pid']."_".$nodeVo['id']; + //类型判断 + if(empty($nodeVo['direction'])){ + $node[$nodeKey]['in'] = 0; + $node[$nodeKey]['out'] = $nodeVo['money']; + $node[$nodeKey]['balance'] = math()->chain($node[$nodeKey-1]['balance'])->sub($nodeVo['money'])->done(); + }else{ + $node[$nodeKey]['in'] = $nodeVo['money']; + $node[$nodeKey]['out'] = 0; + $node[$nodeKey]['balance'] = math()->chain($node[$nodeKey-1]['balance'])->add($nodeVo['money'])->done(); + } + //往来单位 + if(in_array($nodeVo['type'],['buy','bre','omy','oce'])){ + $node[$nodeKey]['current']=search($currentList['supplier'])->where([['id','=',$nodeVo['sourceData']['supplier']]])->find(); + }else if(in_array($nodeVo['type'],['sell','sre','imy','ice'])){ + $node[$nodeKey]['current']=search($currentList['customer'])->where([['id','=',$nodeVo['sourceData']['customer']]])->find(); + }else{ + $node[$nodeKey]['current']=[]; + } + } + } + //汇总数据 + $data[$key]['in']=mathArraySum(array_column($node,'in')); + $data[$key]['out']=mathArraySum(array_column($node,'out')); + $data[$key]['balance']=$node[count($node)-1]['balance']; + $data[$key]['node'] = $node; + } + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'现金银行报表']; + //表格数据 + $field=[ + 'name'=>'账户名称', + 'extension|type'=>'单据类型', + 'sourceData|frameData|name'=>'所属组织', + 'current|name'=>'往来单位', + 'sourceData|time'=>'单据时间', + 'sourceData|number'=>'单据编号', + 'in'=>'收入', + 'out'=>'支出', + 'balance'=>'账户余额', + 'sourceData|userData|name'=>'制单人', + 'sourceData|data'=>'备注', + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + ]]; + //导出execl + buildExcel('现金银行报表',$excel); + } + //应收账款明细表 + public function crs(){ + $input=input('post.'); + if(existFull($input,['page','limit']) && isset($input['type'])){ + $sql=[]; + //CLASS语句 + $sql=fastSql($input,[ + [['customer'=>'id'],'fullEq'], + ]); + //查询类型 + empty($input['type'])||$sql[]=['balance','>',0]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('customer',$sql);//数据鉴权 + //数据查询 + $count=Db::name('customer')->where($sql)->count(); + $data=Db::name('customer')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['examine','=',1]; + $existsSql[]=['customer','in',array_column($data,'id')]; + $existsSql=frameScope($existsSql); + //构造语句 + $union=[]; + $tab=['sell','sre','imy','ice']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where(sqlAuth($t,$existsSql))->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //匹配单据 + $bill=[]; + foreach ($tab as $t) { + $gather=search($record)->where([['mold','=',$t]])->select(); + $db="app\\model\\".ucfirst($t); + $bill=array_merge($bill,$db::with(['frameData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + } + //匹配数据 + foreach ($data as $key=>$vo) { + $data[$key]['key']=$vo['id']; + $data[$key]['cw']=0; + $data[$key]['pia']=0; + $data[$key]['balance']=0; + $node=search($bill)->where([['customer','=',$vo['id']]])->select(); + arraySort($node,'t',SORT_ASC); + //期初查询 + $nodeUnion=[]; + $nodeUnionSql=[ + ['examine','=',1], + ['customer','=',$vo['id']], + ['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0] + ]; + $nodeUnionSql=frameScope($nodeUnionSql); + + $nodeUnion=implode(' UNION ALL ',$nodeUnion); + $stats=DB::query('SELECT * FROM ('.$nodeUnion.') as nodcloud'); + $calc=[]; + + $balance=math()->chain($calc['sell'])->sub($calc['sre'])->sub($calc['imy'])->add($calc['ice'])->done(); + array_unshift($node,['key'=>$vo['id'].'_'.'0','bill'=>'期初余额','balance'=>$balance]); + foreach ($node as $nodeKey=>$nodeVo) { + //跳过期初 + if(!empty($nodeKey)){ + $node[$nodeKey]['key']=$vo['id'].'_'.$nodeVo['id'].'_'.$nodeVo['mold']; + $node[$nodeKey]['bill']=['sell'=>'销售单','sre'=>'销售退货单','imy'=>'收款单','ice'=>'其它收入单'][$nodeVo['mold']]; + if($nodeVo['mold']=='sell'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->done(); + $node[$nodeKey]['pia']=0; + }else if($nodeVo['mold']=='sre'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->mul(-1)->done(); + $node[$nodeKey]['pia']=0; + }else if($nodeVo['mold']=='imy'){ + $node[$nodeKey]['cw']=0; + $node[$nodeKey]['pia']=$nodeVo['total']; + }else if($nodeVo['mold']=='ice'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->done(); + $node[$nodeKey]['pia']=0; + } + $node[$nodeKey]['balance'] = math()->chain($node[$nodeKey-1]['balance'])->add($node[$nodeKey]['cw'])->sub($node[$nodeKey]['pia'])->done(); + } + } + $data[$key]['cw']=mathArraySum(array_column($node,'cw')); + $data[$key]['pia']=mathArraySum(array_column($node,'pia')); + $data[$key]['balance']=$node[count($node)-1]['balance']; + $data[$key]['node']=$node; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //应收账款明细表-导出 + public function crsExports(){ + $input=input('get.'); + if(isset($input['type'])){ + $sql=[]; + //CLASS语句 + $sql=fastSql($input,[ + [['customer'=>'id'],'fullEq'], + ]); + //查询类型 + empty($input['type'])||$sql[]=['balance','>',0]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('customer',$sql);//数据鉴权 + //数据查询 + $count=Db::name('customer')->where($sql)->count(); + $data=Db::name('customer')->where($sql)->order(['id'=>'desc'])->select()->toArray(); + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['examine','=',1]; + $existsSql[]=['customer','in',array_column($data,'id')]; + $existsSql=frameScope($existsSql); + //构造语句 + $union=[]; + $tab=['sell','sre','imy','ice']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where(sqlAuth($t,$existsSql))->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //匹配单据 + $bill=[]; + foreach ($tab as $t) { + $gather=search($record)->where([['mold','=',$t]])->select(); + $db="app\\model\\".ucfirst($t); + $bill=array_merge($bill,$db::with(['frameData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + } + //匹配数据 + foreach ($data as $key=>$vo) { + $data[$key]['cw']=0; + $data[$key]['pia']=0; + $data[$key]['balance']=0; + $node=search($bill)->where([['customer','=',$vo['id']]])->select(); + arraySort($node,'t',SORT_ASC); + //期初查询 + $nodeUnion=[]; + $nodeUnionSql=[ + ['examine','=',1], + ['customer','=',$vo['id']], + ['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0] + ]; + $nodeUnionSql=frameScope($nodeUnionSql); + + $nodeUnion=implode(' UNION ALL ',$nodeUnion); + $stats=DB::query('SELECT * FROM ('.$nodeUnion.') as nodcloud'); + $calc=[]; + + $balance=math()->chain($calc['sell'])->sub($calc['sre'])->sub($calc['imy'])->add($calc['ice'])->done(); + array_unshift($node,['bill'=>'期初余额','balance'=>$balance]); + foreach ($node as $nodeKey=>$nodeVo) { + //跳过期初 + if(!empty($nodeKey)){ + $node[$nodeKey]['bill']=['sell'=>'销售单','sre'=>'销售退货单','imy'=>'收款单','ice'=>'其它收入单'][$nodeVo['mold']]; + if($nodeVo['mold']=='sell'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->done(); + $node[$nodeKey]['pia']=0; + }else if($nodeVo['mold']=='sre'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->mul(-1)->done(); + $node[$nodeKey]['pia']=0; + }else if($nodeVo['mold']=='imy'){ + $node[$nodeKey]['cw']=0; + $node[$nodeKey]['pia']=$nodeVo['total']; + }else if($nodeVo['mold']=='ice'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->done(); + $node[$nodeKey]['pia']=0; + } + $node[$nodeKey]['balance'] = math()->chain($node[$nodeKey-1]['balance'])->add($node[$nodeKey]['cw'])->sub($node[$nodeKey]['pia'])->done(); + } + } + $data[$key]['cw']=mathArraySum(array_column($node,'cw')); + $data[$key]['pia']=mathArraySum(array_column($node,'pia')); + $data[$key]['balance']=$node[count($node)-1]['balance']; + $data[$key]['node']=$node; + } + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'应收账款明细表']; + //表格数据 + $field=[ + 'name'=>'客户', + 'bill'=>'单据类型', + 'frameData|name'=>'所属组织', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'cw'=>'增加应收款', + 'pia'=>'增加预收款', + 'balance'=>'应收款余额', + 'data'=>'备注', + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + ]]; + //导出execl + buildExcel('应收账款明细表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //应付账款明细表 + public function cps(){ + $input=input('post.'); + if(existFull($input,['page','limit']) && isset($input['type'])){ + $sql=[]; + //CLASS语句 + $sql=fastSql($input,[ + [['supplier'=>'id'],'fullEq'], + ]); + //查询类型 + empty($input['type'])||$sql[]=['balance','>',0]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('supplier',$sql);//数据鉴权 + //数据查询 + $count=Db::name('supplier')->where($sql)->count(); + $data=Db::name('supplier')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['examine','=',1]; + $existsSql[]=['supplier','in',array_column($data,'id')]; + $existsSql=frameScope($existsSql); + //构造语句 + $union=[]; + $tab=['buy','bre','omy','oce']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where(sqlAuth($t,$existsSql))->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //匹配单据 + $bill=[]; + foreach ($tab as $t) { + $gather=search($record)->where([['mold','=',$t]])->select(); + $db="app\\model\\".ucfirst($t); + $bill=array_merge($bill,$db::with(['frameData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + } + //匹配数据 + foreach ($data as $key=>$vo) { + $data[$key]['key']=$vo['id']; + $data[$key]['cw']=0; + $data[$key]['pia']=0; + $data[$key]['balance']=0; + $node=search($bill)->where([['supplier','=',$vo['id']]])->select(); + arraySort($node,'t',SORT_ASC); + //期初查询 + $nodeUnion=[]; + $nodeUnionSql=[ + ['examine','=',1], + ['supplier','=',$vo['id']], + ['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0] + ]; + $nodeUnionSql=frameScope($nodeUnionSql); + foreach ($tab as $t) { + $nodeUnion[]=Db::name($t)->where(sqlAuth($t,$nodeUnionSql))->fieldRaw('"'.$t.'" as mold,sum('.(in_array($t,['buy','bre','oce'])?'actual - money':'total').') as calc')->group(['mold'])->buildSql(); + } + $nodeUnion=implode(' UNION ALL ',$nodeUnion); + $stats=DB::query('SELECT * FROM ('.$nodeUnion.') as nodcloud'); + $calc=[]; + foreach ($tab as $t) { + $find=search($stats)->where([['mold','=',$t]])->find(); + if(empty($find)){ + $calc[$t]=0; + }else{ + $calc[$t]=$find['calc']; + } + } + $balance=math()->chain($calc['buy'])->sub($calc['bre'])->sub($calc['omy'])->add($calc['oce'])->done(); + array_unshift($node,['key'=>$vo['id'].'_'.'0','bill'=>'期初余额','balance'=>$balance]); + foreach ($node as $nodeKey=>$nodeVo) { + //跳过期初 + if(!empty($nodeKey)){ + $node[$nodeKey]['key']=$vo['id'].'_'.$nodeVo['id'].'_'.$nodeVo['mold']; + $node[$nodeKey]['bill']=['buy'=>'采购单','bre'=>'采购退货单','omy'=>'付款单','oce'=>'其它支出单'][$nodeVo['mold']]; + if($nodeVo['mold']=='buy'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->done(); + $node[$nodeKey]['pia']=0; + }else if($nodeVo['mold']=='bre'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->mul(-1)->done(); + $node[$nodeKey]['pia']=0; + }else if($nodeVo['mold']=='omy'){ + $node[$nodeKey]['cw']=0; + $node[$nodeKey]['pia']=$nodeVo['total']; + }else if($nodeVo['mold']=='oce'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->done(); + $node[$nodeKey]['pia']=0; + } + $node[$nodeKey]['balance'] = math()->chain($node[$nodeKey-1]['balance'])->add($node[$nodeKey]['cw'])->sub($node[$nodeKey]['pia'])->done(); + } + } + $data[$key]['cw']=mathArraySum(array_column($node,'cw')); + $data[$key]['pia']=mathArraySum(array_column($node,'pia')); + $data[$key]['balance']=$node[count($node)-1]['balance']; + $data[$key]['node']=$node; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //应付账款明细表-导出 + public function cpsExports(){ + $input=input('get.'); + if(isset($input['type'])){ + $sql=[]; + //CLASS语句 + $sql=fastSql($input,[ + [['supplier'=>'id'],'fullEq'], + ]); + //查询类型 + empty($input['type'])||$sql[]=['balance','>',0]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('supplier',$sql);//数据鉴权 + //数据查询 + $count=Db::name('supplier')->where($sql)->count(); + $data=Db::name('supplier')->where($sql)->order(['id'=>'desc'])->select()->toArray(); + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['examine','=',1]; + $existsSql[]=['supplier','in',array_column($data,'id')]; + $existsSql=frameScope($existsSql); + //构造语句 + $union=[]; + $tab=['buy','bre','omy','oce']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where(sqlAuth($t,$existsSql))->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //匹配单据 + $bill=[]; + foreach ($tab as $t) { + $gather=search($record)->where([['mold','=',$t]])->select(); + $db="app\\model\\".ucfirst($t); + $bill=array_merge($bill,$db::with(['frameData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + } + //匹配数据 + foreach ($data as $key=>$vo) { + $data[$key]['cw']=0; + $data[$key]['pia']=0; + $data[$key]['balance']=0; + $node=search($bill)->where([['supplier','=',$vo['id']]])->select(); + arraySort($node,'t',SORT_ASC); + //期初查询 + $nodeUnion=[]; + $nodeUnionSql=[ + ['examine','=',1], + ['supplier','=',$vo['id']], + ['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0] + ]; + $nodeUnionSql=frameScope($nodeUnionSql); + foreach ($tab as $t) { + $nodeUnion[]=Db::name($t)->where(sqlAuth($t,$nodeUnionSql))->fieldRaw('"'.$t.'" as mold,sum('.(in_array($t,['buy','bre','oce'])?'actual - money':'total').') as calc')->group(['mold'])->buildSql(); + } + $nodeUnion=implode(' UNION ALL ',$nodeUnion); + $stats=DB::query('SELECT * FROM ('.$nodeUnion.') as nodcloud'); + $calc=[]; + foreach ($tab as $t) { + $find=search($stats)->where([['mold','=',$t]])->find(); + if(empty($find)){ + $calc[$t]=0; + }else{ + $calc[$t]=$find['calc']; + } + } + $balance=math()->chain($calc['buy'])->sub($calc['bre'])->sub($calc['omy'])->add($calc['oce'])->done(); + array_unshift($node,['bill'=>'期初余额','balance'=>$balance]); + foreach ($node as $nodeKey=>$nodeVo) { + //跳过期初 + if(!empty($nodeKey)){ + $node[$nodeKey]['bill']=['buy'=>'采购单','bre'=>'采购退货单','omy'=>'付款单','oce'=>'其它支出单'][$nodeVo['mold']]; + if($nodeVo['mold']=='buy'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->done(); + $node[$nodeKey]['pia']=0; + }else if($nodeVo['mold']=='bre'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->mul(-1)->done(); + $node[$nodeKey]['pia']=0; + }else if($nodeVo['mold']=='omy'){ + $node[$nodeKey]['cw']=0; + $node[$nodeKey]['pia']=$nodeVo['total']; + }else if($nodeVo['mold']=='oce'){ + $node[$nodeKey]['cw']=math()->chain($nodeVo['actual'])->sub($nodeVo['money'])->done(); + $node[$nodeKey]['pia']=0; + } + $node[$nodeKey]['balance'] = math()->chain($node[$nodeKey-1]['balance'])->add($node[$nodeKey]['cw'])->sub($node[$nodeKey]['pia'])->done(); + } + } + $data[$key]['cw']=mathArraySum(array_column($node,'cw')); + $data[$key]['pia']=mathArraySum(array_column($node,'pia')); + $data[$key]['balance']=$node[count($node)-1]['balance']; + $data[$key]['node']=$node; + } + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'应付账款明细表']; + //表格数据 + $field=[ + 'name'=>'供应商', + 'bill'=>'单据类型', + 'frameData|name'=>'所属组织', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'cw'=>'增加应付款', + 'pia'=>'增加预付款', + 'balance'=>'应付款余额', + 'data'=>'备注', + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + ]]; + //导出execl + buildExcel('应付账款明细表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //客户对账单 + public function cct(){ + $input=input('post.'); + if(existFull($input,['customer']) && isset($input['type'])){ + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['examine','=',1]; + $existsSql[]=['customer','=',$input['customer']]; + $existsSql=frameScope($existsSql); + //构造语句 + $union=[]; + $tab=['sell','sre','imy','ice']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where(sqlAuth($t,$existsSql))->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //匹配单据 + $bill=['class'=>[],'info'=>[]]; + foreach ($tab as $t) { + $gather=search($record)->where([['mold','=',$t]])->select(); + $db=['class'=>"app\\model\\".ucfirst($t),'info'=>"app\\model\\".ucfirst($t).'Info']; + $bill['class']=array_merge($bill['class'],$db['class']::with(['frameData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + //匹配明细 + if(!empty($input['type'])){ + if(in_array($t,['sell','sre'])){ + $detail=$db['info']::with(['goodsData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + }else if($t=='imy'){ + $detail=$db['info']::with(['accountData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + }else if($t=='ice'){ + $detail=$db['info']::with(['ietData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + } + $bill['info'][$t]=$detail; + } + } + arraySort($bill['class'],'t',SORT_ASC); + //期初查询 + $firstUnion=[]; + $firstUnionSql=[ + ['examine','=',1], + ['customer','=',$input['customer']], + ['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0] + ]; + $firstUnionSql=frameScope($firstUnionSql); + + $firstUnion=implode(' UNION ALL ',$firstUnion); + $stats=DB::query('SELECT * FROM ('.$firstUnion.') as nodcloud'); + $calc=[]; + + $balance=math()->chain($calc['sell'])->sub($calc['sre'])->sub($calc['imy'])->add($calc['ice'])->done(); + $data=[ + ['key'=>'0','node'=>[],'bill'=>'期初余额','balance'=>$balance], + ]; + //匹配数据 + foreach ($bill['class'] as $classVo) { + $row=$classVo; + $row['key']=$row['id'].'_'.$row['mold']; + $row['bill']=['sell'=>'销售单','sre'=>'销售退货单','imy'=>'收款单','ice'=>'其它收入单'][$row['mold']]; + if($row['mold']=='sell'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='sre'){ + $row['total']=math()->chain($row['total'])->mul(-1)->done(); + $row['actual']=math()->chain($row['actual'])->mul(-1)->done(); + $row['money']=math()->chain($row['money'])->mul(-1)->done(); + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='imy'){ + $row['actual']=0; + $row['money']=$row['total']; + $row['discount']=0; + }else if($row['mold']=='ice'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + } + $row['balance'] = math()->chain($data[count($data)-1]['balance'])->add($row['actual'])->sub($row['money'])->done(); + //匹配明细 + $node=[]; + if(!empty($input['type'])){ + $list=search($bill['info'][$row['mold']])->where([['pid','=',$row['id']]])->select(); + foreach ($list as $listVo) { + if(in_array($row['mold'],['sell','sre'])){ + $detail=[ + 'name'=>$listVo['goodsData']['name'], + 'attr'=>$listVo['attr'], + 'unit'=>$listVo['unit'], + 'price'=>$listVo['price'], + 'nums'=>$listVo['nums'], + 'dsc'=>$listVo['dsc'], + 'total'=>$listVo['total'], + 'tat'=>$listVo['tat'], + 'tpt'=>$listVo['tpt'] + ]; + }else if($row['mold']=='imy'){ + $detail=[ + 'name'=>$listVo['accountData']['name'], + 'attr'=>'', + 'unit'=>'', + 'price'=>$listVo['money'], + 'nums'=>1, + 'dsc'=>0, + 'total'=>$listVo['money'], + 'tat'=>0, + 'tpt'=>$listVo['money'] + ]; + }else if($row['mold']=='ice'){ + $detail=[ + 'name'=>$listVo['ietData']['name'], + 'attr'=>'', + 'unit'=>'', + 'price'=>$listVo['money'], + 'nums'=>1, + 'dsc'=>0, + 'total'=>$listVo['money'], + 'tat'=>0, + 'tpt'=>$listVo['money'] + ]; + }else{ + $detail=[]; + } + $node[]=['key'=>$row['id'].'_'.$listVo['id'].'_'.$row['mold'],'detail'=>$detail]; + } + } + $row['node']=$node; + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //客户对账单-导出 + public function cctExports(){ + $input=input('get.'); + if(existFull($input,['customer']) && isset($input['type'])){ + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['examine','=',1]; + $existsSql[]=['customer','=',$input['customer']]; + $existsSql=frameScope($existsSql); + //构造语句 + $union=[]; + $tab=['sell','sre','imy','ice']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where(sqlAuth($t,$existsSql))->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //匹配单据 + $bill=['class'=>[],'info'=>[]]; + foreach ($tab as $t) { + $gather=search($record)->where([['mold','=',$t]])->select(); + $db=['class'=>"app\\model\\".ucfirst($t),'info'=>"app\\model\\".ucfirst($t).'Info']; + $bill['class']=array_merge($bill['class'],$db['class']::with(['frameData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + //匹配明细 + if(!empty($input['type'])){ + if(in_array($t,['sell','sre'])){ + $detail=$db['info']::with(['goodsData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + }else if($t=='imy'){ + $detail=$db['info']::with(['accountData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + }else if($t=='ice'){ + $detail=$db['info']::with(['ietData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + } + $bill['info'][$t]=$detail; + } + } + arraySort($bill['class'],'t',SORT_ASC); + //期初查询 + $firstUnion=[]; + $firstUnionSql=[ + ['examine','=',1], + ['customer','=',$input['customer']], + ['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0] + ]; + $firstUnionSql=frameScope($firstUnionSql); + + $firstUnion=implode(' UNION ALL ',$firstUnion); + $stats=DB::query('SELECT * FROM ('.$firstUnion.') as nodcloud'); + $calc=[]; + + $balance=math()->chain($calc['sell'])->sub($calc['sre'])->sub($calc['imy'])->add($calc['ice'])->done(); + $data=[ + ['node'=>[],'bill'=>'期初余额','balance'=>$balance], + ]; + //匹配数据 + foreach ($bill['class'] as $classVo) { + $row=$classVo; + $row['bill']=['sell'=>'销售单','sre'=>'销售退货单','imy'=>'收款单','ice'=>'其它收入单'][$row['mold']]; + if($row['mold']=='sell'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='sre'){ + $row['total']=math()->chain($row['total'])->mul(-1)->done(); + $row['actual']=math()->chain($row['actual'])->mul(-1)->done(); + $row['money']=math()->chain($row['money'])->mul(-1)->done(); + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='imy'){ + $row['actual']=0; + $row['money']=$row['total']; + $row['discount']=0; + }else if($row['mold']=='ice'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + } + $row['balance'] = math()->chain($data[count($data)-1]['balance'])->add($row['actual'])->sub($row['money'])->done(); + //匹配明细 + $node=[]; + if(!empty($input['type'])){ + $list=search($bill['info'][$row['mold']])->where([['pid','=',$row['id']]])->select(); + foreach ($list as $listVo) { + if(in_array($row['mold'],['sell','sre'])){ + $detail=[ + 'name'=>$listVo['goodsData']['name'], + 'attr'=>$listVo['attr'], + 'unit'=>$listVo['unit'], + 'price'=>$listVo['price'], + 'nums'=>$listVo['nums'], + 'dsc'=>$listVo['dsc'], + 'total'=>$listVo['total'], + 'tat'=>$listVo['tat'], + 'tpt'=>$listVo['tpt'] + ]; + }else if($row['mold']=='imy'){ + $detail=[ + 'name'=>$listVo['accountData']['name'], + 'attr'=>'', + 'unit'=>'', + 'price'=>$listVo['money'], + 'nums'=>1, + 'dsc'=>0, + 'total'=>$listVo['money'], + 'tat'=>0, + 'tpt'=>$listVo['money'] + ]; + }else if($row['mold']=='ice'){ + $detail=[ + 'name'=>$listVo['ietData']['name'], + 'attr'=>'', + 'unit'=>'', + 'price'=>$listVo['money'], + 'nums'=>1, + 'dsc'=>0, + 'total'=>$listVo['money'], + 'tat'=>0, + 'tpt'=>$listVo['money'] + ]; + }else{ + $detail=[]; + } + $node[]=['detail'=>$detail]; + } + } + $row['node']=$node; + $data[]=$row; + } + $customer=Db::name('customer')->where([['id','=',$input['customer']]])->find(); + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'客户对账单 [ '.$customer['name'].' ]']; + //表格数据 + $field=[ + [ + 'bill'=>'单据类型', + 'frameData|name'=>'所属组织', + 'time'=>'单据时间', + 'number'=>'单据编号' + ], + [ + 'detail|name'=>'名称', + 'detail|attr'=>'属性', + 'detail|unit'=>'单位', + 'detail|price'=>'单价', + 'detail|nums'=>'数量', + 'detail|dsc'=>'折扣额', + 'detail|total'=>'金额', + 'detail|tat'=>'税额', + 'detail|tpt'=>'价税合计', + ], + [ + 'total'=>'单据金额', + 'discount'=>'优惠金额', + 'actual'=>'应收金额', + 'money'=>'实收金额', + 'balance'=>'应收款余额', + 'data'=>'备注' + ] + ]; + $field=empty($input['type'])?array_merge($field[0],$field[2]):array_merge($field[0],$field[1],$field[2]); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + ]]; + //导出execl + buildExcel('客户对账单',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //供应商对账单 + public function cst(){ + $input=input('post.'); + if(existFull($input,['supplier']) && isset($input['type'])){ + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['examine','=',1]; + $existsSql[]=['supplier','=',$input['supplier']]; + $existsSql=frameScope($existsSql); + //构造语句 + $union=[]; + $tab=['buy','bre','omy','oce']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where(sqlAuth($t,$existsSql))->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //匹配单据 + $bill=['class'=>[],'info'=>[]]; + foreach ($tab as $t) { + $gather=search($record)->where([['mold','=',$t]])->select(); + $db=['class'=>"app\\model\\".ucfirst($t),'info'=>"app\\model\\".ucfirst($t).'Info']; + $bill['class']=array_merge($bill['class'],$db['class']::with(['frameData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + //匹配明细 + if(!empty($input['type'])){ + if(in_array($t,['buy','bre'])){ + $detail=$db['info']::with(['goodsData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + }else if($t=='omy'){ + $detail=$db['info']::with(['accountData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + }else if($t=='oce'){ + $detail=$db['info']::with(['ietData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + } + $bill['info'][$t]=$detail; + } + } + arraySort($bill['class'],'t',SORT_ASC); + //期初查询 + $firstUnion=[]; + $firstUnionSql=[ + ['examine','=',1], + ['supplier','=',$input['supplier']], + ['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0] + ]; + $firstUnionSql=frameScope($firstUnionSql); + foreach ($tab as $t) { + $firstUnion[]=Db::name($t)->where(sqlAuth($t,$firstUnionSql))->fieldRaw('"'.$t.'" as mold,sum('.(in_array($t,['buy','bre','oce'])?'actual - money':'total').') as calc')->group(['mold'])->buildSql(); + } + $firstUnion=implode(' UNION ALL ',$firstUnion); + $stats=DB::query('SELECT * FROM ('.$firstUnion.') as nodcloud'); + $calc=[]; + foreach ($tab as $t) { + $find=search($stats)->where([['mold','=',$t]])->find(); + if(empty($find)){ + $calc[$t]=0; + }else{ + $calc[$t]=$find['calc']; + } + } + $balance=math()->chain($calc['buy'])->sub($calc['bre'])->sub($calc['omy'])->add($calc['oce'])->done(); + $data=[ + ['key'=>'0','node'=>[],'bill'=>'期初余额','balance'=>$balance], + ]; + //匹配数据 + foreach ($bill['class'] as $classVo) { + $row=$classVo; + $row['key']=$row['id'].'_'.$row['mold']; + $row['bill']=['buy'=>'采购单','bre'=>'采购退货单','omy'=>'付款单','oce'=>'其它收入单'][$row['mold']]; + if($row['mold']=='buy'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='bre'){ + $row['total']=math()->chain($row['total'])->mul(-1)->done(); + $row['actual']=math()->chain($row['actual'])->mul(-1)->done(); + $row['money']=math()->chain($row['money'])->mul(-1)->done(); + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='omy'){ + $row['actual']=0; + $row['money']=$row['total']; + $row['discount']=0; + }else if($row['mold']=='oce'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + } + $row['balance'] = math()->chain($data[count($data)-1]['balance'])->add($row['actual'])->sub($row['money'])->done(); + //匹配明细 + $node=[]; + if(!empty($input['type'])){ + $list=search($bill['info'][$row['mold']])->where([['pid','=',$row['id']]])->select(); + foreach ($list as $listVo) { + if(in_array($row['mold'],['buy','bre'])){ + $detail=[ + 'name'=>$listVo['goodsData']['name'], + 'attr'=>$listVo['attr'], + 'unit'=>$listVo['unit'], + 'price'=>$listVo['price'], + 'nums'=>$listVo['nums'], + 'dsc'=>$listVo['dsc'], + 'total'=>$listVo['total'], + 'tat'=>$listVo['tat'], + 'tpt'=>$listVo['tpt'] + ]; + }else if($row['mold']=='omy'){ + $detail=[ + 'name'=>$listVo['accountData']['name'], + 'attr'=>'', + 'unit'=>'', + 'price'=>$listVo['money'], + 'nums'=>1, + 'dsc'=>0, + 'total'=>$listVo['money'], + 'tat'=>0, + 'tpt'=>$listVo['money'] + ]; + }else if($row['mold']=='oce'){ + $detail=[ + 'name'=>$listVo['ietData']['name'], + 'attr'=>'', + 'unit'=>'', + 'price'=>$listVo['money'], + 'nums'=>1, + 'dsc'=>0, + 'total'=>$listVo['money'], + 'tat'=>0, + 'tpt'=>$listVo['money'] + ]; + }else{ + $detail=[]; + } + $node[]=['key'=>$row['id'].'_'.$listVo['id'].'_'.$row['mold'],'detail'=>$detail]; + } + } + $row['node']=$node; + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //供应商对账单-导出 + public function cstExports(){ + $input=input('get.'); + if(existFull($input,['supplier']) && isset($input['type'])){ + //子查询 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['examine','=',1]; + $existsSql[]=['supplier','=',$input['supplier']]; + $existsSql=frameScope($existsSql); + //构造语句 + $union=[]; + $tab=['buy','bre','omy','oce']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where(sqlAuth($t,$existsSql))->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //匹配单据 + $bill=['class'=>[],'info'=>[]]; + foreach ($tab as $t) { + $gather=search($record)->where([['mold','=',$t]])->select(); + $db=['class'=>"app\\model\\".ucfirst($t),'info'=>"app\\model\\".ucfirst($t).'Info']; + $bill['class']=array_merge($bill['class'],$db['class']::with(['frameData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + //匹配明细 + if(!empty($input['type'])){ + if(in_array($t,['buy','bre'])){ + $detail=$db['info']::with(['goodsData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + }else if($t=='omy'){ + $detail=$db['info']::with(['accountData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + }else if($t=='oce'){ + $detail=$db['info']::with(['ietData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + } + $bill['info'][$t]=$detail; + } + } + arraySort($bill['class'],'t',SORT_ASC); + //期初查询 + $firstUnion=[]; + $firstUnionSql=[ + ['examine','=',1], + ['supplier','=',$input['supplier']], + ['time','<',existFull($input,['startTime'])?strtotime($input['startTime']):0] + ]; + $firstUnionSql=frameScope($firstUnionSql); + foreach ($tab as $t) { + $firstUnion[]=Db::name($t)->where(sqlAuth($t,$firstUnionSql))->fieldRaw('"'.$t.'" as mold,sum('.(in_array($t,['buy','bre','oce'])?'actual - money':'total').') as calc')->group(['mold'])->buildSql(); + } + $firstUnion=implode(' UNION ALL ',$firstUnion); + $stats=DB::query('SELECT * FROM ('.$firstUnion.') as nodcloud'); + $calc=[]; + foreach ($tab as $t) { + $find=search($stats)->where([['mold','=',$t]])->find(); + if(empty($find)){ + $calc[$t]=0; + }else{ + $calc[$t]=$find['calc']; + } + } + $balance=math()->chain($calc['buy'])->sub($calc['bre'])->sub($calc['omy'])->add($calc['oce'])->done(); + $data=[ + ['node'=>[],'bill'=>'期初余额','balance'=>$balance], + ]; + //匹配数据 + foreach ($bill['class'] as $classVo) { + $row=$classVo; + $row['bill']=['buy'=>'采购单','bre'=>'采购退货单','omy'=>'付款单','oce'=>'其它收入单'][$row['mold']]; + if($row['mold']=='buy'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='bre'){ + $row['total']=math()->chain($row['total'])->mul(-1)->done(); + $row['actual']=math()->chain($row['actual'])->mul(-1)->done(); + $row['money']=math()->chain($row['money'])->mul(-1)->done(); + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='omy'){ + $row['actual']=0; + $row['money']=$row['total']; + $row['discount']=0; + }else if($row['mold']=='oce'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + } + $row['balance'] = math()->chain($data[count($data)-1]['balance'])->add($row['actual'])->sub($row['money'])->done(); + //匹配明细 + $node=[]; + if(!empty($input['type'])){ + $list=search($bill['info'][$row['mold']])->where([['pid','=',$row['id']]])->select(); + foreach ($list as $listVo) { + if(in_array($row['mold'],['buy','bre'])){ + $detail=[ + 'name'=>$listVo['goodsData']['name'], + 'attr'=>$listVo['attr'], + 'unit'=>$listVo['unit'], + 'price'=>$listVo['price'], + 'nums'=>$listVo['nums'], + 'dsc'=>$listVo['dsc'], + 'total'=>$listVo['total'], + 'tat'=>$listVo['tat'], + 'tpt'=>$listVo['tpt'] + ]; + }else if($row['mold']=='omy'){ + $detail=[ + 'name'=>$listVo['accountData']['name'], + 'attr'=>'', + 'unit'=>'', + 'price'=>$listVo['money'], + 'nums'=>1, + 'dsc'=>0, + 'total'=>$listVo['money'], + 'tat'=>0, + 'tpt'=>$listVo['money'] + ]; + }else if($row['mold']=='oce'){ + $detail=[ + 'name'=>$listVo['ietData']['name'], + 'attr'=>'', + 'unit'=>'', + 'price'=>$listVo['money'], + 'nums'=>1, + 'dsc'=>0, + 'total'=>$listVo['money'], + 'tat'=>0, + 'tpt'=>$listVo['money'] + ]; + }else{ + $detail=[]; + } + $node[]=['detail'=>$detail]; + } + } + $row['node']=$node; + $data[]=$row; + } + $supplier=Db::name('supplier')->where([['id','=',$input['supplier']]])->find(); + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'供应商对账单 [ '.$supplier['name'].' ]']; + //表格数据 + $field=[ + [ + 'bill'=>'单据类型', + 'frameData|name'=>'所属组织', + 'time'=>'单据时间', + 'number'=>'单据编号' + ], + [ + 'detail|name'=>'名称', + 'detail|attr'=>'属性', + 'detail|unit'=>'单位', + 'detail|price'=>'单价', + 'detail|nums'=>'数量', + 'detail|dsc'=>'折扣额', + 'detail|total'=>'金额', + 'detail|tat'=>'税额', + 'detail|tpt'=>'价税合计', + ], + [ + 'total'=>'单据金额', + 'discount'=>'优惠金额', + 'actual'=>'应付金额', + 'money'=>'实付金额', + 'balance'=>'应付款余额', + 'data'=>'备注' + ] + ]; + $field=empty($input['type'])?array_merge($field[0],$field[2]):array_merge($field[0],$field[1],$field[2]); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + ]]; + //导出execl + buildExcel('供应商对账单',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //其它收支明细表 + public function cos(){ + $input=input('post.'); + $sheet=['ice','oce']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(existFull($input,['page','limit']) && is_array($input['mold']) && arrayInArray($input['mold'],$sheet)){ + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['account','fullEq'], + [['data'=>'class.data'],'fullLike'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + + $sql_class=[]; + foreach ($input['mold'] as $mold) { + $sql_class[$mold]=sqlAuth($mold,$sql['class']); + } + //INFO语句 + $sql['info']=fastSql($input,[['iet','fullEq']]); + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold.'_info')->alias('info')->join(['is_'.$mold=>'class'],'info.pid=class.id')->where($sql['info'])->where($sql_class[$mold])->fieldRaw('info.id as info,class.id as class,time,"'.$mold.'" as mold')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $count=DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $table=[ + "class"=>"app\\model\\".ucfirst($mold), + 'info'=>"app\\model\\".ucfirst($mold).'Info', + ]; + $list[$mold]['info']=$table['info']::with(['ietData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + $list[$mold]['class']=$table['class']::with(['frameData','accountData',$mold=='ice'?'customerData':'supplierData'])->where([['id','in',array_column($list[$mold]['info'],'pid')]])->append(['extension'])->select()->toArray(); + } + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $class=search($list[$mold]['class'])->where([['id','=',$recordVo['class']]])->find(); + $info=search($list[$mold]['info'])->where([['id','=',$recordVo['info']]])->find(); + $data[]=[ + 'mold'=>$mold, + 'name'=>['ice'=>'其它收入单','oce'=>'其它支出单'][$mold], + 'current'=>$mold=='ice'?$class['customerData']??[]:$class['supplierData']??[], + 'class'=>$class, + 'info'=>$info, + 'in'=>$mold=='ice'?$info['money']:0, + 'out'=>$mold=='ice'?0:$info['money'] + ]; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //其它收支明细表-导出 + public function cosExports(){ + $input=input('get.'); + $sheet=['ice','oce']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(is_array($input['mold']) && arrayInArray($input['mold'],$sheet)){ + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['account','fullEq'], + [['data'=>'class.data'],'fullLike'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + $sql_class=[]; + foreach ($input['mold'] as $mold) { + $sql_class[$mold]=sqlAuth($mold,$sql['class']); + } + //INFO语句 + $sql['info']=fastSql($input,[['iet','fullEq']]); + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold.'_info')->alias('info')->join(['is_'.$mold=>'class'],'info.pid=class.id')->where($sql['info'])->where($sql_class[$mold])->fieldRaw('info.id as info,class.id as class,time,"'.$mold.'" as mold')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC'); + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $table=[ + "class"=>"app\\model\\".ucfirst($mold), + 'info'=>"app\\model\\".ucfirst($mold).'Info', + ]; + $list[$mold]['info']=$table['info']::with(['ietData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + $list[$mold]['class']=$table['class']::with(['frameData','accountData',$mold=='ice'?'customerData':'supplierData'])->where([['id','in',array_column($list[$mold]['info'],'pid')]])->append(['extension'])->select()->toArray(); + } + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $class=search($list[$mold]['class'])->where([['id','=',$recordVo['class']]])->find(); + $info=search($list[$mold]['info'])->where([['id','=',$recordVo['info']]])->find(); + $data[]=[ + 'mold'=>$mold, + 'name'=>['ice'=>'其它收入单','oce'=>'其它支出单'][$mold], + 'current'=>$mold=='ice'?$class['customerData']??[]:$class['supplierData']??[], + 'class'=>$class, + 'info'=>$info, + 'in'=>$mold=='ice'?$info['money']:0, + 'out'=>$mold=='ice'?0:$info['money'] + ]; + } + $source=$data; + + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'其它收支明细表']; + //表格数据 + $field=[ + "name"=>"单据类型", + "class|frameData|name"=>"所属组织", + "current|name"=>"往来单位", + "class|time"=>"单据时间", + "class|number"=>"单据编号", + "info|ietData|name"=>"收支类别", + "in"=>"收入", + "out"=>"支出", + "class|accountData|name"=>"结算账户", + "class|data"=>"备注信息" + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总收入:'.mathArraySum(array_column($source,'in')), + '总支出:'.mathArraySum(array_column($source,'out')) + ]]; + //导出execl + buildExcel('其它收支明细表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //利润表 + public function cit(){ + $input=input('post.'); + $sql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql[]=['examine','=',1]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('sell',$sql);//数据鉴权[结构一致] + //匹配数据 + $union=[]; + $tab=['sell','sre']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where($sql)->fieldRaw('"'.$t.'" as mold,group_concat(id) as id,sum(actual) as money,sum(cost) as cost')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //成本统计 + $summary=[]; + foreach ($record as $v) { + if(empty($v['id'])){ + $summary[]=['mold'=>$v['mold'],'bct'=>0]; + }else{ + $where=[['class','in',explode(',',$v['id'])],['type','=',$v['mold']] + ]; + $summary[]=Db::name('summary')->where($where)->fieldRaw('"'.$v['mold'].'" as mold,sum(bct) as bct')->select()->toArray()[0]; + } + } + //计算数据 + $si=math()->chain($record[0]['money'])->sub($record[1]['money'])->add($record[2]['money'])->sub($record[3]['money'])->done(); + $cost=math()->chain($record[0]['cost'])->add($record[1]['cost'])->add($record[2]['cost'])->add($record[3]['cost'])->done(); + $bct=math()->chain($summary[0]['bct'])->sub($summary[1]['bct'])->add($summary[2]['bct'])->sub($summary[3]['bct'])->done(); + $profit=math()->chain($si)->sub($cost)->sub($bct)->done(); + $data=[ + ['name'=>'主营业务','money'=>''], + ['name'=>'| - 销售收入','money'=>$si], + ['name'=>'| - 业务成本','money'=>$cost], + ['name'=>'| - 销售成本','money'=>$bct], + ['name'=>'','money'=>''], + ['name'=>'利润','money'=>$profit] + ]; + $result=[ + 'state'=>'success', + 'info'=>$data + ];//返回数据 + return json($result); + } + //利润表-导出 + public function citExports(){ + $input=input('post.'); + $sql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql[]=['examine','=',1]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('sell',$sql);//数据鉴权[结构一致] + //匹配数据 + $union=[]; + $tab=['sell','sre']; + foreach ($tab as $t) { + $union[]=Db::name($t)->where($sql)->fieldRaw('"'.$t.'" as mold,group_concat(id) as id,sum(actual) as money,sum(cost) as cost')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //成本统计 + $summary=[]; + foreach ($record as $v) { + if(empty($v['id'])){ + $summary[]=['mold'=>$v['mold'],'bct'=>0]; + }else{ + $where=[ + ['class','in',explode(',',$v['id'])], + ['type','=',$v['mold']] + ]; + $summary[]=Db::name('summary')->where($where)->fieldRaw('"'.$v['mold'].'" as mold,sum(bct) as bct')->select()->toArray()[0]; + } + } + //计算数据 + $si=math()->chain($record[0]['money'])->sub($record[1]['money'])->add($record[2]['money'])->sub($record[3]['money'])->done(); + $cost=math()->chain($record[0]['cost'])->add($record[1]['cost'])->add($record[2]['cost'])->add($record[3]['cost'])->done(); + $bct=math()->chain($summary[0]['bct'])->sub($summary[1]['bct'])->add($summary[2]['bct'])->sub($summary[3]['bct'])->done(); + $profit=math()->chain($si)->sub($cost)->sub($bct)->done(); + $data=[ + ['name'=>'主营业务','money'=>''], + ['name'=>'销售收入','money'=>$si], + ['name'=>'业务成本','money'=>$cost], + ['name'=>'销售成本','money'=>$bct], + ['name'=>'','money'=>''], + ['name'=>'利润','money'=>$profit] + ]; + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'利润表']; + //表格数据 + $field=[ + "name"=>"项目", + "money"=>"金额" + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('利润表',$excel); + } + //往来单位欠款表 + public function cds(){ + $input=input('post.'); + $sheet=['customer','supplier']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(existFull($input,['page','limit']) && is_array($input['mold']) && arrayInArray($input['mold'],$sheet)){ + $base=fastSql($input,[ + ['name','fullLike'], + ['number','fullLike'], + ['data','fullLike'] + ]); + $base=frameScope($base);//组织数据 + $sql=[]; + foreach ($input['mold'] as $mold) { + if($mold=='customer'){ + $sql[$mold]=sqlAuth('customer',$base);//数据鉴权 + }else{ + $sql[$mold]=sqlAuth('supplier',$base);//数据鉴权 + } + } + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->where($sql[$mold])->fieldRaw('"'.$mold.'" as mold,id,name,number,data,balance')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $count=DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + foreach ($record as $key=>$vo) { + $record[$key]['mold']=['customer'=>'客户','supplier'=>'供应商'][$vo['mold']]; + if($vo['mold']=='customer'){ + $record[$key]['collection']=floatval($vo['balance']); + $record[$key]['payment']=0; + }else{ + $record[$key]['collection']=0; + $record[$key]['payment']=floatval($vo['balance']); + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$record + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //往来单位欠款表-导出 + public function cdsExports(){ + $input=input('get.'); + $sheet=['customer','supplier']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(is_array($input['mold']) && arrayInArray($input['mold'],$sheet)){ + $base=fastSql($input,[ + ['name','fullLike'], + ['number','fullLike'], + ['data','fullLike'] + ]); + $base=frameScope($base);//组织数据 + $sql=[]; + foreach ($input['mold'] as $mold) { + if($mold=='customer'){ + $sql[$mold]=sqlAuth('customer',$base);//数据鉴权 + }else{ + $sql[$mold]=sqlAuth('supplier',$base);//数据鉴权 + } + } + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->where($sql[$mold])->fieldRaw('"'.$mold.'" as mold,id,name,number,data,balance')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + foreach ($record as $key=>$vo) { + $record[$key]['mold']=['customer'=>'客户','supplier'=>'供应商'][$vo['mold']]; + if($vo['mold']=='customer'){ + $record[$key]['collection']=floatval($vo['balance']); + $record[$key]['payment']=0; + }else{ + $record[$key]['collection']=0; + $record[$key]['payment']=floatval($vo['balance']); + } + } + $source=$record; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'往来单位欠款表']; + //表格数据 + $field=[ + "mold"=>"单位类型", + "name"=>"单位名称", + "number"=>"单位编号", + "collection"=>"应收款余额", + "payment"=>"应付款余额", + "data"=>"备注信息" + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总应收款余额:'.mathArraySum(array_column($source,'collection')), + '总应付款余额:'.mathArraySum(array_column($source,'payment')) + ]]; + //导出execl + buildExcel('往来单位欠款表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } +} diff --git a/serve/app/controller/Customer.php b/serve/app/controller/Customer.php new file mode 100644 index 0000000..0c703a2 --- /dev/null +++ b/serve/app/controller/Customer.php @@ -0,0 +1,258 @@ +'name|py'],'fullLike'], + ['number','fullLike'], + ['category','fullEq'], + ['grade','fullEq'], + ['contacts','fullLike'], + [['tel'=>'contacts'],'fullLike'], + ['user','fullEq'], + ['data','fullLike'] + ]);//构造SQL + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('customer',$sql);//数据鉴权 + $count = Customers::where($sql)->count();//获取总条数 + $info = Customers::with(['frameData','userData'])->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //构造|验证 + try { + //排除balance字段|防止更新应收款余额 + unset($input['balance']); + $input['py']=zhToPy($input['name']);//首拼信息 + empty($input['id'])?$this->validate($input,'app\validate\Customer'):$this->validate($input,'app\validate\Customer.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Customers::create($input); + pushLog('新增客户[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Customers::update($input); + pushLog('更新客户[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Customers::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //关联判断 + $exists=[ + ['table'=>'sor','where'=>[['customer','in',$input['parm']]]], + ['table'=>'sell','where'=>[['customer','in',$input['parm']]]], + ['table'=>'sre','where'=>[['customer','in',$input['parm']]]], + ['table'=>'extry','where'=>[['customer','in',$input['parm']]]], + ['table'=>'imy','where'=>[['customer','in',$input['parm']]]], + ['table'=>'bill','where'=>[['customer','in',$input['parm']]]], + ['table'=>'ice','where'=>[['customer','in',$input['parm']]]] + ]; + //多值匹配 + foreach($input['parm'] as $v){ + $exists[]=['table'=>'deploy','where'=>[['source','like','%"customer":'.$v.'%']]]; + } + $exist=moreTableFind($exists); + if(empty($exist)){ + //逻辑处理 + $data=Db::name('customer')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + Db::startTrans(); + try { + Db::name('customer')->where([['id','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除客户[ '.implode(' | ',array_column($data,'name')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + $sql=[];//初始化SQL + $frame=Db::name('frame')->where([['name','in',array_column($data,'C')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'name'=>$dataVo['A'], + 'py'=>zhToPy($dataVo['A']), + 'number'=>$dataVo['B'], + 'frame'=>$dataVo['C'], + 'user'=>getUserID(), + 'category'=>$dataVo['D'], + 'grade'=>$dataVo['E'], + 'bank'=>$dataVo['F'], + 'account'=>$dataVo['G'], + 'tax'=>$dataVo['H'], + 'data'=>$dataVo['I'], + 'contacts'=>(empty($dataVo['J'])&&empty($dataVo['K']))?[]:[['main'=>true,'name'=>$dataVo['J'],'tel'=>$dataVo['K'],'add'=>$dataVo['L'],'data'=>$dataVo['M']]], + 'more'=>[] + ]; + + //所属组织匹配 + $frameFind=search($frame)->where([['name','=',$record['frame']]])->find(); + if(empty($frameFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行所属组织[ '.$record['frame'].' ]未匹配!'); + }else{ + $record['frame']=$frameFind['id']; + } + try { + //数据合法性验证 + $this->validate($record,'app\validate\Customer'); + $sql[]=$record;//加入SQL + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第[ '.$dataKey.' ]行'.$e->getError()]); + exit; + } + } + //判断编号重复 + $column=array_column($sql,'number'); + $unique=array_unique($column); + $diff=array_diff_assoc($column,$unique); + if(!empty($diff)){ + //返回错误信息 + return json(['state'=>'error','info'=>'模板文件客户编号[ '.implode(' | ',$diff).' ]重复!']); + } + //处理关联数据 + foreach($sql as $sqlKey=>$sqlVo){ + $sys=getSys(['crCategory','crGrade']); + //客户类别 + if(!in_array($sqlVo['category'],$sys['crCategory'])){ + $sys['crCategory'][]=$sqlVo['category']; + Sys::where([['name','=','crCategory']])->update(['info'=>json_encode($sys['crCategory'])]); + } + //客户等级 + if(!in_array($sqlVo['grade'],$sys['crGrade'])){ + $sys['crGrade'][]=$sqlVo['grade']; + Sys::where([['name','=','crGrade']])->update(['info'=>json_encode($sys['crGrade'])]); + } + } + //新增数据 + $customer = new Customers; + $customer->saveAll($sql); + pushLog('批量导入[ '.count($sql).' ]条客户数据');//日志 + $result=['state'=>'success','info'=>'成功导入'.count($sql).'行客户数据']; + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $info=Customers::with(['frameData','userData'])->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray();//查询数据 + foreach ($info as $infoKey=>$infoVo) { + $contactsArr=[]; + foreach ($infoVo['contacts'] as $contactsVo) { + $contactsArr[]=$contactsVo['name'].' | '.$contactsVo['tel'].' | '.$contactsVo['add'].' | '.$contactsVo['data']; + } + $info[$infoKey]['contacts']=implode(chr(10),$contactsArr); + } + $field=[ + 'name'=>'客户名称', + 'number'=>'客户编号', + 'category'=>'客户类别', + 'grade'=>'客户等级', + 'bank'=>'开户银行', + 'account'=>'银行账号', + 'tax'=>'纳税号码', + 'balance'=>'应收款余额', + 'frameData|name'=>'所属组织', + 'userData|name'=>'所属用户', + 'data'=>'备注信息', + 'contacts'=>'联系资料' + ]; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'客户信息']; + //表格数据 + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>['总数:'.count($info)]]; + //导出execl + pushLog('导出客户信息');//日志 + buildExcel('客户信息',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Deploy.php b/serve/app/controller/Deploy.php new file mode 100644 index 0000000..86b4bd3 --- /dev/null +++ b/serve/app/controller/Deploy.php @@ -0,0 +1,93 @@ +count();//获取总条数 + $info = Deploys::with(['frameData'])->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + empty($input['id'])?$this->validate($input,'app\validate\Deploy'):$this->validate($input,'app\validate\Deploy.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Deploys::create($input); + pushLog('新增零售配置');//日志 + }else{ + //更新数据 + Deploys::update($input); + pushLog('更新零售配置');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Deploys::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + Db::startTrans(); + try { + Db::name('deploy')->where([['id','=',$input['id']]])->delete(); + pushLog('删除零售配置');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Entry.php b/serve/app/controller/Entry.php new file mode 100644 index 0000000..c73214d --- /dev/null +++ b/serve/app/controller/Entry.php @@ -0,0 +1,976 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['type','fullDec1'], + ['examine','fullDec1'], + ['cse','fullDec1'], + ['check','fullDec1'], + ['user','fullEq'], + ['data','fullLike'] + ]);//构造SQL + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['id','in',array_column(Db::name('entry_info')->where([['goods','in',$goods]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('entry',$sql);//数据鉴权 + $count = Entrys::where($sql)->count();//获取总条数 + $info = Entrys::with(['frameData','peopleData','userData','costData','recordData','supplierData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id']) && isset($input['cost'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['cse']=empty($class['cost'])?3:0; + $class['examine']=0; + empty($class['id'])?$this->validate($class,'app\validate\Entry'):$this->validate($class,'app\validate\Entry.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\EntryInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'商品信息第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //验证Cost + foreach ($input['cost'] as $costKey=>$costVo) { + try { + $this->validate($costVo,'app\validate\Cost'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'单据费用第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Entrys::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'entry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增其它入库单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Entrys::update($class); + Db::name('record')->insert(['type'=>'entry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新其它入库单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + EntryInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new EntryInfo; + $model->saveAll($input['info']); + + //COST数据 + Cost::where([['type','=','entry'],['class','=',$class['id']]])->delete(); + foreach ($input['cost'] as $costKey=>$costVo) { + unset($input['cost'][$costKey]['id']); + $input['cost'][$costKey]['type']='entry'; + $input['cost'][$costKey]['class']=$class['id']; + $input['cost'][$costKey]['time']=$class['time']; + $input['cost'][$costKey]['settle']=0; + $input['cost'][$costKey]['state']=0; + } + $model = new Cost; + $model->saveAll($input['cost']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Entrys::where([['id','=',$input['parm']]])->find(); + $info=EntryInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $cost=Cost::where([['type','=','entry'],['class','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + 'cost'=>$cost + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('entry')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('entry')->where([['id','in',$input['parm']]])->delete(); + Db::name('entry_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('cost')->where([['type','=','entry'],['class','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','entry'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除其它入库单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //核对|反核对 + public function check(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $period=getPeriod(); + $classList=Db::name('entry')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + foreach ($input['parm'] as $parmVo) { + $class=search($classList)->where([['id','=',$parmVo]])->find(); + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(empty($class['check'])){ + Db::name('entry')->where([['id','=',$class['id']]])->update(['check'=>1]); + //1 单据记录 + Db::name('record')->insert(['type'=>'entry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'核对单据']); + //2 记录操作 + pushLog('核对其它入库单[ '.$class['number'].' ]');//单据日志 + }else{ + Db::name('entry')->where([['id','=',$class['id']]])->update(['check'=>0]); + //1 单据记录 + Db::name('record')->insert(['type'=>'entry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反核对单据']); + //2 记录操作 + pushLog('反核对其它入库单[ '.$class['number'].' ]');//单据日志 + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('entry')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('entry_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //1.1 商品数据 + $goodsList=Db::name('goods')->where([['id','in',array_unique(array_column($info,'goods'))]])->select()->toArray(); + //1.2 综合匹配 + if(empty($class['examine'])){ + //1 构造数据 + $batchGather=[]; + $serialGather=[]; + $roomWhereOrSql=[]; + foreach ($info as $infoVo) { + //1 批次号 + empty($infoVo['batch'])||$batchGather[]=$infoVo['batch']; + //2 序列号 + $serialGather=array_merge($serialGather,json_decode($infoVo['serial'])); + //3 仓储条件 + empty($infoVo['warehouse'])||$roomWhereOrSql[]=[['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]]; + } + //2 匹配数据 + empty($batchGather)||$batchList=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + empty($serialGather)||$serialList=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + if(!empty($roomWhereOrSql)){ + //1 去重转存 + $roomWhereOrSql=array_unique($roomWhereOrSql,SORT_REGULAR); + //2 仓储匹配 + $roomList=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + } + } + + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(!empty($class['examine'])){ + //单据费用 + $cost=Db::name('cost')->alias('cost')->where([['type','=','entry'],['class','=',$class['id']]])->whereExists(function($query){ + $query->name('oce_info')->where([['source','=',Db::raw('cost.id')]])->limit(1); + })->find(); + if(!empty($cost)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联其它支出单!']); + exit; + } + } + + //3 INFO验证|构造 + foreach ($info as $infoKey=>$infoVo) { + //1 匹配商品 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + //2 商品类型 + if(empty($goods['type'])){ + //场景验证 + if(empty($class['examine'])){ + //1 多单位处理 + if($goods['unit']==-1){ + //多单位|转存 + $radix=unitRadix($infoVo['unit'],json_decode($goods['units'],true)); + $info[$infoKey]['basic']=[ + 'nums'=>math()->chain($infoVo['nums'])->mul($radix)->done(), + 'price'=>math()->chain($infoVo['price'])->div($radix)->round(4)->done() + ]; + }else{ + //常规单位|转存 + $info[$infoKey]['basic']=[ + 'nums'=>$infoVo['nums'], + 'price'=>$infoVo['price'] + ]; + } + //2 序列号 + $serialData=json_decode($infoVo['serial']); + if(empty($serialData)){ + $info[$infoKey]['serial']=[]; + }else{ + //序列号状态[不存在|已退货] + $serialFind=search($serialList)->where([['goods','=',$infoVo['goods']],['number','in',$serialData],['state','<>',3]])->find(); + if(empty($serialFind)){ + $info[$infoKey]['serial']=$serialData; + }else{ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + }else{ + //1 验证序列号 + $serialInfoCollect=Db::name('serial_info')->where([['type','=','entry'],['info','in',array_column($info,'id')]])->select()->toArray(); + if(!empty($serialInfoCollect)){ + //序列号状态[未销售] + $serialFind=Db::name('serial')->where([['id','in',array_column($serialInfoCollect,'pid')],['state','<>',0]])->find(); + if(!empty($serialFind)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + } + } + } + //4 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $store=['room'=>[],'roomInfo'=>[],'batch'=>[],'batchInfo'=>[],'serial'=>[],'serialInfo'=>[],'serve'=>[],'serveInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //判断商品类型 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + if(empty($goods['type'])){ + //常规商品 + //1 仓储 + $store['room'][]=['warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['basic']['nums']]; + //2 仓储详情 + $store['roomInfo'][]=['pid'=>null,'type'=>'entry','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'direction'=>1,'price'=>$infoVo['basic']['price'],'nums'=>$infoVo['basic']['nums']]; + //3 批次号 + if(empty($infoVo['batch'])){ + $store['batch'][]=[]; + $store['batchInfo'][]=[]; + }else{ + $store['batch'][]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'number'=>$infoVo['batch'],'time'=>$infoVo['mfd'],'nums'=>$infoVo['basic']['nums']]; + $store['batchInfo'][]=['pid'=>null,'type'=>'entry','class'=>$class['id'],'info'=>$infoVo['id'],'direction'=>1,'nums'=>$infoVo['basic']['nums']]; + } + //4 序列号 + if(empty($infoVo['serial'])){ + $store['serial'][]=[]; + $store['serialInfo'][]=[]; + }else{ + $serial=[]; + $serialInfo=[]; + foreach ($infoVo['serial'] as $serialVo) { + $serial[]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'batch'=>null,'goods'=>$infoVo['goods'],'number'=>$serialVo,'state'=>0]; + $serialInfo[]=['pid'=>null,'type'=>'entry','class'=>$class['id'],'info'=>$infoVo['id']]; + } + $store['serial'][]=$serial; + $store['serialInfo'][]=$serialInfo; + } + }else{ + //5 服务商品 + $store['serve'][]=['goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['nums']]; + $store['serveInfo'][]=['pid'=>null,'type'=>'entry','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'price'=>$infoVo['price'],'nums'=>$infoVo['nums']]; + } + } + //2 仓储 + if(!empty($store['room'])){ + //1 构造数据 + $roomInsert=[]; + foreach ($store['room'] as $roomVo) { + $roomFind=search($roomList)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + if(empty($roomFind)){ + $roomVo['nums']=0; + $roomInsert[]=$roomVo; + } + } + //2 创建数据|去重 + empty($roomInsert)||Db::name('room')->insertAll(array_unique($roomInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $roomDuplicate=[]; + $room=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + foreach ($store['room'] as $roomKey=>$roomVo) { + $roomFind=search($room)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + $store['room'][$roomKey]['id']=$roomFind['id']; + $roomDuplicate[]=['id'=>$roomFind['id'],'nums'=>$roomVo['nums']]; + } + //4 更新数据 + Db::name('room')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($roomDuplicate); + } + //3 仓储详情 + if(!empty($store['roomInfo'])){ + //1 填充数据 + foreach ($store['roomInfo'] as $roomInfoKey=>$roomInfoVo) { + $store['roomInfo'][$roomInfoKey]['pid']=$store['room'][$roomInfoKey]['id']; + } + //2 创建数据 + Db::name('room_info')->insertAll($store['roomInfo']); + } + //4 批次号 + if(!empty($store['batch'])){ + //1 构造数据 + $batchData=[]; + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $store['batch'][$batchKey]['room']=$store['room'][$batchKey]['id']; + $batchData[]=$store['batch'][$batchKey]; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchData)){ + //1 构造数据 + $batchInsert=[]; + foreach ($batchData as $batchDataKey=>$batchDataVo) { + $batchFind=search($batchList)->where([['room','=',$batchDataVo['room']],['number','=',$batchDataVo['number']],['time','=',$batchDataVo['time']]])->find(); + if(empty($batchFind)){ + $batchDataVo['nums']=0; + $batchInsert[]=$batchDataVo; + } + } + //2 创建数据|去重 + empty($batchInsert)||Db::name('batch')->insertAll(array_unique($batchInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $batchDuplicate=[]; + $batch=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $batchFind=search($batch)->where([['room','=',$batchVo['room']],['number','=',$batchVo['number']],['time','=',$batchVo['time']]])->find(); + $store['batch'][$batchKey]['id']=$batchFind['id']; + $batchDuplicate[]=['id'=>$batchFind['id'],'nums'=>$batchVo['nums']]; + } + } + //4 更新数据 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($batchDuplicate); + } + } + //5 批次号详情 + if(!empty($store['batchInfo'])){ + //1 构造数据 + $batchInfoInstall=[]; + foreach ($store['batchInfo'] as $batchInfoKey=>$batchInfoVo) { + if(!empty($batchInfoVo)){ + $batchInfoVo['pid']=$store['batch'][$batchInfoKey]['id']; + $batchInfoInstall[]=$batchInfoVo; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchInfoInstall)){ + //创建数据 + Db::name('batch_info')->insertAll($batchInfoInstall); + } + } + //6 序列号 + if(!empty($store['serial'])){ + //1 构造数据 + $serialData=[]; + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $store['serial'][$serialKey][$itemKey]['room']=$store['room'][$serialKey]['id']; + $store['serial'][$serialKey][$itemKey]['batch']=empty($store['batch'][$serialKey])?0:$store['batch'][$serialKey]['id']; + $serialData[]=$store['serial'][$serialKey][$itemKey]; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialData)){ + //1 构造数据 + $serialInsert=[]; + foreach ($serialData as $serialDataKey=>$serialDataVo) { + $serialFind=search($serialList)->where([['room','=',$serialDataVo['room']],['batch','=',$serialDataVo['batch']],['number','=',$serialDataVo['number']]])->find(); + if(empty($serialFind)){ + $serialInsert[]=$serialDataVo; + } + } + //2 创建数据 + empty($serialInsert)||Db::name('serial')->insertAll($serialInsert); + //3 匹配主键|构造更新 + $serialDuplicate=[]; + $serial=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $serialFind=search($serial)->where([['room','=',$itemVo['room']],['batch','=',$itemVo['batch']],['number','=',$itemVo['number']]])->find(); + $store['serial'][$serialKey][$itemKey]['id']=$serialFind['id']; + $serialFind['state']==3&&$serialDuplicate[]=$serialFind['id']; + } + } + } + //4 更新数据|状态变更 + empty($serialDuplicate)||Db::name('serial')->where([['id','in',$serialDuplicate]])->update(['state'=>0]); + } + } + //7 序列号详情 + if(!empty($store['serialInfo'])){ + //1 构造数据 + $serialInfoInstall=[]; + foreach ($store['serialInfo'] as $serialInfoKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $itemVo['pid']=$store['serial'][$serialInfoKey][$itemKey]['id']; + $serialInfoInstall[]=$itemVo; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialInfoInstall)){ + //创建数据 + Db::name('serial_info')->insertAll($serialInfoInstall); + } + } + //8 服务商品 + if(!empty($store['serve'])){ + //1 匹配数据|去重 + $serveWhereOrSql=array_unique(array_map(function($item){ + return [['goods','=',$item['goods']],['attr','=',$item['attr']]]; + },$store['serve']),SORT_REGULAR); + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + //2 构造数据 + $serveInsert=[]; + foreach ($store['serve'] as $serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + if(empty($serveFind)){ + $serveVo['nums']=0; + $serveInsert[]=$serveVo; + } + } + //3 创建数据|去重 + empty($serveInsert)||Db::name('serve')->insertAll(array_unique($serveInsert,SORT_REGULAR)); + //4 匹配主键|构造更新 + $serveDuplicate=[]; + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + foreach ($store['serve'] as $serveKey=>$serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + $store['serve'][$serveKey]['id']=$serveFind['id']; + $serveDuplicate[]=['id'=>$serveFind['id'],'nums'=>$serveVo['nums']]; + } + //5 更新数据 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($serveDuplicate); + } + //9 服务商品详情 + if(!empty($store['serveInfo'])){ + //1 填充数据 + foreach ($store['serveInfo'] as $serveInfoKey=>$serveInfoVo) { + $store['serveInfo'][$serveInfoKey]['pid']=$store['serve'][$serveInfoKey]['id']; + } + //2 创建数据 + Db::name('serve_info')->insertAll($store['serveInfo']); + } + //10 更新单据 + Db::name('entry')->where([['id','=',$class['id']]])->update(['examine'=>1]); + //11 单据记录 + Db::name('record')->insert(['type'=>'entry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //12 收发记录 + $summary=new Summary; + $summary->note('entry',$class['id'],true); + //13 记录操作 + pushLog('审核其它入库单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 匹配数据 + $listSql=[['type','=','entry'],['info','in',array_column($info,'id')]]; + $roomInfoList=Db::name('room_info')->where($listSql)->select()->toArray(); + $batchInfoList=Db::name('batch_info')->where($listSql)->select()->toArray(); + $serialInfoList=Db::name('serial_info')->where($listSql)->select()->toArray(); + $serveInfoList=Db::name('serve_info')->where($listSql)->select()->toArray(); + //1 仓储 + $roomDuplicate=[]; + foreach ($roomInfoList as $roomInfoVo) { + $roomDuplicate[]=['id'=>$roomInfoVo['pid'],'nums'=>$roomInfoVo['nums']]; + } + //2.1 更新仓储 + Db::name('room')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($roomDuplicate); + //2.2 删除仓储详情 + Db::name('room_info')->where([['id','in',array_column($roomInfoList,'id')]])->delete(); + //2.3 仓储|冗余 + $roomPk=array_unique(array_column($roomInfoList,'pid')); + $roomInfoData=Db::name('room_info')->where([['pid','in',$roomPk]])->select()->toArray(); + $roomDiff=array_diff($roomPk,array_unique(array_column($roomInfoData,'pid'))); + empty($roomDiff)||Db::name('room')->where([['id','in',$roomDiff]])->delete(); + //3 批次号 + if(!empty($batchInfoList)){ + //1 构造数据 + $batchInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$batchInfoList); + //2 更新批次号 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($batchInfoDuplicate); + //3 删除批次号详情 + Db::name('batch_info')->where([['id','in',array_column($batchInfoList,'id')]])->delete(); + //4 批次号|冗余 + $batchPk=array_unique(array_column($batchInfoList,'pid')); + $batchInfoData=Db::name('batch_info')->where([['pid','in',$batchPk]])->select()->toArray(); + $batchDiff=array_diff($batchPk,array_unique(array_column($batchInfoData,'pid'))); + empty($batchDiff)||Db::name('batch')->where([['id','in',$batchDiff]])->delete(); + } + //4 序列号 + if(!empty($serialInfoList)){ + //1 更新序列号 + Db::name('serial')->where([['id','in',array_column($serialInfoList,'pid')]])->update(['state'=>3]); + //2 删除序列号详情 + Db::name('serial_info')->where([['id','in',array_column($serialInfoList,'id')]])->delete(); + //3 序列号|冗余 + $serialPk=array_unique(array_column($serialInfoList,'pid')); + $serialInfoData=Db::name('serial_info')->where([['pid','in',$serialPk]])->select()->toArray(); + $serialDiff=array_diff($serialPk,array_unique(array_column($serialInfoData,'pid'))); + empty($serialDiff)||Db::name('serial')->where([['id','in',$serialDiff]])->delete(); + } + //5 服务 + if(!empty($serveInfoList)){ + //1 构造数据 + $serveInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$serveInfoList); + //2 更新服务 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($serveInfoDuplicate); + //3 删除服务详情 + Db::name('serve_info')->where([['id','in',array_column($serveInfoList,'id')]])->delete(); + //4 服务|冗余 + $servePk=array_unique(array_column($serveInfoList,'pid')); + $serveInfoData=Db::name('serve_info')->where([['pid','in',$servePk]])->select()->toArray(); + $serveDiff=array_diff($servePk,array_unique(array_column($serveInfoData,'pid'))); + empty($serveDiff)||Db::name('serve')->where([['id','in',$serveDiff]])->delete(); + } + //6 更新单据 + Db::name('entry')->where([['id','=',$class['id']]])->update(['examine'=>0]); + //7 单据记录 + Db::name('record')->insert(['type'=>'entry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //8 收发记录 + $summary=new Summary; + $summary->note('entry',$class['id'],false); + //9 记录操作 + pushLog('反审核其它入库单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('entry', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //单据类型匹配 + if(in_array($data[3]['D'],['其它入库单','盘盈单'])){ + $type=$data[3]['D']=="其它入库单"?0:1; + }else{ + throw new ValidateException('单据类型[ '.$data[3]['D'].' ]未匹配!'); + } + //关联人员匹配 + if(empty($data[3]['F'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['F']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['F'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'supplier'=>$data[3]['A'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'type'=>$type, + 'total'=>0, + 'people'=>$people['id'], + 'logistics'=>["key"=>"auto","name"=>"自动识别","number"=>$data[3]['G']], + 'file'=>[], + 'data'=>$data[3]['H'], + 'more'=>[], + 'examine'=>0, + 'cse'=>0, + 'check'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Entry');//数据合法性验证 + //初始化INFO + $info=[]; + $goods=Goods::with(['attr'])->where([['name','in',array_column($data,'I')]])->select()->toArray(); + $warehouse=Db::name('warehouse')->where([['name','in',array_column($data,'L')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'goods'=>$dataVo['I'], + 'attr'=>$dataVo['J'], + 'unit'=>$dataVo['K'], + 'warehouse'=>$dataVo['L'], + 'batch'=>$dataVo['M'], + 'mfd'=>$dataVo['N'], + 'price'=>$dataVo['O'], + 'nums'=>$dataVo['P'], + 'serial'=>explode(',',$dataVo['Q']), + 'total'=>0, + 'data'=>$dataVo['S'] + ]; + //商品匹配 + $goodsFind=search($goods)->where([['name','=',$record['goods']]])->find(); + if(empty($goodsFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行商品名称[ '.$record['goods'].' ]未匹配!'); + }else{ + $record['goods']=$goodsFind['id']; + } + //辅助属性匹配 + if(empty($goodsFind['attr'])){ + $record['attr']=''; + }else{ + if(empty($record['attr'])){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性不可为空!'); + }else{ + $attrFind=search($goodsFind['attr'])->where([['name','=',$record['attr']]])->find(); + if(empty($attrFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性[ '.$record['attr'].' ]未匹配!'); + } + } + } + //单位匹配 + if($goodsFind['unit']==-1){ + if(empty($record['unit'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单位不可为空!'); + }else{ + $unitFind=search($goodsFind['units'])->where([['name','=',$record['unit']]])->find(); + if(empty($unitFind) && $goodsFind['units'][0]['source']!=$record['unit']){ + throw new ValidateException('模板文件第'.$dataKey.'行单位[ '.$record['unit'].' ]未匹配!'); + } + } + }else{ + $record['unit']=$goodsFind['unit']; + } + //仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $warehouseFind=search($warehouse)->where([['name','=',$record['warehouse']]])->find(); + if(empty($warehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行仓库[ '.$record['warehouse'].' ]未匹配!'); + }else{ + $record['warehouse']=$warehouseFind['id']; + } + }else{ + //服务产品 + $record['warehouse']=null; + } + //批次号匹配 + if(empty($goodsFind['batch'])){ + $record['batch']=''; + }else{ + if(empty($record['batch'])){ + throw new ValidateException('模板文件第'.$dataKey.'行批次号不可为空!'); + } + } + //生产日期匹配 + if(empty($goodsFind['validity'])){ + $record['mfd']=''; + }else{ + if(empty($record['mfd'])){ + throw new ValidateException('模板文件第'.$dataKey.'行生产日期不可为空!'); + } + } + //成本匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['price'])){ + throw new ValidateException('模板文件第'.$dataKey.'行成本不正确!'); + } + //数量匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['nums']."})?$/",$record['nums'])){ + throw new ValidateException('模板文件第'.$dataKey.'行数量不正确!'); + } + //序列号匹配 + if(empty($goodsFind['serial'])){ + $record['serial']=[]; + }else{ + if(count($record['serial'])==1 && empty($record['serial'][0])){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号不可为空!'); + }else{ + if(count($record['serial'])!=$record['nums']){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号个数与数量不符!'); + } + } + } + try{ + $this->validate($record,'app\validate\EntryInfo');//数据合法性验证 + $record['total']=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['total'])->done();//累加单据成本 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + //序列号重复验证 + $serials=[]; + foreach ($info as $infoVo) { + $serials = array_merge($serials,$infoVo['serial']); + } + if(count($serials)!=count(array_unique($serials))){ + throw new ValidateException('商品信息中存在重复序列号!'); + } + Db::startTrans(); + try { + //新增CLASS + $classData=Entrys::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new EntryInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'entry','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入其它入库单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出其它入库单列表');//日志 + $source=Entrys::with(['frameData','peopleData','userData','recordData','supplierData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'其它入库单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'supplierData|name'=>'供应商', + 'extension|type'=>'单据类型', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据成本', + 'cost'=>'单据费用', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|cse'=>'费用状态', + 'extension|check'=>'核对状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据成本:'.mathArraySum(array_column($source,'total')), + '总单据费用:'.mathArraySum(array_column($source,'cost')) + ]]; + //导出execl + buildExcel('其它入库单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'其它入库单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '供应商:'.$sourceVo['supplierData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'goodsData|spec'=>'规格型号', + 'attr'=>'辅助属性', + 'unit'=>'单位', + 'warehouseData|name'=>'仓库', + 'batch'=>'批次号', + 'mfd'=>'生产日期', + 'price'=>'成本', + 'nums'=>'数量', + 'extension|serial'=>'序列号', + 'total'=>'总成本', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=EntryInfo::with(['goodsData','warehouseData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->append(['extension'])->select()->toArray(); + //批次号匹配 + if(empty(search($info)->where([['goodsData|batch','=',true]])->find())){ + unset($field['batch']); + } + //生产日期匹配 + if(empty(search($info)->where([['goodsData|validity','=',true]])->find())){ + unset($field['mfd']); + } + //序列号匹配 + if(empty(search($info)->where([['goodsData|serial','=',true]])->find())){ + unset($field['extension|serial']); + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据类型:'.$sourceVo['extension']['type'], + '单据成本:'.$sourceVo['total'], + '单据费用:'.$sourceVo['cost'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '物流信息:'.$sourceVo['extension']['logistics'], + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + + } + buildZip('其它入库单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Extry.php b/serve/app/controller/Extry.php new file mode 100644 index 0000000..82896f5 --- /dev/null +++ b/serve/app/controller/Extry.php @@ -0,0 +1,1027 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['type','fullDec1'], + ['examine','fullDec1'], + ['cse','fullDec1'], + ['check','fullDec1'], + ['user','fullEq'], + ['data','fullLike'] + ]);//构造SQL + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['id','in',array_column(Db::name('extry_info')->where([['goods','in',$goods]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('extry',$sql);//数据鉴权 + $count = Extrys::where($sql)->count();//获取总条数 + $info = Extrys::with(['frameData','peopleData','userData','costData','recordData','customerData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id']) && isset($input['cost'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['cse']=empty($class['cost'])?3:0; + $class['examine']=0; + empty($class['id'])?$this->validate($class,'app\validate\Extry'):$this->validate($class,'app\validate\Extry.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\ExtryInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'商品信息第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //验证Cost + foreach ($input['cost'] as $costKey=>$costVo) { + try { + $this->validate($costVo,'app\validate\Cost'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'单据费用第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Extrys::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'extry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增其它出库单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Extrys::update($class); + Db::name('record')->insert(['type'=>'extry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新其它出库单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + ExtryInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new ExtryInfo; + $model->saveAll($input['info']); + + //COST数据 + Cost::where([['type','=','extry'],['class','=',$class['id']]])->delete(); + foreach ($input['cost'] as $costKey=>$costVo) { + unset($input['cost'][$costKey]['id']); + $input['cost'][$costKey]['type']='extry'; + $input['cost'][$costKey]['class']=$class['id']; + $input['cost'][$costKey]['time']=$class['time']; + $input['cost'][$costKey]['settle']=0; + $input['cost'][$costKey]['state']=0; + } + $model = new Cost; + $model->saveAll($input['cost']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Extrys::where([['id','=',$input['parm']]])->find(); + $info=ExtryInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $cost=Cost::where([['type','=','extry'],['class','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + 'cost'=>$cost + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('extry')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('extry')->where([['id','in',$input['parm']]])->delete(); + Db::name('extry_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('cost')->where([['type','=','extry'],['class','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','extry'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除其它出库单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //核对|反核对 + public function check(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $period=getPeriod(); + $classList=Db::name('extry')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + foreach ($input['parm'] as $parmVo) { + $class=search($classList)->where([['id','=',$parmVo]])->find(); + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(empty($class['check'])){ + Db::name('extry')->where([['id','=',$class['id']]])->update(['check'=>1]); + //14 单据记录 + Db::name('record')->insert(['type'=>'extry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'核对单据']); + //15 记录操作 + pushLog('核对其它出库单[ '.$class['number'].' ]');//单据日志 + }else{ + Db::name('extry')->where([['id','=',$class['id']]])->update(['check'=>0]); + //14 单据记录 + Db::name('record')->insert(['type'=>'extry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反核对单据']); + //15 记录操作 + pushLog('反核对其它出库单[ '.$class['number'].' ]');//单据日志 + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $fun=getSys('fun'); + $period=getPeriod(); + $classList=Db::name('extry')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('extry_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //1.1 商品数据 + $goodsList=Db::name('goods')->where([['id','in',array_unique(array_column($info,'goods'))]])->select()->toArray(); + //1.2 综合匹配 + if(empty($class['examine'])){ + //1 构造数据 + $batchGather=[]; + $serialGather=[]; + $roomWhereOrSql=[]; + foreach ($info as $infoVo) { + //1 批次号 + empty($infoVo['batch'])||$batchGather[]=$infoVo['batch']; + //2 序列号 + $serialGather=array_merge($serialGather,json_decode($infoVo['serial'])); + //3 仓储条件 + empty($infoVo['warehouse'])||$roomWhereOrSql[]=[['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]]; + } + //2 匹配数据 + empty($batchGather)||$batchList=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + empty($serialGather)||$serialList=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + if(!empty($roomWhereOrSql)){ + //1 去重转存 + $roomWhereOrSql=array_unique($roomWhereOrSql,SORT_REGULAR); + //2 仓储匹配 + $roomList=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + } + } + + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(!empty($class['examine'])){ + //单据费用 + $cost=Db::name('cost')->alias('cost')->where([['type','=','extry'],['class','=',$class['id']]])->whereExists(function($query){ + $query->name('oce_info')->where([['source','=',Db::raw('cost.id')]])->limit(1); + })->find(); + if(!empty($cost)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联其它支出单!']); + exit; + } + } + + //3 INFO验证|构造 + foreach ($info as $infoKey=>$infoVo) { + //1 匹配商品 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + //2 商品类型 + if(empty($goods['type'])){ + //场景验证 + if(empty($class['examine'])){ + //1 匹配数据 + $room=search($roomList)->where([['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]],true)->find(); + (empty($room)||empty($infoVo['batch']))||$batch=search($batchList)->where([['room','=',$room['id']],['number','=',$infoVo['batch']],['time','=',$infoVo['mfd']]],true)->find(); + //2 多单位处理 + if($goods['unit']==-1){ + //多单位|转存 + $radix=unitRadix($infoVo['unit'],json_decode($goods['units'],true)); + $info[$infoKey]['basic']=[ + 'nums'=>math()->chain($infoVo['nums'])->mul($radix)->done(), + 'price'=>math()->chain($infoVo['price'])->div($radix)->round(4)->done() + ]; + }else{ + //常规单位|转存 + $info[$infoKey]['basic']=[ + 'nums'=>$infoVo['nums'], + 'price'=>$infoVo['price'] + ]; + } + //3 序列号 + $serialData=json_decode($infoVo['serial']); + if(empty($serialData)){ + $info[$infoKey]['serial']=[]; + }else{ + //序列号状态[不存在|未销售] + $serialCollect=search($serialList)->where([['goods','=',$infoVo['goods']],['number','in',$serialData]])->select(); + foreach ($serialCollect as $serialCollectVo) { + if($serialCollectVo['state']==0){ + if(empty($room) || $room['id']!=$serialCollectVo['room']){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]与仓库不匹配!']); + exit; + } + if((empty($infoVo['batch'])&&!empty($serialCollectVo['batch']))||(!empty($infoVo['batch'])&&(empty($batch)||$batch['id']!=$serialCollectVo['batch']))){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]与批次不匹配!']); + exit; + } + }else{ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]状态不正确!']); + exit; + } + } + $info[$infoKey]['serial']=$serialData; + } + //4 负库存验证 + if($fun['overflow']==false){ + //1 仓储验证 + if(empty($room)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行仓储信息不存在!']); + exit; + }else{ + if(bccomp($info[$infoKey]['basic']['nums'],$room['nums'])==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行仓储库存不足!']); + exit; + }else{ + $roomList[$room['rowKey']]['nums']=math()->chain($room['nums'])->sub($info[$infoKey]['basic']['nums'])->done(); + } + } + //2 批次验证 + if(!empty($infoVo['batch'])){ + if(empty($batch)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行批次信息无效!']); + exit; + }else{ + if(bccomp($info[$infoKey]['basic']['nums'],$batch['nums'])==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行批次库存不足!']); + exit; + }else{ + $batchList[$batch['rowKey']]['nums']=math()->chain($batch['nums'])->sub($info[$infoKey]['basic']['nums'])->done(); + } + } + } + //3 序列号验证 + if(!empty($serialData)){ + $serialCount=search($serialList)->where([['room','=',$room['id']],['number','in',$serialData]])->count(); + if($serialCount != count($serialData)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行存在无效序列号!']); + exit; + } + } + } + }else{ + //1 验证序列号 + $serialInfoCollect=Db::name('serial_info')->where([['type','=','extry'],['info','in',array_column($info,'id')]])->select()->toArray(); + if(!empty($serialInfoCollect)){ + //序列号状态[已销售] + $serialFind=Db::name('serial')->where([['id','in',array_column($serialInfoCollect,'pid')],['state','<>',1]])->find(); + if(!empty($serialFind)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + } + } + } + //4 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $store=['room'=>[],'roomInfo'=>[],'batch'=>[],'batchInfo'=>[],'serial'=>[],'serialInfo'=>[],'serve'=>[],'serveInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //判断商品类型 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + if(empty($goods['type'])){ + //常规商品 + //1 仓储 + $store['room'][]=['warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['basic']['nums']]; + //2 仓储详情 + $store['roomInfo'][]=['pid'=>null,'type'=>'extry','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'direction'=>0,'price'=>$infoVo['basic']['price'],'nums'=>$infoVo['basic']['nums']]; + //3 批次号 + if(empty($infoVo['batch'])){ + $store['batch'][]=[]; + $store['batchInfo'][]=[]; + }else{ + $store['batch'][]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'number'=>$infoVo['batch'],'time'=>$infoVo['mfd'],'nums'=>$infoVo['basic']['nums']]; + $store['batchInfo'][]=['pid'=>null,'type'=>'extry','class'=>$class['id'],'info'=>$infoVo['id'],'direction'=>0,'nums'=>$infoVo['basic']['nums']]; + } + //4 序列号 + if(empty($infoVo['serial'])){ + $store['serial'][]=[]; + $store['serialInfo'][]=[]; + }else{ + $serial=[]; + $serialInfo=[]; + foreach ($infoVo['serial'] as $serialVo) { + $serial[]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'batch'=>null,'goods'=>$infoVo['goods'],'number'=>$serialVo,'state'=>1]; + $serialInfo[]=['pid'=>null,'type'=>'extry','class'=>$class['id'],'info'=>$infoVo['id']]; + } + $store['serial'][]=$serial; + $store['serialInfo'][]=$serialInfo; + } + }else{ + //5 服务商品 + $store['serve'][]=['goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['nums']]; + $store['serveInfo'][]=['pid'=>null,'type'=>'extry','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'price'=>$infoVo['price'],'nums'=>$infoVo['nums']]; + } + } + //2 仓储 + if(!empty($store['room'])){ + //1 构造数据 + $roomInsert=[]; + foreach ($store['room'] as $roomVo) { + $roomFind=search($roomList)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + if(empty($roomFind)){ + $roomVo['nums']=0; + $roomInsert[]=$roomVo; + } + } + //2 创建数据|去重 + empty($roomInsert)||Db::name('room')->insertAll(array_unique($roomInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $roomDuplicate=[]; + $room=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + foreach ($store['room'] as $roomKey=>$roomVo) { + $roomFind=search($room)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + $store['room'][$roomKey]['id']=$roomFind['id']; + $roomDuplicate[]=['id'=>$roomFind['id'],'nums'=>$roomVo['nums']]; + } + //4 更新数据 + Db::name('room')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($roomDuplicate); + } + //3 仓储详情 + if(!empty($store['roomInfo'])){ + //1 填充数据 + foreach ($store['roomInfo'] as $roomInfoKey=>$roomInfoVo) { + $store['roomInfo'][$roomInfoKey]['pid']=$store['room'][$roomInfoKey]['id']; + } + //2 创建数据 + Db::name('room_info')->insertAll($store['roomInfo']); + } + //4 批次号 + if(!empty($store['batch'])){ + //1 构造数据 + $batchData=[]; + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $store['batch'][$batchKey]['room']=$store['room'][$batchKey]['id']; + $batchData[]=$store['batch'][$batchKey]; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchData)){ + //1 构造数据 + $batchInsert=[]; + foreach ($batchData as $batchDataKey=>$batchDataVo) { + $batchFind=search($batchList)->where([['room','=',$batchDataVo['room']],['number','=',$batchDataVo['number']],['time','=',$batchDataVo['time']]])->find(); + if(empty($batchFind)){ + $batchDataVo['nums']=0; + $batchInsert[]=$batchDataVo; + } + } + //2 创建数据|去重 + empty($batchInsert)||Db::name('batch')->insertAll(array_unique($batchInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $batchDuplicate=[]; + $batch=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $batchFind=search($batch)->where([['room','=',$batchVo['room']],['number','=',$batchVo['number']],['time','=',$batchVo['time']]])->find(); + $store['batch'][$batchKey]['id']=$batchFind['id']; + $batchDuplicate[]=['id'=>$batchFind['id'],'nums'=>$batchVo['nums']]; + } + } + //4 更新数据 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($batchDuplicate); + } + } + //5 批次号详情 + if(!empty($store['batchInfo'])){ + //1 构造数据 + $batchInfoInstall=[]; + foreach ($store['batchInfo'] as $batchInfoKey=>$batchInfoVo) { + if(!empty($batchInfoVo)){ + $batchInfoVo['pid']=$store['batch'][$batchInfoKey]['id']; + $batchInfoInstall[]=$batchInfoVo; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchInfoInstall)){ + //创建数据 + Db::name('batch_info')->insertAll($batchInfoInstall); + } + } + //6 序列号 + if(!empty($store['serial'])){ + //1 构造数据 + $serialData=[]; + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $store['serial'][$serialKey][$itemKey]['room']=$store['room'][$serialKey]['id']; + $store['serial'][$serialKey][$itemKey]['batch']=empty($store['batch'][$serialKey])?0:$store['batch'][$serialKey]['id']; + $serialData[]=$store['serial'][$serialKey][$itemKey]; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialData)){ + //1 构造数据 + $serialInsert=[]; + foreach ($serialData as $serialDataKey=>$serialDataVo) { + $serialFind=search($serialList)->where([['room','=',$serialDataVo['room']],['batch','=',$serialDataVo['batch']],['number','=',$serialDataVo['number']]])->find(); + if(empty($serialFind)){ + $serialInsert[]=$serialDataVo; + } + } + //2 创建数据 + empty($serialInsert)||Db::name('serial')->insertAll($serialInsert); + //3 匹配主键|构造更新 + $serialDuplicate=[]; + $serial=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $serialFind=search($serial)->where([['room','=',$itemVo['room']],['batch','=',$itemVo['batch']],['number','=',$itemVo['number']]])->find(); + $store['serial'][$serialKey][$itemKey]['id']=$serialFind['id']; + $serialFind['state']==0&&$serialDuplicate[]=$serialFind['id']; + } + } + } + //4 更新数据|状态变更 + empty($serialDuplicate)||Db::name('serial')->where([['id','in',$serialDuplicate]])->update(['state'=>1]); + } + } + //7 序列号详情 + if(!empty($store['serialInfo'])){ + //1 构造数据 + $serialInfoInstall=[]; + foreach ($store['serialInfo'] as $serialInfoKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $itemVo['pid']=$store['serial'][$serialInfoKey][$itemKey]['id']; + $serialInfoInstall[]=$itemVo; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialInfoInstall)){ + //创建数据 + Db::name('serial_info')->insertAll($serialInfoInstall); + } + } + //8 服务商品 + if(!empty($store['serve'])){ + //1 匹配数据|去重 + $serveWhereOrSql=array_unique(array_map(function($item){ + return [['goods','=',$item['goods']],['attr','=',$item['attr']]]; + },$store['serve']),SORT_REGULAR); + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + //2 构造数据 + $serveInsert=[]; + foreach ($store['serve'] as $serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + if(empty($serveFind)){ + $serveVo['nums']=0; + $serveInsert[]=$serveVo; + } + } + //3 创建数据|去重 + empty($serveInsert)||Db::name('serve')->insertAll(array_unique($serveInsert,SORT_REGULAR)); + //4 匹配主键|构造更新 + $serveDuplicate=[]; + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + foreach ($store['serve'] as $serveKey=>$serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + $store['serve'][$serveKey]['id']=$serveFind['id']; + $serveDuplicate[]=['id'=>$serveFind['id'],'nums'=>$serveVo['nums']]; + } + //5 更新数据 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($serveDuplicate); + } + //9 服务商品详情 + if(!empty($store['serveInfo'])){ + //1 填充数据 + foreach ($store['serveInfo'] as $serveInfoKey=>$serveInfoVo) { + $store['serveInfo'][$serveInfoKey]['pid']=$store['serve'][$serveInfoKey]['id']; + } + //2 创建数据 + Db::name('serve_info')->insertAll($store['serveInfo']); + } + //10 更新单据 + Db::name('extry')->where([['id','=',$class['id']]])->update(['examine'=>1]); + //11 单据记录 + Db::name('record')->insert(['type'=>'extry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //12 收发记录 + $summary=new Summary; + $summary->note('extry',$class['id'],true); + //13 记录操作 + pushLog('审核其它出库单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 匹配数据 + $listSql=[['type','=','extry'],['info','in',array_column($info,'id')]]; + $roomInfoList=Db::name('room_info')->where($listSql)->select()->toArray(); + $batchInfoList=Db::name('batch_info')->where($listSql)->select()->toArray(); + $serialInfoList=Db::name('serial_info')->where($listSql)->select()->toArray(); + $serveInfoList=Db::name('serve_info')->where($listSql)->select()->toArray(); + //1 仓储 + $roomDuplicate=[]; + foreach ($roomInfoList as $roomInfoVo) { + $roomDuplicate[]=['id'=>$roomInfoVo['pid'],'nums'=>$roomInfoVo['nums']]; + } + //2.1 更新仓储 + Db::name('room')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($roomDuplicate); + //2.2 删除仓储详情 + Db::name('room_info')->where([['id','in',array_column($roomInfoList,'id')]])->delete(); + //2.3 仓储|冗余 + $roomPk=array_unique(array_column($roomInfoList,'pid')); + $roomInfoData=Db::name('room_info')->where([['pid','in',$roomPk]])->select()->toArray(); + $roomDiff=array_diff($roomPk,array_unique(array_column($roomInfoData,'pid'))); + empty($roomDiff)||Db::name('room')->where([['id','in',$roomDiff]])->delete(); + //3 批次号 + if(!empty($batchInfoList)){ + //1 构造数据 + $batchInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$batchInfoList); + //2 更新批次号 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($batchInfoDuplicate); + //3 删除批次号详情 + Db::name('batch_info')->where([['id','in',array_column($batchInfoList,'id')]])->delete(); + //4 批次号|冗余 + $batchPk=array_unique(array_column($batchInfoList,'pid')); + $batchInfoData=Db::name('batch_info')->where([['pid','in',$batchPk]])->select()->toArray(); + $batchDiff=array_diff($batchPk,array_unique(array_column($batchInfoData,'pid'))); + empty($batchDiff)||Db::name('batch')->where([['id','in',$batchDiff]])->delete(); + } + //4 序列号 + if(!empty($serialInfoList)){ + //1 更新序列号 + Db::name('serial')->where([['id','in',array_column($serialInfoList,'pid')]])->update(['state'=>0]); + //2 删除序列号详情 + Db::name('serial_info')->where([['id','in',array_column($serialInfoList,'id')]])->delete(); + //3 序列号|冗余 + $serialPk=array_unique(array_column($serialInfoList,'pid')); + $serialInfoData=Db::name('serial_info')->where([['pid','in',$serialPk]])->select()->toArray(); + $serialDiff=array_diff($serialPk,array_unique(array_column($serialInfoData,'pid'))); + empty($serialDiff)||Db::name('serial')->where([['id','in',$serialDiff]])->delete(); + } + //5 服务 + if(!empty($serveInfoList)){ + //1 构造数据 + $serveInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$serveInfoList); + //2 更新服务 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($serveInfoDuplicate); + //3 删除服务详情 + Db::name('serve_info')->where([['id','in',array_column($serveInfoList,'id')]])->delete(); + //4 服务|冗余 + $servePk=array_unique(array_column($serveInfoList,'pid')); + $serveInfoData=Db::name('serve_info')->where([['pid','in',$servePk]])->select()->toArray(); + $serveDiff=array_diff($servePk,array_unique(array_column($serveInfoData,'pid'))); + empty($serveDiff)||Db::name('serve')->where([['id','in',$serveDiff]])->delete(); + } + //6 更新单据 + Db::name('extry')->where([['id','=',$class['id']]])->update(['examine'=>0]); + //7 单据记录 + Db::name('record')->insert(['type'=>'extry','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //8 收发记录 + $summary=new Summary; + $summary->note('extry',$class['id'],false); + //9 记录操作 + pushLog('反审核其它出库单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('extry', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //单据类型匹配 + if(in_array($data[3]['C'],['其它出库单','盘亏单'])){ + $type=$data[3]['C']=="其它出库单"?0:1; + }else{ + throw new ValidateException('单据类型[ '.$data[3]['C'].' ]未匹配!'); + } + //关联人员匹配 + if(empty($data[3]['E'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['E']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['E'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'time'=>$data[3]['A'], + 'number'=>$data[3]['B'], + 'type'=>$type, + 'total'=>0, + 'people'=>$people['id'], + 'logistics'=>["key"=>"auto","name"=>"自动识别","number"=>$data[3]['F']], + 'file'=>[], + 'data'=>$data[3]['G'], + 'more'=>[], + 'examine'=>0, + 'cse'=>0, + 'check'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Extry');//数据合法性验证 + //初始化INFO + $info=[]; + $goods=Goods::with(['attr'])->where([['name','in',array_column($data,'H')]])->select()->toArray(); + $warehouse=Db::name('warehouse')->where([['name','in',array_column($data,'K')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'goods'=>$dataVo['H'], + 'attr'=>$dataVo['I'], + 'unit'=>$dataVo['J'], + 'warehouse'=>$dataVo['K'], + 'batch'=>$dataVo['L'], + 'mfd'=>$dataVo['M'], + 'price'=>$dataVo['N'], + 'nums'=>$dataVo['O'], + 'serial'=>explode(',',$dataVo['P']), + 'total'=>0, + 'data'=>$dataVo['R'] + ]; + //商品匹配 + $goodsFind=search($goods)->where([['name','=',$record['goods']]])->find(); + if(empty($goodsFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行商品名称[ '.$record['goods'].' ]未匹配!'); + }else{ + $record['goods']=$goodsFind['id']; + } + //辅助属性匹配 + if(empty($goodsFind['attr'])){ + $record['attr']=''; + }else{ + if(empty($record['attr'])){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性不可为空!'); + }else{ + $attrFind=search($goodsFind['attr'])->where([['name','=',$record['attr']]])->find(); + if(empty($attrFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性[ '.$record['attr'].' ]未匹配!'); + } + } + } + //单位匹配 + if($goodsFind['unit']==-1){ + if(empty($record['unit'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单位不可为空!'); + }else{ + $unitFind=search($goodsFind['units'])->where([['name','=',$record['unit']]])->find(); + if(empty($unitFind) && $goodsFind['units'][0]['source']!=$record['unit']){ + throw new ValidateException('模板文件第'.$dataKey.'行单位[ '.$record['unit'].' ]未匹配!'); + } + } + }else{ + $record['unit']=$goodsFind['unit']; + } + //仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $warehouseFind=search($warehouse)->where([['name','=',$record['warehouse']]])->find(); + if(empty($warehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行仓库[ '.$record['warehouse'].' ]未匹配!'); + }else{ + $record['warehouse']=$warehouseFind['id']; + } + }else{ + //服务产品 + $record['warehouse']=null; + } + //批次号匹配 + if(empty($goodsFind['batch'])){ + $record['batch']=''; + }else{ + if(empty($record['batch'])){ + throw new ValidateException('模板文件第'.$dataKey.'行批次号不可为空!'); + } + } + //生产日期匹配 + if(empty($goodsFind['validity'])){ + $record['mfd']=''; + }else{ + if(empty($record['mfd'])){ + throw new ValidateException('模板文件第'.$dataKey.'行生产日期不可为空!'); + } + } + //成本匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['price'])){ + throw new ValidateException('模板文件第'.$dataKey.'行成本不正确!'); + } + //数量匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['nums']."})?$/",$record['nums'])){ + throw new ValidateException('模板文件第'.$dataKey.'行数量不正确!'); + } + //序列号匹配 + if(empty($goodsFind['serial'])){ + $record['serial']=[]; + }else{ + if(count($record['serial'])==1 && empty($record['serial'][0])){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号不可为空!'); + }else{ + if(count($record['serial'])!=$record['nums']){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号个数与数量不符!'); + } + } + } + try{ + $this->validate($record,'app\validate\ExtryInfo');//数据合法性验证 + $record['total']=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['total'])->done();//累加单据成本 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + //序列号重复验证 + $serials=[]; + foreach ($info as $infoVo) { + $serials = array_merge($serials,$infoVo['serial']); + } + if(count($serials)!=count(array_unique($serials))){ + throw new ValidateException('商品信息中存在重复序列号!'); + } + Db::startTrans(); + try { + //新增CLASS + $classData=Extrys::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new ExtryInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'extry','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入其它出库单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出其它出库单列表');//日志 + $source=Extrys::with(['frameData','peopleData','userData','recordData','customerData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'其它出库单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'extension|type'=>'单据类型', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据成本', + 'cost'=>'单据费用', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|cse'=>'费用状态', + 'extension|check'=>'核对状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据成本:'.mathArraySum(array_column($source,'total')), + '总单据费用:'.mathArraySum(array_column($source,'cost')) + ]]; + //导出execl + buildExcel('其它出库单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'其它出库单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '客户:'.$sourceVo['customerData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'goodsData|spec'=>'规格型号', + 'attr'=>'辅助属性', + 'unit'=>'单位', + 'warehouseData|name'=>'仓库', + 'batch'=>'批次号', + 'mfd'=>'生产日期', + 'price'=>'成本', + 'nums'=>'数量', + 'extension|serial'=>'序列号', + 'total'=>'总成本', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=ExtryInfo::with(['goodsData','warehouseData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->append(['extension'])->select()->toArray(); + //批次号匹配 + if(empty(search($info)->where([['goodsData|batch','=',true]])->find())){ + unset($field['batch']); + } + //生产日期匹配 + if(empty(search($info)->where([['goodsData|validity','=',true]])->find())){ + unset($field['mfd']); + } + //序列号匹配 + if(empty(search($info)->where([['goodsData|serial','=',true]])->find())){ + unset($field['extension|serial']); + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据类型:'.$sourceVo['extension']['type'], + '单据成本:'.$sourceVo['total'], + '单据费用:'.$sourceVo['cost'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '物流信息:'.$sourceVo['extension']['logistics'], + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + + } + buildZip('其它出库单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Field.php b/serve/app/controller/Field.php new file mode 100644 index 0000000..d8455d6 --- /dev/null +++ b/serve/app/controller/Field.php @@ -0,0 +1,98 @@ +count();//获取总条数 + $info = Fields::where($sql)->page($input['page'],$input['limit'])->append(['extension'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + empty($input['id'])?$this->validate($input,'app\validate\Field'):$this->validate($input,'app\validate\Field.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Fields::create($input); + pushLog('新增表单字段[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Fields::update($input); + pushLog('更新表单字段[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Fields::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('field')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + Db::startTrans(); + try { + Db::name('field')->where([['id','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除表单字段[ '.implode(' | ',array_column($data,'name')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} diff --git a/serve/app/controller/Frame.php b/serve/app/controller/Frame.php new file mode 100644 index 0000000..b81eb1d --- /dev/null +++ b/serve/app/controller/Frame.php @@ -0,0 +1,129 @@ +'asc'])->select()); + return json(['state'=>'success','info'=>$frame]); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + if(empty($input['id'])){ + $this->validate($input,'app\validate\Frame'); + }else{ + $this->validate($input,'app\validate\Frame.update'); + //所属不可等于或包含当前 + if(in_array($input['pid'],findTreeArr('frame',$input['id'],'id'))){ + throw new ValidateException('所属组织选择不正确!'); + } + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Frames::create($input); + pushLog('新增组织机构[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Frames::update($input); + pushLog('更新组织机构[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else { + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Frames::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $subFind=Db::name('frame')->where([['pid','=',$input['id']]])->find(); + if(empty($subFind)){ + //关联判断 + $exist=moreTableFind([ + ['table'=>'account','where'=>[['frame','=',$input['id']]]], + ['table'=>'allot','where'=>[['frame','=',$input['id']]]], + ['table'=>'barter','where'=>[['frame','=',$input['id']]]], + ['table'=>'bill','where'=>[['frame','=',$input['id']]]], + ['table'=>'bor','where'=>[['frame','=',$input['id']]]], + ['table'=>'bre','where'=>[['frame','=',$input['id']]]], + ['table'=>'buy','where'=>[['frame','=',$input['id']]]], + ['table'=>'customer','where'=>[['frame','=',$input['id']]]], + ['table'=>'deploy','where'=>[['frame','=',$input['id']]]], + ['table'=>'entry','where'=>[['frame','=',$input['id']]]], + ['table'=>'extry','where'=>[['frame','=',$input['id']]]], + ['table'=>'ice','where'=>[['frame','=',$input['id']]]], + ['table'=>'imy','where'=>[['frame','=',$input['id']]]], + ['table'=>'oce','where'=>[['frame','=',$input['id']]]], + ['table'=>'omy','where'=>[['frame','=',$input['id']]]], + ['table'=>'people','where'=>[['frame','=',$input['id']]]], + ['table'=>'sell','where'=>[['frame','=',$input['id']]]], + ['table'=>'sor','where'=>[['frame','=',$input['id']]]], + ['table'=>'sre','where'=>[['frame','=',$input['id']]]], + ['table'=>'supplier','where'=>[['frame','=',$input['id']]]], + ['table'=>'swap','where'=>[['frame','=',$input['id']]]], + ['table'=>'user','where'=>[['frame','=',$input['id']]]], + ['table'=>'warehouse','where'=>[['frame','=',$input['id']]]], + ]); + if(empty($exist)){ + //逻辑处理 + $find=Db::name('frame')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + try { + Db::name('frame')->where([['id','=',$input['id']]])->delete(); + pushLog('删除组织机构[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'存在子数据,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + +} diff --git a/serve/app/controller/Goods.php b/serve/app/controller/Goods.php new file mode 100644 index 0000000..9afc56a --- /dev/null +++ b/serve/app/controller/Goods.php @@ -0,0 +1,395 @@ +'name|py'],'fullLike'], + ['number','fullLike'], + ['spec','fullLike'], + ['brand','fullEq'], + ['code','fullLike'], + ['type','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + //商品分类树结构查询 + if(existFull($input,['category'])){ + $sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + } + $count = Goodss::where($sql)->count();//获取总条数 + $info = Goodss::with(['categoryData'])->where($sql)->page($input['page'],$input['limit'])->append(['extension'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + + try { + $input['py']=zhToPy($input['name']);//首拼信息 + empty($input['id'])?$this->validate($input,'app\validate\Goods'):$this->validate($input,'app\validate\Goods.update'); + + //关联判断 + if(!empty($input['id'])){ + $exist=moreTableFind([ + ['table'=>'bor_info','where'=>[['goods','=',$input['id']]]], + ['table'=>'buy_info','where'=>[['goods','=',$input['id']]]], + ['table'=>'bre_info','where'=>[['goods','=',$input['id']]]], + ['table'=>'sor_info','where'=>[['goods','=',$input['id']]]], + ['table'=>'sell_info','where'=>[['goods','=',$input['id']]]], + ['table'=>'sre_info','where'=>[['goods','=',$input['id']]]], + ['table'=>'extry_info','where'=>[['goods','=',$input['id']]]], + ['table'=>'entry_info','where'=>[['goods','=',$input['id']]]], + ['table'=>'swap_info','where'=>[['goods','=',$input['id']]]] + ]); + if(!empty($exist)){ + $goods=Db::name('goods')->where([['id','=',$input['id']]])->find(); + if($input['unit'] != $goods['unit']){ + throw new ValidateException('[ 单位 ] 存在数据关联,操作已撤销!'); + }else if($input['type'] != $goods['type']){ + throw new ValidateException('[ 类型 ] 存在数据关联,操作已撤销!'); + }else if($input['serial'] != $goods['serial']){ + throw new ValidateException('[ 序列号 ] 存在数据关联,操作已撤销!'); + }else if($input['batch'] != $goods['batch']){ + throw new ValidateException('[ 批次 ] 存在数据关联,操作已撤销!'); + }else if($input['validity'] != $goods['validity']){ + throw new ValidateException('[ 有效期 ] 存在数据关联,操作已撤销!'); + }else{ + $attr=Db::name('attr')->where([['pid','=',$input['id']]])->select()->toArray(); + $column=[array_column($attr,'name'),array_column($input['attr'],'name')]; + $diff=array_diff($column[0],$column[1]); + if(!empty($diff)){ + throw new ValidateException('[ 辅助属性 ] 存在数据关联,操作已撤销!'); + } + } + } + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证ATTR + if(empty($input['attr'])){ + //验证辅助属性 + foreach ($input['attr'] as $attrKey=>$attrVo) { + try { + $this->validate($attrVo,'app\validate\Attr'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'辅助属性第'.($attrKey+1).'条'.$e->getError()]); + exit; + } + } + } + + //处理数据 + Db::startTrans(); + try { + //GOODS数据 + if(empty($input['id'])){ + //创建数据 + $createInfo=Goodss::create($input); + $input['id']=$createInfo['id'];//转存主键 + pushLog('新增商品[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Goodss::update($input); + pushLog('更新商品[ '.$input['name'].' ]');//日志 + } + + //ATTR数据 + Attr::where([['pid','=',$input['id']]])->delete(); + if(!empty($input['attr'])){ + foreach ($input['attr'] as $attrKey=>$attrVo) { + unset($input['attr'][$attrKey]['id']); + $input['attr'][$attrKey]['pid']=$input['id']; + } + $attr = new Attr; + $attr->saveAll($input['attr']); + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Goodss::with(['attr'])->where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //关联判断 + $exist=moreTableFind([ + ['table'=>'sor_info','where'=>[['goods','in',$input['parm']]]], + ['table'=>'sell_info','where'=>[['goods','in',$input['parm']]]], + ['table'=>'sre_info','where'=>[['goods','in',$input['parm']]]], + ['table'=>'bor_info','where'=>[['goods','in',$input['parm']]]], + ['table'=>'buy_info','where'=>[['goods','in',$input['parm']]]], + ['table'=>'bre_info','where'=>[['goods','in',$input['parm']]]], + ['table'=>'extry_info','where'=>[['goods','in',$input['parm']]]], + ['table'=>'entry_info','where'=>[['goods','in',$input['parm']]]], + ['table'=>'swap_info','where'=>[['goods','in',$input['parm']]]], + ]); + if(empty($exist)){ + //逻辑处理 + $data=Db::name('goods')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + Db::startTrans(); + try { + Db::name('goods')->where([['id','in',$input['parm']]])->delete(); + Db::name('attr')->where([['pid','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除商品[ '.implode(' | ',array_column($data,'name')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file=request()->file('file');//获取上传文件 + if (empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'png,gif,jpg,jpeg']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('goods', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + return json(['state'=>'error','info'=>$e->getMessage()]); + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + $sql=[];//初始化SQL + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'name'=>$dataVo['A'], + 'py'=>zhToPy($dataVo['A']), + 'number'=>$dataVo['B'], + 'spec'=>$dataVo['C'], + 'category'=>$dataVo['D'], + 'brand'=>$dataVo['E'], + 'unit'=>$dataVo['F'], + 'buy'=>$dataVo['G'], + 'sell'=>$dataVo['H'], + 'retail'=>$dataVo['I'], + 'integral'=>$dataVo['J'], + 'code'=>$dataVo['K'], + 'location'=>$dataVo['L'], + 'stock'=>$dataVo['M'], + 'type'=>$dataVo['N']=='常规商品'?0:1, + 'data'=>$dataVo['O'], + 'alias'=>'', + 'imgs'=>[], + 'details'=>'', + 'units'=>[], + 'strategy'=>[], + 'serial'=>0, + 'batch'=>0, + 'protect'=>0, + 'threshold'=>0, + 'more'=>[] + ]; + try { + //数据合法性验证 + $this->validate($record,'app\validate\Goods.imports'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第[ '.$dataKey.' ]行'.$e->getError()]); + exit; + } + $sql[]=$record;//加入SQL + } + //判断名称重复 + $nameColumn=array_column($sql,'name'); + $nameUnique=array_unique($nameColumn); + $nameDiff=array_diff_assoc($nameColumn,$nameUnique); + if(!empty($nameDiff)){ + //返回错误信息 + return json(['state'=>'error','info'=>'模板文件商品名称[ '.implode(' | ',$nameDiff).' ]重复!']); + } + //判断编号重复 + $numberColumn=array_column($sql,'number'); + $numberUnique=array_unique($numberColumn); + $numberDiff=array_diff_assoc($numberColumn,$numberUnique); + if(!empty($numberDiff)){ + //返回错误信息 + return json(['state'=>'error','info'=>'模板文件商品编号[ '.implode(' | ',$numberDiff).' ]重复!']); + } + //处理关联数据 + foreach($sql as $sqlKey=>$sqlVo){ + $sys=getSys(['unit','brand']); + //商品类别 + if(empty($sqlVo['category'])){ + return json(['state'=>'error','info'=>'模板文件第[ '.$sqlKey.' ]行商品类别不可为空!']); + }else{ + $find=Db::name('category')->where([['name','=',$sqlVo['category']]])->find(); + if(empty($find)){ + $insert=Db::name('category')->insertGetId([ + 'pid'=>0, + 'name'=>$sqlVo['category'], + "sort" => 99, + "data" => "自动创建|商品导入" + ]); + $sql[$sqlKey]['category']=$insert; + }else{ + $sql[$sqlKey]['category']=$find['id']; + } + } + //商品品牌 + if(!in_array($sqlVo['brand'],$sys['brand'])){ + $sys['brand'][]=$sqlVo['brand']; + Sys::where([['name','=','brand']])->update(['info'=>json_encode($sys['brand'])]); + } + //商品单位 + if($sqlVo['unit']=='多单位' || $sqlVo['unit']=='-1'){ + return json(['state'=>'error','info'=>'模板文件第[ '.($sqlKey+1).' ]行商品单位[ 多单位 ]为保留字段!']); + }else{ + if(!in_array($sqlVo['unit'],$sys['unit'])){ + $sys['unit'][]=$sqlVo['unit']; + Sys::where([['name','=','unit']])->update(['info'=>json_encode($sys['unit'])]); + } + } + } + //新增数据 + $goods = new Goodss; + $goods->saveAll($sql); + pushLog('批量导入[ '.count($sql).' ]条商品数据');//日志 + $result=['state'=>'success','info'=>'成功导入'.count($sql).'行商品数据']; + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $info=Goodss::with(['categoryData','attr'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询数据 + //字段数据二次处理 + foreach ($info as $infoKey=>$infoVo) { + //图像赋值 + if(empty($infoVo['imgs'])){ + $info[$infoKey]['imgs']=''; + }else{ + $info[$infoKey]['imgs']=[ + 'type'=>'img', + 'info'=>preg_replace("/(http|https):\/\/[^\/]*\//","",$infoVo['imgs'][0]['url']) + ]; + } + //辅助属性赋值 + if(empty($infoVo['attr'])){ + $info[$infoKey]['attr']=''; + }else{ + $attrArr=[]; + foreach ($infoVo['attr'] as $attrVo) { + $attrArr[]='属性名称:'.$attrVo['name'].' # 采购价格:'.$attrVo['buy'].' # 销售价格:'.$attrVo['sell'].' # 零售价格:'.$attrVo['retail'].' # 条形码:'.$attrVo['code']; + } + $info[$infoKey]['attr']=implode(chr(10),$attrArr); + } + //序列商品赋值 + $info[$infoKey]['serial']=$infoVo['serial']?'是':'否'; + //批次商品赋值 + $info[$infoKey]['batch']=$infoVo['batch']?'是':'否'; + } + $field=[ + 'imgs'=>'商品图像', + 'name'=>'商品名称', + 'number'=>'商品编号', + 'spec'=>'规格型号', + 'categoryData|name'=>'商品类别', + 'brand'=>'商品品牌', + 'extension|unit'=>'商品单位', + 'buy'=>'采购价格', + 'sell'=>'销售价格', + 'retail'=>'零售价格', + 'integral'=>'兑换积分', + 'code'=>'商品条码', + 'location'=>'商品货位', + 'stock'=>'库存阈值', + 'extension|type'=>'商品类型', + 'attr'=>'辅助属性', + 'data'=>'备注信息', + 'alias'=>'零售名称', + 'serial'=>'序列商品', + 'batch'=>'批次商品', + 'protect'=>'保质期', + 'threshold'=>'预警阀值', + ]; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'商品信息']; + //表格数据 + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>['总数:'.count($info)]]; + //导出execl + pushLog('导出商品信息');//日志 + buildExcel('商品信息',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Ice.php b/serve/app/controller/Ice.php new file mode 100644 index 0000000..1f9e520 --- /dev/null +++ b/serve/app/controller/Ice.php @@ -0,0 +1,481 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['account','fullEq'], + ['people','fullEq'], + ['user','fullEq'], + ['examine','fullDec1'], + ['nucleus','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('ice',$sql);//数据鉴权 + $count = Ices::where($sql)->count();//获取总条数 + $info = Ices::with(['frameData','customerData','accountData','peopleData','userData','billData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['examine']=0; + $class['nucleus']=0; + empty($class['id'])?$this->validate($class,'app\validate\Ice'):$this->validate($class,'app\validate\Ice.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\IceInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'数据表格第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Ices::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'ice','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增其它收入单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Ices::update($class); + Db::name('record')->insert(['type'=>'ice','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新其它收入单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + IceInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new IceInfo; + $model->saveAll($input['info']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Ices::where([['id','=',$input['parm']]])->find(); + $info=IceInfo::with(['ietData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('ice')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('ice')->where([['id','in',$input['parm']]])->delete(); + Db::name('ice_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','ice'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除其它收入单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('ice')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(!empty($class['examine'])){ + //核销单 + $bill=Db::name('bill_info')->where([['mold','=','ice'],['source','=',$class['id']]])->find(); + if(!empty($bill)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联核销单!']); + exit; + } + } + //3 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->inc('balance',$class['money'])->update(); + //2 创建资金详情 + Db::name('account_info')->insert([ + 'pid'=>$class['account'], + 'type'=>'ice', + 'class'=>$class['id'], + 'time'=>$class['time'], + 'direction'=>1, + 'money'=>$class['money'] + ]); + //3 创建核销记录 + Db::name('ice_bill')->insert([ + 'pid'=>$class['id'], + 'type'=>'ice', + 'source'=>$class['id'], + 'time'=>$class['time'], + 'money'=>$class['money'] + ]); + } + //2 客户|应收款余额 + if(!empty($class['customer'])){ + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('customer')->where([['id','=',$class['customer']]])->dec('balance',$balance)->update(); + } + } + //3 更新单据 + $nucleus=$class['money']==$class['actual']?2:($class['money']==0?0:1); + Db::name('ice')->where([['id','=',$class['id']]])->update(['examine'=>1,'nucleus'=>$nucleus]); + //4 单据记录 + Db::name('record')->insert(['type'=>'ice','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //5 记录操作 + pushLog('审核其它收入单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->dec('balance',$class['money'])->update(); + //2 删除资金详情 + Db::name('account_info')->where([['type','=','ice'],['class','=',$class['id']]])->delete(); + //3 删除核销记录 + Db::name('ice_bill')->where([['pid','=',$class['id']]])->delete(); + } + //2 客户|应收款余额 + if(!empty($class['customer'])){ + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('customer')->where([['id','=',$class['customer']]])->inc('balance',$balance)->update(); + } + } + //3 更新单据 + Db::name('ice')->where([['id','=',$class['id']]])->update(['examine'=>0,'nucleus'=>0]); + //4 单据记录 + Db::name('record')->insert(['type'=>'ice','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //5 记录操作 + pushLog('反审核其它收入单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('ice', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //客户匹配 + if(empty($data[3]['A'])){ + $customer=['id'=>0]; + }else{ + $customer=Db::name('customer')->where([['name','=',$data[3]['A']]])->find(); + if(empty($customer)){ + throw new ValidateException('客户[ '.$data[3]['A'].' ]未匹配!'); + } + } + //结算账户匹配 + $account=Db::name('account')->where([['name','=',$data[3]['E']]])->find(); + if(empty($account)){ + throw new ValidateException('资金账户[ '.$data[3]['E'].' ]未匹配!'); + } + //关联人员匹配 + if(empty($data[3]['F'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['F']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['F'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'customer'=>$customer['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'account'=>$account['id'], + 'people'=>$people['id'], + 'file'=>[], + 'data'=>$data[3]['G'], + 'more'=>[], + 'examine'=>0, + 'nucleus'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Ice');//数据合法性验证 + //初始化INFO + $info=[]; + $iet=Db::name('iet')->where([['name','in',array_column($data,'H')],['type','=',0]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'iet'=>$dataVo['H'], + 'money'=>$dataVo['I'], + 'data'=>$dataVo['J'] + ]; + //收入类别匹配 + $ietFind=search($iet)->where([['name','=',$record['iet']]])->find(); + if(empty($ietFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行收入类别[ '.$record['iet'].' ]未匹配!'); + }else{ + $record['iet']=$ietFind['id']; + } + //结算金额匹配 + if(!preg_match("/^(\-)?\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['money'])){ + throw new ValidateException('模板文件第'.$dataKey.'行结算金额不正确!'); + } + try{ + $this->validate($record,'app\validate\IceInfo');//数据合法性验证 + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['money'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + Db::startTrans(); + try { + //新增CLASS + $classData=Ices::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new IceInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'ice','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入其它收入单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出其它收入单列表');//日志 + $source=Ices::with(['frameData','customerData','accountData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'其它收入单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'actual'=>'实际金额', + 'money'=>'单据收款', + 'extension|amount'=>'核销金额', + 'accountData|name'=>'结算账户', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|nucleus'=>'核销状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据金额:'.mathArraySum(array_column($source,'total')), + '总实际金额:'.mathArraySum(array_column($source,'actual')), + '总单据付款:'.mathArraySum(array_column($source,'money')), + '总核销金额:'.mathArraySum(arrayColumns($source,['extension','amount'])) + ]]; + //导出execl + buildExcel('其它收入单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'其它收入单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '客户:'.$sourceVo['customerData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'ietData|name'=>'收入类别', + 'money'=>'结算金额', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=IceInfo::with(['ietData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->select()->toArray(); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '结算账户:'.arraySeek($sourceVo,'accountData|name'), + '核销金额:'.$sourceVo['extension']['amount'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + } + buildZip('其它收入单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Iet.php b/serve/app/controller/Iet.php new file mode 100644 index 0000000..5607193 --- /dev/null +++ b/serve/app/controller/Iet.php @@ -0,0 +1,103 @@ +count();//获取总条数 + $info = Iets::where($sql)->append(['extension'])->order(['sort'=>'asc', 'id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //构造|验证 + try { + empty($input['id'])?$this->validate($input,'app\validate\Iet'):$this->validate($input,'app\validate\Iet.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Iets::create($input); + pushLog('新增收支类别[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Iets::update($input); + pushLog('更新收支类别[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $info=Iets::where([['id','=',$input['id']]])->find(); + $result=['state'=>'success','info'=>$info]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //关联判断 + $exist=moreTableFind([ + ['table'=>'cost','where'=>[['iet','=',$input['id']]]], + ['table'=>'ice_info','where'=>[['iet','=',$input['id']]]], + ['table'=>'oce_info','where'=>[['iet','=',$input['id']]]], + ]); + if(empty($exist)){ + //逻辑处理 + $find=Db::name('iet')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + try { + Db::name('iet')->where([['id','=',$input['id']]])->delete(); + pushLog('删除收支类别[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Imy.php b/serve/app/controller/Imy.php new file mode 100644 index 0000000..d4610b2 --- /dev/null +++ b/serve/app/controller/Imy.php @@ -0,0 +1,454 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['people','fullEq'], + ['user','fullEq'], + ['examine','fullDec1'], + ['nucleus','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + //结算账户扩展查询 + if(existFull($input,['account'])){ + $sql[]=['id','in',array_column(Db::name('imy_info')->where([['account','=',$input['account']]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('imy',$sql);//数据鉴权 + $count = Imys::where($sql)->count();//获取总条数 + $info = Imys::with(['frameData','customerData','peopleData','userData','billData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['examine']=0; + $class['nucleus']=0; + empty($class['id'])?$this->validate($class,'app\validate\Imy'):$this->validate($class,'app\validate\Imy.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\ImyInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'数据表格第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Imys::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'imy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增收款单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Imys::update($class); + Db::name('record')->insert(['type'=>'imy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新收款单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + ImyInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new ImyInfo; + $model->saveAll($input['info']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Imys::where([['id','=',$input['parm']]])->find(); + $info=ImyInfo::with(['accountData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('imy')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('imy')->where([['id','in',$input['parm']]])->delete(); + Db::name('imy_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','imy'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除收款单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('imy')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('imy_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(!empty($class['examine'])){ + //核销单 + $bill=Db::name('bill_info')->where([['mold','=','imy'],['source','=',$class['id']]])->find(); + if(!empty($bill)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联核销单!']); + exit; + } + } + //3 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $store=['account'=>[],'accountInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //1 资金账户 + $store['account'][]=['id'=>$infoVo['account'],'balance'=>$infoVo['money']]; + //2 资金账户详情 + $store['accountInfo'][]=['pid'=>$infoVo['account'],'type'=>'imy','class'=>$class['id'],'time'=>$class['time'],'direction'=>1,'money'=>$infoVo['money']]; + } + //2 资金账户 + Db::name('account')->duplicate(['balance'=>Db::raw('balance + VALUES(`balance`)')])->insertAll($store['account']); + //3 资金账户 + Db::name('account_info')->insertAll($store['accountInfo']); + //4 客户|应收款余额 + Db::name('customer')->where([['id','=',$class['customer']]])->dec('balance',$class['total'])->update(); + //5 更新单据 + Db::name('imy')->where([['id','=',$class['id']]])->update(['examine'=>1]); + //6 单据记录 + Db::name('record')->insert(['type'=>'imy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //7 记录操作 + pushLog('审核收款单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 匹配数据 + $listSql=[['type','=','imy'],['class','=',$class['id']]]; + $accountInfoList=Db::name('account_info')->where($listSql)->select()->toArray(); + //2 资金账户 + $accountDuplicate=[]; + foreach ($accountInfoList as $accountInfoVo) { + $accountDuplicate[]=['id'=>$accountInfoVo['pid'],'balance'=>$accountInfoVo['money']]; + } + //2.1 更新资金 + Db::name('account')->duplicate(['balance'=>Db::raw('balance - VALUES(`balance`)')])->insertAll($accountDuplicate); + //2.2 删除资金详情 + Db::name('account_info')->where([['id','in',array_column($accountInfoList,'id')]])->delete(); + //3 客户|应收款余额 + Db::name('customer')->where([['id','=',$class['customer']]])->inc('balance',$class['total'])->update(); + //4 更新单据 + Db::name('imy')->where([['id','=',$class['id']]])->update(['examine'=>0]); + //5 单据记录 + Db::name('record')->insert(['type'=>'imy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //6 记录操作 + pushLog('反审核收款单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('imy', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //客户匹配 + $customer=Db::name('customer')->where([['name','=',$data[3]['A']]])->find(); + if(empty($customer)){ + throw new ValidateException('客户[ '.$data[3]['A'].' ]未匹配!'); + } + //关联人员匹配 + if(empty($data[3]['E'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['E']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['E'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'customer'=>$customer['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'people'=>$people['id'], + 'file'=>[], + 'data'=>$data[3]['F'], + 'more'=>[], + 'examine'=>0, + 'nucleus'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Imy');//数据合法性验证 + //初始化INFO + $info=[]; + $account=Db::name('account')->where([['name','in',array_column($data,'G')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'account'=>$dataVo['G'], + 'money'=>$dataVo['H'], + 'settle'=>$dataVo['I'], + 'data'=>$dataVo['J'] + ]; + //结算账户匹配 + $accountFind=search($account)->where([['name','=',$record['account']]])->find(); + if(empty($accountFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行结算账户[ '.$record['account'].' ]未匹配!'); + }else{ + $record['account']=$accountFind['id']; + } + //结算金额匹配 + if(!preg_match("/^(\-)?\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['money'])){ + throw new ValidateException('模板文件第'.$dataKey.'行结算金额不正确!'); + } + try{ + $this->validate($record,'app\validate\ImyInfo');//数据合法性验证 + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['money'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + Db::startTrans(); + try { + //新增CLASS + $classData=Imys::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new ImyInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'imy','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入收款单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出收款单列表');//日志 + $source=Imys::with(['frameData','customerData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'收款单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'extension|amount'=>'核销金额', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|nucleus'=>'核销状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据金额:'.mathArraySum(array_column($source,'total')), + '总核销金额:'.mathArraySum(arrayColumns($source,['extension','amount'])) + ]]; + //导出execl + buildExcel('收款单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'收款单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '客户:'.$sourceVo['customerData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'accountData|name'=>'结算账户', + 'money'=>'结算金额', + 'settle'=>'结算号', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=ImyInfo::with(['accountData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->select()->toArray(); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '核销金额:'.$sourceVo['extension']['amount'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + } + buildZip('收款单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Index.php b/serve/app/controller/Index.php new file mode 100644 index 0000000..acbfda2 --- /dev/null +++ b/serve/app/controller/Index.php @@ -0,0 +1,9 @@ +where(empty($input['warehouse'])?sqlAuth('warehouse',[]):[['id','in',$input['warehouse']]])->order(['id'=>'desc'])->select()->toArray(); + //构造表头|集合 + $column=[]; + foreach ($warehouse as $warehouseVo) { + $column[]=['id'=>$warehouseVo['id'],'key'=>'stock_'.$warehouseVo['id'],'name'=>$warehouseVo['name']]; + } + //匹配商品 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'], + ['spec','fullLike'], + ['brand','fullEq'], + ['code','fullLike'], + ['data','fullLike'] + ]);//构造SQL + //商品类型 + $sql[]=['type','=',0]; + //辅助属性扩展查询 + $sqlOr=existFull($input,['code'])?[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]:[]; + //商品分类树结构查询 + existFull($input,['category'])&&$sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + //获取总条数 + $count = Goods::where($sql)->whereOr($sqlOr)->count(); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->order(['id'=>'desc'])->page($input['page'],$input['limit'])->append(['extension'])->select()->toArray(); + //唯一标识|属性处理 + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['key']=$infoVo['id']; + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + $info[$infoKey]['attr'][$attrKey]['key']=$infoVo['id'].'.'.$attrVo['id']; + //属性处理 + if(existFull($input,['code']) && !in_array($input['code'],[$infoVo['code'],$attrVo['code']])){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //查询库存数据 + $room=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['goods','in',array_column($info,'id')]])->select()->toArray(); + //库存集合[w:仓库|g:商品|a:属性] + $gather=['g'=>[],'wg'=>[],'ga'=>[],'wga'=>[]]; + foreach ($room as $roomVo) { + //商品 + $g=md5_16($roomVo['goods']); + $gather['g'][$g]=math()->chain($gather['g'][$g]??0)->add($roomVo['nums'])->done(); + //仓库|商品 + $wg=md5_16($roomVo['warehouse'].'&'.$roomVo['goods']); + $gather['wg'][$wg]=math()->chain($gather['wg'][$wg]??0)->add($roomVo['nums'])->done(); + //判断属性 + if(!empty($roomVo['attr'])){ + //商品|属性 + $ga=md5_16($roomVo['goods'].'&'.$roomVo['attr']); + $gather['ga'][$ga]=math()->chain($gather['ga'][$ga]??0)->add($roomVo['nums'])->done(); + //仓库|商品|属性 + $wga=md5_16($roomVo['warehouse'].'&'.$roomVo['goods'].'&'.$roomVo['attr']); + $gather['wga'][$wga]=math()->chain($gather['wga'][$wga]??0)->add($roomVo['nums'])->done(); + } + } + //数量匹配|库存处理|结构处理 + foreach ($info as $infoKey=>$infoVo) { + //商品 + $g=md5_16($infoVo['id']); + $info[$infoKey]['summary']=isset($gather['g'][$g])?($infoVo['unit']=='-1'?unitSwitch($gather['g'][$g],$infoVo['units']):$gather['g'][$g]):0; + //仓库|商品 + $record=[]; + //单位数据 + if($infoVo['unit']=='-1'){ + $enter=[]; + $unit=array_reverse(array_merge([['name'=>$infoVo['units'][0]['source']]],$infoVo['units'])); + foreach ($unit as $unitVo) { + $enter[]=['name'=>$unitVo['name'],'nums'=>'']; + } + }else{ + $enter=''; + } + foreach ($column as $columnVo) { + $wg=md5_16($columnVo['id'].'&'.$infoVo['id']); + $record['stock_'.$columnVo['id']]=[ + 'warehouse'=>$columnVo['id'], + 'basis'=>$gather['wg'][$wg]??0, + 'basisAlias'=>isset($gather['wg'][$wg])?($infoVo['unit']=='-1'?unitSwitch($gather['wg'][$wg],$infoVo['units']):$gather['wg'][$wg]):0, + 'enter'=>$enter, + 'diff'=>0, + 'diffAlias'=>'' + ]; + } + $info[$infoKey]['record']=$record; + //匹配辅助属性 + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //商品|属性 + $ga=md5_16($infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['summary']=isset($gather['ga'][$ga])?($infoVo['unit']=='-1'?unitSwitch($gather['ga'][$ga],$infoVo['units']):$gather['ga'][$ga]):0; + //仓库|商品|属性 + $record=[]; + foreach ($column as $columnVo) { + $wga=md5_16($columnVo['id'].'&'.$infoVo['id'].'&'.$attrVo['name']); + $record['stock_'.$columnVo['id']]=[ + 'warehouse'=>$columnVo['id'], + 'basis'=>$gather['wga'][$wga]??0, + 'basisAlias'=>isset($gather['wga'][$wga])?($infoVo['unit']=='-1'?unitSwitch($gather['wga'][$wga],$infoVo['units']):$gather['wga'][$wga]):0, + 'enter'=>$enter, + 'diff'=>0, + 'diffAlias'=>'' + ]; + } + $info[$infoKey]['attr'][$attrKey]['record']=$record; + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info, + 'column'=>$column + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + pushLog('导出库存盘点单');//日志 + //匹配商品 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'], + ['spec','fullLike'], + ['brand','fullEq'], + ['code','fullLike'], + ['data','fullLike'] + ]);//构造SQL + //商品类型 + $sql[]=['type','=',0]; + //辅助属性扩展查询 + $sqlOr=existFull($input,['code'])?[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]:[]; + //商品分类树结构查询 + existFull($input,['category'])&&$sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //属性处理 + foreach ($info as $infoKey=>$infoVo) { + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //属性处理 + if(existFull($input,['code']) && !in_array($input['code'],[$infoVo['code'],$attrVo['code']])){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //结构重组 + $source=[]; + foreach ($info as $infoVo) { + $infoVo['enter']=''; + $source[]=$infoVo; + if(!empty($infoVo['attr'])){ + foreach ($infoVo['attr'] as $attrVo) { + $attrVo['name']='|- '.$attrVo['name']; + $attrVo['enter']=''; + $source[]=$attrVo; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'库存盘点单']; + //表格数据 + $field=['name'=>'商品名称','enter'=>'盘点数','number'=>'商品编号','spec'=>'规格型号','categoryData|name'=>'商品分类','brand'=>'商品品牌','extension|unit'=>'商品单位','code'=>'商品条码','data'=>'商品备注']; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('库存盘点单',$excel); + } + //生成盘盈单 + public function buildEntry(){ + $input=input('post.'); + if(existFull($input,['info'])){ + $class=['total'=>0,'type'=>1]; + $fun=getSys('fun'); + $list=[ + 'goods'=>Goods::where([['id','in',array_unique(array_column($input['info'],'goods'))]])->select()->toArray(), + 'warehouse'=>Warehouse::where([['id','in',array_unique(array_column($input['info'],'warehouse'))]])->select()->toArray(), + ]; + foreach ($input['info'] as $infoVo) { + $record=[]; + $goods=search($list['goods'])->where([['id','=',$infoVo['goods']]])->find(); + $warehouse=search($list['warehouse'])->where([['id','=',$infoVo['warehouse']]])->find(); + $record['goods']=$infoVo['goods']; + $record['goodsData']=$goods; + $record['attr']=$infoVo['attr']; + $record['unit']=$infoVo['unit']; + $record['warehouse']=$infoVo['warehouse']; + $record['warehouseData']=$warehouse; + $record['batch']=''; + $record['mfd']=''; + $record['price']=$goods['buy']; + $record['nums']=$infoVo['nums']; + $record['serial']=[]; + $record['total']=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + $record['data']=''; + //转存数据 + $info[]=$record; + $class['total']=math()->chain($class['total'])->add($record['total'])->done();//累加单据成本 + } + $result=['state'=>'success','info'=>['class'=>$class,'info'=>$info]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //生成盘亏单 + public function buildExtry(){ + $input=input('post.'); + if(existFull($input,['info']) && is_array($input['info'])){ + $class=['total'=>0,'type'=>1]; + $fun=getSys('fun'); + $list=[ + 'goods'=>Goods::where([['id','in',array_unique(array_column($input['info'],'goods'))]])->select()->toArray(), + 'warehouse'=>Warehouse::where([['id','in',array_unique(array_column($input['info'],'warehouse'))]])->select()->toArray(), + ]; + foreach ($input['info'] as $infoVo) { + $record=[]; + $goods=search($list['goods'])->where([['id','=',$infoVo['goods']]])->find(); + $warehouse=search($list['warehouse'])->where([['id','=',$infoVo['warehouse']]])->find(); + $record['goods']=$infoVo['goods']; + $record['goodsData']=$goods; + $record['attr']=$infoVo['attr']; + $record['unit']=$infoVo['unit']; + $record['warehouse']=$infoVo['warehouse']; + $record['warehouseData']=$warehouse; + $record['batch']=''; + $record['mfd']=''; + $record['price']=$goods['buy']; + $record['nums']=abs($infoVo['nums']); + $record['serial']=[]; + $record['total']=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + $record['data']=''; + //转存数据 + $info[]=$record; + $class['total']=math()->chain($class['total'])->add($record['total'])->done();//累加单据成本 + } + $result=['state'=>'success','info'=>['class'=>$class,'info'=>$info]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Invoice.php b/serve/app/controller/Invoice.php new file mode 100644 index 0000000..3ae2c58 --- /dev/null +++ b/serve/app/controller/Invoice.php @@ -0,0 +1,420 @@ +'class.number'],'fullLike'], + ['invoice','fullIn'], + [['startTime'=>'class.time'],'startTime'], + [['endTime'=>'class.time'],'endTime'], + ]); + $base[]=['examine','=',1]; + $base[]=['invoice','<>',3]; + $base=frameScope($base); + //匹配语句 + $sql=[]; + foreach ($input['mold'] as $mold) { + if(in_array($mold,['buy','bre'])){ + $sql[$mold]=array_merge($base,fastSql($input,[['supplier','fullEq']])); + }else{ + $sql[$mold]=array_merge($base,fastSql($input,[['customer','fullEq']])); + } + $sql[$mold]=sqlAuth($mold,$sql[$mold]);//数据鉴权 + } + //构造查询 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->alias('class')->where($sql[$mold])->leftJoin(['is_invoice'=>'invoice'],'class.id=invoice.class and invoice.type="'.$mold.'"')->fieldRaw('"'.$mold.'" as mold,class.id,class.time,sum(invoice.money) as iat')->group('class.id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $count=DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + //匹配数据 + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $db="app\\model\\".ucfirst($mold); + if(in_array($mold,['buy','bre'])){ + $list[$mold]=$db::with(['frameData','supplierData'])->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray(); + }else{ + $list[$mold]=$db::with(['frameData','customerData'])->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray(); + } + } + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $row=search($list[$mold])->where([['id','=',$recordVo['id']]])->find(); + $row['mold']=$mold; + $row['name']=['buy'=>'采购单','bre'=>'采购退货单','sell'=>'销售单','sre'=>'销售退货单'][$mold]; + $row['current']=in_array($mold,['buy','bre'])?$row['supplierData']:$row['customerData']; + $row['iat']=floatval($recordVo['iat']); + $row['ani']=math()->chain($row['actual'])->sub($row['iat'])->done(); + $row['money']=""; + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //开具发票 + public function save(){ + $input=input('post.'); + if(existFull($input,['data'])&& is_array($input['data'])){ + //验证数据 + foreach ($input['data'] as $key=>$vo) { + try { + $this->validate($vo,'app\validate\Invoice'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'选中数据第'.($key+1).'条'.$e->getError()]); + exit; + } + } + //单据匹配 + $gather=[]; + $tab=['buy','bre','sell','sre']; + foreach ($input['data'] as $vo) { + in_array($vo['type'],$tab)&&$gather[$vo['type']][]=$vo['class']; + } + $union=[]; + foreach ($gather as $mold=>$vo) { + $union[]=Db::name($mold)->alias('class')->where([['class.id','in',$vo]])->leftJoin(['is_invoice'=>'invoice'],'class.id=invoice.class and invoice.type="'.$mold.'"')->fieldRaw('"'.$mold.'" as mold,class.id,class.actual as actual, sum(invoice.money) as iat')->group('class.id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //验证数据 + foreach ($input['data'] as $key=>$vo) { + $find=search($record)->where([['mold','=',$vo['type']],['id','=',$vo['class']]])->find(); + $ani=math()->chain($find['actual'])->sub($find['iat'])->done(); + if(bccomp($vo['money'],$ani)==1){ + return json(['state'=>'error','info'=>'选中数据第'.($key+1).'条发票金额超出未开票金额!']); + exit; + }else{ + $input['data'][$key]['ani']=$ani; + } + } + //处理数据 + Db::startTrans(); + try { + $bill=[]; + foreach ($input['data'] as $key=>$vo) { + //发票状态 + $bill[$vo['type']]['class'][]=[ + 'id'=>$vo['class'], + 'invoice'=>bccomp($vo['money'],$vo['ani'])==0?2:1 + ]; + //发票记录 + $bill[$vo['type']]['record'][]=['type'=>$vo['type'],'source'=>$vo['class'],'time'=>time(),'user'=>getUserID(),'info'=>'开具发票[ '.floatval($vo['money']).' ]']; + unset($input['data'][$key]['iat']); + } + //更新单据状态 + foreach ($bill as $mold=>$vo) { + Db::name($mold)->duplicate(['invoice'=>Db::raw('VALUES(`invoice`)')])->insertAll($vo['class']); + Db::name('record')->insertAll($vo['record']); + } + //添加发票记录 + $model = new \app\model\Invoice; + $model->saveAll($input['data']); + pushLog('开具购销发票');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('bor', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state'=>'error','info'=>$e->getMessage()]; + } + } + return json($result); + } + //购销发票-导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + pushLog('导出购销发票');//日志 + $parm=[]; + $tab=['buy','bre','sell','sre']; + foreach($input['parm'] as $vo){ + if(in_array($vo['mold'],$tab)){ + $parm[$vo['mold']][]=$vo['id']; + } + } + //匹配数据 + $list=[]; + foreach ($parm as $mold=>$vo) { + $db="app\\model\\".ucfirst($mold); + if(in_array($mold,['buy','bre'])){ + $list[$mold]=$db::with(['frameData','supplierData'])->alias('class')->where([['class.id','in',$vo]])->leftJoin(['is_invoice'=>'invoice'],'class.id=invoice.class and invoice.type="'.$mold.'"')->fieldRaw('class.*,sum(invoice.money) as iat')->group('class.id')->append(['extension'])->select()->toArray(); + }else{ + $list[$mold]=$db::with(['frameData','customerData'])->alias('class')->where([['class.id','in',$vo]])->leftJoin(['is_invoice'=>'invoice'],'class.id=invoice.class and invoice.type="'.$mold.'"')->fieldRaw('class.*,sum(invoice.money) as iat')->group('class.id')->append(['extension'])->select()->toArray(); + } + } + $data=[]; + foreach ($input['parm'] as $vo) { + $mold=$vo['mold']; + $row=search($list[$mold])->where([['id','=',$vo['id']]])->find(); + $row['name']=['buy'=>'采购单','bre'=>'采购退货单','sell'=>'销售单','sre'=>'销售退货单'][$mold]; + $row['current']=in_array($mold,['buy','bre'])?$row['supplierData']:$row['customerData']; + $row['iat']=floatval($row['iat']); + $row['ani']=math()->chain($row['actual'])->sub($row['iat'])->done(); + $data[]=$row; + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'购销发票']; + //表格数据 + $field=[ + 'name'=>'单据类型', + 'frameData|name'=>'所属组织', + 'current|name'=>'往来单位', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'extension|invoice'=>'发票状态', + 'actual'=>'单据金额', + 'iat'=>'已开票金额', + 'ani'=>'未开票金额' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '单据总金额:'.mathArraySum(array_column($source,'actual')), + '已开票总金额:'.mathArraySum(array_column($source,'iat')), + '未开票总金额:'.mathArraySum(array_column($source,'ani')) + ]]; + //导出execl + buildExcel('购销发票',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //报表数据 + public function form(){ + $input=input('post.'); + $sheet=['buy','bre','sell','sre']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(existFull($input,['page','limit']) && arrayInArray($input['mold'],$sheet)){ + $sql=[]; + //构造SQL|INVOICE + $sql['invoice']=fastSql($input,[ + [['mold'=>'type'],'fullIn'], + [['inr'=>'number'],'fullLike'], + ['title','fullLike'], + ]); + + //构造SQL|CLASS|基础语句 + $sql['base']=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ]); + $sql['base']=frameScope($sql['base']); + //数据表 + foreach ($input['mold'] as $t) { + if(in_array($t,['buy','bre'])){ + $sql[$t]=array_merge($sql['base'],[['id','=',Db::raw('invoice.class')]],fastSql($input,[['supplier','fullEq']])); + }else{ + $sql[$t]=array_merge($sql['base'],[['id','=',Db::raw('invoice.class')]],fastSql($input,[['customer','fullEq']])); + } + $sql[$t]=sqlAuth($t,$sql[$t]);//数据鉴权 + } + //多源匹配 + $union=[]; + foreach ($input['mold'] as $t) { + //匹配类型|减少查询 + if(in_array($t,$input['mold'])){ + $union[]=Db::name($t)->where([ + ['invoice.type','=',$t], + ])->where(empty($sql[$t])?[]:[$sql[$t]])->limit(1)->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $count=Invoices::alias('invoice')->where($sql['invoice'])->whereExists($union)->count(); + $info=Invoices::with(['sourceData'=>['frameData']])->alias('invoice')->where($sql['invoice'])->whereExists($union)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + + //匹配供应商|客户 + $current=[ + 'supplier'=>Db::name('supplier')->where([['id','in',arrayColumns(search($info)->where([['type','in',['buy','bre']]])->select(),['sourceData','supplier'])]])->select()->toArray(), + 'customer'=>Db::name('customer')->where([['id','in',arrayColumns(search($info)->where([['type','in',['sell','sre']]])->select(),['sourceData','customer'])]])->select()->toArray(), + ]; + $data=[]; + foreach ($info as $infoVo) { + $row=$infoVo; + $mold=$infoVo['type']; + $row['name']=['buy'=>'采购单','bre'=>'采购退货单','sell'=>'销售单','sre'=>'销售退货单'][$mold]; + if(in_array($mold,['buy','bre'])){ + $row['current']=search($current['supplier'])->where([['id','=',$row['sourceData']['supplier']]])->find(); + }else{ + $row['current']=search($current['customer'])->where([['id','=',$row['sourceData']['customer']]])->find(); + } + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('invoice')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + Db::startTrans(); + try { + $gather=[]; + $record=[]; + //匹配数据 + foreach ($data as $key=>$vo) { + $gather[$vo['type']][]=$vo['class']; + $record[]=['type'=>$vo['type'],'source'=>$vo['class'],'time'=>time(),'user'=>getUserID(),'info'=>'删除发票[ '.floatval($vo['money']).' ]']; + } + //插入单据记录 + Db::name('record')->insertAll($record); + //删除发票记录 + Db::name('invoice')->where([['id','in',$input['parm']]])->delete(); + //匹配发票记录 + $union=[]; + foreach ($gather as $mold=>$vo) { + $union[]=Db::name($mold)->alias('class')->where([['class.id','in',$vo]])->leftJoin(['is_invoice'=>'invoice'],'class.id=invoice.class and invoice.type="'.$mold.'"')->fieldRaw('"'.$mold.'" as mold,class.id,count(invoice.id) as length')->group('class.id')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + $list=Db::query('SELECT * FROM ('.$union.') as nodcloud'); + //更新单据状态 + $bill=[]; + foreach($list as $vo){ + $bill[$vo['mold']][]=['id'=>$vo['id'],'invoice'=>empty($vo['length'])?0:1]; + } + foreach($bill as $mold=>$vo){ + Db::name($mold)->duplicate(['invoice'=>Db::raw('VALUES(`invoice`)')])->insertAll($vo); + + } + pushLog('删除购销发票');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //购销发票报表-导出 + public function formExports(){ + $input=input('get.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + pushLog('导出购销发票报表');//日志 + $info=Invoices::with(['sourceData'=>['frameData']])->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + //匹配供应商|客户 + $current=[ + 'supplier'=>Db::name('supplier')->where([['id','in',arrayColumns(search($info)->where([['type','in',['buy','bre']]])->select(),['sourceData','supplier'])]])->select()->toArray(), + 'customer'=>Db::name('customer')->where([['id','in',arrayColumns(search($info)->where([['type','in',['sell','sre']]])->select(),['sourceData','customer'])]])->select()->toArray(), + ]; + $data=[]; + foreach ($info as $infoVo) { + $row=$infoVo; + $mold=$infoVo['type']; + $row['name']=['buy'=>'采购单','bre'=>'采购退货单','sell'=>'销售单','sre'=>'销售退货单'][$mold]; + if(in_array($mold,['buy','bre'])){ + $row['current']=search($current['supplier'])->where([['id','=',$row['sourceData']['supplier']]])->find(); + }else{ + $row['current']=search($current['customer'])->where([['id','=',$row['sourceData']['customer']]])->find(); + } + $data[]=$row; + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'购销发票报表']; + //表格数据 + $field=[ + 'name'=>'单据类型', + 'sourceData|frameData|name'=>'所属组织', + 'current|name'=>'往来单位', + 'sourceData|time'=>'单据时间', + 'sourceData|number'=>'单据编号', + 'sourceData|actual'=>'单据金额', + 'time'=>'开票时间', + 'number'=>'发票号码', + 'title'=>'发票抬头', + 'money'=>'发票金额', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '单据总金额:'.mathArraySum(arrayColumns($source,['sourceData','actual'])), + '发票总金额:'.mathArraySum(array_column($source,'money')) + ]]; + //导出execl + buildExcel('购销发票报表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } +} diff --git a/serve/app/controller/Log.php b/serve/app/controller/Log.php new file mode 100644 index 0000000..bf68e65 --- /dev/null +++ b/serve/app/controller/Log.php @@ -0,0 +1,45 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]);//构造SQL + $sql=sqlAuth('log',$sql); + $count = Logs::where($sql)->count();//获取总条数 + $info = Logs::with(['userData'])->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //清空 + public function empty(){ + Db::startTrans(); + try { + Db::query("truncate table is_log"); + pushLog('清空操作日志');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + return json($result); + } +} diff --git a/serve/app/controller/Main.php b/serve/app/controller/Main.php new file mode 100644 index 0000000..3c892da --- /dev/null +++ b/serve/app/controller/Main.php @@ -0,0 +1,186 @@ +where(sqlAuth($t,$rowWhere))->fieldRaw('GROUP_CONCAT(`id`) as id,sum(actual) as actual')->select()->toArray()[0]; + }elseif($t=='imy'){ + $group[$v][$t]=Db::name($t)->where(sqlAuth($t,$rowWhere))->fieldRaw('sum(total) as total')->select()->toArray()[0]; + }else{ + $group[$v][$t]=Db::name($t)->where(sqlAuth($t,$rowWhere))->fieldRaw('sum(actual) as actual')->select()->toArray()[0]; + } + } + } + + $lattice['sve']=[ + 'today'=>empty($group['today']['sell']['actual'])?0:floatval($group['today']['sell']['actual']), + 'yesterday'=>empty($group['yesterday']['sell']['actual'])?0:$group['yesterday']['sell']['actual'], + ]; + $lattice['nos']=[ + 'today'=>[ + 'sell'=>empty($group['today']['sell']['id'])?[]:explode(',',$group['today']['sell']['id']) + ], + 'yesterday'=>[ + 'sell'=>empty($group['yesterday']['sell']['id'])?[]:explode(',',$group['yesterday']['sell']['id']) + ] + ]; + $lattice['spt']=[ + 'today'=>Db::name('summary')->whereOr([ + [['type','=','sell'],['class','in',$lattice['nos']['today']['sell']]] + ])->fieldRaw('sum(bct) as bct')->select()->toArray()[0]['bct'], + 'yesterday'=>Db::name('summary')->whereOr([ + [['type','=','sell'],['class','in',$lattice['nos']['yesterday']['sell']]] + ])->fieldRaw('sum(bct) as bct')->select()->toArray()[0]['bct'] + ]; + $lattice['spt']=[ + 'today'=>math()->chain($lattice['sve']['today'])->sub($lattice['spt']['today'])->done(), + 'yesterday'=>math()->chain($lattice['sve']['yesterday'])->sub($lattice['spt']['yesterday'])->done() + ]; + $lattice['nos']=[ + 'today'=>count(array_merge($lattice['nos']['today']['sell'])), + 'yesterday'=>count(array_merge($lattice['nos']['yesterday']['sell'])), + ]; + $lattice['fund']=[ + 'today'=>math()->chain($lattice['sve']['today'])->add($group['today']['imy']['total'])->add($group['today']['ice']['actual'])->done(), + 'yesterday'=>math()->chain($lattice['sve']['yesterday'])->add($group['yesterday']['imy']['total'])->add($group['yesterday']['ice']['actual'])->done(), + ]; + $lattice['sve']['yesterday']=empty($lattice['sve']['yesterday'])?(empty($lattice['sve']['today'])?'0':'100'):math()->chain($lattice['sve']['today'])->div($lattice['sve']['yesterday'])->mul(100)->round(2)->done(); + $lattice['spt']['yesterday']=empty($lattice['spt']['yesterday'])?(empty($lattice['spt']['today'])?'0':'100'):math()->chain($lattice['spt']['today'])->div($lattice['spt']['yesterday'])->mul(100)->round(2)->done(); + $lattice['nos']['yesterday']=empty($lattice['nos']['yesterday'])?(empty($lattice['nos']['today'])?'0':'100'):math()->chain($lattice['nos']['today'])->div($lattice['nos']['yesterday'])->mul(100)->round(2)->done(); + $lattice['fund']['yesterday']=empty($lattice['fund']['yesterday'])?(empty($lattice['fund']['today'])?'0':'100'):math()->chain($lattice['fund']['today'])->div($lattice['fund']['yesterday'])->mul(100)->round(2)->done(); + + + + //汇总信息 + $list=[ + 'room'=>Db::name('room')->field(['id','nums'])->where(sqlAuth('room',[]))->select()->toArray(), + 'customer'=>Db::name('customer')->field(['id','balance'])->where(sqlAuth('customer',frameScope([])))->select()->toArray(), + 'supplier'=>Db::name('supplier')->field(['id','balance'])->where(sqlAuth('supplier',frameScope([])))->select()->toArray() + ]; + $summary=[]; + $summary['goods']=Db::name('goods')->count(); + $summary['customer']=count($list['customer']); + $summary['supplier']=count($list['supplier']); + $summary['room']=mathArraySum(array_column($list['room'],'nums')); + $summary['rwg'] = Db::name('room')->alias('room')->where([['id','in',array_column($list['room'],'id')]])->whereExists( + Db::name('goods')->where([['id','=',Db::raw('room.goods')],['room.nums','<=',Db::raw('stock')]])->buildSql(false) + )->count(); + $summary['bwg'] = Db::name('batch')->alias('batch')->where(sqlAuth('batch',[]))->whereExists( + Db::name('goods')->where([['id','=',Db::raw('batch.goods')]])->whereRaw('batch.time + (threshold * 86400) < :time',['time'=>strtotime(date('Y-m-d',time()))])->buildSql(false) + )->count(); + + //资产数据 + $assets['account']=Db::name('account')->fieldRaw('(sum(initial)+sum(balance)) as money')->where(sqlAuth('account',frameScope([])))->select()[0]['money']; + $sy=Db::name('summary')->fieldRaw('direction,sum(bct) as bct')->where(sqlAuth('summary'))->group(['direction'])->order('direction')->select()->toArray(); + $assets['rsy']=empty($sy)?0:(count($sy)==2?math()->chain($sy[1]['bct'])->sub($sy[0]['bct'])->done():($sy[0]['direction']==0?-$sy[0]['bct']:$sy[0]['bct'])); + $assets['cas']=mathArraySum(array_column($list['customer'],'balance')); + $assets['sas']=mathArraySum(array_column($list['supplier'],'balance')); + $assets['all']=math()->chain($assets['account'])->add($assets['rsy'])->add($assets['cas'])->sub($assets['sas'])->done(); + //位数处理 + foreach ($summary as $k=>$v){$summary[$k]=floatval($v);} + foreach ($assets as $k=>$v){$assets[$k]=floatval($v);} + + //数据概括 + $fun=getSys('fun'); + $option=[]; + $deploy=[ + [ + 'title'=>['text'=>'','left'=>'center'], + 'xAxis'=>['type'=>'category','boundaryGap'=>false,'data'=>[]], + 'grid'=>['top'=>'12%','left'=>'1%','right'=>'1%','bottom'=>'0%','containLabel'=>true], + 'yAxis'=>['type'=>'value'], + 'series'=>[['data'=>[],'type'=>'line','areaStyle'=>[]]], + 'tooltip'=>['trigger'=>'axis','axisPointer'=>['type'=>'cross']] + ], + [ + 'title'=>['text'=>'库存数据','left'=>'center'], + 'tooltip'=>['trigger'=>'item'], + 'legend'=>['orient'=>'vertical','left'=>'left'], + 'series'=>[['type'=>'pie','radius'=>'60%','data'=>[]]] + ] + ]; + $table=['buy'=>'采购单','bre'=>'采购退货单','sell'=>'销售单','sre'=>'销售退货单','imy'=>'收款单','omy'=>'付款单']; + $where=[['time','>=',time()-($fun['days']*86400)],['time','<=',time()],['examine','=',1]]; + foreach($table as $k=>$v){ + $bill=Db::name($k)->fieldRaw('time,sum('.(in_array($k,['imy','omy'])?'total':'actual').') as actual')->where(sqlAuth($k,$where))->group('time')->select()->toArray(); + $xData=getOldDay($fun['days']); + $yData=[]; + foreach($xData as $date){ + $t=strtotime($date); + $find=search($bill)->where([['time','=',$t]])->find(); + $yData[]=empty($find)?0:$find['actual']; + } + $replica=$deploy[0]; + $replica['title']['text']=$v; + $replica['xAxis']['data']=$xData; + $replica['series'][0]['data']=$yData; + $option[]=$replica; + } + //库存分布 + $pie=Db::name('room')->fieldRaw('warehouse,sum(nums) as nums')->where([['id','in',array_column($list['room'],'id')]])->group(['warehouse'])->select()->toArray(); + $wlt=Db::name('warehouse')->where([['id','in',array_column($pie,'warehouse')]])->select(); + $replica=$deploy[1]; + foreach($pie as $v){ + $w=search($wlt)->where([['id','=',$v['warehouse']]])->find(); + $replica['series']['0']['data'][]=['value'=>$v['nums'],'name'=>$w['name']]; + } + $option[]=$replica; + + // 资金数据 + $fund=[ + 'xAxis'=>['type'=>'category','data'=>[]], + 'grid'=>['top'=>'6%','left'=>'1%','right'=>'1%','bottom'=>'0%','containLabel'=>true], + 'yAxis'=>['type'=>'value'], + 'series'=>[['data'=>[],'type'=>'bar','itemStyle'=>(object)[]]], + 'tooltip'=>['trigger'=>'axis','axisPointer'=>['type'=>'cross']] + ]; + $fundData=Db::name('account')->fieldRaw('name,(initial+balance) as money')->where(sqlAuth('account',frameScope([])))->select()->toArray(); + foreach ($fundData as $v) { + $fund['xAxis']['data'][]=$v['name']; + $fund['series'][0]['data'][]=$v['money']; + } + if(empty($fund['xAxis']['data'])){ + $fund['xAxis']['data'][]='无数据'; + $fund['series'][0]['data'][]=0; + } + //负载监测 + $load=[]; + $cacheMaxSize=256; + $load['cache']['size']=getDirSize(pathChange('runtime')); + $load['cache']['rate']=round($load['cache']['size']*100/$cacheMaxSize,2); + $mysqlMaxSize=256; + $load['mysql']['size']=getMysqlSize(); + $load['mysql']['rate']=round($load['mysql']['size']*100/$mysqlMaxSize,2); + + //运行环境 + $run=[ + 'os'=>PHP_OS, + 'soft'=>$_SERVER['SERVER_SOFTWARE'], + 'php'=>PHP_VERSION, + 'mysql'=>Db::query("select VERSION() as ver")[0]['ver'], + 'protocol'=>$_SERVER['SERVER_PROTOCOL'] + ]; + return json([ + 'state'=>'success', + 'info'=>[ + 'lattice'=>$lattice, + 'summary'=>$summary, + 'option'=>$option, + 'assets'=>$assets, + 'fund'=>$fund, + 'load'=>$load, + 'run'=>$run + ] + ]); + } +} diff --git a/serve/app/controller/Menu.php b/serve/app/controller/Menu.php new file mode 100644 index 0000000..a9833eb --- /dev/null +++ b/serve/app/controller/Menu.php @@ -0,0 +1,102 @@ +'asc'])->append(['extension'])->select()); + return json(['state'=>'success','info'=>$menu]); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + if(empty($input['id'])){ + $this->validate($input,'app\validate\Menu'); + }else{ + $this->validate($input,'app\validate\Menu.update'); + //所属不可等于或包含当前 + if(in_array($input['pid'],findTreeArr('menu',$input['id'],'id'))){ + throw new ValidateException('所属菜单选择不正确!'); + } + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Menus::create($input); + pushLog('新增菜单[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Menus::update($input); + pushLog('更新菜单[ '.$input['name'].' ]');//日志 + } + + //修改上级架构菜单地址|#group + if($input['type']!=1){ + Menus::where([['id','=',$input['pid']]])->update(['resource'=>'#group']); + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Menus::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $subFind=Db::name('menu')->where([['pid','=',$input['id']]])->find(); + if(empty($subFind)){ + $find=Db::name('menu')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + try { + Db::name('menu')->where([['id','=',$input['id']]])->delete(); + pushLog('删除菜单[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在子数据,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} diff --git a/serve/app/controller/Mould.php b/serve/app/controller/Mould.php new file mode 100644 index 0000000..7443543 --- /dev/null +++ b/serve/app/controller/Mould.php @@ -0,0 +1,200 @@ +count();//获取总条数 + $info = Moulds::where($sql)->page($input['page'],$input['limit'])->order(['key'=>'asc','sort'=>'asc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + empty($input['id'])?$this->validate($input,'app\validate\Mould'):$this->validate($input,'app\validate\Mould.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Moulds::create($input); + pushLog('新增模板[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Moulds::update($input); + pushLog('更新模板[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Moulds::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //复制 + public function copy(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $find=Moulds::where([['id','=',$input['id']]])->find()->toArray(); + pushLog('复制模板[ '.$find['name'].' ]');//日志 + unset($find['id']);//移除主键 + $find['name']=$find['name'].'|复制'; + Moulds::create($find); + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $find=Db::name('mould')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + try { + Db::name('mould')->where([['id','=',$input['id']]])->delete(); + pushLog('删除模板[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.mould');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + try{ + validate(['file'=>['fileSize'=>1024*1024,'fileExt'=>'md']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('mould', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $json=json_decode(file_get_contents($filePath),true); + if(existFull($json,['name','key','source','code','data'])){ + $createInfo=Moulds::create($json); + pushLog('导入模板[ '.$createInfo['name'].' ]');//日志 + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'模板文件参数不正确!']; + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + delOverdueFile('static.file.mould');//删除过期文件 + $input=input('get.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + pushLog('导出打印模板');//日志 + $info=Moulds::where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray();//查询数据 + $zipFile=[]; + foreach ($info as $infoVo) { + unset($infoVo['id']); + $fileName = str_replace(['/','\\',':','*','"','<','>','|','?'],'_',$infoVo['name']); + $filePath = pathChange('static.file.mould').$fileName.'.md'; + file_put_contents($filePath,json_encode($infoVo)); + $zipFile[]=$filePath; + } + buildZip('模板文件',$zipFile); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } + + // --- 场景函数 --- + + //获取|ID + public function find(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $mould=Moulds::where([['id','=',$input['id']]])->find(); + $result=[ + 'state'=>'success', + 'info'=>$mould + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取|KEY + public function select(){ + $input=input('post.'); + if(existFull($input,['key'])){ + $moulds=Moulds::where([['key','in',$input['key']]])->order(['sort'=>'asc'])->select(); + $result=[ + 'state'=>'success', + 'info'=>$moulds + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //更新|模板编辑 + public function update(){ + $input=input('post.'); + if(existFull($input,['id','code'])){ + Moulds::where([['id','=',$input['id']]])->update(['code'=>$input['code']]); + $result=['state'=>'success',]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Mrt.php b/serve/app/controller/Mrt.php new file mode 100644 index 0000000..6772553 --- /dev/null +++ b/serve/app/controller/Mrt.php @@ -0,0 +1,476 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['user','fullEq'], + ['people','fullEq'] + ]); + $sql[]=['examine','=',1]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('sell',$sql);//数据鉴权[结构一致] + $union=[]; + $tab=['sell','sre']; + foreach ($tab as $t) { + if(in_array($t,$input['mold'])){ + $union[]=Db::name($t)->where($sql)->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + } + $union=implode(' UNION ALL ',$union); + $count=DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + $bill=['class'=>[],'summary'=>[],'info'=>[],''=>[]]; + foreach ($tab as $t) { + if(in_array($t,$input['mold'])){ + $gather=search($record)->where([['mold','=',$t]])->select(); + $db=['class'=>"app\\model\\".ucfirst($t),'info'=>"app\\model\\".ucfirst($t).'Info']; + $bill['class']=array_merge($bill['class'],$db['class']::with(['frameData','customerData','userData','peopleData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + $bill['summary']=array_merge($bill['summary'],Db::name('summary')->where([['type','=',$t],['class','in',array_column($gather,'id')]])->field(['type','class','info','bct'])->select()->toArray()); + //匹配明细 + if(!empty($input['type'])){ + $bill['info'][$t]=$db['info']::with(['goodsData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + } + } + } + arraySort($bill['class'],'t',SORT_ASC); + $data=[]; + //匹配数据 + foreach ($bill['class'] as $classVo) { + $row=$classVo; + $row['key']=$row['id'].'_'.$row['mold']; + $row['bill']=['sell'=>'销售单','sre'=>'销售退货单'][$row['mold']]; + if($row['mold']=='sell'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='sre'){ + $row['total']=math()->chain($row['total'])->mul(-1)->done(); + $row['actual']=math()->chain($row['actual'])->mul(-1)->done(); + $row['money']=math()->chain($row['money'])->mul(-1)->done(); + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + } + $summary=search($bill['summary'])->where([['type','=',$row['mold']],['class','=',$row['id']]])->select(); + $row['act']=mathArraySum(array_column($summary,'bct')); + if($row['bill']=='销售退货单' || $row['bill']=='零售退货单'){ + $row['act']=math()->chain($row['act'])->mul(-1)->done(); + $row['gpt']=math()->chain($row['actual'])->sub($row['act'])->done(); + $row['gpr']='-'.(empty($row['actual'])?(empty($row['gpt'])?'0':'-100'):math()->chain($row['gpt'])->div($row['actual'])->mul(100)->round(2)->done()).'%'; + $row['npt']=math()->chain($row['gpt'])->sub($row['cost'])->done(); + $row['npr']='-'.(empty($row['actual'])?(empty($row['npt'])?'0':'-100'):math()->chain($row['npt'])->div($row['actual'])->mul(100)->round(2)->done()).'%'; + }else{ + $row['gpt']=math()->chain($row['actual'])->sub($row['act'])->done(); + $row['gpr']=(empty($row['actual'])?(empty($row['gpt'])?'0':'-100'):math()->chain($row['gpt'])->div($row['actual'])->mul(100)->round(2)->done()).'%'; + $row['npt']=math()->chain($row['gpt'])->sub($row['cost'])->done(); + $row['npr']=(empty($row['actual'])?(empty($row['npt'])?'0':'-100'):math()->chain($row['npt'])->div($row['actual'])->mul(100)->round(2)->done()).'%'; + } + + + + + //匹配明细 + $node=[]; + if(!empty($input['type'])){ + $list=search($bill['info'][$row['mold']])->where([['pid','=',$row['id']]])->select(); + foreach ($list as $listVo) { + $detail=[ + 'name'=>$listVo['goodsData']['name'], + 'attr'=>$listVo['attr'], + 'unit'=>$listVo['unit'], + 'price'=>$listVo['price'], + 'nums'=>$listVo['nums'], + 'dsc'=>$listVo['dsc'], + 'total'=>$listVo['total'], + 'tat'=>$listVo['tat'], + 'tpt'=>$listVo['tpt'] + ]; + $calc=[]; + $calc['act']=empty($listVo['goodsData']['type'])?floatval(search($summary)->where([['info','=',$listVo['id']]])->find()['bct']):0; + $calc['gpt']=math()->chain($detail['tpt'])->sub($calc['act'])->done(); + $calc['gpr']=(empty($detail['tpt'])?(empty($calc['gpt'])?'0':'-100'):math()->chain($calc['gpt'])->div($detail['tpt'])->mul(100)->round(2)->done()).'%'; + $node[]=['key'=>$row['id'].'_'.$listVo['id'].'_'.$row['mold'],'detail'=>$detail,'act'=>$calc['act'],'gpt'=>$calc['gpt'],'gpr'=>$calc['gpr']]; + } + } + $row['node']=$node; + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //销售利润表-导出 + public function mptExports(){ + $input=input('get.'); + $sheet=['sell','sre']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(isset($input['type']) && is_array($input['mold']) && arrayInArray($input['mold'],$sheet)){ + $sql=fastSql($input,[ + ['customer','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['user','fullEq'], + ['people','fullEq'] + ]); + $sql[]=['examine','=',1]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('sell',$sql);//数据鉴权[结构一致] + $union=[]; + $tab=['sell','sre']; + foreach ($tab as $t) { + if(in_array($t,$input['mold'])){ + $union[]=Db::name($t)->where($sql)->fieldRaw('"'.$t.'" as mold,id')->buildSql(); + } + } + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + $bill=['class'=>[],'summary'=>[],'info'=>[],''=>[]]; + foreach ($tab as $t) { + if(in_array($t,$input['mold'])){ + $gather=search($record)->where([['mold','=',$t]])->select(); + $db=['class'=>"app\\model\\".ucfirst($t),'info'=>"app\\model\\".ucfirst($t).'Info']; + $bill['class']=array_merge($bill['class'],$db['class']::with(['frameData','customerData','userData','peopleData'])->fieldRaw('*,"'.$t.'" as mold,time as t')->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray()); + $bill['summary']=array_merge($bill['summary'],Db::name('summary')->where([['type','=',$t],['class','in',array_column($gather,'id')]])->field(['type','class','info','bct'])->select()->toArray()); + //匹配明细 + if(!empty($input['type'])){ + $bill['info'][$t]=$db['info']::with(['goodsData'])->where([['pid','in',array_column($gather,'id')]])->select()->toArray(); + } + } + } + arraySort($bill['class'],'t',SORT_ASC); + $data=[]; + //匹配数据 + foreach ($bill['class'] as $classVo) { + $row=$classVo; + $row['bill']=['sell'=>'销售单','sre'=>'销售退货单'][$row['mold']]; + if($row['mold']=='sell'){ + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + }else if($row['mold']=='sre'){ + $row['total']=math()->chain($row['total'])->mul(-1)->done(); + $row['actual']=math()->chain($row['actual'])->mul(-1)->done(); + $row['money']=math()->chain($row['money'])->mul(-1)->done(); + $row['discount']=math()->chain($row['total'])->sub($row['actual'])->done(); + } + $summary=search($bill['summary'])->where([['type','=',$row['mold']],['class','=',$row['id']]])->select(); + $row['act']=mathArraySum(array_column($summary,'bct')); + if($row['bill']=='销售退货单' || $row['bill']=='零售退货单'){ + $row['act']=math()->chain($row['act'])->mul(-1)->done(); + $row['gpt']=math()->chain($row['actual'])->sub($row['act'])->done(); + $row['gpr']='-'.(empty($row['actual'])?(empty($row['gpt'])?'0':'-100'):math()->chain($row['gpt'])->div($row['actual'])->mul(100)->round(2)->done()).'%'; + $row['npt']=math()->chain($row['gpt'])->sub($row['cost'])->done(); + $row['npr']='-'.(empty($row['actual'])?(empty($row['npt'])?'0':'-100'):math()->chain($row['npt'])->div($row['actual'])->mul(100)->round(2)->done()).'%'; + }else{ + $row['gpt']=math()->chain($row['actual'])->sub($row['act'])->done(); + $row['gpr']=(empty($row['actual'])?(empty($row['gpt'])?'0':'-100'):math()->chain($row['gpt'])->div($row['actual'])->mul(100)->round(2)->done()).'%'; + $row['npt']=math()->chain($row['gpt'])->sub($row['cost'])->done(); + $row['npr']=(empty($row['actual'])?(empty($row['npt'])?'0':'-100'):math()->chain($row['npt'])->div($row['actual'])->mul(100)->round(2)->done()).'%'; + } + //匹配明细 + $node=[]; + if(!empty($input['type'])){ + $list=search($bill['info'][$row['mold']])->where([['pid','=',$row['id']]])->select(); + foreach ($list as $listVo) { + $detail=[ + 'name'=>$listVo['goodsData']['name'], + 'attr'=>$listVo['attr'], + 'unit'=>$listVo['unit'], + 'price'=>$listVo['price'], + 'nums'=>$listVo['nums'], + 'dsc'=>$listVo['dsc'], + 'total'=>$listVo['total'], + 'tat'=>$listVo['tat'], + 'tpt'=>$listVo['tpt'] + ]; + $calc=[]; + $calc['act']=empty($listVo['goodsData']['type'])?floatval(search($summary)->where([['info','=',$listVo['id']]])->find()['bct']):0; + $calc['gpt']=math()->chain($detail['tpt'])->sub($calc['act'])->done(); + $calc['gpr']=(empty($detail['tpt'])?(empty($calc['gpt'])?'0':'-100'):math()->chain($calc['gpt'])->div($detail['tpt'])->mul(100)->round(2)->done()).'%'; + $node[]=['detail'=>$detail,'act'=>$calc['act'],'gpt'=>$calc['gpt'],'gpr'=>$calc['gpr']]; + } + } + $row['node']=$node; + $data[]=$row; + } + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售利润表']; + //表格数据 + $field=[ + [ + 'bill'=>'单据类型', + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'time'=>'单据时间', + 'number'=>'单据编号' + ], + [ + 'detail|name'=>'商品名称', + 'detail|attr'=>'辅助属性', + 'detail|unit'=>'单位', + 'detail|price'=>'单价', + 'detail|nums'=>'数量', + 'detail|dsc'=>'折扣额', + 'detail|total'=>'金额', + 'detail|tat'=>'税额', + 'detail|tpt'=>'价税合计' + ], + [ + 'total'=>'单据金额', + 'discount'=>'优惠金额', + 'actual'=>'实际金额', + 'act'=>'成本', + 'gpt'=>'毛利润', + 'gpr'=>'毛利率', + 'cost'=>'单据费用', + 'npt'=>'净利润', + 'npr'=>'净利率', + 'extension|amount'=>'核销金额', + 'extension|nucleus'=>'核销状态', + 'userData|name'=>'制单人', + 'peopleData|name'=>'关联人员', + 'data'=>'备注信息' + ] + ]; + $field=empty($input['type'])?array_merge($field[0],$field[2]):array_merge($field[0],$field[1],$field[2]); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + ]]; + //导出execl + buildExcel('销售利润表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //销售排行表 + public function mot(){ + $input=input('post.'); + if(existFull($input,['page','limit'])){ + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'] + ]); + $goods=Db::name('goods')->where($sql)->select()->toArray(); + //数据匹配 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['goods','in',array_column($goods,'id')]; + $existsSql[]=['examine','=',1]; + $existsSql=frameScope($existsSql); + $existsSql=sqlAuth('sell',$existsSql);//结构一致 + //多源匹配 + $union=[]; + $tab=['sell','sre']; + foreach ($tab as $t) { + $union[0][]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($existsSql)->fieldRaw('goods,attr,sum(nums) as nums')->group(['goods,attr'])->buildSql(); + } + $union_0=implode(' UNION ALL ',$union[0]); + $count=DB::query('select count(*) as count from ( SELECT count(*) FROM ('.$union_0.') as f GROUP BY goods,attr ) as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union_0.') as nodcloud GROUP BY goods,attr ORDER BY `nums` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + //构造条件|减少查询 + foreach ($existsSql as $k=>$v) { + if($v[0]=='goods'){ + $existsSql[$k][2]=array_column($record,'goods'); + break; + } + } + foreach ($tab as $t) { + $union[1][]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($existsSql)->fieldRaw('"'.$t.'" as mold,goods,attr,group_concat(info.id) as id,sum(dsc) as dsc,'.($t=='barter'?'0 as tat,sum(info.total) as tpt':'sum(tat) as tat,sum(tpt) as tpt'))->group(['goods,attr'])->buildSql(); + } + $union_1=implode(' UNION ALL ',$union[1]); + $list=DB::query('SELECT * FROM ('.$union_1.') as nodcloud'); + //获取数据 + $summary=[]; + foreach ($tab as $t) { + $gather=explode(',',implode(',',array_column(search($list)->where([['mold','=',$t]])->select(),'id'))); + $summary[$t]=Db::name('summary')->where([['type','=',$t],['info','in',$gather]])->select()->toArray(); + } + $data=[]; + //统计数据 + foreach ($record as $vo) { + $row=[]; + $g=search($goods)->where([['id','=',$vo['goods']]])->find(); + $row['goodsData']=$g; + $row['attr']=$vo['attr']; + $row['unit']=$g['unit']==-1?'多单位':$g['unit']; + $base=[['goods','=',$vo['goods']],['attr','=',$vo['attr']]]; + $gather=[]; + foreach ($tab as $t) { + $b=search($list)->where(array_merge($base,[['mold','=',$t]]))->find(); + $s=search($summary[$t])->where(array_merge($base,[['type','=',$t]]))->select(); + $gather['nums'][$t]=mathArraySum(array_column($s,'nums')); + $gather['dsc'][$t]=empty($b)?0:$b['dsc']; + $gather['tat'][$t]=empty($b)?0:$b['tat']; + $gather['tpt'][$t]=empty($b)?0:$b['tpt']; + $gather['bct'][$t]=mathArraySum(array_column($s,'bct')); + } + $nums=math()->chain($gather['nums']['sell'])->sub($gather['nums']['sre'])->done(); + $row['nums']=$g['unit']==-1?unitSwitch($nums,json_decode($g['units'],true)):$nums; + $row['dsc']=math()->chain($gather['dsc']['sell'])->sub($gather['dsc']['sre'])->done(); + $row['tat']=math()->chain($gather['tat']['sell'])->sub($gather['tat']['sre'])->done(); + $row['tpt']=math()->chain($gather['tpt']['sell'])->sub($gather['tpt']['sre'])->done(); + $row['bct']=math()->chain($gather['bct']['sell'])->sub($gather['bct']['sre'])->done(); + $row['uct']=empty($nums)?0:math()->chain($row['bct'])->div($nums)->round(2)->abs()->done(); + $total=math()->chain($row['tpt'])->sub($row['tat'])->done(); + $row['gpt']=math()->chain($total)->sub($row['bct'])->done(); + $row['gpr']=(empty($total)?(empty($row['gpt'])?'0':'-100'):math()->chain($row['gpt'])->div($total)->mul(100)->round(2)->done()).'%'; + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //销售排行表-导出 + public function motExports(){ + $input=input('get.'); + pushLog('导出销售排行表');//日志 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'] + ]); + $goods=Db::name('goods')->where($sql)->select()->toArray(); + //数据匹配 + $existsSql=fastSql($input,[ + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['goods','in',array_column($goods,'id')]; + $existsSql[]=['examine','=',1]; + $existsSql=frameScope($existsSql); + $existsSql=sqlAuth('buy',$existsSql);//结构一致 + //多源匹配 + $union=[]; + $tab=['sell','sre']; + foreach ($tab as $t) { + $union[0][]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($existsSql)->fieldRaw('goods,attr,sum(nums) as nums')->group(['goods,attr'])->buildSql(); + } + $union_0=implode(' UNION ALL ',$union[0]); + $count=DB::query('select count(*) as count from ( SELECT count(*) FROM ('.$union_0.') as f GROUP BY goods,attr ) as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union_0.') as nodcloud GROUP BY goods,attr ORDER BY `nums` DESC'); + //匹配数据 + foreach ($tab as $t) { + $union[1][]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($existsSql)->fieldRaw('"'.$t.'" as mold,goods,attr,group_concat(info.id) as id,sum(dsc) as dsc,'.($t=='barter'?'0 as tat,sum(info.total) as tpt':'sum(tat) as tat,sum(tpt) as tpt'))->group(['goods,attr'])->buildSql(); + } + $union_1=implode(' UNION ALL ',$union[1]); + $list=DB::query('SELECT * FROM ('.$union_1.') as nodcloud'); + //获取数据 + $summary=[]; + foreach ($tab as $t) { + $gather=explode(',',implode(',',array_column(search($list)->where([['mold','=',$t]])->select(),'id'))); + $summary[$t]=Db::name('summary')->where([['type','=',$t],['info','in',$gather]])->select()->toArray(); + } + $data=[]; + //统计数据 + foreach ($record as $vo) { + $row=[]; + $g=search($goods)->where([['id','=',$vo['goods']]])->find(); + $row['goodsData']=$g; + $row['attr']=$vo['attr']; + $row['unit']=$g['unit']==-1?'多单位':$g['unit']; + $base=[['goods','=',$vo['goods']],['attr','=',$vo['attr']]]; + $gather=[]; + foreach ($tab as $t) { + $b=search($list)->where(array_merge($base,[['mold','=',$t]]))->find(); + $s=search($summary[$t])->where(array_merge($base,[['type','=',$t]]))->select(); + $gather['nums'][$t]=mathArraySum(array_column($s,'nums')); + $gather['dsc'][$t]=empty($b)?0:$b['dsc']; + $gather['tat'][$t]=empty($b)?0:$b['tat']; + $gather['tpt'][$t]=empty($b)?0:$b['tpt']; + $gather['bct'][$t]=mathArraySum(array_column($s,'bct')); + } + $nums=math()->chain($gather['nums']['sell'])->sub($gather['nums']['sre'])->done(); + $row['nums']=$g['unit']==-1?unitSwitch($nums,json_decode($g['units'],true)):$nums; + $row['dsc']=math()->chain($gather['dsc']['sell'])->sub($gather['dsc']['sre'])->done(); + $row['tat']=math()->chain($gather['tat']['sell'])->sub($gather['tat']['sre'])->done(); + $row['tpt']=math()->chain($gather['tpt']['sell'])->sub($gather['tpt']['sre'])->done(); + $row['bct']=math()->chain($gather['bct']['sell'])->sub($gather['bct']['sre'])->done(); + $row['uct']=empty($nums)?0:math()->chain($row['bct'])->div($nums)->round(2)->abs()->done(); + $total=math()->chain($row['tpt'])->sub($row['tat'])->done(); + $row['gpt']=math()->chain($total)->sub($row['bct'])->done(); + $row['gpr']=(empty($total)?(empty($row['gpt'])?'0':'-100'):math()->chain($row['gpt'])->div($total)->mul(100)->round(2)->done()).'%'; + $data[]=$row; + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售排行表']; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'attr'=>'辅助属性', + 'goodsData|number'=>'商品编号', + 'goodsData|spec'=>'规格型号', + 'unit'=>'单位', + 'nums'=>'数量', + 'dsc'=>'折扣额', + 'tat'=>'税额', + 'tpt'=>'价税合计', + 'uct'=>'成本', + 'bct'=>'总成本', + 'gpt'=>'毛利润', + 'gpr'=>'毛利率' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source) + ]]; + //导出execl + buildExcel('销售排行表',$excel); + } +} diff --git a/serve/app/controller/Oce.php b/serve/app/controller/Oce.php new file mode 100644 index 0000000..e3c2ccb --- /dev/null +++ b/serve/app/controller/Oce.php @@ -0,0 +1,569 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['account','fullEq'], + ['people','fullEq'], + ['user','fullEq'], + ['examine','fullDec1'], + ['nucleus','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('oce',$sql);//数据鉴权 + $count = Oces::where($sql)->count();//获取总条数 + $info = Oces::with(['frameData','supplierData','accountData','peopleData','userData','billData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['examine']=0; + $class['nucleus']=0; + empty($class['id'])?$this->validate($class,'app\validate\Oce'):$this->validate($class,'app\validate\Oce.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\OceInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'数据表格第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Oces::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'oce','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增其它支出单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Oces::update($class); + Db::name('record')->insert(['type'=>'oce','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新其它支出单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + OceInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new OceInfo; + $model->saveAll($input['info']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Oces::where([['id','=',$input['parm']]])->find(); + $info=OceInfo::with(['ietData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('oce')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('oce')->where([['id','in',$input['parm']]])->delete(); + Db::name('oce_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','oce'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除其它支出单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('oce')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('oce_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + //3 综合匹配 + $sourceSum=mathArraySum(array_column($info,'source')); + if(!empty($sourceSum)){ + //2.1 匹配费用 + $costList=Db::name('cost')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + //2.1 构造数据 + $costGather=array_map(function($row){ + return [['type','=',$row['type']],['class','=',$row['class']]]; + },$costList); + } + //4 数据验证 + if(empty($class['examine'])){ + if(!empty($sourceSum)){ + // 关联验证 + foreach ($info as $infoKey=>$infoVo) { + $cost=search($costList)->where([['id','=',$infoVo['source']]])->find(); + if(!empty($cost)){ + if(bccomp(math()->chain($cost['settle'])->add($infoVo['money'])->done(),$cost['money'])==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行结算金额超出可结算费用!']); + exit; + } + } + } + } + }else{ + //核销单 + $bill=Db::name('bill_info')->where([['mold','=','oce'],['source','=',$class['id']]])->find(); + if(!empty($bill)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联核销单!']); + exit; + } + } + //5 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 关联单据 + $store=['cost'=>[],'costInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + if(!empty($infoVo['source'])){ + //关联费用 + $store['cost'][]=['id'=>$infoVo['source'],'settle'=>$infoVo['money']]; + //关联费用记录 + $store['costInfo'][]=['pid'=>$infoVo['source'],'oce'=>$class['id'],'time'=>$class['time'],'money'=>$infoVo['money']]; + } + } + //1.1 处理数据 + if(!empty($store['cost'])){ + //1 更新详情 + Db::name('cost')->duplicate(['settle'=>Db::raw('settle + VALUES(`settle`)')])->insertAll($store['cost']); + //2 更新状态 + Db::name('cost')->where([['id','in',array_column($store['cost'],'id')]])->update(['state'=>Db::raw('CASE WHEN settle = money THEN 2 ELSE 1 END')]); + //3 插入记录 + Db::name('cost_info')->insertAll($store['costInfo']); + //4 更新单据 + $costGroup=Db::name('cost')->whereOr($costGather)->fieldRaw('type,class,group_concat(state) as states')->group(['type','class'])->select()->toArray(); + //4.1 组装数据 + $bill=[]; + foreach ($costGroup as $costGroupVo) { + $states=explode(',',$costGroupVo['states']); + $bill[$costGroupVo['type']][]=['id'=>$costGroupVo['class'],'cse'=>mathArraySum($states)==count($states)*2?2:1]; + } + //4.2 更新状态 + foreach($bill as $billKey => $billVo){ + Db::name($billKey)->duplicate(['cse'=>Db::raw('VALUES(`cse`)')])->insertAll($billVo); + } + } + //2 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->dec('balance',$class['money'])->update(); + //2 创建资金详情 + Db::name('account_info')->insert([ + 'pid'=>$class['account'], + 'type'=>'oce', + 'class'=>$class['id'], + 'time'=>$class['time'], + 'direction'=>0, + 'money'=>$class['money'] + ]); + //3 创建核销记录 + Db::name('oce_bill')->insert([ + 'pid'=>$class['id'], + 'type'=>'oce', + 'source'=>$class['id'], + 'time'=>$class['time'], + 'money'=>$class['money'] + ]); + } + //3 供应商|应付款余额 + if(!empty($class['supplier'])){ + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('supplier')->where([['id','=',$class['supplier']]])->inc('balance',$balance)->update(); + } + } + //4 更新单据 + $nucleus=$class['money']==$class['actual']?2:($class['money']==0?0:1); + Db::name('oce')->where([['id','=',$class['id']]])->update(['examine'=>1,'nucleus'=>$nucleus]); + //5 单据记录 + Db::name('record')->insert(['type'=>'oce','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //6 记录操作 + pushLog('审核其它支出单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 关联单据 + $store=['cost'=>[],'costInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + if(!empty($infoVo['source'])){ + //关联费用 + $store['cost'][]=['id'=>$infoVo['source'],'settle'=>$infoVo['money']]; + //关联费用记录 + $store['costInfo'][]=[['pid','=',$infoVo['source']],['oce','=',$class['id']]]; + } + } + //1.1 处理数据 + if(!empty($store['cost'])){ + //1 更新详情 + Db::name('cost')->duplicate(['settle'=>Db::raw('settle - VALUES(`settle`)')])->insertAll($store['cost']); + //2 更新状态 + Db::name('cost')->where([['id','in',array_column($store['cost'],'id')]])->update(['state'=>Db::raw('CASE WHEN settle = 0 THEN 0 ELSE 1 END')]); + //3 删除记录 + Db::name('cost_info')->whereOr($store['costInfo'])->delete(); + //4 更新单据 + $costGroup=Db::name('cost')->whereOr($costGather)->fieldRaw('type,class,group_concat(state) as states')->group(['type','class'])->select()->toArray(); + //4.1 组装数据 + $bill=[]; + foreach ($costGroup as $costGroupVo) { + $states=explode(',',$costGroupVo['states']); + $bill[$costGroupVo['type']][]=['id'=>$costGroupVo['class'],'cse'=>empty(mathArraySum($states))?0:1]; + } + //4.2 更新状态 + foreach($bill as $billKey => $billVo){ + Db::name($billKey)->duplicate(['cse'=>Db::raw('VALUES(`cse`)')])->insertAll($billVo); + } + } + //2 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->inc('balance',$class['money'])->update(); + //2 删除资金详情 + Db::name('account_info')->where([['type','=','oce'],['class','=',$class['id']]])->delete(); + //3 删除核销记录 + Db::name('oce_bill')->where([['pid','=',$class['id']]])->delete(); + } + //3 供应商|应付款余额 + if(!empty($class['supplier'])){ + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('supplier')->where([['id','=',$class['supplier']]])->dec('balance',$balance)->update(); + } + } + //4 更新单据 + Db::name('oce')->where([['id','=',$class['id']]])->update(['examine'=>0,'nucleus'=>0]); + //5 单据记录 + Db::name('record')->insert(['type'=>'oce','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //6 记录操作 + pushLog('反审核其它支出单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('oce', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //供应商匹配 + if(empty($data[3]['A'])){ + $supplier=['id'=>0]; + }else{ + $supplier=Db::name('supplier')->where([['name','=',$data[3]['A']]])->find(); + if(empty($supplier)){ + throw new ValidateException('供应商[ '.$data[3]['A'].' ]未匹配!'); + } + } + //结算账户匹配 + $account=Db::name('account')->where([['name','=',$data[3]['E']]])->find(); + if(empty($account)){ + throw new ValidateException('资金账户[ '.$data[3]['E'].' ]未匹配!'); + } + //关联人员匹配 + if(empty($data[3]['F'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['F']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['F'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'supplier'=>$supplier['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'account'=>$account['id'], + 'people'=>$people['id'], + 'file'=>[], + 'data'=>$data[3]['G'], + 'more'=>[], + 'examine'=>0, + 'nucleus'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Oce');//数据合法性验证 + //初始化INFO + $info=[]; + $iet=Db::name('iet')->where([['name','in',array_column($data,'H')],['type','=',1]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'iet'=>$dataVo['H'], + 'money'=>$dataVo['I'], + 'data'=>$dataVo['J'] + ]; + //支出类别匹配 + $ietFind=search($iet)->where([['name','=',$record['iet']]])->find(); + if(empty($ietFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行支出类别[ '.$record['iet'].' ]未匹配!'); + }else{ + $record['iet']=$ietFind['id']; + } + //结算金额匹配 + if(!preg_match("/^(\-)?\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['money'])){ + throw new ValidateException('模板文件第'.$dataKey.'行结算金额不正确!'); + } + try{ + $this->validate($record,'app\validate\OceInfo');//数据合法性验证 + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['money'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + Db::startTrans(); + try { + //新增CLASS + $classData=Oces::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new OceInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'oce','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入其它支出单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出其它支出单列表');//日志 + $source=Oces::with(['frameData','supplierData','accountData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'其它支出单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'supplierData|name'=>'供应商', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'actual'=>'实际金额', + 'money'=>'单据收款', + 'extension|amount'=>'核销金额', + 'accountData|name'=>'结算账户', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|nucleus'=>'核销状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据金额:'.mathArraySum(array_column($source,'total')), + '总实际金额:'.mathArraySum(array_column($source,'actual')), + '总单据付款:'.mathArraySum(array_column($source,'money')), + '总核销金额:'.mathArraySum(arrayColumns($source,['extension','amount'])) + ]]; + //导出execl + buildExcel('其它支出单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'其它支出单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '供应商:'.$sourceVo['supplierData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'ietData|name'=>'支出类别', + 'money'=>'结算金额', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=OceInfo::with(['ietData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->select()->toArray(); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '结算账户:'.arraySeek($sourceVo,'accountData|name'), + '核销金额:'.$sourceVo['extension']['amount'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + } + buildZip('其它支出单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Often.php b/serve/app/controller/Often.php new file mode 100644 index 0000000..ff3df6d --- /dev/null +++ b/serve/app/controller/Often.php @@ -0,0 +1,45 @@ +where($sql)->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['parm'])){ + $userID=getUserID(); + //处理数据 + Db::startTrans(); + try { + Db::name('often')->where([['user','=',$userID]])->delete(); + + $insert=[]; + foreach ($input['parm'] as $v) { + $insert[]=['user'=>$userID,'name'=>$v['name'],'key'=>$v['key']]; + } + empty($insert)||Db::name('often')->insertAll($insert); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Omy.php b/serve/app/controller/Omy.php new file mode 100644 index 0000000..98fddfb --- /dev/null +++ b/serve/app/controller/Omy.php @@ -0,0 +1,454 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['people','fullEq'], + ['user','fullEq'], + ['examine','fullDec1'], + ['nucleus','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + //结算账户扩展查询 + if(existFull($input,['account'])){ + $sql[]=['id','in',array_column(Db::name('omy_info')->where([['account','=',$input['account']]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('omy',$sql);//数据鉴权 + $count = Omys::where($sql)->count();//获取总条数 + $info = Omys::with(['frameData','supplierData','peopleData','userData','billData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['examine']=0; + $class['nucleus']=0; + empty($class['id'])?$this->validate($class,'app\validate\Omy'):$this->validate($class,'app\validate\Omy.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\OmyInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'数据表格第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Omys::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'omy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增付款单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Omys::update($class); + Db::name('record')->insert(['type'=>'omy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新付款单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + OmyInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new OmyInfo; + $model->saveAll($input['info']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Omys::where([['id','=',$input['parm']]])->find(); + $info=OmyInfo::with(['accountData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('omy')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('omy')->where([['id','in',$input['parm']]])->delete(); + Db::name('omy_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','omy'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除付款单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('omy')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('omy_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(!empty($class['examine'])){ + //核销单 + $bill=Db::name('bill_info')->where([['mold','=','omy'],['source','=',$class['id']]])->find(); + if(!empty($bill)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联核销单!']); + exit; + } + } + //3 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $store=['account'=>[],'accountInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //1 资金账户 + $store['account'][]=['id'=>$infoVo['account'],'balance'=>$infoVo['money']]; + //2 资金账户详情 + $store['accountInfo'][]=['pid'=>$infoVo['account'],'type'=>'omy','class'=>$class['id'],'time'=>$class['time'],'direction'=>0,'money'=>$infoVo['money']]; + } + //2 资金账户 + Db::name('account')->duplicate(['balance'=>Db::raw('balance - VALUES(`balance`)')])->insertAll($store['account']); + //3 资金账户 + Db::name('account_info')->insertAll($store['accountInfo']); + //4 供应商|应付款余额 + Db::name('supplier')->where([['id','=',$class['supplier']]])->dec('balance',$class['total'])->update(); + //5 更新单据 + Db::name('omy')->where([['id','=',$class['id']]])->update(['examine'=>1]); + //6 单据记录 + Db::name('record')->insert(['type'=>'omy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //7 记录操作 + pushLog('审核付款单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 匹配数据 + $listSql=[['type','=','omy'],['class','=',$class['id']]]; + $accountInfoList=Db::name('account_info')->where($listSql)->select()->toArray(); + //2 资金账户 + $accountDuplicate=[]; + foreach ($accountInfoList as $accountInfoVo) { + $accountDuplicate[]=['id'=>$accountInfoVo['pid'],'balance'=>$accountInfoVo['money']]; + } + //2.1 更新资金 + Db::name('account')->duplicate(['balance'=>Db::raw('balance + VALUES(`balance`)')])->insertAll($accountDuplicate); + //2.2 删除资金详情 + Db::name('account_info')->where([['id','in',array_column($accountInfoList,'id')]])->delete(); + //3 供应商|应付款余额 + Db::name('supplier')->where([['id','=',$class['supplier']]])->inc('balance',$class['total'])->update(); + //4 更新单据 + Db::name('omy')->where([['id','=',$class['id']]])->update(['examine'=>0]); + //5 单据记录 + Db::name('record')->insert(['type'=>'omy','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //6 记录操作 + pushLog('反审核付款单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('omy', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //供应商匹配 + $supplier=Db::name('supplier')->where([['name','=',$data[3]['A']]])->find(); + if(empty($supplier)){ + throw new ValidateException('供应商[ '.$data[3]['A'].' ]未匹配!'); + } + //关联人员匹配 + if(empty($data[3]['E'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['E']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['E'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'supplier'=>$supplier['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'people'=>$people['id'], + 'file'=>[], + 'data'=>$data[3]['F'], + 'more'=>[], + 'examine'=>0, + 'nucleus'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Omy');//数据合法性验证 + //初始化INFO + $info=[]; + $account=Db::name('account')->where([['name','in',array_column($data,'G')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'account'=>$dataVo['G'], + 'money'=>$dataVo['H'], + 'settle'=>$dataVo['I'], + 'data'=>$dataVo['J'] + ]; + //结算账户匹配 + $accountFind=search($account)->where([['name','=',$record['account']]])->find(); + if(empty($accountFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行结算账户[ '.$record['account'].' ]未匹配!'); + }else{ + $record['account']=$accountFind['id']; + } + //结算金额匹配 + if(!preg_match("/^(\-)?\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['money'])){ + throw new ValidateException('模板文件第'.$dataKey.'行结算金额不正确!'); + } + try{ + $this->validate($record,'app\validate\OmyInfo');//数据合法性验证 + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['money'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + Db::startTrans(); + try { + //新增CLASS + $classData=Omys::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new OmyInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'omy','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入付款单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出付款单列表');//日志 + $source=Omys::with(['frameData','supplierData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'付款单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'supplierData|name'=>'供应商', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'extension|amount'=>'核销金额', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|nucleus'=>'核销状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据金额:'.mathArraySum(array_column($source,'total')), + '总核销金额:'.mathArraySum(arrayColumns($source,['extension','amount'])) + ]]; + //导出execl + buildExcel('付款单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'付款单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '供应商:'.$sourceVo['supplierData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'accountData|name'=>'结算账户', + 'money'=>'结算金额', + 'settle'=>'结算号', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=OmyInfo::with(['accountData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->select()->toArray(); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '核销金额:'.$sourceVo['extension']['amount'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + } + buildZip('付款单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/People.php b/serve/app/controller/People.php new file mode 100644 index 0000000..0a5d686 --- /dev/null +++ b/serve/app/controller/People.php @@ -0,0 +1,235 @@ +'name|py'],'fullLike'], + ['number','fullLike'], + ['sex','fullDec1'], + ['tel','fullLike'], + ['add','fullLike'], + ['card','fullLike'], + ['data','fullLike'] + ]);//构造SQL + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('people',$sql);//数据鉴权 + $count = Peoples::where($sql)->count();//获取总条数 + $info = Peoples::with(['frameData'])->append(['extension'])->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //构造|验证 + try { + $input['py']=zhToPy($input['name']);//首拼信息 + empty($input['id'])?$this->validate($input,'app\validate\People'):$this->validate($input,'app\validate\People.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Peoples::create($input); + pushLog('新增人员[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Peoples::update($input); + pushLog('更新人员[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Peoples::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //关联判断 + $exist=moreTableFind([ + ['table'=>'allot','where'=>[['people','in',$input['parm']]]], + ['table'=>'barter','where'=>[['people','in',$input['parm']]]], + ['table'=>'bill','where'=>[['people','in',$input['parm']]]], + ['table'=>'bor','where'=>[['people','in',$input['parm']]]], + ['table'=>'bre','where'=>[['people','in',$input['parm']]]], + ['table'=>'buy','where'=>[['people','in',$input['parm']]]], + ['table'=>'entry','where'=>[['people','in',$input['parm']]]], + ['table'=>'extry','where'=>[['people','in',$input['parm']]]], + ['table'=>'ice','where'=>[['people','in',$input['parm']]]], + ['table'=>'oce','where'=>[['people','in',$input['parm']]]], + ['table'=>'imy','where'=>[['people','in',$input['parm']]]], + ['table'=>'omy','where'=>[['people','in',$input['parm']]]], + ['table'=>'sell','where'=>[['people','in',$input['parm']]]], + ['table'=>'sor','where'=>[['people','in',$input['parm']]]], + ['table'=>'sre','where'=>[['people','in',$input['parm']]]], + ['table'=>'swap','where'=>[['people','in',$input['parm']]]] + ]); + if(empty($exist)){ + //逻辑处理 + $data=Db::name('people')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + Db::startTrans(); + try { + Db::name('people')->where([['id','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除人员[ '.implode(' | ',array_column($data,'name')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除列名行 + $sql=[];//初始化SQL + $frame=Db::name('frame')->where([['name','in',array_column($data,'C')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'name'=>$dataVo['A'], + 'py'=>zhToPy($dataVo['A']), + 'number'=>$dataVo['B'], + 'frame'=>$dataVo['C'], + 'sex'=>$dataVo['D'], + 'tel'=>$dataVo['E'], + 'add'=>$dataVo['F'], + 'card'=>$dataVo['G'], + 'data'=>$dataVo['H'], + 'more'=>[] + ]; + //所属组织匹配 + $frameFind=search($frame)->where([['name','=',$record['frame']]])->find(); + if(empty($frameFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行所属组织[ '.$record['frame'].' ]未匹配!'); + }else{ + $record['frame']=$frameFind['id']; + } + //人员性别匹配 + if(in_array($record['sex'],['男','女'])){ + $record['sex']=$record['sex']=='男'?1:0; + }else{ + throw new ValidateException('模板文件第'.$dataKey.'行人员性别[ '.$record['sex'].' ]未匹配!'); + } + try { + //数据合法性验证 + $this->validate($record,'app\validate\People'); + $sql[]=$record;//加入SQL + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第[ '.$dataKey.' ]行'.$e->getError()]); + exit; + } + } + //判断编号重复 + $column=array_column($sql,'number'); + $unique=array_unique($column); + $diff=array_diff_assoc($column,$unique); + if(!empty($diff)){ + //返回错误信息 + return json(['state'=>'error','info'=>'模板文件人员编号[ '.implode(' | ',$diff).' ]重复!']); + } + //新增数据 + $customer = new Peoples; + $customer->saveAll($sql); + pushLog('批量导入[ '.count($sql).' ]条人员数据');//日志 + $result=['state'=>'success','info'=>'成功导入'.count($sql).'行人员数据']; + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $info=Peoples::with(['frameData'])->append(['extension'])->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray();//查询数据 + $field=[ + 'name'=>'人员名称', + 'number'=>'人员编号', + 'frameData|name'=>'所属组织', + 'extension|sex'=>'人员性别', + 'tel'=>'联系电话', + 'add'=>'联系地址', + 'card'=>'身份证号', + 'data'=>'备注信息' + ]; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'人员信息']; + //表格数据 + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>['总数:'.count($info)]]; + //导出execl + pushLog('导出人员信息');//日志 + buildExcel('人员信息',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Period.php b/serve/app/controller/Period.php new file mode 100644 index 0000000..8e98daf --- /dev/null +++ b/serve/app/controller/Period.php @@ -0,0 +1,51 @@ +count();//获取总条数 + $info = Periods::with(['userData'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //结账 + public function save(){ + $input=input('post.'); + if(existFull($input,['date']) && strtotime($input['date'])){ + $period=getPeriod(); + $date=strtotime($input['date']); + if($date>$period){ + $data=['date'=>$date,'time'=>time(),'user'=>getUserID()]; + Db::name('period')->insert($data); + pushLog('结账操作');//日志 + + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'结账周期不正确!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //反结账 + public function back(){ + $period=getPeriod(); + $row=db('period')->where([['date','=',$period]])->delete(); + pushLog('反结账操作');//日志 + return json(['state'=>'success']); + } +} diff --git a/serve/app/controller/Role.php b/serve/app/controller/Role.php new file mode 100644 index 0000000..874138b --- /dev/null +++ b/serve/app/controller/Role.php @@ -0,0 +1,103 @@ +count();//获取总条数 + $info = Roles::where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + empty($input['id'])?$this->validate($input,'app\validate\Role'):$this->validate($input,'app\validate\Role.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Roles::create($input); + pushLog('新增用户角色[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Roles::update($input); + pushLog('更新用户角色[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Roles::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //关联判断 + $exist=moreTableFind([ + ['table'=>'user','where'=>[['role','=',$input['id']]]], + ]); + //判断数据是否存在 + if(!$exist){ + $find=Db::name('role')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + try { + Db::name('role')->where([['id','=',$input['id']]])->delete(); + pushLog('删除用户角色[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Sell.php b/serve/app/controller/Sell.php new file mode 100644 index 0000000..b574fe6 --- /dev/null +++ b/serve/app/controller/Sell.php @@ -0,0 +1,1298 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['examine','fullDec1'], + ['nucleus','fullDec1'], + ['cse','fullDec1'], + ['invoice','fullDec1'], + ['check','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['id','in',array_column(Db::name('sell_info')->where([['goods','in',$goods]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('sell',$sql);//数据鉴权 + $count = Sells::where($sql)->count();//获取总条数 + $info = Sells::with(['frameData','customerData','peopleData','userData','billData','costData','invoiceData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + //关联单据 + if(!empty($info)){ + $sor=Db::name('sor')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + $sre=Db::name('sre')->where([['source','in',array_column($info,'id')]])->select()->toArray(); + foreach ($info as $infoKey=>$infoVo) { + //销售订单 + $sorData=array_map(function($item){ + return ['type'=>'销售订单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'sor','id'=>$item['id']]; + },search($sor)->where([['id','=',$infoVo['source']]])->select()); + //销售退货单 + $sreData=array_map(function($item){ + return ['type'=>'销售退货单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'sre','id'=>$item['id']]; + },search($sre)->where([['source','=',$infoVo['id']]])->select()); + //合并排序 + $merge=array_merge($sorData,$sreData); + array_multisort(array_column($merge,'sort'),SORT_DESC,$merge); + $info[$infoKey]['relation']=$merge; + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['cse']=empty($class['cost'])?3:0; + $class['invoice']=empty($class['actual'])?3:0; + $class['examine']=0; + $class['nucleus']=0; + empty($class['id'])?$this->validate($class,'app\validate\Sell'):$this->validate($class,'app\validate\Sell.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\SellInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'商品信息第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //验证Cost + foreach ($input['cost'] as $costKey=>$costVo) { + try { + $this->validate($costVo,'app\validate\Cost'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'单据费用第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Sells::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'sell','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增销售单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Sells::update($class); + Db::name('record')->insert(['type'=>'sell','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新销售单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + SellInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + $input['info'][$infoKey]['retreat']=0;//初始|退货数量 + } + $model = new SellInfo; + $model->saveAll($input['info']); + + //COST数据 + Cost::where([['type','=','sell'],['class','=',$class['id']]])->delete(); + foreach ($input['cost'] as $costKey=>$costVo) { + unset($input['cost'][$costKey]['id']); + $input['cost'][$costKey]['type']='sell'; + $input['cost'][$costKey]['class']=$class['id']; + $input['cost'][$costKey]['time']=$class['time']; + $input['cost'][$costKey]['settle']=0; + $input['cost'][$costKey]['state']=0; + } + $model = new Cost; + $model->saveAll($input['cost']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Sells::where([['id','=',$input['parm']]])->find(); + $info=SellInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $cost=Cost::where([['type','=','sell'],['class','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + 'cost'=>$cost, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //关联验证 + $exist=moreTableFind([['table'=>'sre','where'=>[['source','in',$input['parm']]]]]); + if($exist){ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + }else{ + $data=Db::name('sell')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('sell')->where([['id','in',$input['parm']]])->delete(); + Db::name('sell_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('cost')->where([['type','=','sell'],['class','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','sell'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除销售单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //核对|反核对 + public function check(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $period=getPeriod(); + $classList=Db::name('sell')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + foreach ($input['parm'] as $parmVo) { + $class=search($classList)->where([['id','=',$parmVo]])->find(); + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(empty($class['check'])){ + Db::name('sell')->where([['id','=',$class['id']]])->update(['check'=>1]); + //1 单据记录 + Db::name('record')->insert(['type'=>'sell','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'核对单据']); + //2 记录操作 + pushLog('核对销售单[ '.$class['number'].' ]');//单据日志 + }else{ + Db::name('sell')->where([['id','=',$class['id']]])->update(['check'=>0]); + //1 单据记录 + Db::name('record')->insert(['type'=>'sell','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反核对单据']); + //2 记录操作 + pushLog('反核对销售单[ '.$class['number'].' ]');//单据日志 + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $fun=getSys('fun'); + $period=getPeriod(); + $classList=Db::name('sell')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('sell_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //1.1 商品数据 + $goodsList=Db::name('goods')->where([['id','in',array_unique(array_column($info,'goods'))]])->select()->toArray(); + //1.2 综合匹配 + if(empty($class['examine'])){ + //1 关联单据 + empty($class['source'])||$sorInfoList=Db::name('sor_info')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + //2 构造数据 + $batchGather=[]; + $serialGather=[]; + $roomWhereOrSql=[]; + foreach ($info as $infoVo) { + //1 批次号 + empty($infoVo['batch'])||$batchGather[]=$infoVo['batch']; + //2 序列号 + $serialGather=array_merge($serialGather,json_decode($infoVo['serial'])); + //3 仓储条件 + empty($infoVo['warehouse'])||$roomWhereOrSql[]=[['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]]; + } + //3 匹配数据 + empty($batchGather)||$batchList=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + empty($serialGather)||$serialList=Db::name('serial')->where([['number','in',$serialGather],['state','<>',2]])->select()->toArray(); + if(!empty($roomWhereOrSql)){ + //1 去重转存 + $roomWhereOrSql=array_unique($roomWhereOrSql,SORT_REGULAR); + //2 仓储匹配 + $roomList=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + } + } + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(empty($class['examine'])){ + //销售订单 + if(!empty($class['source'])){ + $sor=Db::name('sor')->where([['id','=',$class['source']]])->find(); + if(in_array($sor['state'],[2,3])){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:关联订单状态不正确!']); + exit; + } + } + }else{ + //1 销售订单 + if(!empty($class['source'])){ + $sor=Db::name('sor')->where([['id','=',$class['source']]])->find(); + if(in_array($sor['state'],[0,3])){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:关联订单状态不正确!']); + exit; + } + } + //2 销售退货单 + $sre=Db::name('sre')->where([['source','=',$class['id']]])->find(); + if(!empty($sre)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联销售退货单!']); + exit; + } + //3 核销单 + $bill=Db::name('bill_info')->where([['mold','=','sell'],['source','=',$class['id']]])->find(); + if(!empty($bill)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联核销单!']); + exit; + } + //4 单据费用 + $cost=Db::name('cost')->alias('cost')->where([['type','=','sell'],['class','=',$class['id']]])->whereExists(function($query){ + $query->name('oce_info')->where([['source','=',Db::raw('cost.id')]])->limit(1); + })->find(); + if(!empty($cost)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联其它支出单!']); + exit; + } + //5 单据发票 + $invoice=Db::name('invoice')->where([['type','=','sell'],['class','=',$class['id']]])->find(); + if(!empty($invoice)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联单据发票!']); + exit; + } + } + //3 INFO验证|构造 + foreach ($info as $infoKey=>$infoVo) { + //1 匹配商品 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + //2 商品类型 + if(empty($goods['type'])){ + //场景验证 + if(empty($class['examine'])){ + //1 匹配数据 + $room=search($roomList)->where([['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]],true)->find(); + (empty($room)||empty($infoVo['batch']))||$batch=search($batchList)->where([['room','=',$room['id']],['number','=',$infoVo['batch']],['time','=',$infoVo['mfd']]],true)->find(); + //2 关联单据 + if(!empty($infoVo['source'])){ + $sorInfo=search($sorInfoList)->where([['id','=',$infoVo['source']]])->find(); + if(!empty($sorInfo)){ + if($sorInfo['unit']!=$infoVo['unit']){ + //单位匹配 + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行单位与销售订单不匹配!']); + exit; + }elseif(bccomp(math()->chain($sorInfo['handle'])->add($infoVo['nums'])->done(),$sorInfo['nums'])==1){ + //数量匹配 + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行超出销售订单可出库数量!']); + exit; + } + } + + } + //3 多单位处理 + if($goods['unit']==-1){ + //多单位|转存 + $radix=unitRadix($infoVo['unit'],json_decode($goods['units'],true)); + $info[$infoKey]['basic']=[ + 'nums'=>math()->chain($infoVo['nums'])->mul($radix)->done(), + 'price'=>math()->chain($infoVo['price'])->div($radix)->round(4)->done() + ]; + }else{ + //常规单位|转存 + $info[$infoKey]['basic']=[ + 'nums'=>$infoVo['nums'], + 'price'=>$infoVo['price'] + ]; + } + //4 序列号 + $serialData=json_decode($infoVo['serial']); + if(empty($serialData)){ + $info[$infoKey]['serial']=[]; + }else{ + //序列号状态[不存在|未销售] + $serialCollect=search($serialList)->where([['goods','=',$infoVo['goods']],['number','in',$serialData]])->select(); + foreach ($serialCollect as $serialCollectVo) { + if($serialCollectVo['state']==0){ + if(empty($room) || $room['id']!=$serialCollectVo['room']){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]与仓库不匹配!']); + exit; + } + if((empty($infoVo['batch'])&&!empty($serialCollectVo['batch']))||(!empty($infoVo['batch'])&&(empty($batch)||$batch['id']!=$serialCollectVo['batch']))){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]与批次不匹配!']); + exit; + } + }else{ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]状态不正确!']); + exit; + } + } + $info[$infoKey]['serial']=$serialData; + } + //5 负库存验证 + if($fun['overflow']==false){ + //1 仓储验证 + if(empty($room)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行仓储信息不存在!']); + exit; + }else{ + if(bccomp($info[$infoKey]['basic']['nums'],$room['nums'])==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行仓储库存不足!']); + exit; + }else{ + $roomList[$room['rowKey']]['nums']=math()->chain($room['nums'])->sub($info[$infoKey]['basic']['nums'])->done(); + } + } + //2 批次验证 + if(!empty($infoVo['batch'])){ + if(empty($batch)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行批次信息无效!']); + exit; + }else{ + if(bccomp($info[$infoKey]['basic']['nums'],$batch['nums'])==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行批次库存不足!']); + exit; + }else{ + $batchList[$batch['rowKey']]['nums']=math()->chain($batch['nums'])->sub($info[$infoKey]['basic']['nums'])->done(); + } + } + } + //3 序列号验证 + if(!empty($serialData)){ + $serialCount=search($serialList)->where([['room','=',$room['id']],['number','in',$serialData]])->count(); + if($serialCount != count($serialData)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行存在无效序列号!']); + exit; + } + } + } + }else{ + //1 验证序列号 + $serialInfoCollect=Db::name('serial_info')->where([['type','=','sell'],['info','in',array_column($info,'id')]])->select()->toArray(); + if(!empty($serialInfoCollect)){ + //序列号状态[已销售] + $serialFind=Db::name('serial')->where([['id','in',array_column($serialInfoCollect,'pid')],['state','<>',1]])->find(); + if(!empty($serialFind)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + } + } + } + //4 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $store=['sorInfo'=>[],'room'=>[],'roomInfo'=>[],'batch'=>[],'batchInfo'=>[],'serial'=>[],'serialInfo'=>[],'serve'=>[],'serveInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //1 关联单据 + empty($infoVo['source'])||$store['sorInfo'][]=['id'=>$infoVo['source'],'handle'=>$infoVo['nums']]; + //2 判断商品类型 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + if(empty($goods['type'])){ + //常规商品 + //1 仓储 + $store['room'][]=['warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['basic']['nums']]; + //2 仓储详情 + $store['roomInfo'][]=['pid'=>null,'type'=>'sell','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'direction'=>0,'price'=>$infoVo['basic']['price'],'nums'=>$infoVo['basic']['nums']]; + //3 批次号 + if(empty($infoVo['batch'])){ + $store['batch'][]=[]; + $store['batchInfo'][]=[]; + }else{ + $store['batch'][]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'number'=>$infoVo['batch'],'time'=>$infoVo['mfd'],'nums'=>$infoVo['basic']['nums']]; + $store['batchInfo'][]=['pid'=>null,'type'=>'sell','class'=>$class['id'],'info'=>$infoVo['id'],'direction'=>0,'nums'=>$infoVo['basic']['nums']]; + } + //4 序列号 + if(empty($infoVo['serial'])){ + $store['serial'][]=[]; + $store['serialInfo'][]=[]; + }else{ + $serial=[]; + $serialInfo=[]; + foreach ($infoVo['serial'] as $serialVo) { + $serial[]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'batch'=>null,'goods'=>$infoVo['goods'],'number'=>$serialVo,'state'=>1]; + $serialInfo[]=['pid'=>null,'type'=>'sell','class'=>$class['id'],'info'=>$infoVo['id']]; + } + $store['serial'][]=$serial; + $store['serialInfo'][]=$serialInfo; + } + }else{ + //5 服务 + $store['serve'][]=['goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['nums']]; + $store['serveInfo'][]=['pid'=>null,'type'=>'sell','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'price'=>$infoVo['price'],'nums'=>$infoVo['nums']]; + } + } + //2 关联单据 + if(!empty($store['sorInfo'])){ + //1 更新详情 + Db::name('sor_info')->duplicate(['handle'=>Db::raw('handle + VALUES(`handle`)')])->insertAll($store['sorInfo']); + //2 更新CLASS + $sorInfo=Db::name('sor_info')->where([['pid','=',$class['source']]])->select()->toArray(); + $state=mathArraySum(array_column($sorInfo,'nums'))==mathArraySum(array_column($sorInfo,'handle'))?2:1; + Db::name('sor')->where([['id','=',$class['source']]])->update(['state'=>$state]); + } + //3 仓储 + if(!empty($store['room'])){ + //1 构造数据 + $roomInsert=[]; + foreach ($store['room'] as $roomVo) { + $roomFind=search($roomList)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + if(empty($roomFind)){ + $roomVo['nums']=0; + $roomInsert[]=$roomVo; + } + } + //2 创建数据|去重 + empty($roomInsert)||Db::name('room')->insertAll(array_unique($roomInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $roomDuplicate=[]; + $room=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + foreach ($store['room'] as $roomKey=>$roomVo) { + $roomFind=search($room)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + $store['room'][$roomKey]['id']=$roomFind['id']; + $roomDuplicate[]=['id'=>$roomFind['id'],'nums'=>$roomVo['nums']]; + } + //4 更新数据 + Db::name('room')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($roomDuplicate); + } + //4 仓储详情 + if(!empty($store['roomInfo'])){ + //1 填充数据 + foreach ($store['roomInfo'] as $roomInfoKey=>$roomInfoVo) { + $store['roomInfo'][$roomInfoKey]['pid']=$store['room'][$roomInfoKey]['id']; + } + //2 创建数据 + Db::name('room_info')->insertAll($store['roomInfo']); + } + //5 批次号 + if(!empty($store['batch'])){ + //1 构造数据 + $batchData=[]; + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $store['batch'][$batchKey]['room']=$store['room'][$batchKey]['id']; + $batchData[]=$store['batch'][$batchKey]; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchData)){ + //1 构造数据 + $batchInsert=[]; + foreach ($batchData as $batchDataKey=>$batchDataVo) { + $batchFind=search($batchList)->where([['room','=',$batchDataVo['room']],['number','=',$batchDataVo['number']],['time','=',$batchDataVo['time']]])->find(); + if(empty($batchFind)){ + $batchDataVo['nums']=0; + $batchInsert[]=$batchDataVo; + } + } + //2 创建数据|去重 + empty($batchInsert)||Db::name('batch')->insertAll(array_unique($batchInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $batchDuplicate=[]; + $batch=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $batchFind=search($batch)->where([['room','=',$batchVo['room']],['number','=',$batchVo['number']],['time','=',$batchVo['time']]])->find(); + $store['batch'][$batchKey]['id']=$batchFind['id']; + $batchDuplicate[]=['id'=>$batchFind['id'],'nums'=>$batchVo['nums']]; + } + } + //4 更新数据 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($batchDuplicate); + } + } + //6 批次号详情 + if(!empty($store['batchInfo'])){ + //1 构造数据 + $batchInfoInstall=[]; + foreach ($store['batchInfo'] as $batchInfoKey=>$batchInfoVo) { + if(!empty($batchInfoVo)){ + $batchInfoVo['pid']=$store['batch'][$batchInfoKey]['id']; + $batchInfoInstall[]=$batchInfoVo; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchInfoInstall)){ + //创建数据 + Db::name('batch_info')->insertAll($batchInfoInstall); + } + } + //7 序列号 + if(!empty($store['serial'])){ + //1 构造数据 + $serialData=[]; + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $store['serial'][$serialKey][$itemKey]['room']=$store['room'][$serialKey]['id']; + $store['serial'][$serialKey][$itemKey]['batch']=empty($store['batch'][$serialKey])?0:$store['batch'][$serialKey]['id']; + $serialData[]=$store['serial'][$serialKey][$itemKey]; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialData)){ + //1 构造数据 + $serialInsert=[]; + foreach ($serialData as $serialDataKey=>$serialDataVo) { + $serialFind=search($serialList)->where([['room','=',$serialDataVo['room']],['batch','=',$serialDataVo['batch']],['number','=',$serialDataVo['number']]])->find(); + if(empty($serialFind)){ + $serialInsert[]=$serialDataVo; + } + } + //2 创建数据 + empty($serialInsert)||Db::name('serial')->insertAll($serialInsert); + //3 匹配主键|构造更新 + $serialDuplicate=[]; + $serial=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $serialFind=search($serial)->where([['room','=',$itemVo['room']],['batch','=',$itemVo['batch']],['number','=',$itemVo['number']]])->find(); + $store['serial'][$serialKey][$itemKey]['id']=$serialFind['id']; + $serialFind['state']==0&&$serialDuplicate[]=$serialFind['id']; + } + } + } + //4 更新数据|状态变更 + empty($serialDuplicate)||Db::name('serial')->where([['id','in',$serialDuplicate]])->update(['state'=>1]); + } + } + //8 序列号详情 + if(!empty($store['serialInfo'])){ + //1 构造数据 + $serialInfoInstall=[]; + foreach ($store['serialInfo'] as $serialInfoKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $itemVo['pid']=$store['serial'][$serialInfoKey][$itemKey]['id']; + $serialInfoInstall[]=$itemVo; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialInfoInstall)){ + //创建数据 + Db::name('serial_info')->insertAll($serialInfoInstall); + } + } + //9 服务商品 + if(!empty($store['serve'])){ + //1 匹配数据|去重 + $serveWhereOrSql=array_unique(array_map(function($item){ + return [['goods','=',$item['goods']],['attr','=',$item['attr']]]; + },$store['serve']),SORT_REGULAR); + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + //2 构造数据 + $serveInsert=[]; + foreach ($store['serve'] as $serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + if(empty($serveFind)){ + $serveVo['nums']=0; + $serveInsert[]=$serveVo; + } + } + //3 创建数据|去重 + empty($serveInsert)||Db::name('serve')->insertAll(array_unique($serveInsert,SORT_REGULAR)); + //4 匹配主键|构造更新 + $serveDuplicate=[]; + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + foreach ($store['serve'] as $serveKey=>$serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + $store['serve'][$serveKey]['id']=$serveFind['id']; + $serveDuplicate[]=['id'=>$serveFind['id'],'nums'=>$serveVo['nums']]; + } + //5 更新数据 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($serveDuplicate); + } + //10 服务商品详情 + if(!empty($store['serveInfo'])){ + //1 填充数据 + foreach ($store['serveInfo'] as $serveInfoKey=>$serveInfoVo) { + $store['serveInfo'][$serveInfoKey]['pid']=$store['serve'][$serveInfoKey]['id']; + } + //2 创建数据 + Db::name('serve_info')->insertAll($store['serveInfo']); + } + //11 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->inc('balance',$class['money'])->update(); + //2 创建资金详情 + Db::name('account_info')->insert([ + 'pid'=>$class['account'], + 'type'=>'sell', + 'class'=>$class['id'], + 'time'=>$class['time'], + 'direction'=>1, + 'money'=>$class['money'] + ]); + //3 创建核销记录 + Db::name('sell_bill')->insert([ + 'pid'=>$class['id'], + 'type'=>'sell', + 'source'=>$class['id'], + 'time'=>$class['time'], + 'money'=>$class['money'] + ]); + } + //12 客户|应收款余额 + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('customer')->where([['id','=',$class['customer']]])->inc('balance',$balance)->update(); + } + //13 更新单据 + $nucleus=$class['money']==$class['actual']?2:($class['money']==0?0:1); + Db::name('sell')->where([['id','=',$class['id']]])->update(['examine'=>1,'nucleus'=>$nucleus]); + //14 单据记录 + Db::name('record')->insert(['type'=>'sell','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //15 收发记录 + $summary=new Summary; + $summary->note('sell',$class['id'],true); + //16 记录操作 + pushLog('审核销售单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 匹配数据 + $listSql=[['type','=','sell'],['info','in',array_column($info,'id')]]; + $roomInfoList=Db::name('room_info')->where($listSql)->select()->toArray(); + $batchInfoList=Db::name('batch_info')->where($listSql)->select()->toArray(); + $serialInfoList=Db::name('serial_info')->where($listSql)->select()->toArray(); + $serveInfoList=Db::name('serve_info')->where($listSql)->select()->toArray(); + //2 关联单据 + if(!empty($class['source'])){ + //1 更新详情 + $sorInfoDuplicate=[]; + foreach ($info as $infoVo) { + empty($infoVo['source'])||$sorInfoDuplicate[]=['id'=>$infoVo['source'],'handle'=>$infoVo['nums']]; + } + empty($sorInfoDuplicate)||Db::name('sor_info')->duplicate(['handle'=>Db::raw('handle - VALUES(`handle`)')])->insertAll($sorInfoDuplicate); + //2 更新CALSS + $sorInfo=Db::name('sor_info')->where([['pid','=',$class['source']]])->select()->toArray(); + $state=empty(mathArraySum(array_column($sorInfo,'handle')))?0:1; + Db::name('sor')->where([['id','=',$class['source']]])->update(['state'=>$state]); + } + //3 仓储 + $roomDuplicate=[]; + foreach ($roomInfoList as $roomInfoVo) { + $roomDuplicate[]=['id'=>$roomInfoVo['pid'],'nums'=>$roomInfoVo['nums']]; + } + //3.1 更新仓储 + Db::name('room')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($roomDuplicate); + //3.2 删除仓储详情 + Db::name('room_info')->where([['id','in',array_column($roomInfoList,'id')]])->delete(); + //3.3 仓储|冗余 + $roomPk=array_unique(array_column($roomInfoList,'pid')); + $roomInfoData=Db::name('room_info')->where([['pid','in',$roomPk]])->select()->toArray(); + $roomDiff=array_diff($roomPk,array_unique(array_column($roomInfoData,'pid'))); + empty($roomDiff)||Db::name('room')->where([['id','in',$roomDiff]])->delete(); + //4 批次号 + if(!empty($batchInfoList)){ + //1 构造数据 + $batchInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$batchInfoList); + //2 更新批次号 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($batchInfoDuplicate); + //3 删除批次号详情 + Db::name('batch_info')->where([['id','in',array_column($batchInfoList,'id')]])->delete(); + //4 批次号|冗余 + $batchPk=array_unique(array_column($batchInfoList,'pid')); + $batchInfoData=Db::name('batch_info')->where([['pid','in',$batchPk]])->select()->toArray(); + $batchDiff=array_diff($batchPk,array_unique(array_column($batchInfoData,'pid'))); + empty($batchDiff)||Db::name('batch')->where([['id','in',$batchDiff]])->delete(); + } + //5 序列号 + if(!empty($serialInfoList)){ + //1 更新序列号 + Db::name('serial')->where([['id','in',array_column($serialInfoList,'pid')]])->update(['state'=>0]); + //2 删除序列号详情 + Db::name('serial_info')->where([['id','in',array_column($serialInfoList,'id')]])->delete(); + //3 序列号|冗余 + $serialPk=array_unique(array_column($serialInfoList,'pid')); + $serialInfoData=Db::name('serial_info')->where([['pid','in',$serialPk]])->select()->toArray(); + $serialDiff=array_diff($serialPk,array_unique(array_column($serialInfoData,'pid'))); + empty($serialDiff)||Db::name('serial')->where([['id','in',$serialDiff]])->delete(); + } + //6 服务 + if(!empty($serveInfoList)){ + //1 构造数据 + $serveInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$serveInfoList); + //2 更新服务 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($serveInfoDuplicate); + //3 删除服务详情 + Db::name('serve_info')->where([['id','in',array_column($serveInfoList,'id')]])->delete(); + //4 服务|冗余 + $servePk=array_unique(array_column($serveInfoList,'pid')); + $serveInfoData=Db::name('serve_info')->where([['pid','in',$servePk]])->select()->toArray(); + $serveDiff=array_diff($servePk,array_unique(array_column($serveInfoData,'pid'))); + empty($serveDiff)||Db::name('serve')->where([['id','in',$serveDiff]])->delete(); + } + //7 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->dec('balance',$class['money'])->update(); + //2 删除资金详情 + Db::name('account_info')->where([['type','=','sell'],['class','=',$class['id']]])->delete(); + //3 删除核销记录 + Db::name('sell_bill')->where([['pid','=',$class['id']]])->delete(); + } + //8 客户|应收款余额 + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('customer')->where([['id','=',$class['customer']]])->dec('balance',$balance)->update(); + } + //9 更新单据 + Db::name('sell')->where([['id','=',$class['id']]])->update(['examine'=>0,'nucleus'=>0]); + //10 单据记录 + Db::name('record')->insert(['type'=>'sell','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //11 收发记录 + $summary=new Summary; + $summary->note('sell',$class['id'],false); + //12 记录操作 + pushLog('反审核销售单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('sell', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //生成销售退货单 + public function buildSre(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //源数据 + $source=[ + 'class'=>Sells::where([['id','=',$input['id']]])->find(), + 'info'=>SellInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['id']]])->order(['id'=>'asc'])->select()->toArray() + ]; + //状态验证 + if(mathArraySum(array_column($source['info'],'nums'))==mathArraySum(array_column($source['info'],'retreat'))){ + $result=['state'=>'warning','info'=>'操作失败,无可生成的数据!']; + }else{ + //CLASS数据 + $class=[ + 'source'=>$source['class']['id'], + 'customer'=>$source['class']['customer'], + 'total'=>0 + ]; + //INFO数据 + $info=[]; + $fun=getSys('fun'); + foreach ($source['info'] as $infoVo) { + //判断入库状态 + if(bccomp($infoVo['nums'],$infoVo['retreat'])==1){ + $infoVo['source']=$infoVo['id']; + $infoVo['serial']=[]; + //重算价格 + $infoVo['nums']=math()->chain($infoVo['nums'])->sub($infoVo['retreat'])->done(); + $storage=math()->chain($infoVo['price'])->mul($infoVo['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($infoVo['discount']==0){ + $infoVo['total']=$storage; + }else{ + $infoVo['dsc']=math()->chain($storage)->div(100)->mul($infoVo['discount'])->round($fun['digit']['money'])->done(); + $infoVo['total']=math()->chain($storage)->sub($infoVo['dsc'])->done(); + } + //税额|价税合计 + if($infoVo['tax']==0){ + $infoVo['tpt']=$infoVo['total']; + }else{ + $infoVo['tat']=math()->chain($infoVo['total'])->div(100)->mul($infoVo['tax'])->round(2)->done(); + $infoVo['tpt']=math()->chain($infoVo['total'])->add($infoVo['tat'])->done(); + } + //转存数据 + $info[]=$infoVo; + $class['total']=math()->chain($class['total'])->add($infoVo['tpt'])->done();//累加单据金额 + } + } + $result=['state'=>'success','info'=>['class'=>$class,'info'=>$info]]; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //客户匹配 + $customer=Db::name('customer')->where([['name','=',$data[3]['A']]])->find(); + if(empty($customer)){ + throw new ValidateException('客户[ '.$data[3]['A'].' ]未匹配!'); + } + //结算账户匹配 + if(empty($data[3]['F'])){ + $account=['id'=>0]; + }else{ + $account=Db::name('account')->where([['name','=',$data[3]['G']]])->find(); + if(empty($account)){ + throw new ValidateException('结算账户[ '.$data[3]['G'].' ]不正确!'); + } + } + //关联人员匹配 + if(empty($data[3]['H'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['H']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['H'].' ]未匹配!'); + } + } + $class=[ + 'source'=>0, + 'frame'=>userInfo(getUserID(),'frame'), + 'customer'=>$customer['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'actual'=>$data[3]['E'], + 'money'=>$data[3]['F'], + 'account'=>$account['id'], + 'people'=>$people['id'], + 'logistics'=>["key"=>"auto","name"=>"自动识别","number"=>$data[3]['I']], + 'file'=>[], + 'data'=>$data[3]['J'], + 'more'=>[], + 'examine'=>0, + 'nucleus'=>0, + 'cse'=>0, + 'invoice'=>0, + 'check'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Sell');//数据合法性验证 + //初始化INFO + $info=[]; + $goods=Goods::with(['attr'])->where([['name','in',array_column($data,'K')]])->select()->toArray(); + $warehouse=Db::name('warehouse')->where([['name','in',array_column($data,'N')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'source'=>0, + 'goods'=>$dataVo['K'], + 'attr'=>$dataVo['L'], + 'unit'=>$dataVo['M'], + 'warehouse'=>$dataVo['N'], + 'batch'=>$dataVo['O'], + 'mfd'=>$dataVo['P'], + 'price'=>$dataVo['Q'], + 'nums'=>$dataVo['R'], + 'serial'=>explode(',',$dataVo['S']), + 'discount'=>$dataVo['T'], + 'dsc'=>0, + 'total'=>0, + 'tax'=>$dataVo['W'], + 'tat'=>0, + 'tpt'=>0, + 'data'=>$dataVo['Z'], + 'retreat'=>0, + ]; + //商品匹配 + $goodsFind=search($goods)->where([['name','=',$record['goods']]])->find(); + if(empty($goodsFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行商品名称[ '.$record['goods'].' ]未匹配!'); + }else{ + $record['goods']=$goodsFind['id']; + } + //辅助属性匹配 + if(empty($goodsFind['attr'])){ + $record['attr']=''; + }else{ + if(empty($record['attr'])){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性不可为空!'); + }else{ + $attrFind=search($goodsFind['attr'])->where([['name','=',$record['attr']]])->find(); + if(empty($attrFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性[ '.$record['attr'].' ]未匹配!'); + } + } + } + //单位匹配 + if($goodsFind['unit']==-1){ + if(empty($record['unit'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单位不可为空!'); + }else{ + $unitFind=search($goodsFind['units'])->where([['name','=',$record['unit']]])->find(); + if(empty($unitFind) && $goodsFind['units'][0]['source']!=$record['unit']){ + throw new ValidateException('模板文件第'.$dataKey.'行单位[ '.$record['unit'].' ]未匹配!'); + } + } + }else{ + $record['unit']=$goodsFind['unit']; + } + //仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $warehouseFind=search($warehouse)->where([['name','=',$record['warehouse']]])->find(); + if(empty($warehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行仓库[ '.$record['warehouse'].' ]未匹配!'); + }else{ + $record['warehouse']=$warehouseFind['id']; + } + }else{ + //服务产品 + $record['warehouse']=null; + } + //批次号匹配 + if(empty($goodsFind['batch'])){ + $record['batch']=''; + }else{ + if(empty($record['batch'])){ + throw new ValidateException('模板文件第'.$dataKey.'行批次号不可为空!'); + } + } + //生产日期匹配 + if(empty($goodsFind['validity'])){ + $record['mfd']=''; + }else{ + if(empty($record['mfd'])){ + throw new ValidateException('模板文件第'.$dataKey.'行生产日期不可为空!'); + } + } + //单价匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['price'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单价不正确!'); + } + //数量匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['nums']."})?$/",$record['nums'])){ + throw new ValidateException('模板文件第'.$dataKey.'行数量不正确!'); + } + //序列号匹配 + if(empty($goodsFind['serial'])){ + $record['serial']=[]; + }else{ + if(count($record['serial'])==1 && empty($record['serial'][0])){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号不可为空!'); + }else{ + if(count($record['serial'])!=$record['nums']){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号个数与数量不符!'); + } + } + } + try{ + $this->validate($record,'app\validate\SellInfo');//数据合法性验证 + $storage=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($record['discount']==0){ + $record['total']=$storage; + }else{ + $record['dsc']=math()->chain($storage)->div(100)->mul($record['discount'])->round($fun['digit']['money'])->done(); + $record['total']=math()->chain($storage)->sub($record['dsc'])->done(); + } + //税额|价税合计 + if($record['tax']==0){ + $record['tpt']=$record['total']; + }else{ + $record['tat']=math()->chain($record['total'])->div(100)->mul($record['tax'])->round(2)->done(); + $record['tpt']=math()->chain($record['total'])->add($record['tat'])->done(); + } + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['tpt'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + //序列号重复验证 + $serials=[]; + foreach ($info as $infoVo) { + $serials = array_merge($serials,$infoVo['serial']); + } + if(count($serials)!=count(array_unique($serials))){ + throw new ValidateException('商品信息中存在重复序列号!'); + } + //CLASS数据验证 + if(bccomp($class['total'],$class['actual'])==-1){ + throw new ValidateException('实际金额不可大于单据金额[ '.$class['total'].' ]!'); + }else if(bccomp($class['actual'],$class['money'])==-1){ + throw new ValidateException('实收金额不可大于实际金额[ '.floatval($class['actual']).' ]!'); + }else{ + Db::startTrans(); + try { + //新增CLASS + $classData=Sells::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new SellInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'sell','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入销售单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出销售单列表');//日志 + $source=Sells::with(['frameData','customerData','accountData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'actual'=>'实际金额', + 'money'=>'单据收款', + 'extension|amount'=>'核销金额', + 'cost'=>'单据费用', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|nucleus'=>'核销状态', + 'extension|cse'=>'费用状态', + 'extension|invoice'=>'发票状态', + 'extension|check'=>'核对状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据金额:'.mathArraySum(array_column($source,'total')), + '总实际金额:'.mathArraySum(array_column($source,'actual')), + '总单据收款:'.mathArraySum(array_column($source,'money')), + '总核销金额:'.mathArraySum(arrayColumns($source,['extension','amount'])), + '总单据费用:'.mathArraySum(array_column($source,'cost')) + ]]; + //导出execl + buildExcel('销售单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '客户:'.$sourceVo['customerData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'goodsData|spec'=>'规格型号', + 'attr'=>'辅助属性', + 'unit'=>'单位', + 'warehouseData|name'=>'仓库', + 'batch'=>'批次号', + 'mfd'=>'生产日期', + 'price'=>'单价', + 'nums'=>'数量', + 'extension|serial'=>'序列号', + 'retreat'=>'退货数量', + 'discount'=>'折扣率', + 'dsc'=>'折扣额', + 'total'=>'金额', + 'tax'=>'税率', + 'tat'=>'税额', + 'tpt'=>'价税合计', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=SellInfo::with(['goodsData','warehouseData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->append(['extension'])->select()->toArray(); + //批次号匹配 + if(empty(search($info)->where([['goodsData|batch','=',true]])->find())){ + unset($field['batch']); + } + //生产日期匹配 + if(empty(search($info)->where([['goodsData|validity','=',true]])->find())){ + unset($field['mfd']); + } + //序列号匹配 + if(empty(search($info)->where([['goodsData|serial','=',true]])->find())){ + unset($field['extension|serial']); + } + //退货数量匹配 + if(empty(search($info)->where([['retreat','<>',0]])->find())){ + unset($field['retreat']); + } + //税金匹配 + $fun=getSys('fun'); + if(empty(search($info)->where([['tax','<>',0]])->find()) && !$fun['tax']){ + unset($field['tax']); + unset($field['tat']); + unset($field['tpt']); + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '单据费用:'.$sourceVo['cost'], + '实际金额:'.$sourceVo['actual'], + '核销金额:'.$sourceVo['extension']['amount'], + '结算账户:'.arraySeek($sourceVo,'accountData|name'), + '发票信息:'.$sourceVo['invoice'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '物流信息:'.$sourceVo['extension']['logistics'], + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + + } + buildZip('销售单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Serial.php b/serve/app/controller/Serial.php new file mode 100644 index 0000000..5995408 --- /dev/null +++ b/serve/app/controller/Serial.php @@ -0,0 +1,450 @@ +where(empty($input['warehouse'])?sqlAuth('warehouse',[]):[['id','in',$input['warehouse']]])->select()->toArray(); + //匹配商品 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'], + ['spec','fullLike'], + ['brand','fullEq'], + ['code','fullLike'] + ]);//构造SQL + //商品类型 + $sql[]=['type','=',0]; + //辅助属性扩展查询 + $sqlOr=existFull($input,['code'])?[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]:[]; + //商品分类树结构查询 + existFull($input,['category'])&&$sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + //批次查询 + $serialSql=fastSql($input,[ + [['serial'=>'number'],'fullLike'], + ['state','fullDec1'] + ]);//构造SQL + $serialSql[]=['warehouse','in',array_column($warehouse,'id')]; + //查询操作 + if(existFull($input,['batch'])){ + $exists=Db::name('batch')->where([['number','like','%'.$input['batch'].'%'],['id','=',Db::raw('serial.batch')]])->buildSql(false); + $serial=Db::name('serial')->where($serialSql)->alias('serial')->whereExists($exists)->select()->toArray(); + }else{ + $serial=Db::name('serial')->where($serialSql)->select()->toArray(); + } + //查询商品 + $sql[]=['id','in',array_column($serial,'goods')]; + //获取总条数 + $count = Goods::where($sql)->whereOr($sqlOr)->count(); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->order(['id'=>'desc'])->page($input['page'],$input['limit'])->append(['extension'])->select()->toArray(); + //唯一标识|属性处理 + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['key']=$infoVo['id']; + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + $info[$infoKey]['attr'][$attrKey]['key']=$infoVo['id'].'.'.$attrVo['id']; + //属性处理 + if(existFull($input,['code']) && !in_array($input['code'],[$infoVo['code'],$attrVo['code']])){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //库存集合[g:商品|a:属性] + $gather=['g'=>[],'ga'=>[]]; + //二次匹配 + $serial=search($serial)->where([['goods','in',array_column($info,'id')]])->select(); + //查询库存数据-仓储 + $room=Db::name('room')->where([['id','in',array_unique(array_column($serial,'room'))]])->select()->toArray(); + //构造序列数据 + foreach ($serial as $serialKey=>$serialVo) { + //商品 + $g=md5_16($serialVo['goods']); + $gather['g'][$g]=math()->chain($gather['g'][$g]??0)->add(1)->done(); + //判断属性 + $find=search($room)->where([['id','=',$serialVo['room']]])->find(); + if(empty($find['attr'])){ + $serial[$serialKey]['attr']=null; + }else{ + //商品|属性 + $ga=md5_16($serialVo['goods'].'&'.$find['attr']); + $gather['ga'][$ga]=math()->chain($gather['ga'][$ga]??0)->add(1)->done(); + $serial[$serialKey]['attr']=$find['attr']; + } + } + //匹配数据 + $batch=Db::name('batch')->where([['id','in',array_unique(array_column($serial,'batch'))]])->select()->toArray(); + foreach ($info as $infoKey=>$infoVo) { + //商品 + $g=md5_16($infoVo['id']); + $info[$infoKey]['summary']=isset($gather['g'][$g])?$gather['g'][$g]:0; + if(empty($infoVo['attr'])){ + $list=search($serial)->where([['goods','=',$infoVo['id']],['attr','=',null]])->select(); + foreach ($list as $listVo) { + $row=[ + 'key'=>md5_16($infoVo['id'].'&'.$listVo['id']), + 'serial'=>$listVo['id'], + 'name'=>$listVo['number'], + 'summary'=>1, + 'state'=>['未销售','已销售','已调拨','已退货'][$listVo['state']] + ]; + //仓库信息 + $warehouseFind=search($warehouse)->where([['id','=',$listVo['warehouse']]])->find(); + $row['warehouse']=$warehouseFind['name']; + //批次信息 + if(empty($listVo['batch'])){ + $row['batch']=''; + }else{ + $batchFind=search($batch)->where([['id','=',$listVo['batch']]])->find(); + $row['batch']=$batchFind['number']; + } + $info[$infoKey]['attr'][]=$row; + } + }else{ + $list=search($serial)->where([['goods','=',$infoVo['id']],['attr','<>',null]])->select(); + //匹配辅助属性 + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //商品|属性 + $ga=md5_16($infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['summary']=isset($gather['ga'][$ga])?$gather['ga'][$ga]:0; + $select=search($list)->where([['attr','=',$attrVo['name']]])->select(); + foreach ($select as $selectVo) { + $row=[ + 'key'=>md5_16($infoVo['id'].'&'.$selectVo['id']), + 'serial'=>$selectVo['id'], + 'name'=>$selectVo['number'], + 'summary'=>1, + 'state'=>['未销售','已销售','已调拨','已退货'][$selectVo['state']] + ]; + //仓库信息 + $warehouseFind=search($warehouse)->where([['id','=',$selectVo['warehouse']]])->find(); + $row['warehouse']=$warehouseFind['name']; + //批次信息 + if(empty($selectVo['batch'])){ + $row['batch']=''; + }else{ + $batchFind=search($batch)->where([['id','=',$selectVo['batch']]])->find(); + $row['batch']=$batchFind['number']; + } + $info[$infoKey]['attr'][$attrKey]['attr'][]=$row; + } + if(empty($select))unset($info[$infoKey]['attr'][$attrKey]); + } + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + + //导出 + public function exports(){ + $input=input('get.'); + existFull($input,['warehouse'])||$input['warehouse']=[]; + if(isset($input['warehouse']) && is_array($input['warehouse'])){ + pushLog('导出序列列表');//日志 + //匹配仓库 + $warehouse = Db::name('warehouse')->where(empty($input['warehouse'])?sqlAuth('warehouse',[]):[['id','in',$input['warehouse']]])->select()->toArray(); + //匹配商品 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'], + ['spec','fullLike'], + ['brand','fullEq'], + ['code','fullLike'] + ]);//构造SQL + //商品类型 + $sql[]=['type','=',0]; + //辅助属性扩展查询 + $sqlOr=existFull($input,['code'])?[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]:[]; + //商品分类树结构查询 + existFull($input,['category'])&&$sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + //批次查询 + $serialSql=fastSql($input,[ + [['serial'=>'number'],'fullLike'], + ['state','fullDec1'] + ]);//构造SQL + $serialSql[]=['warehouse','in',array_column($warehouse,'id')]; + //查询操作 + if(existFull($input,['batch'])){ + $exists=Db::name('batch')->where([['number','like','%'.$input['batch'].'%'],['id','=',Db::raw('serial.batch')]])->buildSql(false); + $serial=Db::name('serial')->where($serialSql)->alias('serial')->whereExists($exists)->select()->toArray(); + }else{ + $serial=Db::name('serial')->where($serialSql)->select()->toArray(); + } + //查询商品 + $sql[]=['id','in',array_column($serial,'goods')]; + //获取总条数 + $count = Goods::where($sql)->whereOr($sqlOr)->count(); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //唯一标识|属性处理 + foreach ($info as $infoKey=>$infoVo) { + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //属性处理 + if(existFull($input,['code']) && !in_array($input['code'],[$infoVo['code'],$attrVo['code']])){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //库存集合[g:商品|a:属性] + $gather=['g'=>[],'ga'=>[]]; + //二次匹配 + $serial=search($serial)->where([['goods','in',array_column($info,'id')]])->select(); + //查询库存数据-仓储 + $room=Db::name('room')->where([['id','in',array_unique(array_column($serial,'room'))]])->select()->toArray(); + //构造序列数据 + foreach ($serial as $serialKey=>$serialVo) { + //商品 + $g=md5_16($serialVo['goods']); + $gather['g'][$g]=math()->chain($gather['g'][$g]??0)->add(1)->done(); + //判断属性 + $find=search($room)->where([['id','=',$serialVo['room']]])->find(); + if(empty($find['attr'])){ + $serial[$serialKey]['attr']=null; + }else{ + //商品|属性 + $ga=md5_16($serialVo['goods'].'&'.$find['attr']); + $gather['ga'][$ga]=math()->chain($gather['ga'][$ga]??0)->add(1)->done(); + $serial[$serialKey]['attr']=$find['attr']; + } + } + //匹配数据 + $batch=Db::name('batch')->where([['id','in',array_unique(array_column($serial,'batch'))]])->select()->toArray(); + foreach ($info as $infoKey=>$infoVo) { + //商品 + $g=md5_16($infoVo['id']); + $info[$infoKey]['summary']=isset($gather['g'][$g])?$gather['g'][$g]:0; + if(empty($infoVo['attr'])){ + $list=search($serial)->where([['goods','=',$infoVo['id']],['attr','=',null]])->select(); + foreach ($list as $listVo) { + $row=[ + 'name'=>$listVo['number'], + 'summary'=>1, + 'state'=>['未销售','已销售','已调拨','已退货'][$listVo['state']] + ]; + //仓库信息 + $warehouseFind=search($warehouse)->where([['id','=',$listVo['warehouse']]])->find(); + $row['warehouse']=$warehouseFind['name']; + //批次信息 + if(empty($listVo['batch'])){ + $row['batch']=''; + }else{ + $batchFind=search($batch)->where([['id','=',$listVo['batch']]])->find(); + $row['batch']=$batchFind['number']; + } + $info[$infoKey]['attr'][]=$row; + } + }else{ + $list=search($serial)->where([['goods','=',$infoVo['id']],['attr','<>',null]])->select(); + //匹配辅助属性 + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //商品|属性 + $ga=md5_16($infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['summary']=isset($gather['ga'][$ga])?$gather['ga'][$ga]:0; + $select=search($list)->where([['attr','=',$attrVo['name']]])->select(); + foreach ($select as $selectVo) { + $row=[ + 'name'=>$selectVo['number'], + 'summary'=>1, + 'state'=>['未销售','已销售','已调拨','已退货'][$selectVo['state']] + ]; + //仓库信息 + $warehouseFind=search($warehouse)->where([['id','=',$selectVo['warehouse']]])->find(); + $row['warehouse']=$warehouseFind['name']; + //批次信息 + if(empty($selectVo['batch'])){ + $row['batch']=''; + }else{ + $batchFind=search($batch)->where([['id','=',$selectVo['batch']]])->find(); + $row['batch']=$batchFind['number']; + } + $info[$infoKey]['attr'][$attrKey]['attr'][]=$row; + } + if(empty($select))unset($info[$infoKey]['attr'][$attrKey]); + } + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + } + //结构重组 + $source=[]; + foreach ($info as $infoVo) { + $source[]=$infoVo; + if(!empty($infoVo['attr'])){ + foreach ($infoVo['attr'] as $attrVo) { + $attrVo['name']='|- '.$attrVo['name']; + $source[]=$attrVo; + if(existFull($attrVo,['attr'])){ + foreach ($attrVo['attr'] as $subVo) { + $subVo['name']='|-- '.$subVo['name']; + $source[]=$subVo; + } + } + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'序列列表']; + //表格数据 + $field=array_merge(['name'=>'商品名称','summary'=>'库存数量','state'=>'序列状态','warehouse'=>'所属仓库','batch'=>'所属批次','number'=>'商品编号','spec'=>'规格型号','categoryData|name'=>'商品分类','brand'=>'商品品牌','extension|unit'=>'商品单位','code'=>'商品条码','data'=>'商品备注']); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('序列列表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } + + + //详情列表 + public function detailRecord(){ + $input=input('post.'); + $sheet=['buy','bre','sell','sre','swapOut','swapEnter','entry','extry']; + existFull($input,['type'])||$input['type']=$sheet; + if(existFull($input,['page','limit','serial']) && is_arrays($input,['serial','type']) && arrayInArray($input['type'],$sheet)){ + //构造SQL|serial + $sql=fastSql($input,[ + [['serial'=>'id'],'fullIn'] + ]); + //查询仓储数据 + $serial=Db::name('serial')->where($sql)->field(['id'])->select()->toArray(); + if(empty($serial)){ + $count=0; + $info=[]; + }else{ + //构造SQL|SERIALINFO + $infoSql=fastSql($input,[['type','fullIn']]); + $infoSql[]=['pid','in',array_column($serial,'id')]; + //子查询SQL + $existsSql=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['id','=',Db::raw('info.class')]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + //匹配类型|减少查询 + if(in_array($k,$input['type'])){ + $union[]=Db::name($v)->where([['info.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $count=SerialInfo::alias('info')->where($infoSql)->whereExists($union)->count(); + $info=SerialInfo::with(['sourceData'=>['frameData']])->alias('info')->where($infoSql)->whereExists($union)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //详情导出 + public function detailExports(){ + $input=input('get.'); + $sheet=['buy','bre','sell','sre','swapOut','swapEnter','entry','extry']; + existFull($input,['serial'])||$input['serial']=[]; + existFull($input,['type'])||$input['type']=$sheet; + if(existFull($input,['serial']) && is_arrays($input,['serial','type']) && arrayInArray($input['type'],$sheet)){ + pushLog('导出序列详情');//日志 + //构造SQL|serial + $sql=fastSql($input,[ + [['serial'=>'id'],'fullIn'] + ]); + //查询仓储数据 + $serial=Db::name('serial')->where($sql)->field(['id','number'])->select()->toArray(); + if(empty($serial)){ + $source=[]; + }else{ + //构造SQL|SERIALINFO + $infoSql=fastSql($input,[['type','fullIn']]); + $infoSql[]=['pid','in',array_column($serial,'id')]; + //子查询SQL + $existsSql=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['id','=',Db::raw('info.class')]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + //匹配类型|减少查询 + if(in_array($k,$input['type'])){ + $union[]=Db::name($v)->where([['info.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $source=SerialInfo::with(['sourceData'=>['frameData']])->alias('info')->where($infoSql)->whereExists($union)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'序列详情']; + //表格数据 + $field=[ + 'sourceData|frameData|name'=>'所属组织', + 'sourceData|time'=>'操作时间', + 'extension|type'=>'单据类型', + 'sourceData|number'=>'单据编号' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('序列详情',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Service.php b/serve/app/controller/Service.php new file mode 100644 index 0000000..63cc844 --- /dev/null +++ b/serve/app/controller/Service.php @@ -0,0 +1,627 @@ +select()->toArray(),-1); + }else{ + $frame=Db::name('frame')->where([['id','in',$userFrame]])->select()->toArray(); + //追加子数据 + foreach ($frame as $frameKey=>$frameVo) { + $frame[$frameKey]['sub']=[]; + } + } + //获取用户权限菜单 + $menu = $tree::hTree(getRootMemu()); + //获取全局字段配置 + $fields = getFields(); + //获取用户权限数据 + $root = getUserRoot(); + //获取商品类别数据 + $category = $tree::hTree(Db::name('category')->order(['sort'=>'asc'])->select()->toArray(),-1); + //获取仓库数据 + $warehouse=Db::name('warehouse')->where(sqlAuth('warehouse',[]))->field(['id','name'])->order(['id'=>'desc'])->select(); + //获取资金账户 + $account=Db::name('account')->where(sqlAuth('account',[]))->field(['id','name'])->order(['id'=>'desc'])->select(); + //获取收支类别 + $ietList=Db::name('iet')->order(['sort'=>'asc'])->select()->toArray(); + $iet=['in'=>search($ietList)->where([['type','=',0]])->select(),'out'=>search($ietList)->where([['type','=',1]])->select()]; + //获取常用功能 + $often = Db::name('often')->where([['user','=',getUserId()]])->field(['name','key'])->select(); + //获取系统参数 + $sys = getSys(['name','icp','notice','brand','unit','crCategory','crGrade','srCategory','fun','logistics']); + //返回数据 + return json(['state' => 'success','info' => [ + 'frame' => $frame, + 'menu' => $menu, + 'fields' => $fields, + 'root'=>$root, + 'category' => $category, + 'warehouse' => $warehouse, + 'account' => $account, + 'iet' => $iet, + 'often' => $often, + 'sys' => $sys + ]]); + } + //获取|组织数据 + public function getFrame(){ + $cache=cache(getToken()); + $result = ['state' => 'success','info'=>isset($cache['frame'])?$cache['frame']:[]]; + return json($result); + } + //保存|组织数据 + public function saveFrame(){ + $input=input('post.'); + if(existFull($input,['parm']) || is_array($input['parm'])){ + $token=getToken(); + $cache=cache($token); + $cache['frame']=$input['parm']; + cache($token,$cache); + $result = ['state' => 'success']; + }else{ + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //获取|商品列表 + public function goodsRecord(){ + $input = input('post.'); + if (existFull($input,['page','limit'])) { + $sql=fastSql($input,[ + [['mate'=>'name|py|number|spec'],'fullLike'], + ['code','fullEq'], + ['brand','fullEq'], + ['type','fullDec1'], + ['data','fullLike'] + ]); + //辅助属性扩展查询 + $sqlOr=existFull($input,['code'])?[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]:[]; + //商品分类树结构查询 + existFull($input,['category'])&&$sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + //获取总条数 + $count = Goods::where($sql)->whereOr($sqlOr)->count(); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //唯一标识|属性处理 + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['key']=$infoVo['id']; + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + $info[$infoKey]['attr'][$attrKey]['key']=$infoVo['id'].'.'.$attrVo['id']; + //属性处理 + if(existFull($input,['code']) && !in_array($input['code'],[$infoVo['code'],$attrVo['code']])){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + //返回数据 + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //商品|扫码接口 + public function goodsScan(){ + $input = input('post.'); + if (existFull($input,['code'])) { + $sql=[['code','=',$input['code']]]; + $sqlOr=[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]; + //查询数据 + $info = Goods::with(['attr'])->where($sql)->whereOr($sqlOr)->order(['id'=>'desc'])->select()->toArray(); + //处理|辅助属性条形码 + foreach ($info as $infoKey=>$infoVo) { + //匹配|有辅助属性|主条形码不同 + if(!empty($infoVo['attr']) && $infoVo['code']!=$input['code']){ + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + if($attrVo['code']!=$input['code']){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + } + $result = [ + 'state' => 'success', + 'info' => $info + ]; + //返回数据 + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //获取|库存信息 + public function goodsDepot(){ + $input = input('post.'); + if (existFull($input,['page','limit','goods']) && isset($input['attr'])){ + //查询数据 + $warehouseSql=sqlAuth('warehouse',[]); + $count=Db::name('warehouse')->where($warehouseSql)->count(); + $warehouse=Db::name('warehouse')->where($warehouseSql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //匹配数据 + $room=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['goods','=',$input['goods']],['attr','=',$input['attr']]])->select()->toArray(); + //构造数据 + $info=[]; + foreach ($warehouse as $warehouseVo) { + $item=['warehouse'=>$warehouseVo['id']]; + $item['name']=$warehouseVo['name']; + //仓储查询 + $roomFind=search($room)->where([['warehouse','=',$warehouseVo['id']]])->find(); + //记录赋值 + $item['nums']=empty($roomFind)?0:floatval($roomFind['nums']); + //记录转存 + $info[]=$item; + } + //数据处理|单位转换 + $goods=Db::name('goods')->where([['id','=',$input['goods']]])->find(); + if($goods['unit']=='-1'){ + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['nums']=unitSwitch($infoVo['nums'],json_decode($goods['units'],true)); + } + } + //返回数据 + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //商品|最近价格 + public function recentPrice(){ + $input = input('post.'); + if(existFull($input,['model','source','goods']) && in_array($input['model'],['bor','buy','bre','sor','sell','sre']) && isset($input['attr']) && isset($input['unit'])){ + $model=$input['model']; + //构造CLASS条件 + $sql=[['examine','=',1]]; + //场景匹配 + in_array($model,['bor','buy','bre'])&&$sql[]=['supplier','=',$input['source']];//供应商 + in_array($model,['sor','sell','sre'])&&$sql[]=['customer','=',$input['source']];//客户 + //查询CLASS数据 + $sql=sqlAuth($model,$sql);//数据鉴权 + $class=Db::name($model)->where($sql)->field(['id'])->order(['id'=>'desc'])->select()->toArray(); + if(empty($class)){ + $result = ['state' => 'success','info' => 0]; + }else{ + //查询INFO数据 + $parm=[ + ['pid','in',array_column($class,'id')], + ['goods','=',$input['goods']], + ['attr','=',$input['attr']], + ['unit','=',$input['unit']] + ]; + $info=Db::name($model.'_info')->where($parm)->order(['pid'=>'desc'])->find(); + if(empty($info)){ + $result = ['state' => 'success','info' => 0]; + }else{ + $result = ['state' => 'success','info' => floatval($info['price'])]; + } + } + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //商品序列号 + public function getSerial(){ + $input = input('post.'); + if(existFull($input,['page','limit','warehouse','goods']) && isset($input['attr']) && isset($input['batch']) && isset($input['mfd']) && isset($input['state'])){ + $room=Db::name('room')->where([['warehouse','=',$input['warehouse']],['goods','=',$input['goods']],['attr','=',$input['attr']]])->find(); + if(empty($room)){ + $result = ['state' => 'success','count' => 0,'info' => []]; + }else{ + if(empty($input['batch'])){ + $batch=['id'=>0]; + }else{ + $batch=Db::name('batch')->where([['room','=',$room['id']],['number','=',$input['batch']],['time','=',empty($input['mfd'])?0:strtotime($input['mfd'])]])->find(); + if(empty($batch)){ + return json(['state' => 'success','count' => 0,'info' => []]); + exit; + } + } + $count=Serial::where([['room','=',$room['id']],['batch','=',$batch['id']],['state','=',$input['state']]])->count(); + $info=Serial::where([['room','=',$room['id']],['batch','=',$batch['id']],['state','=',$input['state']]])->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'asc'])->select(); + $result = ['state' => 'success','count' => $count,'info' => $info]; + } + }else{ + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //商品批次号 + public function getBatch(){ + $input = input('post.'); + if(existFull($input,['page','limit','warehouse','goods']) && isset($input['attr'])){ + //匹配仓储 + $room=Db::name('room')->where([['warehouse','=',$input['warehouse']],['goods','=',$input['goods']],['attr','=',$input['attr']]])->find(); + if(empty($room)){ + $result = ['state' => 'success','count' => 0,'info' => []]; + }else{ + //匹配批次号 + $sql=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]);//构造SQL + $sql[]=['room','=',$room['id']]; + $count=Batch::where($sql)->count(); + $info=Batch::where($sql)->page($input['page'],$input['limit'])->order(['id'=>'asc'])->select()->toArray(); + //数据处理|单位转换 + $goods=Db::name('goods')->where([['id','=',$input['goods']]])->find(); + if($goods['unit']=='-1'){ + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['nums']=unitSwitch($infoVo['nums'],json_decode($goods['units'],true)); + } + } + $result = ['state' => 'success','count' => $count,'info' => $info]; + } + }else{ + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //单据列表 + public function billRecord(){ + $input = input('post.'); + if (existFull($input,['page','limit','mold']) && in_array($input['mold'],['imy','omy','buy','bre','sell','sre','ice','oce'])) { + if(in_array($input['mold'],['omy','buy','bre','oce'])){ + $sql=fastSql($input,[ + ['supplier','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['user','fullEq'], + ['data','fullLike'] + ]); + }else{ + $sql=fastSql($input,[ + ['customer','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['user','fullEq'], + ['data','fullLike'] + ]); + } + $sql[]=['examine','=',1]; + $sql[]=existFull($input,['nucleus'])?['nucleus','=',$input['nucleus']-1]:['nucleus','in',[0,1]]; + $sql=sqlAuth($input['mold'],$sql);//数据鉴权 + $table=['imy'=>'\app\model\Imy','omy'=>'\app\model\Omy','buy'=>'\app\model\Buy','bre'=>'\app\model\Bre','sell'=>'\app\model\Sell','sre'=>'\app\model\Sre','ice'=>'\app\model\Ice','oce'=>'\app\model\Oce']; + $count = $table[$input['mold']]::where($sql)->count();//获取总条数 + $info = $table[$input['mold']]::with(['frameData','userData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + //数据处理 + foreach ($info as $key=>$vo) { + in_array($input['mold'],['buy','bre','sell','sre','ice','oce'])&&$info[$key]['total']=$vo['actual']; + } + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + //返回数据 + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //匹配|下拉接口 + public function getScene() { + $input = input('post.'); + if (existFull($input,['id','scene'])) { + $find=Db::name($input['scene'])->where([['id','=',$input['id']]])->find(); + $result=['state' => 'success','info' => $find]; + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //用户角色|下拉接口 + public function roleRecord() { + $input = input('post.'); + if (existFull($input,['page','limit'])) { + //构造SQL + $sql = fastSql($input,[ + [['query'=>'name|py'],'fullLike'] + ]); + $count = Db::name('role')->where($sql)->count(); + //获取总条数 + $info = Db::name('role')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //查询分页数据 + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + //返回数据 + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //用户数据|下拉接口 + public function userRecord() { + $input = input('post.'); + if (existFull($input,['page','limit'])) { + //构造SQL + $sql = fastSql($input,[ + [['query'=>'name|py'],'fullLike'] + ]); + isset($input['noAuth']) || ($sql = sqlAuth('user',$sql)); + //数据鉴权 + $count = Db::name('user')->where($sql)->count(); + //获取总条数 + $info = Db::name('user')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //查询分页数据 + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + //返回数据 + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //人员数据|下拉接口 + public function peopleRecord() { + $input = input('post.'); + if (existFull($input,['page','limit'])) { + //构造SQL + $sql = fastSql($input,[ + [['query'=>'name|py'],'fullLike'] + ]); + isset($input['noAuth']) || ($sql = sqlAuth('people',$sql)); + //数据鉴权 + $count = Db::name('people')->where($sql)->count(); + //获取总条数 + $info = Db::name('people')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //查询分页数据 + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + //返回数据 + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //仓库数据|下拉接口 + public function warehouseRecord() { + $input = input('post.'); + if (existFull($input,['page','limit'])) { + //构造SQL + $sql = fastSql($input,[ + [['query'=>'name|py'],'fullLike'] + ]); + $sql = sqlAuth('warehouse',$sql);//数据鉴权 + $count = Db::name('warehouse')->where($sql)->count(); + //获取总条数 + $info = Db::name('warehouse')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //查询分页数据 + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + //返回数据 + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //供应商数据|下拉接口 + public function supplierRecord() { + $input = input('post.'); + if (existFull($input,['page','limit'])) { + //构造SQL + $sql = fastSql($input,[ + [['query'=>'name|py'],'fullLike'] + ]); + $sql = sqlAuth('supplier',$sql);//数据鉴权 + $count = Db::name('supplier')->where($sql)->count(); + //获取总条数 + $info = Db::name('supplier')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //查询分页数据 + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + //返回数据 + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //客户数据|下拉接口 + public function customerRecord() { + $input = input('post.'); + if (existFull($input,['page','limit'])) { + //构造SQL + $sql = fastSql($input,[ + [['query'=>'name|py|contacts'],'fullLike'] + ]); + $sql = sqlAuth('customer',$sql);//数据鉴权 + $count = Db::name('customer')->where($sql)->count(); + //获取总条数 + $info = Db::name('customer')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //查询分页数据 + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + //返回数据 + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //资金账户|下拉接口 + public function accountRecord() { + $input = input('post.'); + if (existFull($input,['page','limit'])) { + //构造SQL + $sql = fastSql($input,[ + [['query'=>'name'],'fullLike'] + ]); + $sql = sqlAuth('account',$sql);//数据鉴权 + $count = Db::name('account')->where($sql)->count(); + //获取总条数 + $info = Db::name('account')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //查询分页数据 + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //收支类别|下拉接口 + public function ietRecord() { + $input = input('post.'); + if (existFull($input,['page','limit'])) { + //构造SQL + $sql = fastSql($input,[ + [['query'=>'name'],'fullLike'] + ]); + $count = Db::name('iet')->where($sql)->count(); + //获取总条数 + $info = Db::name('iet')->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray(); + //查询分页数据 + $result = [ + 'state' => 'success', + 'count' => $count, + 'info' => $info + ]; + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //费用详情|数据接口 + public function getCost() { + $input = input('post.'); + if (existFull($input,['cost'])) { + $info=Cost::with(['sourceData','ietData'])->where([['id','=',$input['cost']]])->append(['extension'])->find()->toArray(); + $info['uat']=math()->chain($info['money'])->sub($info['settle'])->done(); + $result = ['state' => 'success','info' => $info]; + } else { + $result = ['state' => 'error','info' => '传入参数不完整!']; + } + return json($result); + } + //零售配置 + public function getDeploy(){ + $deploy=getFrameDeploy(); + if(!empty($deploy)){ + //安全处理-隐藏接口配置 + $deploy['wechat']=[ + 'enable'=>$deploy['wechat']['enable'], + 'account'=>$deploy['wechat']['account'] + ]; + $deploy['ali']=[ + 'enable'=>$deploy['ali']['enable'], + 'account'=>$deploy['ali']['account'] + ]; + } + return json(['state'=>'success','info'=>$deploy]); + } + //扩展字段文件上传 + public function fieldUpload() { + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('field', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result=['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //编辑器图像上传 + public function editorUpload(){ + $files=request()->file('images');//获取上传文件 + if(empty($files)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + //文件限制2MB + foreach ($files as $file) { + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'png,gif,jpg,jpeg']])->check(['file'=>$file]); + }catch(ValidateException $e) { + return json(['state'=>'error','info'=>$e->getMessage()]); + exit; + } + } + foreach ($files as $file) { + $fileInfo=Filesystem::disk('upload')->putFile('editor', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $data[]=$filePath; + } + $result=['state'=>'success','info'=>$data]; + } + return json($result); + } + //获取版本信息 + public function getUpgrade(){ + $ask = json_decode(curl('https://www.nodcloud.com/api/service/version',false,['product' => config('soft.product'),'edition' => config('soft.edition'),'version' => config('soft.version')],'GET'),true); + if(empty($ask)){ + $resule = ['state' => 'success','info'=>['ver'=>config('soft.version'),'new'=>config('soft.version'),'url'=>'']]; + }else{ + if($ask['state']=='success'){ + $resule = ['state' => 'success','info'=>['ver'=>config('soft.version'),'new'=>$ask['info']['version'],'url'=>$ask['info']['url']]]; + }elseif($ask['state']=='warning'){ + $resule = ['state' => 'error','info' => $ask['message']]; + }else{ + $resule = ['state' => 'error','info' => '版本服务系统异常!']; + } + } + return json($resule); + } + //清空缓存文件 + public function clachCache(){ + delCache(); + delDir('runtime.log'); + delDir('runtime.session'); + return json(['state'=>'success']); + } + //退出 + public function out(){ + pushLog('退出登录'); + cache(getToken(),NULL); + return json(['state' => 'success']); + } +} \ No newline at end of file diff --git a/serve/app/controller/Sor.php b/serve/app/controller/Sor.php new file mode 100644 index 0000000..0345170 --- /dev/null +++ b/serve/app/controller/Sor.php @@ -0,0 +1,692 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['startArrival'=>'arrival'],'startTime'], + [['endArrival'=>'arrival'],'endTime'], + ['user','fullEq'], + ['examine','fullDec1'], + ['state','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['id','in',array_column(Db::name('sor_info')->where([['goods','in',$goods]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('sor',$sql);//数据鉴权 + $count = Sors::where($sql)->count();//获取总条数 + $info = Sors::with(['frameData','customerData','peopleData','userData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + //关联单据 + if(!empty($info)){ + $bor=Db::name('bor')->where([['source','in',array_column($info,'id')]])->select()->toArray(); + $sell=Db::name('sell')->where([['source','in',array_column($info,'id')]])->select()->toArray(); + foreach ($info as $infoKey=>$infoVo) { + //采购订单 + $borData=array_map(function($item){ + return ['type'=>'采购订单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'bor','id'=>$item['id']]; + },search($bor)->where([['source','=',$infoVo['id']]])->select()); + //采购单 + $sellData=array_map(function($item){ + return ['type'=>'销售单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'sell','id'=>$item['id']]; + },search($sell)->where([['source','=',$infoVo['id']]])->select()); + //合并排序 + $merge=array_merge($borData,$sellData); + array_multisort(array_column($merge,'sort'),SORT_DESC,$merge); + $info[$infoKey]['relation']=$merge; + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['examine']=0; + empty($class['id'])?$this->validate($class,'app\validate\Sor'):$this->validate($class,'app\validate\Sor.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\SorInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'商品信息第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Sors::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'sor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增销售订单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Sors::update($class); + Db::name('record')->insert(['type'=>'sor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新销售订单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + SorInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + $input['info'][$infoKey]['handle']=0;//初始|出库数量 + } + $model = new SorInfo; + $model->saveAll($input['info']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Sors::where([['id','=',$input['parm']]])->find(); + $info=SorInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //关联验证 + $exist=moreTableFind([ + ['table'=>'bor','where'=>[['source','in',$input['parm']]]], + ['table'=>'sell','where'=>[['source','in',$input['parm']]]] + ]); + if($exist){ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + }else{ + $data=Db::name('sor')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('sor')->where([['id','in',$input['parm']]])->delete(); + Db::name('sor_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','sor'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除销售订单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('sor')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + //2 综合处理 + foreach ($classList as $class) { + //1 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(!empty($class['examine'])){ + //销售单 + $sell=Db::name('sell')->where([['source','=',$class['id']]])->find(); + if(!empty($sell)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该订单存在关联销售单!']); + exit; + } + } + //2 数据处理 + Db::startTrans(); + try { + //场景判断 + if(empty($class['examine'])){ + //审核 + Db::name('sor')->where([['id','=',$class['id']]])->update(['examine'=>1]); + Db::name('record')->insert(['type'=>'sor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + pushLog('审核销售订单[ '.$class['number'].' ]');//日志 + }else{ + //反审核 + Db::name('sor')->where([['id','=',$class['id']]])->update(['examine'=>0]); + Db::name('record')->insert(['type'=>'sor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + pushLog('反审核销售订单[ '.$class['number'].' ]');//日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //开启|关闭 + public function update(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $period=getPeriod(); + $class=Db::name('sor')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据失败,原因:单据日期与结账日期冲突!']); + exit; + }else{ + try { + if($class['state']==3){ + //开启 + Db::name('sor')->where([['id','=',$class['id']]])->update(['state'=>1]); + Db::name('record')->insert(['type'=>'sor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'开启单据']); + pushLog('开启销售订单[ '.$class['number'].' ]');//日志 + }else{ + //关闭 + Db::name('sor')->where([['id','=',$class['id']]])->update(['state'=>3]); + Db::name('record')->insert(['type'=>'sor','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'关闭单据']); + pushLog('关闭销售订单[ '.$class['number'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return empty($parm)?json($result):$result; + } + //生成销售单 + public function buildSell(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //源数据 + $source=[ + 'class'=>Sors::where([['id','=',$input['id']]])->find(), + 'info'=>SorInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['id']]])->order(['id'=>'asc'])->select()->toArray() + ]; + //状态验证 + if($source['class']['state']!=2){ + //CLASS数据 + $class=[ + 'source'=>$source['class']['id'], + 'customer'=>$source['class']['customer'], + 'total'=>0 + ]; + //INFO数据 + $info=[]; + $fun=getSys('fun'); + foreach ($source['info'] as $infoVo) { + //判断入库状态 + if(bccomp($infoVo['nums'],$infoVo['handle'])==1){ + $infoVo['source']=$infoVo['id']; + $infoVo['serial']=[]; + $infoVo['batch']=''; + $infoVo['mfd']=''; + $infoVo['retreat']=0; + //重算价格 + $infoVo['nums']=math()->chain($infoVo['nums'])->sub($infoVo['handle'])->done(); + $storage=math()->chain($infoVo['price'])->mul($infoVo['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($infoVo['discount']==0){ + $infoVo['total']=$storage; + }else{ + $infoVo['dsc']=math()->chain($storage)->div(100)->mul($infoVo['discount'])->round($fun['digit']['money'])->done(); + $infoVo['total']=math()->chain($storage)->sub($infoVo['dsc'])->done(); + } + //税额|价税合计 + if($infoVo['tax']==0){ + $infoVo['tpt']=$infoVo['total']; + }else{ + $infoVo['tat']=math()->chain($infoVo['total'])->div(100)->mul($infoVo['tax'])->round(2)->done(); + $infoVo['tpt']=math()->chain($infoVo['total'])->add($infoVo['tat'])->done(); + } + //转存数据 + $info[]=$infoVo; + $class['total']=math()->chain($class['total'])->add($infoVo['tpt'])->done();//累加单据金额 + } + } + $result=['state'=>'success','info'=>['class'=>$class,'info'=>$info]]; + }else{ + $result=['state'=>'warning','info'=>'操作失败,订单状态为已出库!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //生产采购订单 + public function buildBor(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //源数据 + $source=[ + 'class'=>Sors::where([['id','=',$input['id']]])->find(), + 'info'=>SorInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['id']]])->order(['id'=>'asc'])->select()->toArray() + ]; + //状态验证 + if($source['class']['state']!=2){ + //CLASS数据 + $class=[ + 'source'=>$source['class']['id'], + 'total'=>0 + ]; + //INFO数据 + $info=[]; + $fun=getSys('fun'); + foreach ($source['info'] as $infoVo) { + //判断入库状态 + if(bccomp($infoVo['nums'],$infoVo['handle'])==1){ + $infoVo['handle']=0; + //重算价格 + $infoVo['price']=$infoVo['goodsData']['buy']; + $infoVo['nums']=math()->chain($infoVo['nums'])->sub($infoVo['handle'])->done(); + $storage=math()->chain($infoVo['price'])->mul($infoVo['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($infoVo['discount']==0){ + $infoVo['total']=$storage; + }else{ + $infoVo['dsc']=math()->chain($storage)->div(100)->mul($infoVo['discount'])->round($fun['digit']['money'])->done(); + $infoVo['total']=math()->chain($storage)->sub($infoVo['dsc'])->done(); + } + //税额|价税合计 + if($infoVo['tax']==0){ + $infoVo['tpt']=$infoVo['total']; + }else{ + $infoVo['tat']=math()->chain($infoVo['total'])->div(100)->mul($infoVo['tax'])->round(2)->done(); + $infoVo['tpt']=math()->chain($infoVo['total'])->add($infoVo['tat'])->done(); + } + //转存数据 + $info[]=$infoVo; + $class['total']=math()->chain($class['total'])->add($infoVo['tpt'])->done();//累加单据金额 + } + } + $result=['state'=>'success','info'=>['class'=>$class,'info'=>$info]]; + }else{ + $result=['state'=>'warning','info'=>'操作失败,订单状态为已出库!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('sor', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state'=>'error','info'=>$e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //客户匹配 + $customer=Db::name('customer')->where([['name','=',$data[3]['A']]])->find(); + if(empty($customer)){ + throw new ValidateException('客户[ '.$data[3]['A'].' ]未匹配!'); + } + //关联人员匹配 + if(empty($data[3]['F'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['F']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['F'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'customer'=>$customer['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'actual'=>$data[3]['E'], + 'people'=>$people['id'], + 'arrival'=>$data[3]['G'], + 'logistics'=>["key"=>"auto","name"=>"自动识别","number"=>$data[3]['H']], + 'file'=>[], + 'data'=>$data[3]['I'], + 'more'=>[], + 'examine'=>0, + 'state'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Sor');//数据合法性验证 + //初始化INFO + $info=[]; + $goods=Goods::with(['attr'])->where([['name','in',array_column($data,'J')]])->select()->toArray(); + $warehouse=Db::name('warehouse')->where([['name','in',array_column($data,'M')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'goods'=>$dataVo['J'], + 'attr'=>$dataVo['K'], + 'unit'=>$dataVo['L'], + 'warehouse'=>$dataVo['M'], + 'price'=>$dataVo['N'], + 'nums'=>$dataVo['O'], + 'discount'=>$dataVo['P'], + 'dsc'=>0, + 'total'=>0, + 'tax'=>$dataVo['S'], + 'tat'=>0, + 'tpt'=>0, + 'data'=>$dataVo['V'], + 'handle'=>0, + ]; + //商品匹配 + $goodsFind=search($goods)->where([['name','=',$record['goods']]])->find(); + if(empty($goodsFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行商品名称[ '.$record['goods'].' ]未匹配!'); + }else{ + $record['goods']=$goodsFind['id']; + } + //辅助属性匹配 + if(empty($goodsFind['attr'])){ + $record['attr']=''; + }else{ + if(empty($record['attr'])){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性不可为空!'); + }else{ + $attrFind=search($goodsFind['attr'])->where([['name','=',$record['attr']]])->find(); + if(empty($attrFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性[ '.$record['attr'].' ]未匹配!'); + } + } + } + //单位匹配 + if($goodsFind['unit']==-1){ + if(empty($record['unit'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单位不可为空!'); + }else{ + $unitFind=search($goodsFind['units'])->where([['name','=',$record['unit']]])->find(); + if(empty($unitFind) && $goodsFind['units'][0]['source']!=$record['unit']){ + throw new ValidateException('模板文件第'.$dataKey.'行单位[ '.$record['unit'].' ]未匹配!'); + } + } + }else{ + $record['unit']=$goodsFind['unit']; + } + //仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $warehouseFind=search($warehouse)->where([['name','=',$record['warehouse']]])->find(); + if(empty($warehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行仓库[ '.$record['warehouse'].' ]未匹配!'); + }else{ + $record['warehouse']=$warehouseFind['id']; + } + }else{ + //服务产品 + $record['warehouse']=null; + } + //单价匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['price'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单价不正确!'); + } + //数量匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['nums']."})?$/",$record['nums'])){ + throw new ValidateException('模板文件第'.$dataKey.'行数量不正确!'); + } + try{ + $this->validate($record,'app\validate\SorInfo');//数据合法性验证 + $storage=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($record['discount']==0){ + $record['total']=$storage; + }else{ + $record['dsc']=math()->chain($storage)->div(100)->mul($record['discount'])->round($fun['digit']['money'])->done(); + $record['total']=math()->chain($storage)->sub($record['dsc'])->done(); + } + //税额|价税合计 + if($record['tax']==0){ + $record['tpt']=$record['total']; + }else{ + + $record['tat']=math()->chain($record['total'])->div(100)->mul($record['tax'])->round(2)->done(); + $record['tpt']=math()->chain($record['total'])->add($record['tat'])->done(); + } + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['tpt'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + //CLASS数据验证 + if(bccomp($class['total'],$class['actual'])==-1){ + throw new ValidateException('实际金额不可大于单据金额[ '.$class['total'].' ]!'); + }else{ + Db::startTrans(); + try { + //新增CLASS + $classData=Sors::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new SorInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'sor','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入销售订单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出销售订单列表');//日志 + $source=Sors::with(['frameData','customerData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售订单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'actual'=>'实际金额', + 'arrival'=>'到货日期', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|state'=>'出库状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>['总数:'.count($source),'总单据金额:'.mathArraySum(array_column($source,'total')),'总实际金额:'.mathArraySum(array_column($source,'actual'))]]; + //导出execl + buildExcel('销售订单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售订单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '客户:'.$sourceVo['customerData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'goodsData|spec'=>'规格型号', + 'attr'=>'辅助属性', + 'unit'=>'单位', + 'warehouseData|name'=>'仓库', + 'price'=>'单价', + 'nums'=>'数量', + 'handle'=>'出库数量', + 'discount'=>'折扣率', + 'dsc'=>'折扣额', + 'total'=>'金额', + 'tax'=>'税率', + 'tat'=>'税额', + 'tpt'=>'价税合计', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=SorInfo::with(['goodsData','warehouseData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->select()->toArray(); + //税金匹配 + $fun=getSys('fun'); + if(empty(search($info)->where([['tax','<>',0]])->find()) && !$fun['tax']){ + unset($field['tax']); + unset($field['tat']); + unset($field['tpt']); + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '实际金额:'.$sourceVo['actual'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '到货日期:'.$sourceVo['arrival'], + '物流信息:'.$sourceVo['extension']['logistics'], + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + } + buildZip('销售订单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} diff --git a/serve/app/controller/Sre.php b/serve/app/controller/Sre.php new file mode 100644 index 0000000..2727e81 --- /dev/null +++ b/serve/app/controller/Sre.php @@ -0,0 +1,1175 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['examine','fullDec1'], + ['nucleus','fullDec1'], + ['cse','fullDec1'], + ['invoice','fullDec1'], + ['check','fullDec1'], + ['data','fullLike'] + ]);//构造SQL + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['id','in',array_column(Db::name('sre_info')->where([['goods','in',$goods]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('sre',$sql);//数据鉴权 + $count = Sres::where($sql)->count();//获取总条数 + $info = Sres::with(['frameData','customerData','peopleData','userData','billData','costData','invoiceData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + //关联单据 + if(!empty($info)){ + $sell=Db::name('sell')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + foreach ($info as $infoKey=>$infoVo) { + //销售单 + $relation=array_map(function($item){ + return ['type'=>'销售单','time'=>date('Y-m-d',$item['time']),'number'=>$item['number'],'sort'=>$item['time'],'sort'=>$item['time'],'sort'=>$item['time'],'types'=>'sell','id'=>$item['id']]; + },search($sell)->where([['id','=',$infoVo['source']]])->select()); + //数据排序 + array_multisort(array_column($relation,'sort'),SORT_DESC,$relation); + $info[$infoKey]['relation']=$relation; + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['cse']=empty($class['cost'])?3:0; + $class['invoice']=empty($class['actual'])?3:0; + $class['examine']=0; + $class['nucleus']=0; + empty($class['id'])?$this->validate($class,'app\validate\Sre'):$this->validate($class,'app\validate\Sre.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\SreInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'商品信息第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //验证Cost + foreach ($input['cost'] as $costKey=>$costVo) { + try { + $this->validate($costVo,'app\validate\Cost'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'单据费用第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Sres::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'sre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增销售退货单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Sres::update($class); + Db::name('record')->insert(['type'=>'sre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新销售退货单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + SreInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new SreInfo; + $model->saveAll($input['info']); + + //COST数据 + Cost::where([['type','=','sre'],['class','=',$class['id']]])->delete(); + foreach ($input['cost'] as $costKey=>$costVo) { + unset($input['cost'][$costKey]['id']); + $input['cost'][$costKey]['type']='sre'; + $input['cost'][$costKey]['class']=$class['id']; + $input['cost'][$costKey]['time']=$class['time']; + $input['cost'][$costKey]['settle']=0; + $input['cost'][$costKey]['state']=0; + } + $model = new Cost; + $model->saveAll($input['cost']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Sres::where([['id','=',$input['parm']]])->find(); + $info=SreInfo::with(['goodsData','warehouseData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $cost=Cost::where([['type','=','sre'],['class','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + 'cost'=>$cost, + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('sre')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('sre')->where([['id','in',$input['parm']]])->delete(); + Db::name('sre_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('cost')->where([['type','=','sre'],['class','in',$input['parm']]])->delete(); + Db::name('record')->where([['type','=','sre'],['source','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除销售退货单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //核对|反核对 + public function check(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $period=getPeriod(); + $classList=Db::name('sre')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + foreach ($input['parm'] as $parmVo) { + $class=search($classList)->where([['id','=',$parmVo]])->find(); + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(empty($class['check'])){ + Db::name('sre')->where([['id','=',$class['id']]])->update(['check'=>1]); + //1 单据记录 + Db::name('record')->insert(['type'=>'sre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'核对单据']); + //2 记录操作 + pushLog('核对销售退货单[ '.$class['number'].' ]');//单据日志 + }else{ + Db::name('sre')->where([['id','=',$class['id']]])->update(['check'=>0]); + //1 单据记录 + Db::name('record')->insert(['type'=>'sre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反核对单据']); + //2 记录操作 + pushLog('反核对销售退货单[ '.$class['number'].' ]');//单据日志 + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $period=getPeriod(); + $classList=Db::name('sre')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('sre_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //1.1 商品数据 + $goodsList=Db::name('goods')->where([['id','in',array_unique(array_column($info,'goods'))]])->select()->toArray(); + //1.2 综合匹配 + if(empty($class['examine'])){ + //1 关联单据 + empty($class['source'])||$sellInfoList=Db::name('sell_info')->where([['id','in',array_column($info,'source')]])->select()->toArray(); + //2 构造数据 + $batchGather=[]; + $serialGather=[]; + $roomWhereOrSql=[]; + foreach ($info as $infoVo) { + //1 批次号 + empty($infoVo['batch'])||$batchGather[]=$infoVo['batch']; + //2 序列号 + $serialGather=array_merge($serialGather,json_decode($infoVo['serial'])); + //3 仓储条件 + empty($infoVo['warehouse'])||$roomWhereOrSql[]=[['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]]; + } + //3 匹配数据 + empty($batchGather)||$batchList=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + empty($serialGather)||$serialList=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + if(!empty($roomWhereOrSql)){ + //1 去重转存 + $roomWhereOrSql=array_unique($roomWhereOrSql,SORT_REGULAR); + //2 仓储匹配 + $roomList=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + } + } + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(!empty($class['examine'])){ + //1 核销单 + $bill=Db::name('bill_info')->where([['mold','=','sre'],['source','=',$class['id']]])->find(); + if(!empty($bill)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联核销单!']); + exit; + } + //2 单据费用 + $cost=Db::name('cost')->alias('cost')->where([['type','=','sre'],['class','=',$class['id']]])->whereExists(function($query){ + $query->name('oce_info')->where([['source','=',Db::raw('cost.id')]])->limit(1); + })->find(); + if(!empty($cost)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联其它支出单!']); + exit; + } + //3 单据发票 + $invoice=Db::name('invoice')->where([['type','=','sre'],['class','=',$class['id']]])->find(); + if(!empty($invoice)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联单据发票!']); + exit; + } + } + //3 INFO验证|构造 + foreach ($info as $infoKey=>$infoVo) { + //1 匹配商品 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + //2 商品类型 + if(empty($goods['type'])){ + //场景验证 + if(empty($class['examine'])){ + //1 关联单据 + if(!empty($infoVo['source'])){ + $sellInfo=search($sellInfoList)->where([['id','=',$infoVo['source']]])->find(); + if(!empty($sellInfo)){ + if($sellInfo['unit']!=$infoVo['unit']){ + //单位匹配 + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行单位与销售单不匹配!']); + exit; + }elseif(bccomp(math()->chain($sellInfo['retreat'])->add($infoVo['nums'])->done(),$sellInfo['nums'])==1){ + //数量匹配 + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行超出销售单可退货数量!']); + exit; + } + } + + } + //2 多单位处理 + if($goods['unit']==-1){ + //多单位|转存 + $radix=unitRadix($infoVo['unit'],json_decode($goods['units'],true)); + $info[$infoKey]['basic']=[ + 'nums'=>math()->chain($infoVo['nums'])->mul($radix)->done(), + 'price'=>math()->chain($infoVo['price'])->div($radix)->round(4)->done() + ]; + }else{ + //常规单位|转存 + $info[$infoKey]['basic']=[ + 'nums'=>$infoVo['nums'], + 'price'=>$infoVo['price'] + ]; + } + //3 序列号 + $serialData=json_decode($infoVo['serial']); + if(empty($serialData)){ + $info[$infoKey]['serial']=[]; + }else{ + //序列号状态[不存在|已销售] + $serialFind=search($serialList)->where([['goods','=',$infoVo['goods']],['number','in',$serialData],['state','<>',1]])->find(); + if(empty($serialFind)){ + $info[$infoKey]['serial']=$serialData; + }else{ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + }else{ + //1 验证序列号 + $serialInfoCollect=Db::name('serial_info')->where([['type','=','sre'],['info','in',array_column($info,'id')]])->select()->toArray(); + if(!empty($serialInfoCollect)){ + //序列号状态[未销售] + $serialFind=Db::name('serial')->where([['id','in',array_column($serialInfoCollect,'pid')],['state','<>',0]])->find(); + if(!empty($serialFind)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + } + } + } + //4 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $store=['sellInfo'=>[],'room'=>[],'roomInfo'=>[],'batch'=>[],'batchInfo'=>[],'serial'=>[],'serialInfo'=>[],'serve'=>[],'serveInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //1 关联单据 + empty($infoVo['source'])||$store['sellInfo'][]=['id'=>$infoVo['source'],'retreat'=>$infoVo['nums']]; + //2 判断商品类型 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + if(empty($goods['type'])){ + //常规商品 + //1 仓储 + $store['room'][]=['warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['basic']['nums']]; + //2 仓储详情 + $store['roomInfo'][]=['pid'=>null,'type'=>'sre','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'direction'=>1,'price'=>$infoVo['basic']['price'],'nums'=>$infoVo['basic']['nums']]; + //3 批次号 + if(empty($infoVo['batch'])){ + $store['batch'][]=[]; + $store['batchInfo'][]=[]; + }else{ + $store['batch'][]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'number'=>$infoVo['batch'],'time'=>$infoVo['mfd'],'nums'=>$infoVo['basic']['nums']]; + $store['batchInfo'][]=['pid'=>null,'type'=>'sre','class'=>$class['id'],'info'=>$infoVo['id'],'direction'=>1,'nums'=>$infoVo['basic']['nums']]; + } + //4 序列号 + if(empty($infoVo['serial'])){ + $store['serial'][]=[]; + $store['serialInfo'][]=[]; + }else{ + $serial=[]; + $serialInfo=[]; + foreach ($infoVo['serial'] as $serialVo) { + $serial[]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'batch'=>null,'goods'=>$infoVo['goods'],'number'=>$serialVo,'state'=>0]; + $serialInfo[]=['pid'=>null,'type'=>'sre','class'=>$class['id'],'info'=>$infoVo['id']]; + } + $store['serial'][]=$serial; + $store['serialInfo'][]=$serialInfo; + } + }else{ + //5 服务商品 + $store['serve'][]=['goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['nums']]; + $store['serveInfo'][]=['pid'=>null,'type'=>'sre','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'price'=>$infoVo['price'],'nums'=>$infoVo['nums']]; + } + } + //2 关联单据 + if(!empty($store['sellInfo'])){ + //更新详情 + Db::name('sell_info')->duplicate(['retreat'=>Db::raw('retreat + VALUES(`retreat`)')])->insertAll($store['sellInfo']); + $sellInfo=Db::name('sell_info')->where([['id','in',array_column($store['sellInfo'],'id')]])->select()->toArray(); + $sorInfoDuplicate=[]; + foreach ($sellInfo as $sellVo){ + $nums=search($store['sellInfo'])->where([['id','=',$sellVo['id']]])->find()['retreat']; + empty($sellVo['source'])||$sorInfoDuplicate[]=['id'=>$sellVo['source'],'handle'=>$nums]; + } + if(!empty($sorInfoDuplicate)){ + //更新详情 + Db::name('sor_info')->duplicate(['handle'=>Db::raw('handle - VALUES(`handle`)')])->insertAll($sorInfoDuplicate); + //2 更新销售订单CLASS + $sorInfo=Db::name('sor_info')->where([['id','in',array_column($sellInfo,'source')]])->select()->toArray(); + if(array_sum(array_column($sorInfo,'handle'))==0){ + $state=0; + }else{ + $state=mathArraySum(array_column($sorInfo,'nums'))==mathArraySum(array_column($sorInfo,'handle'))?2:1; + } + Db::name('sor')->where([['id','=',$sorInfo[0]['pid']]])->update(['state'=>$state]); + } + + } + //3 仓储 + if(!empty($store['room'])){ + //1 构造数据 + $roomInsert=[]; + foreach ($store['room'] as $roomVo) { + $roomFind=search($roomList)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + if(empty($roomFind)){ + $roomVo['nums']=0; + $roomInsert[]=$roomVo; + } + } + //2 创建数据|去重 + empty($roomInsert)||Db::name('room')->insertAll(array_unique($roomInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $roomDuplicate=[]; + $room=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + foreach ($store['room'] as $roomKey=>$roomVo) { + $roomFind=search($room)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + $store['room'][$roomKey]['id']=$roomFind['id']; + $roomDuplicate[]=['id'=>$roomFind['id'],'nums'=>$roomVo['nums']]; + } + //4 更新数据 + Db::name('room')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($roomDuplicate); + } + //4 仓储详情 + if(!empty($store['roomInfo'])){ + //1 填充数据 + foreach ($store['roomInfo'] as $roomInfoKey=>$roomInfoVo) { + $store['roomInfo'][$roomInfoKey]['pid']=$store['room'][$roomInfoKey]['id']; + } + //2 创建数据 + Db::name('room_info')->insertAll($store['roomInfo']); + } + //5 批次号 + if(!empty($store['batch'])){ + //1 构造数据 + $batchData=[]; + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $store['batch'][$batchKey]['room']=$store['room'][$batchKey]['id']; + $batchData[]=$store['batch'][$batchKey]; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchData)){ + //1 构造数据 + $batchInsert=[]; + foreach ($batchData as $batchDataKey=>$batchDataVo) { + $batchFind=search($batchList)->where([['room','=',$batchDataVo['room']],['number','=',$batchDataVo['number']],['time','=',$batchDataVo['time']]])->find(); + if(empty($batchFind)){ + $batchDataVo['nums']=0; + $batchInsert[]=$batchDataVo; + } + } + //2 创建数据|去重 + empty($batchInsert)||Db::name('batch')->insertAll(array_unique($batchInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $batchDuplicate=[]; + $batch=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + foreach ($store['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $batchFind=search($batch)->where([['room','=',$batchVo['room']],['number','=',$batchVo['number']],['time','=',$batchVo['time']]])->find(); + $store['batch'][$batchKey]['id']=$batchFind['id']; + $batchDuplicate[]=['id'=>$batchFind['id'],'nums'=>$batchVo['nums']]; + } + } + //4 更新数据 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($batchDuplicate); + } + } + //6 批次号详情 + if(!empty($store['batchInfo'])){ + //1 构造数据 + $batchInfoInstall=[]; + foreach ($store['batchInfo'] as $batchInfoKey=>$batchInfoVo) { + if(!empty($batchInfoVo)){ + $batchInfoVo['pid']=$store['batch'][$batchInfoKey]['id']; + $batchInfoInstall[]=$batchInfoVo; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchInfoInstall)){ + //创建数据 + Db::name('batch_info')->insertAll($batchInfoInstall); + } + } + //7 序列号 + if(!empty($store['serial'])){ + //1 构造数据 + $serialData=[]; + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $store['serial'][$serialKey][$itemKey]['room']=$store['room'][$serialKey]['id']; + $store['serial'][$serialKey][$itemKey]['batch']=empty($store['batch'][$serialKey])?0:$store['batch'][$serialKey]['id']; + $serialData[]=$store['serial'][$serialKey][$itemKey]; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialData)){ + //1 构造数据 + $serialInsert=[]; + foreach ($serialData as $serialDataKey=>$serialDataVo) { + $serialFind=search($serialList)->where([['room','=',$serialDataVo['room']],['batch','=',$serialDataVo['batch']],['number','=',$serialDataVo['number']]])->find(); + if(empty($serialFind)){ + $serialInsert[]=$serialDataVo; + } + } + //2 创建数据 + empty($serialInsert)||Db::name('serial')->insertAll($serialInsert); + //3 匹配主键|构造更新 + $serialDuplicate=[]; + $serial=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + foreach ($store['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $serialFind=search($serial)->where([['room','=',$itemVo['room']],['batch','=',$itemVo['batch']],['number','=',$itemVo['number']]])->find(); + $store['serial'][$serialKey][$itemKey]['id']=$serialFind['id']; + $serialFind['state']==1&&$serialDuplicate[]=$serialFind['id']; + } + } + } + //4 更新数据|状态变更 + empty($serialDuplicate)||Db::name('serial')->where([['id','in',$serialDuplicate]])->update(['state'=>0]); + } + } + //8 序列号详情 + if(!empty($store['serialInfo'])){ + //1 构造数据 + $serialInfoInstall=[]; + foreach ($store['serialInfo'] as $serialInfoKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $itemVo['pid']=$store['serial'][$serialInfoKey][$itemKey]['id']; + $serialInfoInstall[]=$itemVo; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialInfoInstall)){ + //创建数据 + Db::name('serial_info')->insertAll($serialInfoInstall); + } + } + //9 服务商品 + if(!empty($store['serve'])){ + //1 匹配数据|去重 + $serveWhereOrSql=array_unique(array_map(function($item){ + return [['goods','=',$item['goods']],['attr','=',$item['attr']]]; + },$store['serve']),SORT_REGULAR); + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + //2 构造数据 + $serveInsert=[]; + foreach ($store['serve'] as $serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + if(empty($serveFind)){ + $serveVo['nums']=0; + $serveInsert[]=$serveVo; + } + } + //3 创建数据|去重 + empty($serveInsert)||Db::name('serve')->insertAll(array_unique($serveInsert,SORT_REGULAR)); + //4 匹配主键|构造更新 + $serveDuplicate=[]; + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + foreach ($store['serve'] as $serveKey=>$serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + $store['serve'][$serveKey]['id']=$serveFind['id']; + $serveDuplicate[]=['id'=>$serveFind['id'],'nums'=>$serveVo['nums']]; + } + //5 更新数据 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($serveDuplicate); + } + //10 服务商品详情 + if(!empty($store['serveInfo'])){ + //1 填充数据 + foreach ($store['serveInfo'] as $serveInfoKey=>$serveInfoVo) { + $store['serveInfo'][$serveInfoKey]['pid']=$store['serve'][$serveInfoKey]['id']; + } + //2 创建数据 + Db::name('serve_info')->insertAll($store['serveInfo']); + } + //11 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->dec('balance',$class['money'])->update(); + //2 创建资金详情 + Db::name('account_info')->insert([ + 'pid'=>$class['account'], + 'type'=>'sre', + 'class'=>$class['id'], + 'time'=>$class['time'], + 'direction'=>0, + 'money'=>$class['money'] + ]); + //3 创建核销记录 + Db::name('sre_bill')->insert([ + 'pid'=>$class['id'], + 'type'=>'sre', + 'source'=>$class['id'], + 'time'=>$class['time'], + 'money'=>$class['money'] + ]); + } + //12 客户|应收款余额 + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('customer')->where([['id','=',$class['customer']]])->dec('balance',$balance)->update(); + } + //13 更新单据 + $nucleus=$class['money']==$class['actual']?2:($class['money']==0?0:1); + Db::name('sre')->where([['id','=',$class['id']]])->update(['examine'=>1,'nucleus'=>$nucleus]); + //14 单据记录 + Db::name('record')->insert(['type'=>'sre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //15 收发记录 + $summary=new Summary; + $summary->note('sre',$class['id'],true); + //16 记录操作 + pushLog('审核销售退货单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //1 匹配数据 + $listSql=[['type','=','sre'],['info','in',array_column($info,'id')]]; + $roomInfoList=Db::name('room_info')->where($listSql)->select()->toArray(); + $batchInfoList=Db::name('batch_info')->where($listSql)->select()->toArray(); + $serialInfoList=Db::name('serial_info')->where($listSql)->select()->toArray(); + $serveInfoList=Db::name('serve_info')->where($listSql)->select()->toArray(); + //2 关联单据 + if(!empty($class['source'])){ + //更新详情 + $sellInfoDuplicate=[]; + foreach ($info as $infoVo) { + empty($infoVo['source'])||$sellInfoDuplicate[]=['id'=>$infoVo['source'],'retreat'=>$infoVo['nums']]; + } + empty($sellInfoDuplicate)||Db::name('sell_info')->duplicate(['retreat'=>Db::raw('retreat - VALUES(`retreat`)')])->insertAll($sellInfoDuplicate); + //查询是否关联销售订单 + $sellInfo=Db::name('sell_info')->where([['id','in',array_column($sellInfoDuplicate,'id')]])->select()->toArray(); + $sorInfoDuplicate=[]; + foreach ($sellInfo as $sellVo){ + empty($sellVo['source'])||$sorInfoDuplicate[]=['id'=>$sellVo['source'],'handle'=>$infoVo['nums']]; + } + if(!empty($sorInfoDuplicate)){ + //更新详情 + Db::name('sor_info')->duplicate(['handle'=>Db::raw('handle + VALUES(`handle`)')])->insertAll($sorInfoDuplicate); + //2 更新销售订单CLASS + $sorInfo=Db::name('sor_info')->where([['id','in',array_column($sellInfo,'source')]])->select()->toArray(); + $state=mathArraySum(array_column($sorInfo,'nums'))==mathArraySum(array_column($sorInfo,'handle'))?2:1; + Db::name('sor')->where([['id','=',$sorInfo[0]['pid']]])->update(['state'=>$state]); + } + + } + //3 仓储 + $roomDuplicate=[]; + foreach ($roomInfoList as $roomInfoVo) { + $roomDuplicate[]=['id'=>$roomInfoVo['pid'],'nums'=>$roomInfoVo['nums']]; + } + //3.1 更新仓储 + Db::name('room')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($roomDuplicate); + //3.2 删除仓储详情 + Db::name('room_info')->where([['id','in',array_column($roomInfoList,'id')]])->delete(); + //3.3 仓储|冗余 + $roomPk=array_unique(array_column($roomInfoList,'pid')); + $roomInfoData=Db::name('room_info')->where([['pid','in',$roomPk]])->select()->toArray(); + $roomDiff=array_diff($roomPk,array_unique(array_column($roomInfoData,'pid'))); + empty($roomDiff)||Db::name('room')->where([['id','in',$roomDiff]])->delete(); + //4 批次号 + if(!empty($batchInfoList)){ + //1 构造数据 + $batchInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$batchInfoList); + //2 更新批次号 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($batchInfoDuplicate); + //3 删除批次号详情 + Db::name('batch_info')->where([['id','in',array_column($batchInfoList,'id')]])->delete(); + //4 批次号|冗余 + $batchPk=array_unique(array_column($batchInfoList,'pid')); + $batchInfoData=Db::name('batch_info')->where([['pid','in',$batchPk]])->select()->toArray(); + $batchDiff=array_diff($batchPk,array_unique(array_column($batchInfoData,'pid'))); + empty($batchDiff)||Db::name('batch')->where([['id','in',$batchDiff]])->delete(); + } + //5 序列号 + if(!empty($serialInfoList)){ + //1 更新序列号 + Db::name('serial')->where([['id','in',array_column($serialInfoList,'pid')]])->update(['state'=>1]); + //2 删除序列号详情 + Db::name('serial_info')->where([['id','in',array_column($serialInfoList,'id')]])->delete(); + //3 序列号|冗余 + $serialPk=array_unique(array_column($serialInfoList,'pid')); + $serialInfoData=Db::name('serial_info')->where([['pid','in',$serialPk]])->select()->toArray(); + $serialDiff=array_diff($serialPk,array_unique(array_column($serialInfoData,'pid'))); + empty($serialDiff)||Db::name('serial')->where([['id','in',$serialDiff]])->delete(); + } + //6 服务 + if(!empty($serveInfoList)){ + //1 构造数据 + $serveInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$serveInfoList); + //2 更新服务 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($serveInfoDuplicate); + //3 删除服务详情 + Db::name('serve_info')->where([['id','in',array_column($serveInfoList,'id')]])->delete(); + //4 服务|冗余 + $servePk=array_unique(array_column($serveInfoList,'pid')); + $serveInfoData=Db::name('serve_info')->where([['pid','in',$servePk]])->select()->toArray(); + $serveDiff=array_diff($servePk,array_unique(array_column($serveInfoData,'pid'))); + empty($serveDiff)||Db::name('serve')->where([['id','in',$serveDiff]])->delete(); + } + //7 资金|核销 + if(!empty($class['money'])){ + //1 更新资金账户 + Db::name('account')->where([['id','=',$class['account']]])->inc('balance',$class['money'])->update(); + //2 删除资金详情 + Db::name('account_info')->where([['type','=','sre'],['class','=',$class['id']]])->delete(); + //3 删除核销记录 + Db::name('sre_bill')->where([['pid','=',$class['id']]])->delete(); + } + //8 客户|应收款余额 + $balance=math()->chain($class['actual'])->sub($class['money'])->done(); + if(!empty($balance)){ + Db::name('customer')->where([['id','=',$class['customer']]])->inc('balance',$balance)->update(); + } + //9 更新单据 + Db::name('sre')->where([['id','=',$class['id']]])->update(['examine'=>0,'nucleus'=>0]); + //10 单据记录 + Db::name('record')->insert(['type'=>'sre','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //11 收发记录 + $summary=new Summary; + $summary->note('sre',$class['id'],false); + //12 记录操作 + pushLog('反审核销售退货单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('sre', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //客户匹配 + $customer=Db::name('customer')->where([['name','=',$data[3]['A']]])->find(); + if(empty($customer)){ + throw new ValidateException('客户[ '.$data[3]['A'].' ]未匹配!'); + } + //结算账户匹配 + if(empty($data[3]['F'])){ + $account=['id'=>0]; + }else{ + $account=Db::name('account')->where([['name','=',$data[3]['G']]])->find(); + if(empty($account)){ + throw new ValidateException('结算账户[ '.$data[3]['G'].' ]不正确!'); + } + } + //关联人员匹配 + if(empty($data[3]['H'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['H']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['H'].' ]未匹配!'); + } + } + $class=[ + 'source'=>0, + 'frame'=>userInfo(getUserID(),'frame'), + 'customer'=>$customer['id'], + 'time'=>$data[3]['B'], + 'number'=>$data[3]['C'], + 'total'=>0, + 'actual'=>$data[3]['E'], + 'money'=>$data[3]['F'], + 'account'=>$account['id'], + 'people'=>$people['id'], + 'logistics'=>["key"=>"auto","name"=>"自动识别","number"=>$data[3]['I']], + 'file'=>[], + 'data'=>$data[3]['J'], + 'more'=>[], + 'examine'=>0, + 'nucleus'=>0, + 'cse'=>0, + 'invoice'=>0, + 'check'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Sre');//数据合法性验证 + //初始化INFO + $info=[]; + $goods=Goods::with(['attr'])->where([['name','in',array_column($data,'K')]])->select()->toArray(); + $warehouse=Db::name('warehouse')->where([['name','in',array_column($data,'N')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'source'=>0, + 'goods'=>$dataVo['K'], + 'attr'=>$dataVo['L'], + 'unit'=>$dataVo['M'], + 'warehouse'=>$dataVo['N'], + 'batch'=>$dataVo['O'], + 'mfd'=>$dataVo['P'], + 'price'=>$dataVo['Q'], + 'nums'=>$dataVo['R'], + 'serial'=>explode(',',$dataVo['S']), + 'discount'=>$dataVo['T'], + 'dsc'=>0, + 'total'=>0, + 'tax'=>$dataVo['W'], + 'tat'=>0, + 'tpt'=>0, + 'data'=>$dataVo['Z'], + ]; + //商品匹配 + $goodsFind=search($goods)->where([['name','=',$record['goods']]])->find(); + if(empty($goodsFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行商品名称[ '.$record['goods'].' ]未匹配!'); + }else{ + $record['goods']=$goodsFind['id']; + } + //辅助属性匹配 + if(empty($goodsFind['attr'])){ + $record['attr']=''; + }else{ + if(empty($record['attr'])){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性不可为空!'); + }else{ + $attrFind=search($goodsFind['attr'])->where([['name','=',$record['attr']]])->find(); + if(empty($attrFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性[ '.$record['attr'].' ]未匹配!'); + } + } + } + //单位匹配 + if($goodsFind['unit']==-1){ + if(empty($record['unit'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单位不可为空!'); + }else{ + $unitFind=search($goodsFind['units'])->where([['name','=',$record['unit']]])->find(); + if(empty($unitFind) && $goodsFind['units'][0]['source']!=$record['unit']){ + throw new ValidateException('模板文件第'.$dataKey.'行单位[ '.$record['unit'].' ]未匹配!'); + } + } + }else{ + $record['unit']=$goodsFind['unit']; + } + //仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $warehouseFind=search($warehouse)->where([['name','=',$record['warehouse']]])->find(); + if(empty($warehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行仓库[ '.$record['warehouse'].' ]未匹配!'); + }else{ + $record['warehouse']=$warehouseFind['id']; + } + }else{ + //服务产品 + $record['warehouse']=null; + } + //批次号匹配 + if(empty($goodsFind['batch'])){ + $record['batch']=''; + }else{ + if(empty($record['batch'])){ + throw new ValidateException('模板文件第'.$dataKey.'行批次号不可为空!'); + } + } + //生产日期匹配 + if(empty($goodsFind['validity'])){ + $record['mfd']=''; + }else{ + if(empty($record['mfd'])){ + throw new ValidateException('模板文件第'.$dataKey.'行生产日期不可为空!'); + } + } + //单价匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['price'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单价不正确!'); + } + //数量匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['nums']."})?$/",$record['nums'])){ + throw new ValidateException('模板文件第'.$dataKey.'行数量不正确!'); + } + //序列号匹配 + if(empty($goodsFind['serial'])){ + $record['serial']=[]; + }else{ + if(count($record['serial'])==1 && empty($record['serial'][0])){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号不可为空!'); + }else{ + if(count($record['serial'])!=$record['nums']){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号个数与数量不符!'); + } + } + } + try{ + $this->validate($record,'app\validate\SreInfo');//数据合法性验证 + $storage=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + //折扣额|金额 + if($record['discount']==0){ + $record['total']=$storage; + }else{ + $record['dsc']=math()->chain($storage)->div(100)->mul($record['discount'])->round($fun['digit']['money'])->done(); + $record['total']=math()->chain($storage)->sub($record['dsc'])->done(); + } + //税额|价税合计 + if($record['tax']==0){ + $record['tpt']=$record['total']; + }else{ + $record['tat']=math()->chain($record['total'])->div(100)->mul($record['tax'])->round(2)->done(); + $record['tpt']=math()->chain($record['total'])->add($record['tat'])->done(); + } + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['tpt'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + //序列号重复验证 + $serials=[]; + foreach ($info as $infoVo) { + $serials = array_merge($serials,$infoVo['serial']); + } + if(count($serials)!=count(array_unique($serials))){ + throw new ValidateException('商品信息中存在重复序列号!'); + } + //CLASS数据验证 + if(bccomp($class['total'],$class['actual'])==-1){ + throw new ValidateException('实际金额不可大于单据金额[ '.$class['total'].' ]!'); + }else if(bccomp($class['actual'],$class['money'])==-1){ + throw new ValidateException('实付金额不可大于实际金额[ '.floatval($class['actual']).' ]!'); + }else{ + Db::startTrans(); + try { + //新增CLASS + $classData=Sres::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new SreInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'sre','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入销售退货单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出销售退货单列表');//日志 + $source=Sres::with(['frameData','customerData','accountData','peopleData','userData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售退货单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据金额', + 'actual'=>'实际金额', + 'money'=>'单据付款', + 'extension|amount'=>'核销金额', + 'cost'=>'单据费用', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|nucleus'=>'核销状态', + 'extension|cse'=>'费用状态', + 'extension|invoice'=>'发票状态', + 'extension|check'=>'核对状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据金额:'.mathArraySum(array_column($source,'total')), + '总实际金额:'.mathArraySum(array_column($source,'actual')), + '总单据付款:'.mathArraySum(array_column($source,'money')), + '总核销金额:'.mathArraySum(arrayColumns($source,['extension','amount'])), + '总单据费用:'.mathArraySum(array_column($source,'cost')) + ]]; + //导出execl + buildExcel('销售退货单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售退货单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '客户:'.$sourceVo['customerData']['name'], + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'goodsData|spec'=>'规格型号', + 'attr'=>'辅助属性', + 'unit'=>'单位', + 'warehouseData|name'=>'仓库', + 'batch'=>'批次号', + 'mfd'=>'生产日期', + 'price'=>'单价', + 'nums'=>'数量', + 'extension|serial'=>'序列号', + 'discount'=>'折扣率', + 'dsc'=>'折扣额', + 'total'=>'金额', + 'tax'=>'税率', + 'tat'=>'税额', + 'tpt'=>'价税合计', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=SreInfo::with(['goodsData','warehouseData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->append(['extension'])->select()->toArray(); + //批次号匹配 + if(empty(search($info)->where([['goodsData|batch','=',true]])->find())){ + unset($field['batch']); + } + //生产日期匹配 + if(empty(search($info)->where([['goodsData|validity','=',true]])->find())){ + unset($field['mfd']); + } + //序列号匹配 + if(empty(search($info)->where([['goodsData|serial','=',true]])->find())){ + unset($field['extension|serial']); + } + //税金匹配 + $fun=getSys('fun'); + if(empty(search($info)->where([['tax','<>',0]])->find()) && !$fun['tax']){ + unset($field['tax']); + unset($field['tat']); + unset($field['tpt']); + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据金额:'.$sourceVo['total'], + '单据费用:'.$sourceVo['cost'], + '实际金额:'.$sourceVo['actual'], + '核销金额:'.$sourceVo['extension']['amount'], + '结算账户:'.arraySeek($sourceVo,'accountData|name'), + '发票信息:'.$sourceVo['invoice'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '物流信息:'.$sourceVo['extension']['logistics'], + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + + } + buildZip('销售退货单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Srt.php b/serve/app/controller/Srt.php new file mode 100644 index 0000000..e4f8c5d --- /dev/null +++ b/serve/app/controller/Srt.php @@ -0,0 +1,968 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['startArrival'=>'arrival'],'startTime'], + [['endArrival'=>'arrival'],'endTime'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + $sql['class']=sqlAuth('sor',$sql['class']);//数据鉴权 + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + $sql['or']=[]; + //状态匹配 + if(existFull($input,['state'])){ + foreach ($input['state'] as $stateVo) { + $sql['or'][]=[['handle','=',0],Db::raw('handle > 0 AND handle < nums'),['handle','=',Db::raw('nums')]][$stateVo]; + } + } + //判断排序 + if(empty($input['type'])){ + //单据排序 + $record=Db::name('sor')->alias('class')->join(['is_sor_info'=>'info'],'class.id=info.pid')->where($sql['class'])->where($sql['info'])->where(function($query)use($sql){$query->whereOr($sql['or']);})->fieldRaw('class.id as class,group_concat(info.id) as info')->group('class.id')->order('class.id', 'desc')->select()->toArray(); + $data=[]; + $count=count($record); + if(!empty($record)){ + $classList = \app\model\Sor::with(['frameData','customerData'])->where([['id','in',array_column($record,'class')]])->append(['extension'])->page($input['page'],$input['limit'])->select()->toArray(); + $infoList = \app\model\SorInfo::with(['goodsData','warehouseData'])->where([['pid','in',array_column($classList,'id')],['id','in',array_unique(explode(',',implode(',',array_column($record,'info'))))]])->select()->toArray(); + foreach ($classList as $class) { + $class['key']=$class['id']; + $class['money']=$class['actual']; + $class['nmy']=0; + $info=search($infoList)->where([['pid','=',$class['id']]])->select(); + foreach ($info as $key=>$vo) { + $info[$key]['key']=$class['id'].'_'.$vo['id']; + $info[$key]['price']=math()->chain($vo['tpt'])->div($vo['nums'])->round(2)->done(); + $info[$key]['money']=$vo['tpt']; + $info[$key]['extension']['state']=$vo['handle']==0?'未出库':($vo['handle']==$vo['nums']?'已出库':'部分出库'); + $info[$key]['nns']=math()->chain($vo['nums'])->sub($vo['handle'])->done(); + $info[$key]['nmy']=math()->chain($info[$key]['price'])->mul($info[$key]['nns'])->done(); + //汇总数据 + $class['nmy']=math()->chain($class['nmy'])->add($info[$key]['nmy'])->done(); + } + $class['node']=$info; + $data[]=$class; + } + } + }else{ + //商品排序 + $record=Db::name('sor_info')->alias('info')->join(['is_sor'=>'class'],'info.pid=class.id')->where($sql['class'])->where($sql['info'])->where(function($query)use($sql){$query->whereOr($sql['or']);})->fieldRaw('info.id as row,group_concat(info.id) as info')->group('info.goods,info.attr,info.warehouse')->order('info.id', 'desc')->select()->toArray(); + $data=[]; + $count=count($record); + if(!empty($record)){ + $record = array_slice($record,$input['limit']*($input['page']-1),$input['limit']); + $infoList = \app\model\SorInfo::with(['goodsData','warehouseData'])->where([['id','in',array_unique(explode(',',implode(',',array_column($record,'info'))))]])->select()->toArray(); + $classList = \app\model\Sor::with(['frameData','customerData'])->where([['id','in',array_unique(array_column($infoList,'pid'))]])->append(['extension'])->select()->toArray(); + foreach ($record as $recordVo) { + $info=search($infoList)->where([['id','in',explode(',',$recordVo['info'])]])->select(); + $row=$info[0]; + $row['key']=$row['id']; + $row['unit']=''; + $row['price']=''; + $row['nums']=0; + $row['money']=0; + $row['nns']=0; + $row['nmy']=0; + foreach ($info as $vo) { + $class=search($classList)->where([['id','=',$vo['pid']]])->find(); + $class['key']=$vo['id'].'_'.$class['id']; + $class['unit']=$vo['unit']; + $class['price']=math()->chain($vo['tpt'])->div($vo['nums'])->round(2)->done(); + $class['nums']=$vo['nums']; + $class['money']=$vo['tpt']; + $class['extension']['state']=$vo['handle']==0?'未出库':($vo['handle']==$vo['nums']?'已出库':'部分出库'); + $class['nns']=math()->chain($vo['nums'])->sub($vo['handle'])->done(); + $class['nmy']=math()->chain($class['price'])->mul($class['nns'])->done(); + $class['data']=$vo['data']; + $class['basic']=['nums'=>$vo['nums'],'nns'=>$class['nns']]; + //汇总数据 + $row['money']=math()->chain($row['money'])->add($vo['tpt'])->done(); + $row['nmy']=math()->chain($row['nmy'])->add($class['nmy'])->done(); + //单位转换 + if($vo['goodsData']['unit']=='-1'){ + $radix=unitRadix($vo['unit'],$vo['goodsData']['units']); + $row['nums']=math()->chain($class['nums'])->mul($radix)->add($row['nums'])->done(); + $row['nns']=math()->chain($class['nns'])->mul($radix)->add($row['nns'])->done(); + }else{ + $row['nums']=math()->chain($class['nums'])->add($row['nums'])->done(); + $row['nns']=math()->chain($class['nns'])->add($row['nns'])->done(); + } + $row['node'][]=$class; + } + $row['extension']['state']=$row['nns']==0?'已出库':($row['nns']==$row['nums']?'未出库':'部分出库'); + //单位处理 + if($row['goodsData']['unit']=='-1'){ + $row['nums']=unitSwitch($row['nums'],$row['goodsData']['units']); + $row['nns']=unitSwitch($row['nns'],$row['goodsData']['units']); + } + $data[]=$row; + } + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //销售订单跟踪表-导出 + public function sttExports(){ + $input=input('get.'); + existFull($input,['state'])||$input['state']=[]; + existFull($input,['warehouse'])||$input['warehouse']=[]; + if(is_arrays($input,['state','warehouse']) && isset($input['type'])){ + pushLog('导出销售订单跟踪表');//日志 + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['customer','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['startArrival'=>'arrival'],'startTime'], + [['endArrival'=>'arrival'],'endTime'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + $sql['class']=sqlAuth('sor',$sql['class']);//数据鉴权 + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullDivisionIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + $sql['or']=[]; + //状态匹配 + if(existFull($input,['state'])){ + foreach ($input['state'] as $stateVo) { + $sql['or'][]=[['handle','=',0],Db::raw('handle > 0 AND handle < nums'),['handle','=',Db::raw('nums')]][$stateVo]; + } + } + //判断排序 + if(empty($input['type'])){ + //单据排序 + $record=Db::name('sor')->alias('class')->join(['is_sor_info'=>'info'],'class.id=info.pid')->where($sql['class'])->where($sql['info'])->where(function($query)use($sql){$query->whereOr($sql['or']);})->fieldRaw('class.id as class,group_concat(info.id) as info')->group('class.id')->order('class.id', 'desc')->select()->toArray(); + $data=[]; + $count=count($record); + if(!empty($record)){ + $classList = \app\model\Sor::with(['frameData','customerData'])->where([['id','in',array_column($record,'class')]])->append(['extension'])->select()->toArray(); + $infoList = \app\model\SorInfo::with(['goodsData','warehouseData'])->where([['pid','in',array_column($classList,'id')],['id','in',array_unique(explode(',',implode(',',array_column($record,'info'))))]])->select()->toArray(); + foreach ($classList as $class) { + $class['key']=$class['id']; + $class['money']=$class['actual']; + $class['nmy']=0; + $info=search($infoList)->where([['pid','=',$class['id']]])->select(); + foreach ($info as $key=>$vo) { + $info[$key]['key']=$class['id'].'_'.$vo['id']; + $info[$key]['price']=math()->chain($vo['tpt'])->div($vo['nums'])->round(2)->done(); + $info[$key]['money']=$vo['tpt']; + $info[$key]['extension']['state']=$vo['handle']==0?'未出库':($vo['handle']==$vo['nums']?'已出库':'部分出库'); + $info[$key]['nns']=math()->chain($vo['nums'])->sub($vo['handle'])->done(); + $info[$key]['nmy']=math()->chain($info[$key]['price'])->mul($info[$key]['nns'])->done(); + //汇总数据 + $class['nmy']=math()->chain($class['nmy'])->add($info[$key]['nmy'])->done(); + } + $class['node']=$info; + $data[]=$class; + } + } + }else{ + //商品排序 + $record=Db::name('sor_info')->alias('info')->join(['is_sor'=>'class'],'info.pid=class.id')->where($sql['class'])->where($sql['info'])->where(function($query)use($sql){$query->whereOr($sql['or']);})->fieldRaw('info.id as row,group_concat(info.id) as info')->group('info.goods,info.attr,info.warehouse')->order('info.id', 'desc')->select()->toArray(); + $data=[]; + $count=count($record); + if(!empty($record)){ + $infoList = \app\model\SorInfo::with(['goodsData','warehouseData'])->where([['id','in',array_unique(explode(',',implode(',',array_column($record,'info'))))]])->select()->toArray(); + $classList = \app\model\Sor::with(['frameData','customerData'])->where([['id','in',array_unique(array_column($infoList,'pid'))]])->append(['extension'])->select()->toArray(); + foreach ($record as $recordVo) { + $info=search($infoList)->where([['id','in',explode(',',$recordVo['info'])]])->select(); + $row=$info[0]; + $row['key']=$row['id']; + $row['unit']=''; + $row['price']=''; + $row['nums']=0; + $row['money']=0; + $row['nns']=0; + $row['nmy']=0; + foreach ($info as $vo) { + $class=search($classList)->where([['id','=',$vo['pid']]])->find(); + $class['key']=$vo['id'].'_'.$class['id']; + $class['unit']=$vo['unit']; + $class['price']=math()->chain($vo['tpt'])->div($vo['nums'])->round(2)->done(); + $class['nums']=$vo['nums']; + $class['money']=$vo['tpt']; + $class['extension']['state']=$vo['handle']==0?'未出库':($vo['handle']==$vo['nums']?'已出库':'部分出库'); + $class['nns']=math()->chain($vo['nums'])->sub($vo['handle'])->done(); + $class['nmy']=math()->chain($class['price'])->mul($class['nns'])->done(); + $class['data']=$vo['data']; + $class['basic']=['nums'=>$vo['nums'],'nns'=>$class['nns']]; + //汇总数据 + $row['money']=math()->chain($row['money'])->add($vo['tpt'])->done(); + $row['nmy']=math()->chain($row['nmy'])->add($class['nmy'])->done(); + //单位转换 + if($vo['goodsData']['unit']=='-1'){ + $radix=unitRadix($vo['unit'],$vo['goodsData']['units']); + $row['nums']=math()->chain($class['nums'])->mul($radix)->add($row['nums'])->done(); + $row['nns']=math()->chain($class['nns'])->mul($radix)->add($row['nns'])->done(); + }else{ + $row['nums']=math()->chain($class['nums'])->add($row['nums'])->done(); + $row['nns']=math()->chain($class['nns'])->add($row['nns'])->done(); + } + $row['node'][]=$class; + } + $row['extension']['state']=$row['nns']==0?'已出库':($row['nns']==$row['nums']?'未出库':'部分出库'); + //单位处理 + if($row['goodsData']['unit']=='-1'){ + $row['nums']=unitSwitch($row['nums'],$row['goodsData']['units']); + $row['nns']=unitSwitch($row['nns'],$row['goodsData']['units']); + } + $data[]=$row; + } + } + } + //结构重组 + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售订单跟踪表']; + //表格数据 + $field=[ + [ + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'goodsData|name'=>'商品名称', + 'attr'=>'辅助属性', + 'warehouseData|name'=>'仓库', + ],[ + 'goodsData|name'=>'商品名称', + 'attr'=>'辅助属性', + 'warehouseData|name'=>'仓库', + 'frameData|name'=>'所属组织', + 'customerData|name'=>'客户', + 'time'=>'单据时间', + 'number'=>'单据编号' + ],[ + 'unit'=>'单位', + 'price'=>'单价', + 'nums'=>'数量', + 'money'=>'金额', + 'extension|state'=>'出库状态', + 'nns'=>'未出库数量', + 'nmy'=>'未出库金额', + 'arrival'=>'到货日期', + 'data'=>'备注信息' + ] + ]; + $field=array_merge(empty($input['type'])?$field[0]:$field[1],$field[2]); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('销售订单跟踪表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //销售明细表 + public function slt(){ + $input=input('post.'); + $sheet=['sell','sre']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(existFull($input,['page','limit']) && is_arrays($input,['warehouse','mold']) && arrayInArray($input['mold'],$sheet)){ + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['customer','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['data'=>'class.data'],'fullLike'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + //数据鉴权[结构一致] + $sql['class']=sqlAuth('sell',$sql['class']); + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + //组装查询语句 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold.'_info')->alias('info')->join(['is_'.$mold=>'class'],'info.pid=class.id')->where($sql['info'])->where($sql['class'])->fieldRaw('info.id as info,class.id as class,time,"'.$mold.'" as mold')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $count=DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $table=[ + "class"=>"app\\model\\".ucfirst($mold), + 'info'=>"app\\model\\".ucfirst($mold).'Info', + ]; + $list[$mold]['info']=$table['info']::with(['goodsData','warehouseData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + $list[$mold]['class']=$table['class']::with(['frameData','customerData'])->where([['id','in',array_column($list[$mold]['info'],'pid')]])->append(['extension'])->select()->toArray(); + } + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $data[]=[ + 'mold'=>$mold, + 'name'=>['sell'=>'销售单','sre'=>'销售退货单'][$mold], + 'class'=>search($list[$mold]['class'])->where([['id','=',$recordVo['class']]])->find(), + 'info'=>search($list[$mold]['info'])->where([['id','=',$recordVo['info']]])->find() + ]; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //销售明细表-导出 + public function sltExports(){ + $input=input('get.'); + $sheet=['sell','sre']; + existFull($input,['warehouse'])||$input['warehouse']=[]; + existFull($input,['mold'])||$input['mold']=$sheet; + if(is_arrays($input,['warehouse','mold']) && arrayInArray($input['mold'],$sheet)){ + pushLog('导出销售明细表');//日志 + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['customer','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['data'=>'class.data'],'fullLike'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + //数据鉴权[结构一致] + $sql['class']=sqlAuth('sell',$sql['class']); + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullDivisionIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + //组装查询语句 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold.'_info')->alias('info')->join(['is_'.$mold=>'class'],'info.pid=class.id')->where($sql['info'])->where($sql['class'])->fieldRaw('info.id as info,class.id as class,time,"'.$mold.'" as mold')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC'); + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $table=[ + "class"=>"app\\model\\".ucfirst($mold), + 'info'=>"app\\model\\".ucfirst($mold).'Info', + ]; + $list[$mold]['info']=$table['info']::with(['goodsData','warehouseData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + $list[$mold]['class']=$table['class']::with(['frameData','customerData'])->where([['id','in',array_column($list[$mold]['info'],'pid')]])->append(['extension'])->select()->toArray(); + } + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $data[]=[ + 'mold'=>$mold, + 'name'=>['sell'=>'销售单','sre'=>'销售退货单'][$mold], + 'class'=>search($list[$mold]['class'])->where([['id','=',$recordVo['class']]])->find(), + 'info'=>search($list[$mold]['info'])->where([['id','=',$recordVo['info']]])->find() + ]; + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售明细表']; + //表格数据 + $field=[ + 'name'=>'单据类型', + 'class|frameData|name'=>'所属组织', + 'class|customerData|name'=>'客户', + 'class|time'=>'单据时间', + 'class|number'=>'单据编号', + 'info|goodsData|name'=>'商品名称', + 'info|attr'=>'辅助属性', + 'info|warehouseData|name'=>'仓库', + 'info|unit'=>'单位', + 'info|price'=>'单价', + 'info|nums'=>'数量', + 'info|dsc'=>'折扣额', + 'info|total'=>'金额', + 'info|tat'=>'税额', + 'info|tpt'=>'价税合计', + 'class|data'=>'备注信息', + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $math=['sell'=>[],'sre'=>[]]; + foreach ($source as $sourceVo) { + $math[$sourceVo['mold']][]=$sourceVo['info']['tpt']; + } + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '销售总金额:'.mathArraySum($math['sell']), + '销售退货总金额:'.mathArraySum($math['sre']) + ]]; + //导出execl + buildExcel('销售明细表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //销售汇总表 + public function ssy(){ + $input=input('post.'); + if(existFull($input,['page','limit']) && is_array($input['warehouse']) && isset($input['type'])){ + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['customer','fullEq'], + ['user','fullEq'], + ['people','fullEq'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + $sql['class']=sqlAuth('sell',$sql['class']);//数据鉴权[结构一致] + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + //构造语句 + $union=[]; + $tab=['sell','sre']; + foreach ($tab as $t) { + $union[]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($sql['class'])->where($sql['info'])->fieldRaw('"'.$t.'" as mold,class.customer as customer,class.user as user,class.people as people,info.id as info,goods,attr,warehouse,unit,nums,tpt')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //判断类型 + if($input['type']==0){ + //按商品 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by goods,attr,warehouse ORDER BY `goods` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + }else if($input['type']==1){ + //按客户 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by customer,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,customer,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by customer,goods,attr,warehouse ORDER BY `customer` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + }else if($input['type']==2){ + //按用户 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by user,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,user,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by user,goods,attr,warehouse ORDER BY `user` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + }else{ + //按人员 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by people,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,people,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by people,goods,attr,warehouse ORDER BY `people` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + } + //构造数据 + $group = []; + foreach($record as $vo){ + $moldList = explode(",", $vo['mold']); + $infoList = explode(",", $vo['info']); + $unitList = explode(",", $vo['unit']); + $numsList = explode(",", $vo['nums']); + $tptList = explode(",", $vo['tpt']); + $row=['mold'=>$moldList[0],'info'=>$infoList[0]]; + foreach ($moldList as $key => $mold) { + $row[$mold]['unit'][]=$unitList[$key]; + $row[$mold]['nums'][]=$numsList[$key]; + $row[$mold]['tpt'][]=$tptList[$key]; + } + $input['type']==1&&$row['customer']=$vo['customer'];//客户转存 + $input['type']==2&&$row['user']=$vo['user'];//用户转存 + $input['type']==3&&$row['people']=$vo['people'];//人员转存 + $group[]=$row; + } + //数据匹配 + $infoList=[]; + foreach ($tab as $t) { + $mold="app\\model\\".ucfirst($t).'Info'; + $gather=search($group)->where([['mold','=',$t]])->select(); + $infoList[$t]=$mold::with(['goodsData','warehouseData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + } + //查询类型-匹配客户 + $input['type']==1&&$customerList=db::name('customer')->where([['id','in',array_column($group,'customer')]])->select()->toArray(); + //查询类型-匹配用户 + $input['type']==2&&$userList=db::name('user')->where([['id','in',array_column($group,'user')]])->select()->toArray(); + //查询类型-匹配人员 + $input['type']==3&&$peopleList=db::name('people')->where([['id','in',array_column($group,'people')]])->select()->toArray(); + //数据处理 + $data=[]; + foreach ($group as $groupVo) { + $row=search($infoList[$groupVo['mold']])->where([['id','=',$groupVo['info']]])->find(); + $row['unit']=$row['goodsData']['unit']==-1?'多单位':$row['unit']; + foreach ($tab as $t) { + if(isset($groupVo[$t])){ + if($row['goodsData']['unit']==-1){ + $base=0; + foreach ($groupVo[$t]['unit'] as $key=> $unit) { + $radix=unitRadix($unit,$row['goodsData']['units']); + $base=math()->chain($groupVo[$t]['nums'][$key])->mul($radix)->add($base)->done(); + } + $row[$t]=['base'=>$base,'nums'=>unitSwitch($base,$row['goodsData']['units']),'money'=>mathArraySum($groupVo[$t]['tpt'])]; + $row[$t]['price']=math()->chain($row[$t]['money'])->div($base)->round(2)->done(); + }else{ + $row[$t]=['nums'=>mathArraySum($groupVo[$t]['nums']),'money'=>mathArraySum($groupVo[$t]['tpt'])]; + $row[$t]['price']=math()->chain($row[$t]['money'])->div($row[$t]['nums'])->round(2)->done(); + $row[$t]['base']=$row[$t]['nums']; + } + }else{ + $row[$t]=['base'=>0,'price'=>0,'nums'=>0,'money'=>0]; + } + } + $row['summary']['nums']=math()->chain($row['sell']['base'])->sub($row['sre']['base'])->done(); + $row['goodsData']['unit']==-1&&$row['summary']['nums']=unitSwitch($row['summary']['nums'],$row['goodsData']['units']); + $row['summary']['money']=math()->chain($row['sell']['money'])->sub($row['sre']['money'])->done(); + //类型匹配 + $input['type']==1&&$row['customer']=search($customerList)->where([['id','=',$groupVo['customer']]])->find();//匹配客户 + $input['type']==2&&$row['user']=search($userList)->where([['id','=',$groupVo['user']]])->find();//匹配用户 + $input['type']==3&&$row['people']=search($peopleList)->where([['id','=',$groupVo['people']]])->find();//匹配人员 + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //销售汇总表-导出 + public function ssyExports(){ + $input=input('get.'); + existFull($input,['warehouse'])||$input['warehouse']=[]; + if(is_array($input['warehouse']) && isset($input['type'])){ + pushLog('导出销售汇总表');//日志 + $sql=[]; + //CLASS语句 + $sql['class']=fastSql($input,[ + ['customer','fullEq'], + ['user','fullEq'], + ['people','fullEq'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql['class'][]=['examine','=',1]; + $sql['class']=frameScope($sql['class']);//组织数据 + $sql['class']=sqlAuth('sell',$sql['class']);//数据鉴权[结构一致] + //INFO语句 + $sql['info']=fastSql($input,[['warehouse','fullDivisionIn']]); + //商品匹配 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql['info'][]=['goods','in',$goods]; + } + //构造语句 + $union=[]; + $tab=['sell','sre']; + foreach ($tab as $t) { + $union[]=Db::name($t.'_info')->alias('info')->join(['is_'.$t=>'class'],'info.pid=class.id')->where($sql['class'])->where($sql['info'])->fieldRaw('"'.$t.'" as mold,class.customer as customer,class.user as user,class.people as people,info.id as info,goods,attr,warehouse,unit,nums,tpt')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //判断类型 + if($input['type']==0){ + //按商品 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by goods,attr,warehouse ORDER BY `goods` DESC'); + }else if($input['type']==1){ + //按客户 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by customer,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,customer,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by customer,goods,attr,warehouse ORDER BY `customer` DESC'); + }else if($input['type']==2){ + //按用户 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by user,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,user,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by user,goods,attr,warehouse ORDER BY `user` DESC'); + }else{ + //按人员 + $count=count(DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud group by people,goods,attr,warehouse')); + $record = DB::query('SELECT group_concat(mold) as mold,people,group_concat(info) as info,group_concat(unit) as unit,group_concat(nums) as nums,group_concat(tpt) as tpt FROM ( '.$union.' ) as nodcloud group by people,goods,attr,warehouse ORDER BY `people` DESC'); + } + //构造数据 + $group = []; + foreach($record as $vo){ + $moldList = explode(",", $vo['mold']); + $infoList = explode(",", $vo['info']); + $unitList = explode(",", $vo['unit']); + $numsList = explode(",", $vo['nums']); + $tptList = explode(",", $vo['tpt']); + $row=['mold'=>$moldList[0],'info'=>$infoList[0]]; + foreach ($moldList as $key => $mold) { + $row[$mold]['unit'][]=$unitList[$key]; + $row[$mold]['nums'][]=$numsList[$key]; + $row[$mold]['tpt'][]=$tptList[$key]; + } + $input['type']==1&&$row['customer']=$vo['customer'];//客户转存 + $input['type']==2&&$row['user']=$vo['user'];//用户转存 + $input['type']==3&&$row['people']=$vo['people'];//人员转存 + $group[]=$row; + } + //数据匹配 + $infoList=[]; + foreach ($tab as $t) { + $mold="app\\model\\".ucfirst($t).'Info'; + $gather=search($group)->where([['mold','=',$t]])->select(); + $infoList[$t]=$mold::with(['goodsData','warehouseData'])->where([['id','in',array_column($gather,'info')]])->select()->toArray(); + } + //查询类型-匹配客户 + $input['type']==1&&$customerList=db::name('customer')->where([['id','in',array_column($group,'customer')]])->select()->toArray(); + //查询类型-匹配用户 + $input['type']==2&&$userList=db::name('user')->where([['id','in',array_column($group,'user')]])->select()->toArray(); + //查询类型-匹配人员 + $input['type']==3&&$peopleList=db::name('people')->where([['id','in',array_column($group,'people')]])->select()->toArray(); + //数据处理 + $data=[]; + foreach ($group as $groupVo) { + $row=search($infoList[$groupVo['mold']])->where([['id','=',$groupVo['info']]])->find(); + $row['unit']=$row['goodsData']['unit']==-1?'多单位':$row['unit']; + foreach ($tab as $t) { + if(isset($groupVo[$t])){ + if($row['goodsData']['unit']==-1){ + $base=0; + foreach ($groupVo[$t]['unit'] as $key=> $unit) { + $radix=unitRadix($unit,$row['goodsData']['units']); + $base=math()->chain($groupVo[$t]['nums'][$key])->mul($radix)->add($base)->done(); + } + $row[$t]=['base'=>$base,'nums'=>unitSwitch($base,$row['goodsData']['units']),'money'=>mathArraySum($groupVo[$t]['tpt'])]; + $row[$t]['price']=math()->chain($row[$t]['money'])->div($base)->round(2)->done(); + }else{ + $row[$t]=['nums'=>mathArraySum($groupVo[$t]['nums']),'money'=>mathArraySum($groupVo[$t]['tpt'])]; + $row[$t]['price']=math()->chain($row[$t]['money'])->div($row[$t]['nums'])->round(2)->done(); + $row[$t]['base']=$row[$t]['nums']; + } + }else{ + $row[$t]=['base'=>0,'price'=>0,'nums'=>0,'money'=>0]; + } + } + $row['summary']['nums']=math()->chain($row['sell']['base'])->sub($row['sre']['base'])->done(); + $row['goodsData']['unit']==-1&&$row['summary']['nums']=unitSwitch($row['summary']['nums'],$row['goodsData']['units']); + $row['summary']['money']=math()->chain($row['sell']['money'])->sub($row['sre']['money'])->done(); + //类型匹配 + $input['type']==1&&$row['customer']=search($customerList)->where([['id','=',$groupVo['customer']]])->find();//匹配客户 + $input['type']==2&&$row['user']=search($userList)->where([['id','=',$groupVo['user']]])->find();//匹配用户 + $input['type']==3&&$row['people']=search($peopleList)->where([['id','=',$groupVo['people']]])->find();//匹配人员 + $data[]=$row; + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售汇总表']; + //表格数据 + $field=[ + [ + "customer|name"=>"客户" + ], + [ + "user|name"=>"用户" + ], + [ + "people|name"=>"关联人员" + ], + [ + "goodsData|name"=>"商品名称", + "attr"=>"辅助属性", + "warehouseData|name"=>"仓库", + "unit"=>"单位", + "sell|price"=>"销售单价", + "sell|nums"=>"销售数量", + "sell|money"=>"销售金额", + "sre|price"=>"购退单价", + "sre|nums"=>"购退数量", + "sre|money"=>"购退金额", + "summary|nums"=>"汇总数量", + "summary|money"=>"汇总金额" + ] + ]; + $field=[$field[3],array_merge($field[0],$field[3]),array_merge($field[1],$field[3]),array_merge($field[2],$field[3]),][$input['type']]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '销售总金额:'.mathArraySum(arrayColumns($source,['sell','money'])), + '销售退货总金额:'.mathArraySum(arrayColumns($source,['sre','money'])), + '汇总金额:'.mathArraySum(arrayColumns($source,['summary','money'])) + ]]; + //导出execl + buildExcel('销售汇总表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //销售收款表 + public function sbt(){ + $input=input('post.'); + $sheet=['sell','sre']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(existFull($input,['page','limit']) && is_arrays($input,['nucleus','mold']) && arrayInArray($input['mold'],$sheet)){ + $sql=[]; + //CLASS语句 + $sql=fastSql($input,[ + ['customer','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['nucleus','fullIn'] + ]); + $sql[]=['examine','=',1]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('sell',$sql);//数据鉴权[结构一致] + //组装语句 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->where($sql)->fieldRaw('"'.$mold.'" as mold,id,time')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $count=DB::query('SELECT COUNT(*) as count FROM ('.$union.') as nodcloud')[0]["count"]; + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC LIMIT '.pageCalc($input['page'],$input['limit'],'str')); + //匹配数据 + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $db="app\\model\\".ucfirst($mold); + $list[$mold]=$db::with(['frameData','customerData','billData'])->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray(); + } + //构造数据 + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $row=search($list[$mold])->where([['id','=',$recordVo['id']]])->find(); + $row['key']=$mold.'_'.$recordVo['id']; + $row['name']=['sell'=>'销售单','sre'=>'销售退货单'][$mold]; + $row['balance']=$row['extension']['anwo']; + $row['rate']=in_array($row['nucleus'],['0','2'])?['0%','','100%'][$row['nucleus']]:math()->chain($row['extension']['amount'])->div($row['actual'])->mul(100)->round(2)->done().'%'; + $row['node']=[]; + $bill=search($row['billData'])->where([['type','=','bill']])->select(); + foreach ($bill as $billVo) { + $node=[ + 'key'=>$row['key'].'_'.$billVo['id'], + 'name'=>'核销单', + 'time'=>$billVo['time'], + 'number'=>$billVo['sourceData']['number'], + 'money'=>$billVo['money'], + ]; + //反转金额 + in_array($mold,['sre'])&&$node['money']*=-1; + $row['node'][]=$node; + } + //反转金额 + if(in_array($mold,['sre'])){ + $row['total']*=-1; + $row['actual']*=-1; + $row['money']*=-1; + $row['balance']*=-1; + } + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //销售收款表-导出 + public function sbtExports(){ + $input=input('get.'); + $sheet=['sell','sre']; + existFull($input,['nucleus'])||$input['nucleus']=[]; + existFull($input,['mold'])||$input['mold']=$sheet; + if(is_arrays($input,['nucleus','mold']) && arrayInArray($input['mold'],$sheet)){ + pushLog('导出销售收款表');//日志 + $sql=[]; + //CLASS语句 + $sql=fastSql($input,[ + ['customer','fullEq'], + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['nucleus','fullDivisionIn'] + ]); + $sql[]=['examine','=',1]; + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('sell',$sql);//数据鉴权[结构一致] + //组装语句 + $union=[]; + foreach ($input['mold'] as $mold) { + $union[]=Db::name($mold)->where($sql)->fieldRaw('"'.$mold.'" as mold,id,time')->buildSql(); + } + $union=implode(' UNION ALL ',$union); + //获取总条数 + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud ORDER BY `time` DESC'); + //匹配数据 + $list=[]; + foreach ($input['mold'] as $mold) { + $gather=search($record)->where([['mold','=',$mold]])->select(); + $db="app\\model\\".ucfirst($mold); + $list[$mold]=$db::with(['frameData','customerData','billData'])->where([['id','in',array_column($gather,'id')]])->append(['extension'])->select()->toArray(); + } + //构造数据 + $data=[]; + foreach ($record as $recordVo) { + $mold=$recordVo['mold']; + $row=search($list[$mold])->where([['id','=',$recordVo['id']]])->find(); + $row['key']=$mold.'_'.$recordVo['id']; + $row['name']=['sell'=>'销售单','sre'=>'销售退货单'][$mold]; + $row['balance']=$row['extension']['anwo']; + $row['rate']=in_array($row['nucleus'],['0','2'])?['0%','','100%'][$row['nucleus']]:math()->chain($row['extension']['amount'])->div($row['actual'])->mul(100)->round(2)->done().'%'; + $row['node']=[]; + $bill=search($row['billData'])->where([['type','=','bill']])->select(); + foreach ($bill as $billVo) { + $node=[ + 'key'=>$row['key'].'_'.$billVo['id'], + 'name'=>'核销单', + 'time'=>$billVo['time'], + 'number'=>$billVo['sourceData']['number'], + 'money'=>$billVo['money'], + ]; + //反转金额 + in_array($mold,['sre'])&&$node['money']*=-1; + $row['node'][]=$node; + } + //反转金额 + if(in_array($mold,['sre'])){ + $row['total']*=-1; + $row['actual']*=-1; + $row['money']*=-1; + $row['balance']*=-1; + } + $data[]=$row; + } + $source=[]; + foreach ($data as $dataVo) { + $source[]=$dataVo; + if(!empty($dataVo['node'])){ + foreach ($dataVo['node'] as $node) { + $source[]=$node; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'销售收款表']; + //表格数据 + $field=[ + "name"=>"单据类型", + "frameData|name"=>"所属组织", + "customerData|name"=>"客户", + "time"=>"单据时间", + "number"=>"单据编号", + "total"=>"单据金额", + "actual"=>"实际金额", + "money"=>"单据付款", + "balance"=>"应付款余额", + "rate"=>"付款率", + "extension|nucleus"=>"核销状态", + "data"=>"备注信息" + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '应收款总余额:'.mathArraySum(array_column($source,'balance')) + ]]; + //导出execl + buildExcel('销售收款表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } +} diff --git a/serve/app/controller/Stock.php b/serve/app/controller/Stock.php new file mode 100644 index 0000000..f8f2130 --- /dev/null +++ b/serve/app/controller/Stock.php @@ -0,0 +1,437 @@ +where(empty($input['warehouse'])?sqlAuth('warehouse',[]):[['id','in',$input['warehouse']]])->order(['id'=>'desc'])->select()->toArray(); + //构造表头|集合 + $column=[]; + foreach ($warehouse as $warehouseVo) { + $column[]=['id'=>$warehouseVo['id'],'key'=>'stock_'.$warehouseVo['id'],'name'=>$warehouseVo['name']]; + } + //匹配商品 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'], + ['spec','fullLike'], + ['brand','fullEq'], + ['code','fullLike'] + ]);//构造SQL + //商品类型 + $sql[]=['type','=',0]; + //辅助属性扩展查询 + $sqlOr=existFull($input,['code'])?[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]:[]; + //商品分类树结构查询 + existFull($input,['category'])&&$sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + //查询类型 + if($input['state']==0){ + //获取总条数 + $count = Goods::where($sql)->whereOr($sqlOr)->count(); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->order(['id'=>'desc'])->page($input['page'],$input['limit'])->append(['extension'])->select()->toArray(); + }elseif($input['state']==1){ + $exists=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['nums','<>',0],['goods','=',Db::raw('goods.id')]])->buildSql(false); + //获取总条数 + $count = Goods::where($sql)->whereOr($sqlOr)->alias('goods')->whereExists($exists)->count(); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->alias('goods')->whereExists($exists)->order(['id'=>'desc'])->page($input['page'],$input['limit'])->append(['extension'])->select()->toArray(); + }else{ + //子查询 + $exists=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['goods','=',Db::raw('goods.id')],['nums','<=',Db::raw('goods.stock')]])->buildSql(false); + //获取总条数 + $count = Goods::where($sql)->whereOr($sqlOr)->alias('goods')->whereExists($exists)->count(); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->alias('goods')->whereExists($exists)->order(['id'=>'desc'])->page($input['page'],$input['limit'])->append(['extension'])->select()->toArray(); + } + //唯一标识|属性处理 + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['key']=$infoVo['id']; + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + $info[$infoKey]['attr'][$attrKey]['key']=$infoVo['id'].'.'.$attrVo['id']; + //属性处理 + if(existFull($input,['code']) && !in_array($input['code'],[$infoVo['code'],$attrVo['code']])){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //查询库存数据 + $room=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['goods','in',array_column($info,'id')]])->select()->toArray(); + //库存集合[w:仓库|g:商品|a:属性] + $gather=['g'=>[],'wg'=>[],'ga'=>[],'wga'=>[]]; + foreach ($room as $roomVo) { + //商品 + $g=md5_16($roomVo['goods']); + $gather['g'][$g]=math()->chain($gather['g'][$g]??0)->add($roomVo['nums'])->done(); + //仓库|商品 + $wg=md5_16($roomVo['warehouse'].'&'.$roomVo['goods']); + $gather['wg'][$wg]=math()->chain($gather['wg'][$wg]??0)->add($roomVo['nums'])->done(); + //判断属性 + if(!empty($roomVo['attr'])){ + //商品|属性 + $ga=md5_16($roomVo['goods'].'&'.$roomVo['attr']); + $gather['ga'][$ga]=math()->chain($gather['ga'][$ga]??0)->add($roomVo['nums'])->done(); + //仓库|商品|属性 + $wga=md5_16($roomVo['warehouse'].'&'.$roomVo['goods'].'&'.$roomVo['attr']); + $gather['wga'][$wga]=math()->chain($gather['wga'][$wga]??0)->add($roomVo['nums'])->done(); + } + } + //数量匹配|库存处理 + foreach ($info as $infoKey=>$infoVo) { + //商品 + $g=md5_16($infoVo['id']); + $info[$infoKey]['summary']=isset($gather['g'][$g])?($infoVo['unit']=='-1'?unitSwitch($gather['g'][$g],$infoVo['units']):$gather['g'][$g]):0; + //仓库|商品 + foreach ($column as $columnVo) { + $wg=md5_16($columnVo['id'].'&'.$infoVo['id']); + $info[$infoKey]['stock_'.$columnVo['id']]=isset($gather['wg'][$wg])?($infoVo['unit']=='-1'?unitSwitch($gather['wg'][$wg],$infoVo['units']):$gather['wg'][$wg]):0; + } + //匹配辅助属性 + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //商品|属性 + $ga=md5_16($infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['summary']=isset($gather['ga'][$ga])?($infoVo['unit']=='-1'?unitSwitch($gather['ga'][$ga],$infoVo['units']):$gather['ga'][$ga]):0; + //仓库|商品|属性 + foreach ($column as $columnVo) { + $wga=md5_16($columnVo['id'].'&'.$infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['stock_'.$columnVo['id']]=isset($gather['wga'][$wga])?($infoVo['unit']=='-1'?unitSwitch($gather['wga'][$wga],$infoVo['units']):$gather['wga'][$wga]):0; + $input['state']==2&&$info[$infoKey]['attr'][$attrKey]['stocks'][]=$info[$infoKey]['attr'][$attrKey]['stock_'.$columnVo['id']]; + } + //非零库存|排除属性为零 + if($input['state']==1 && $info[$infoKey]['attr'][$attrKey]['summary']==0){ + unset($info[$infoKey]['attr'][$attrKey]); + } + //预警库存 + if($input['state']==2){ + $exist=false; + foreach ($info[$infoKey]['attr'][$attrKey]['stocks'] as $stockVo) { + if($stockVo<=$info[$infoKey]['stock']){ + $exist=true; + break; + } + } + if(!$exist)unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info, + 'column'=>$column + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + existFull($input,['warehouse'])||$input['warehouse']=[]; + if(isset($input['warehouse']) && is_array($input['warehouse']) && isset($input['state']) && in_array($input['state'],[0,1,2])){ + pushLog('导出库存列表');//日志 + //匹配仓库 + $warehouse = Db::name('warehouse')->where(empty($input['warehouse'])?sqlAuth('warehouse',[]):[['id','in',$input['warehouse']]])->order(['id'=>'desc'])->select()->toArray(); + //构造表头 + $column=[]; + foreach ($warehouse as $warehouseVo) { + $column['stock_'.$warehouseVo['id']]=$warehouseVo['name']; + } + //匹配商品 + $sql=fastSql($input,[ + [['name'=>'name|py'],'fullLike'], + ['number','fullLike'], + ['spec','fullLike'], + ['brand','fullEq'], + ['code','fullLike'] + ]);//构造SQL + //商品类型 + $sql[]=['type','=',0]; + //辅助属性扩展查询 + $sqlOr=existFull($input,['code'])?[['id','in',array_column(Db::name('attr')->where([['code','=',$input['code']]])->select()->toArray(),'pid')]]:[]; + //商品分类树结构查询 + existFull($input,['category'])&&$sql[]=['category','in',findTreeArr('category',$input['category'],'id')]; + //查询类型 + if($input['state']==0){ + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + }elseif($input['state']==1){ + $exists=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['nums','<>',0],['goods','=',Db::raw('goods.id')]])->buildSql(false); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->alias('goods')->whereExists($exists)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + }else{ + //子查询 + $exists=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['goods','=',Db::raw('goods.id')],['nums','<=',Db::raw('goods.stock')]])->buildSql(false); + //获取总条数 + $count = Goods::where($sql)->whereOr($sqlOr)->alias('goods')->whereExists($exists)->count(); + //查询分页数据 + $info = Goods::with(['categoryData','attr'])->where($sql)->whereOr($sqlOr)->alias('goods')->whereExists($exists)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + } + //属性处理 + foreach ($info as $infoKey=>$infoVo) { + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //属性处理 + if(existFull($input,['code']) && !in_array($input['code'],[$infoVo['code'],$attrVo['code']])){ + unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //查询库存数据 + $room=Db::name('room')->where([['warehouse','in',array_column($warehouse,'id')],['goods','in',array_column($info,'id')]])->select()->toArray(); + //库存集合[w:仓库|g:商品|a:属性] + $gather=['g'=>[],'wg'=>[],'ga'=>[],'wga'=>[]]; + foreach ($room as $roomVo) { + //商品 + $g=md5_16($roomVo['goods']); + $gather['g'][$g]=math()->chain($gather['g'][$g]??0)->add($roomVo['nums'])->done(); + //仓库|商品 + $wg=md5_16($roomVo['warehouse'].'&'.$roomVo['goods']); + $gather['wg'][$wg]=math()->chain($gather['wg'][$wg]??0)->add($roomVo['nums'])->done(); + //判断属性 + if(!empty($roomVo['attr'])){ + //商品|属性 + $ga=md5_16($roomVo['goods'].'&'.$roomVo['attr']); + $gather['ga'][$ga]=math()->chain($gather['ga'][$ga]??0)->add($roomVo['nums'])->done(); + //仓库|商品|属性 + $wga=md5_16($roomVo['warehouse'].'&'.$roomVo['goods'].'&'.$roomVo['attr']); + $gather['wga'][$wga]=math()->chain($gather['wga'][$wga]??0)->add($roomVo['nums'])->done(); + } + } + + //数量匹配|库存处理 + foreach ($info as $infoKey=>$infoVo) { + //商品 + $g=md5_16($infoVo['id']); + $info[$infoKey]['summary']=isset($gather['g'][$g])?($infoVo['unit']=='-1'?unitSwitch($gather['g'][$g],$infoVo['units']):$gather['g'][$g]):0; + //仓库|商品 + foreach ($warehouse as $warehouseVo) { + $wg=md5_16($warehouseVo['id'].'&'.$infoVo['id']); + $info[$infoKey]['stock_'.$warehouseVo['id']]=isset($gather['wg'][$wg])?($infoVo['unit']=='-1'?unitSwitch($gather['wg'][$wg],$infoVo['units']):$gather['wg'][$wg]):0; + + } + //匹配辅助属性 + foreach ($infoVo['attr'] as $attrKey=>$attrVo) { + //商品|属性 + $ga=md5_16($infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['summary']=isset($gather['ga'][$ga])?($infoVo['unit']=='-1'?unitSwitch($gather['ga'][$ga],$infoVo['units']):$gather['ga'][$ga]):0; + //仓库|商品|属性 + foreach ($warehouse as $warehouseVo) { + $wga=md5_16($warehouseVo['id'].'&'.$infoVo['id'].'&'.$attrVo['name']); + $info[$infoKey]['attr'][$attrKey]['stock_'.$warehouseVo['id']]=isset($gather['wga'][$wga])?($infoVo['unit']=='-1'?unitSwitch($gather['wga'][$wga],$infoVo['units']):$gather['wga'][$wga]):0; + $input['state']==2&&$info[$infoKey]['attr'][$attrKey]['stocks'][]=$info[$infoKey]['attr'][$attrKey]['stock_'.$warehouseVo['id']]; + } + //非零库存|排除属性为零 + if($input['state']==1 && $info[$infoKey]['attr'][$attrKey]['summary']==0){ + unset($info[$infoKey]['attr'][$attrKey]); + } + //预警库存 + if($input['state']==2){ + $exist=false; + foreach ($info[$infoKey]['attr'][$attrKey]['stocks'] as $stockVo) { + if($stockVo<=$info[$infoKey]['stock']){ + $exist=true; + break; + } + } + if(!$exist)unset($info[$infoKey]['attr'][$attrKey]); + } + } + //重建索引 + $info[$infoKey]['attr']=array_values($info[$infoKey]['attr']); + } + //结构重组 + $source=[]; + foreach ($info as $infoVo) { + $source[]=$infoVo; + if(!empty($infoVo['attr'])){ + foreach ($infoVo['attr'] as $attrVo) { + $attrVo['name']='|- '.$attrVo['name']; + $source[]=$attrVo; + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'库存列表']; + //表格数据 + $field=array_merge(['name'=>'商品名称','summary'=>'库存数量'],$column,['stock'=>'预警阈值','number'=>'商品编号','spec'=>'规格型号','categoryData|name'=>'商品分类','brand'=>'商品品牌','extension|unit'=>'商品单位','code'=>'商品条码','data'=>'商品备注']); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('库存列表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } + //详情列表 + public function detailRecord(){ + $input=input('post.'); + $sheet=['buy','bre','sell','sre','swapOut','swapEnter','entry','extry']; + existFull($input,['type'])||$input['type']=$sheet; + if(existFull($input,['page','limit','goods','warehouse']) && is_arrays($input,['warehouse','type']) && arrayInArray($input['type'],$sheet)){ + //构造SQL|ROOM + $roomSql=fastSql($input,[ + ['warehouse','fullIn'], + ['goods','fullEq'] + ]); + isset($input['attr'])&&$roomSql[]=['attr','=',$input['attr']]; + //查询仓储数据 + $room=Db::name('room')->where($roomSql)->field(['id'])->select()->toArray(); + if(empty($room)){ + $count=0; + $info=[]; + }else{ + //构造SQL|ROOMINFO + $infoSql=fastSql($input,[['type','fullIn']]); + $infoSql[]=['pid','in',array_column($room,'id')]; + //子查询SQL + $existsSql=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['id','=',Db::raw('info.class')]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + //匹配类型|减少查询 + if(in_array($k,$input['type'])){ + $union[]=Db::name($v)->where([['info.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $count=RoomInfo::alias('info')->where($infoSql)->whereExists($union)->count(); + $info=RoomInfo::with(['sourceData'=>['frameData']])->alias('info')->where($infoSql)->whereExists($union)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //处理多单位 + if(!empty($info)){ + $goods=Db::name('goods')->where([['id','=',$input['goods']]])->find(); + if($goods['unit']=='-1'){ + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['nums']=unitSwitch($infoVo['nums'],json_decode($goods['units'],true)); + } + } + } + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //详情导出 + public function detailExports(){ + $input=input('get.'); + $sheet=['buy','bre','sell','sre','swapOut','swapEnter','entry','extry']; + existFull($input,['type'])||$input['type']=$sheet; + if(existFull($input,['goods','warehouse']) && is_arrays($input,['warehouse','type']) && arrayInArray($input['type'],$sheet)){ + pushLog('导出库存详情');//日志 + //商品数据 + $goods=Db::name('goods')->where([['id','=',$input['goods']]])->find(); + //构造SQL|ROOM + $roomSql=fastSql($input,[ + ['warehouse','fullIn'], + ['goods','fullEq'] + ]); + isset($input['attr'])&&$roomSql[]=['attr','=',$input['attr']]; + //查询仓储数据 + $room=Db::name('room')->where($roomSql)->field(['id'])->select()->toArray(); + if(empty($room)){ + $source=[]; + }else{ + //构造SQL|ROOMINFO + $infoSql=fastSql($input,[['type','fullIn']]); + $infoSql[]=['pid','in',array_column($room,'id')]; + //子查询SQL + $existsSql=fastSql($input,[ + ['number','fullLike'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $existsSql[]=['id','=',Db::raw('info.class')]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + //匹配类型|减少查询 + if(in_array($k,$input['type'])){ + $union[]=Db::name($v)->where([['info.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $source=RoomInfo::with(['sourceData'=>['frameData']])->alias('info')->where($infoSql)->whereExists($union)->order(['id'=>'desc'])->append(['extension'])->select()->toArray(); + //处理多单位 + if(!empty($source)){ + $goods=Db::name('goods')->where([['id','=',$input['goods']]])->find(); + if($goods['unit']=='-1'){ + foreach ($source as $sourceKey=>$sourceVo) { + $source[$sourceKey]['nums']=unitSwitch($sourceVo['nums'],json_decode($goods['units'],true)); + } + } + } + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'库存详情']; + //表格数据 + $field=[ + 'sourceData|frameData|name'=>'所属组织', + 'sourceData|time'=>'操作时间', + 'extension|type'=>'单据类型', + 'sourceData|number'=>'单据编号', + 'extension|direction'=>'操作类型', + 'nums'=>'操作数量' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('库存详情',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Summary.php b/serve/app/controller/Summary.php new file mode 100644 index 0000000..e074a9c --- /dev/null +++ b/serve/app/controller/Summary.php @@ -0,0 +1,289 @@ +where([['time','>',$period]])->count(); + //计价方式 + $fun=getSys('fun'); + $info=[ + 'valuation'=>['base'=>'基础计价','ma'=>'移动平均','fifo'=>'先进先出'][$fun['valuation']], + 'branch'=>['总仓核算','分仓核算'][$fun['branch']], + 'rule'=>['def'=>'结存结余','attr'=>'辅助属性','batch'=>'批次日期','aab'=>'属性批次'][$fun['rule']], + ]; + //初始结账 + $summary=Db::name('summary')->where([['time','>',$period]])->field(['id'])->select()->toArray(); + $fifo=Db::name('fifo')->where([['out','in',array_column($summary,'id')]])->select()->toArray(); + $relation=[]; + foreach ($fifo as $v) { + $relation[]=['id'=>$v['in'],'handle'=>$v['handle']]; + } + if(!empty($relation)){ + Db::name('summary')->duplicate(['handle'=>Db::raw('handle - VALUES(`handle`)')])->insertAll($relation); + Db::name('fifo')->where([['id','in',array_column($fifo,'id')]])->delete(); + } + Db::name('summary')->where([['id','in',array_column($summary,'id')]])->delete(); + pushLog('执行数据校准');//日志 + //返回数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ]; + return json($result); + } + //收发处理 + public function note($type,$class,$mold){ + //场景判断 + if($mold){ + //记录 + $info=Db::name('room_info')->where([['type','=',$type],['class','=',$class]])->order(['time','id'])->field(['id'])->select()->toArray(); + $this->handle(array_column($info,'id')); + }else{ + //清除 + $summary=Db::name('summary')->where([['type','=',$type],['class','=',$class]])->field(['id'])->select()->toArray(); + $fifo=Db::name('fifo')->where([['out','in',array_column($summary,'id')]])->select()->toArray(); + $relation=[]; + foreach ($fifo as $v) { + $relation[]=['id'=>$v['in'],'handle'=>$v['handle']]; + } + if(!empty($relation)){ + Db::name('summary')->duplicate(['handle'=>Db::raw('handle - VALUES(`handle`)')])->insertAll($relation); + Db::name('fifo')->where([['id','in',array_column($fifo,'id')]])->delete(); + } + Db::name('summary')->where([['id','in',array_column($summary,'id')]])->delete(); + } + } + //轮询数据 + public function poll() { + $input=input('post.'); + if(existFull($input,['page','limit'])){ + Db::startTrans(); + try { + $period=getPeriod(); + $info=Db::name('room_info')->where([['time','>',$period]])->page($input['page'],$input['limit'])->order(['time','id'])->field(['id'])->select()->toArray(); + $this->handle(array_column($info,'id')); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + dd($e); + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //收发记录 + public function handle($arr){ + if(empty($arr)) return; + //查询记录 + $info = Db::name('room_info')->where([['id','in',$arr]])->order(['time','id'])->select()->toArray(); + //匹配单据 + $union=[]; + $tab=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($tab as $t=>$m) { + $gather=search($info)->where([['type','=',$t]])->select(); + if(!empty($gather)){ + $union[]=Db::name($m.'_info')->where([['id','in',array_column($gather,'info')]])->fieldRaw('"'.$t.'" as mold,id,goods,attr,'.($t=='swapEnter'?'storehouse as warehouse':'warehouse').',batch,mfd,serial')->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $record=DB::query('SELECT * FROM ('.$union.') as nodcloud'); + //构造数据 + $summary=[]; + //exist结存|balance结余 + //[0,0,0,0]=[商品总仓|商品分仓|规则总仓|规则分仓] + $def=['exist'=>[0,0,0,0],'balance'=>[0,0,0,0]]; + foreach ($info as $vo) { + $row=search($record)->where([['mold','=',$vo['type']],['id','=',$vo['info']]])->find(); + $summary[]=[ + 'pid'=>$vo['id'], + 'type'=>$vo['type'], + 'class'=>$vo['class'], + 'info'=>$vo['info'], + 'time'=>$vo['time'], + 'goods'=>$row['goods'], + 'attr'=>$row['attr'], + 'warehouse'=>$row['warehouse'], + 'batch'=>$row['batch'], + 'mfd'=>$row['mfd'], + 'serial'=>$row['serial'], + 'direction'=>$vo['direction'], + 'price'=>$vo['price'], + 'nums'=>$vo['nums'], + 'uct'=>0, + 'bct'=>0, + 'exist'=>json_encode($def['exist']), + 'balance'=>json_encode($def['balance']), + 'handle'=>0 + ]; + } + Db::name('summary')->insertAll($summary); + $summary=Db::name('summary')->where([['pid','in',array_column($summary,'pid')]])->order(['id'])->select()->toArray(); + //处理数据 + $fun=getSys('fun'); + $goods=Db::name('goods')->where([['id','in',array_column($summary,'goods')]])->field(['id','buy'])->select()->toArray(); + $attr=Db::name('attr')->where([['pid','in',array_column($summary,'goods')]])->field(['pid','name','buy'])->select()->toArray(); + foreach ($summary as $vo) { + $sql=[ + [['id','<',$vo['id']],['goods','=',$vo['goods']]], + [['warehouse','=',$vo['warehouse']]] + ]; + //规则语句 + if($fun['rule']=='def'){ + $sql[]=[]; + }else if($fun['rule']=='attr'){ + $sql[]=[['attr','=',$vo['attr']]]; + }else if($fun['rule']=='batch'){ + $sql[]=[['batch','=',$vo['batch']],['mfd','=',$vo['mfd']]]; + }else{ + $sql[]=[['attr','=',$vo['attr']],['batch','=',$vo['batch']],['mfd','=',$vo['mfd']]]; + } + //[商品总仓|商品分仓|规则总仓|规则分仓] + $senten=[$sql[0],array_merge($sql[0],$sql[1]),array_merge($sql[0],$sql[2]),array_merge($sql[0],$sql[1],$sql[2])]; + $first=[]; + $first[]=Db::name('summary')->where($senten[0])->order(['id'=>'DESC'])->find(); + $first[]=Db::name('summary')->where($senten[1])->order(['id'=>'DESC'])->find(); + $first[]=Db::name('summary')->where($senten[2])->order(['id'=>'DESC'])->find(); + $first[]=Db::name('summary')->where($senten[3])->order(['id'=>'DESC'])->find(); + //默认值 + foreach ($first as $k=>$v) { + if(empty($v)){ + $first[$k]=$def; + }else{ + $first[$k]=['exist'=>json_decode($v['exist']),'balance'=>json_decode($v['balance'])]; + } + } + //数据处理 + $g=search($goods)->where([['id','=',$vo['goods']]])->find(); + $a=search($attr)->where([['pid','=',$vo['goods']],['name','=',$vo['attr']]])->find(); + $buy=empty($a)?$g['buy']:$a['buy']; + //序列判断 + $serial=json_decode($vo['serial']); + if(empty($serial)){ + //计价方法 + if($fun['valuation']=='base'){ + //基础计价法 + if(in_array($vo['type'],['buy','bre','swapOut','swapEnter','entry','extry'])){ + $uct=$vo['price']; + }else{ + $uct=$buy; + } + }else if($fun['valuation']=='ma'){ + //移动平均法 + if(in_array($vo['type'],['buy','bre','swapOut','swapEnter','entry','extry'])){ + $uct=$vo['price']; + }else{ + //[空|负]库存取采购价 + //正常库存取结余除结存 + if(empty($fun['branch'])){ + $uct=$first[2]['exist'][2]<=0?$buy:math()->chain($first[2]['balance'][2])->div($first[2]['exist'][2])->done(); + }else{ + $uct=$first[3]['exist'][3]<=0?$buy:math()->chain($first[3]['balance'][3])->div($first[3]['exist'][3])->round(2)->done(); + } + } + }else{ + //先进先出法 + if(in_array($vo['type'],['buy','swapEnter','entry'])){ + $uct=$vo['price']; + }else if(in_array($vo['type'],['sre','vre'])){ + $uct=$buy; + }else{ + $where=[ + ['id','<',$vo['id']], + ['goods','=',$vo['goods']], + ['attr','=',$vo['attr']], + ['batch','=',$vo['batch']], + ['mfd','=',$vo['mfd']], + ['direction','=',1], + [DB::raw('nums'),'<>',DB::raw('handle')] + ]; + empty($fun['branch'])&&$where[]=['warehouse','=',$vo['warehouse']]; + $build=DB::name('summary')->where($where)->fieldRaw('id,uct,(nums - handle) as usable,(@sum := @sum + (nums - handle)) as sum')->order('id')->buildSql(false); + $build=str_replace("WHERE","CROSS JOIN ( SELECT @sum := 0 ) t WHERE",$build); + $list=DB::query('SELECT * FROM ('.$build.') as nodcloud WHERE sum < '.$vo['nums'].' or (sum >= '.$vo['nums'].' and sum - usable < '.$vo['nums'].');'); + if(empty($list)){ + //[无入库]取采购价 + $uct=$buy; + }else{ + $uct=0; + $knot=$vo['nums']; + $relation=[]; + foreach ($list as $v) { + if($knot<=$v['usable']){ + $relation[]=['id'=>$v['id'],'handle'=>$knot]; + $calc=math()->chain($knot)->mul($v['uct'])->done(); + $uct=math()->chain($uct)->add($calc)->done(); + break; + }else{ + $relation[]=['id'=>$v['id'],'handle'=>$v['usable']]; + $calc=math()->chain($v['usable'])->mul($v['uct'])->done(); + $uct=math()->chain($uct)->add($calc)->done(); + $knot=math()->chain($knot)->sub($v['usable'])->done(); + } + } + $uct=math()->chain($uct)->div($vo['nums'])->done(); + Db::name('summary')->duplicate(['handle'=>Db::raw('handle + VALUES(`handle`)')])->insertAll($relation); + $fifo=[]; + foreach ($relation as $v) { + $fifo[]=['out'=>$vo['id'],'in'=>$v['id'],'handle'=>$v['handle']]; + } + Db::name('fifo')->insertAll($fifo); + } + } + } + }else{ + //序列产品 + if(in_array($vo['type'],['buy','swapEnter','entry'])){ + //[无入库]取采购价 + $uct=$vo['price']; + }else{ + $uct=0; + foreach ($serial as $v) { + $row=DB::name('summary')->where([ + ['id','<',$vo['id']], + ['goods','=',$vo['goods']], + ['serial','like','%"'.$v.'"%'] + ])->field(['uct'])->order(['id'=>'DESC'])->find(); + $uct=math()->chain($uct)->add(empty($row)?$buy:$row['uct'])->done(); + } + $uct=math()->chain($uct)->div($vo['nums'])->done(); + } + + + } + //综合处理 + $uct=math()->chain($uct)->round($fun['digit']['money'])->done(); + $exist=[ + empty($vo['direction'])?math()->chain($first[0]['exist'][0])->sub($vo['nums'])->done():math()->chain($first[0]['exist'][0])->add($vo['nums'])->done(), + empty($vo['direction'])?math()->chain($first[1]['exist'][1])->sub($vo['nums'])->done():math()->chain($first[1]['exist'][1])->add($vo['nums'])->done(), + empty($vo['direction'])?math()->chain($first[2]['exist'][2])->sub($vo['nums'])->done():math()->chain($first[2]['exist'][2])->add($vo['nums'])->done(), + empty($vo['direction'])?math()->chain($first[3]['exist'][3])->sub($vo['nums'])->done():math()->chain($first[3]['exist'][3])->add($vo['nums'])->done() + ]; + $bct=math()->chain($uct)->mul($vo['nums'])->done(); + $balance=[ + empty($vo['direction'])?math()->chain($first[0]['balance'][0])->sub($bct)->done():math()->chain($first[0]['balance'][0])->add($bct)->done(), + empty($vo['direction'])?math()->chain($first[1]['balance'][1])->sub($bct)->done():math()->chain($first[1]['balance'][1])->add($bct)->done(), + empty($vo['direction'])?math()->chain($first[2]['balance'][2])->sub($bct)->done():math()->chain($first[2]['balance'][2])->add($bct)->done(), + empty($vo['direction'])?math()->chain($first[3]['balance'][3])->sub($bct)->done():math()->chain($first[3]['balance'][3])->add($bct)->done() + ]; + foreach ($exist as $k=>$v){ + $v==0&&$balance[$k]=0; + } + $exist=json_encode($exist); + $balance=json_encode($balance); + Db::name('summary')->where([['id','=',$vo['id']]])->update(['uct'=>$uct,'bct'=>$bct,'exist'=>$exist,'balance'=>$balance]); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Supplier.php b/serve/app/controller/Supplier.php new file mode 100644 index 0000000..515c41d --- /dev/null +++ b/serve/app/controller/Supplier.php @@ -0,0 +1,246 @@ +'name|py'],'fullLike'], + ['number','fullLike'], + ['category','fullEq'], + ['contacts','fullLike'], + [['tel'=>'contacts'],'fullLike'], + ['user','fullEq'], + ['data','fullLike'] + ]);//构造SQL + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('supplier',$sql);//数据鉴权 + $count = Suppliers::where($sql)->count();//获取总条数 + $info = Suppliers::with(['frameData','userData'])->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //构造|验证 + try { + //排除balance字段|防止更新应付款余额 + unset($input['balance']); + $input['py']=zhToPy($input['name']);//首拼信息 + empty($input['id'])?$this->validate($input,'app\validate\Supplier'):$this->validate($input,'app\validate\Supplier.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Suppliers::create($input); + pushLog('新增供应商[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Suppliers::update($input); + pushLog('更新供应商[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Suppliers::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $exist=moreTableFind([ + ['table'=>'bor','where'=>[['supplier','in',$input['parm']]]], + ['table'=>'buy','where'=>[['supplier','in',$input['parm']]]], + ['table'=>'bre','where'=>[['supplier','in',$input['parm']]]], + ['table'=>'entry','where'=>[['supplier','in',$input['parm']]]], + ['table'=>'omy','where'=>[['supplier','in',$input['parm']]]], + ['table'=>'bill','where'=>[['customer','in',$input['parm']]]], + ['table'=>'oce','where'=>[['supplier','in',$input['parm']]]], + ]); + if(empty($exist)){ + $data=Db::name('supplier')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + Db::startTrans(); + try { + Db::name('supplier')->where([['id','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除供应商[ '.implode(' | ',array_column($data,'name')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + $sql=[];//初始化SQL + $frame=Db::name('frame')->where([['name','in',array_column($data,'C')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'name'=>$dataVo['A'], + 'py'=>zhToPy($dataVo['A']), + 'number'=>$dataVo['B'], + 'frame'=>$dataVo['C'], + 'user'=>getUserID(), + 'category'=>$dataVo['D'], + 'rate'=>$dataVo['E'], + 'bank'=>$dataVo['F'], + 'account'=>$dataVo['G'], + 'tax'=>$dataVo['H'], + 'data'=>$dataVo['I'], + 'contacts'=>(empty($dataVo['J'])&&empty($dataVo['K']))?[]:[['main'=>true,'name'=>$dataVo['J'],'tel'=>$dataVo['K'],'add'=>$dataVo['L'],'data'=>$dataVo['M']]], + 'more'=>[] + ]; + + //所属组织匹配 + $frameFind=search($frame)->where([['name','=',$record['frame']]])->find(); + if(empty($frameFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行所属组织[ '.$record['frame'].' ]未匹配!'); + }else{ + $record['frame']=$frameFind['id']; + } + //数据合法性验证 + try { + $this->validate($record,'app\validate\Supplier'); + $sql[]=$record;//加入SQL + } catch (ValidateException $e) { + //返回错误信息 + return json(['state'=>'error','info'=>'模板文件第[ '.$dataKey.' ]行'.$e->getError()]); + exit; + } + } + //判断编号重复 + $column=array_column($sql,'number'); + $unique=array_unique($column); + $diff=array_diff_assoc($column,$unique); + if(!empty($diff)){ + //返回错误信息 + return json(['state'=>'error','info'=>'模板文件供应商编号[ '.implode(' | ',$diff).' ]重复!']); + } + //处理关联数据 + foreach($sql as $sqlKey=>$sqlVo){ + $sys=getSys(['srCategory']); + //供应商类别 + if(!in_array($sqlVo['category'],$sys['srCategory'])){ + $sys['srCategory'][]=$sqlVo['category']; + Sys::where([['name','=','srCategory']])->update(['info'=>json_encode($sys['srCategory'])]); + } + } + //新增数据 + $supplier = new Suppliers; + $supplier->saveAll($sql); + pushLog('批量导入[ '.count($sql).' ]条供应商数据');//日志 + $result=['state'=>'success','info'=>'成功导入'.count($sql).'行供应商数据']; + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $info=Suppliers::with(['frameData','userData'])->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray();//查询数据 + foreach ($info as $infoKey=>$infoVo) { + $contactsArr=[]; + foreach ($infoVo['contacts'] as $contactsVo) { + $contactsArr[]=$contactsVo['name'].' | '.$contactsVo['tel'].' | '.$contactsVo['add'].' | '.$contactsVo['data']; + } + $info[$infoKey]['contacts']=implode(chr(10),$contactsArr); + } + $field=[ + 'name'=>'供应商名称', + 'number'=>'供应商编号', + 'category'=>'供应商类别', + 'rate'=>'增值税税率', + 'bank'=>'开户银行', + 'account'=>'银行账号', + 'tax'=>'纳税号码', + 'balance'=>'应付款余额', + 'frameData|name'=>'所属组织', + 'userData|name'=>'所属用户', + 'data'=>'备注信息', + 'contacts'=>'联系资料' + ]; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'供应商信息']; + //表格数据 + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>['总数:'.count($info)]]; + //导出execl + pushLog('导出供应商信息');//日志 + buildExcel('供应商信息',$excel); + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Swap.php b/serve/app/controller/Swap.php new file mode 100644 index 0000000..5098005 --- /dev/null +++ b/serve/app/controller/Swap.php @@ -0,0 +1,1229 @@ +'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + ['examine','fullDec1'], + ['cse','fullDec1'], + ['user','fullEq'], + ['data','fullLike'] + ]);//构造SQL + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['id','in',array_column(Db::name('swap_info')->where([['goods','in',$goods]])->select()->toArray(),'pid')]; + } + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('swap',$sql);//数据鉴权 + $count = Swaps::where($sql)->count();//获取总条数 + $info = Swaps::with(['frameData','peopleData','userData','costData','recordData'])->where($sql)->append(['extension'])->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select()->toArray();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(existFull($input,['class','info']) && isset($input['class']['id']) && isset($input['cost'])){ + //构造|验证CLASS + try { + $class=$input['class']; + $class['frame']=userInfo(getUserID(),'frame'); + $class['user']=getUserID(); + $class['cse']=empty($class['cost'])?3:0; + $class['examine']=0; + empty($class['id'])?$this->validate($class,'app\validate\Swap'):$this->validate($class,'app\validate\Swap.update'); + $period=getPeriod(); + if(strtotime($class['time'])<=$period){ + throw new ValidateException('单据日期与结账日期冲突!'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //验证INFO + foreach ($input['info'] as $infoKey=>$infoVo) { + try { + $this->validate($infoVo,'app\validate\SwapInfo'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'商品信息第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //验证Cost + foreach ($input['cost'] as $costKey=>$costVo) { + try { + $this->validate($costVo,'app\validate\Cost'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'单据费用第'.($infoKey+1).'条'.$e->getError()]); + exit; + } + } + + //处理数据 + Db::startTrans(); + try { + //CLASS数据 + if(empty($class['id'])){ + //创建数据 + $createInfo=Swaps::create($class); + $class['id']=$createInfo['id'];//转存主键 + Db::name('record')->insert(['type'=>'swap','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'新增单据']); + pushLog('新增调拨单[ '.$class['number'].' ]');//日志 + }else{ + //更新数据 + $updateInfo=Swaps::update($class); + Db::name('record')->insert(['type'=>'swap','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'更新单据']); + pushLog('更新调拨单[ '.$class['number'].' ]');//日志 + } + + //INFO数据 + SwapInfo::where([['pid','=',$class['id']]])->delete(); + foreach ($input['info'] as $infoKey=>$infoVo) { + $input['info'][$infoKey]['pid']=$class['id']; + } + $model = new SwapInfo; + $model->saveAll($input['info']); + + //COST数据 + Cost::where([['type','=','swap'],['class','=',$class['id']]])->delete(); + foreach ($input['cost'] as $costKey=>$costVo) { + unset($input['cost'][$costKey]['id']); + $input['cost'][$costKey]['type']='swap'; + $input['cost'][$costKey]['class']=$class['id']; + $input['cost'][$costKey]['time']=$class['time']; + $input['cost'][$costKey]['settle']=0; + $input['cost'][$costKey]['state']=0; + } + $model = new Cost; + $model->saveAll($input['cost']); + + Db::commit(); + $result=['state'=>'success','info'=>$class['id']]; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['parm'])){ + $class=Swaps::where([['id','=',$input['parm']]])->find(); + $info=SwapInfo::with(['goodsData','warehouseData','storehouseData'])->where([['pid','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $cost=Cost::where([['type','=','swap'],['class','=',$input['parm']]])->order(['id'=>'asc'])->select(); + $result=['state'=>'success','info'=>[ + 'class'=>$class, + 'info'=>$info, + 'cost'=>$cost + ]]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + $data=Db::name('swap')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $search=search($data)->where([['examine','=','1']])->find(); + if(empty($search)){ + Db::startTrans(); + try { + Db::name('swap')->where([['id','in',$input['parm']]])->delete(); + Db::name('swap_info')->where([['pid','in',$input['parm']]])->delete(); + Db::name('cost')->where([['type','=','swap'],['class','in',$input['parm']]])->delete(); + Db::name('log')->insert(['time'=>time(),'user'=>getUserID(),'info'=>'删除调拨单[ '.implode(' | ',array_column($data,'number')).' ]']); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'单据['.$search['number'].']已审核,不可删除!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //审核|反审核 + public function examine(){ + $input=input('post.'); + if(existFull($input,['parm']) && is_array($input['parm'])){ + //1 基础数据 + $fun=getSys('fun'); + $period=getPeriod(); + $classList=Db::name('swap')->where([['id','in',$input['parm']]])->order(['id'=>'desc'])->select()->toArray(); + $infoList=Db::name('swap_info')->where([['pid','in',$input['parm']]])->order(['id'=>'asc'])->select()->toArray(); + //2 综合处理 + foreach ($input['parm'] as $parmVo) { + //1 匹配数据 + $class=search($classList)->where([['id','=',$parmVo]])->find(); + $info=search($infoList)->where([['pid','=',$parmVo]])->select(); + //1.1 商品数据 + $goodsList=Db::name('goods')->where([['id','in',array_unique(array_column($info,'goods'))]])->select()->toArray(); + //1.2 综合匹配 + if(empty($class['examine'])){ + //1 构造数据 + $batchGather=[]; + $serialGather=[]; + $roomWhereOrSql=[]; + $toRoomWhereOrSql=[]; + foreach ($info as $infoVo) { + //1 批次号 + empty($infoVo['batch'])||$batchGather[]=$infoVo['batch']; + //2 序列号 + $serialGather=array_merge($serialGather,json_decode($infoVo['serial'])); + //3 仓储条件|调出 + empty($infoVo['warehouse'])||$roomWhereOrSql[]=[['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]]; + //4 仓储条件|调入 + empty($infoVo['storehouse'])||$toRoomWhereOrSql[]=[['warehouse','=',$infoVo['storehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]]; + } + //3 匹配数据 + empty($batchGather)||$batchList=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + empty($serialGather)||$serialList=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + //4 仓储数据|调出 + if(!empty($roomWhereOrSql)){ + //1 去重转存 + $roomWhereOrSql=array_unique($roomWhereOrSql,SORT_REGULAR); + //2 仓储匹配 + $roomList=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + } + //5 仓储数据|调入 + if(!empty($toRoomWhereOrSql)){ + //1 去重转存 + $toRoomWhereOrSql=array_unique($toRoomWhereOrSql,SORT_REGULAR); + //2 仓储匹配 + $toRoomList=Db::name('room')->whereOr($toRoomWhereOrSql)->select()->toArray(); + } + } + //2 CLASS验证 + if($class['time']<=$period){ + return json(['state'=>'error','info'=>'操作单据[ '.$class['number'].' ]失败,原因:单据日期与结账日期冲突!']); + exit; + } + if(empty($class['examine'])){ + //2 单据费用 + $cost=Db::name('cost')->alias('cost')->where([['type','=','swap'],['class','=',$class['id']]])->whereExists(function($query){ + $query->name('oce_info')->where([['source','=',Db::raw('cost.id')]])->limit(1); + })->find(); + if(!empty($cost)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:该单据存在关联其它支出单!']); + exit; + } + } + //3 INFO验证|构造 + foreach ($info as $infoKey=>$infoVo) { + //1 匹配商品 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + //2 商品类型 + if(empty($goods['type'])){ + //场景验证 + if(empty($class['examine'])){ + //1 匹配数据 + $room=search($roomList)->where([['warehouse','=',$infoVo['warehouse']],['goods','=',$infoVo['goods']],['attr','=',$infoVo['attr']]],true)->find(); + (empty($room)||empty($infoVo['batch']))||$batch=search($batchList)->where([['room','=',$room['id']],['number','=',$infoVo['batch']],['time','=',$infoVo['mfd']]],true)->find(); + //2 多单位处理 + if($goods['unit']==-1){ + //多单位|转存 + $radix=unitRadix($infoVo['unit'],json_decode($goods['units'],true)); + $info[$infoKey]['basic']=[ + 'nums'=>math()->chain($infoVo['nums'])->mul($radix)->done(), + 'price'=>math()->chain($infoVo['price'])->div($radix)->round(4)->done() + ]; + }else{ + //常规单位|转存 + $info[$infoKey]['basic']=[ + 'nums'=>$infoVo['nums'], + 'price'=>$infoVo['price'] + ]; + } + //3 序列号 + $serialData=json_decode($infoVo['serial']); + if(empty($serialData)){ + $info[$infoKey]['serial']=[]; + }else{ + //序列号状态[不存在|未销售] + $serialCollect=search($serialList)->where([['goods','=',$infoVo['goods']],['number','in',$serialData]])->select(); + foreach ($serialCollect as $serialCollectVo) { + if($serialCollectVo['state']==0){ + if(empty($room) || $room['id']!=$serialCollectVo['room']){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]与仓库不匹配!']); + exit; + } + if((empty($infoVo['batch'])&&!empty($serialCollectVo['batch']))||(!empty($infoVo['batch'])&&(empty($batch)||$batch['id']!=$serialCollectVo['batch']))){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]与批次不匹配!']); + exit; + } + }else{ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialCollectVo['number'].' ]状态不正确!']); + exit; + } + } + $info[$infoKey]['serial']=$serialData; + } + //4 负库存验证 + if($fun['overflow']==false){ + //1 仓储验证 + if(empty($room)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行仓储信息不存在!']); + exit; + }else{ + if(bccomp($info[$infoKey]['basic']['nums'],$room['nums'])==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行仓储库存不足!']); + exit; + }else{ + $roomList[$room['rowKey']]['nums']=math()->chain($room['nums'])->sub($info[$infoKey]['basic']['nums'])->done(); + } + } + //2 批次验证 + if(!empty($infoVo['batch'])){ + $batchFind=search($batchList)->where([['room','=',$room['id']],['number','=',$infoVo['batch']],['time','=',$infoVo['mfd']]],true)->find(); + if(empty($batchFind)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行批次信息无效!']); + exit; + }else{ + if(bccomp($info[$infoKey]['basic']['nums'],$batchFind['nums'])==1){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行批次库存不足!']); + exit; + }else{ + $batchList[$batchFind['rowKey']]['nums']=math()->chain($batchFind['nums'])->sub($info[$infoKey]['basic']['nums'])->done(); + } + } + } + //3 序列号验证 + if(!empty($serialData)){ + $serialCount=search($serialList)->where([['room','=',$room['id']],['number','in',$serialData]])->count(); + if($serialCount != count($serialData)){ + return json(['state'=>'error','info'=>'审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行存在无效序列号!']); + exit; + } + } + } + }else{ + //1 验证序列号|调出 + $serialInfoCollect=Db::name('serial_info')->where([['type','=','swapOut'],['info','in',array_column($info,'id')]])->select()->toArray(); + if(!empty($serialInfoCollect)){ + //序列号状态对[已调拨] + $serialFind=Db::name('serial')->where([['id','in',array_column($serialInfoCollect,'pid')],['state','<>',2]])->find(); + if(!empty($serialFind)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + //2 验证序列号|调入 + $serialInfoCollect=Db::name('serial_info')->where([['type','=','swapEnter'],['info','in',array_column($info,'id')]])->select()->toArray(); + if(!empty($serialInfoCollect)){ + //序列号状态对[未销售] + $serialFind=Db::name('serial')->where([['id','in',array_column($serialInfoCollect,'pid')],['state','<>',0]])->find(); + if(!empty($serialFind)){ + return json(['state'=>'error','info'=>'反审核单据[ '.$class['number'].' ]失败,原因:第'.($infoKey+1).'行序列号[ '.$serialFind['number'].' ]状态不正确!']); + exit; + } + } + } + } + } + //4 数据处理 + Db::startTrans(); + try { + //场景验证 + if(empty($class['examine'])){ + //审核 + //1 构造数据 + $outStore=['room'=>[],'roomInfo'=>[],'batch'=>[],'batchInfo'=>[],'serial'=>[],'serialInfo'=>[],'serve'=>[],'serveInfo'=>[]]; + $enterStore=['room'=>[],'roomInfo'=>[],'batch'=>[],'batchInfo'=>[],'serial'=>[],'serialInfo'=>[],'serve'=>[],'serveInfo'=>[]]; + foreach ($info as $infoKey=>$infoVo){ + //判断商品类型 + $goods=search($goodsList)->where([['id','=',$infoVo['goods']]])->find(); + if(empty($goods['type'])){ + //常规商品 + //--- 调出数据 --- + //1 仓储 + $outStore['room'][]=['warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['basic']['nums']]; + //2 仓储详情 + $outStore['roomInfo'][]=['pid'=>null,'type'=>'swapOut','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'direction'=>0,'price'=>$infoVo['basic']['price'],'nums'=>$infoVo['basic']['nums']]; + //3 批次号 + if(empty($infoVo['batch'])){ + $outStore['batch'][]=[]; + $outStore['batchInfo'][]=[]; + }else{ + $outStore['batch'][]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'goods'=>$infoVo['goods'],'number'=>$infoVo['batch'],'time'=>$infoVo['mfd'],'nums'=>$infoVo['basic']['nums']]; + $outStore['batchInfo'][]=['pid'=>null,'type'=>'swapOut','class'=>$class['id'],'info'=>$infoVo['id'],'direction'=>0,'nums'=>$infoVo['basic']['nums']]; + } + //4 序列号 + if(empty($infoVo['serial'])){ + $outStore['serial'][]=[]; + $outStore['serialInfo'][]=[]; + }else{ + $serial=[]; + $serialInfo=[]; + foreach ($infoVo['serial'] as $serialVo) { + $serial[]=['room'=>null,'warehouse'=>$infoVo['warehouse'],'batch'=>null,'goods'=>$infoVo['goods'],'number'=>$serialVo,'state'=>2]; + $serialInfo[]=['pid'=>null,'type'=>'swapOut','class'=>$class['id'],'info'=>$infoVo['id']]; + } + $outStore['serial'][]=$serial; + $outStore['serialInfo'][]=$serialInfo; + } + //--- 调入数据 --- + //5 仓储 + $enterStore['room'][]=['warehouse'=>$infoVo['storehouse'],'goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['basic']['nums']]; + //6 仓储详情 + $enterStore['roomInfo'][]=['pid'=>null,'type'=>'swapEnter','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'direction'=>1,'price'=>$infoVo['basic']['price'],'nums'=>$infoVo['basic']['nums']]; + //7 批次号 + if(empty($infoVo['batch'])){ + $enterStore['batch'][]=[]; + $enterStore['batchInfo'][]=[]; + }else{ + $enterStore['batch'][]=['room'=>null,'warehouse'=>$infoVo['storehouse'],'goods'=>$infoVo['goods'],'number'=>$infoVo['batch'],'time'=>$infoVo['mfd'],'nums'=>$infoVo['basic']['nums']]; + $enterStore['batchInfo'][]=['pid'=>null,'type'=>'swapEnter','class'=>$class['id'],'info'=>$infoVo['id'],'direction'=>1,'nums'=>$infoVo['basic']['nums']]; + } + //8 序列号 + if(empty($infoVo['serial'])){ + $enterStore['serial'][]=[]; + $enterStore['serialInfo'][]=[]; + }else{ + $serial=[]; + $serialInfo=[]; + foreach ($infoVo['serial'] as $serialVo) { + $serial[]=['room'=>null,'warehouse'=>$infoVo['storehouse'],'batch'=>null,'goods'=>$infoVo['goods'],'number'=>$serialVo,'state'=>0]; + $serialInfo[]=['pid'=>null,'type'=>'swapEnter','class'=>$class['id'],'info'=>$infoVo['id']]; + } + $enterStore['serial'][]=$serial; + $enterStore['serialInfo'][]=$serialInfo; + } + }else{ + //9 服务商品 + $outStore['serve'][]=['goods'=>$infoVo['goods'],'attr'=>$infoVo['attr'],'nums'=>$infoVo['nums']]; + $outStore['serveInfo'][]=['pid'=>null,'type'=>'swap','class'=>$class['id'],'info'=>$infoVo['id'],'time'=>$class['time'],'price'=>$infoVo['price'],'nums'=>$infoVo['nums']]; + } + } + //--- 调出数据 --- + //2 仓储 + if(!empty($outStore['room'])){ + //1 构造数据 + $roomInsert=[]; + foreach ($outStore['room'] as $roomVo) { + $roomFind=search($roomList)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + if(empty($roomFind)){ + $roomVo['nums']=0; + $roomInsert[]=$roomVo; + } + } + //2 创建数据|去重 + empty($roomInsert)||Db::name('room')->insertAll(array_unique($roomInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $roomDuplicate=[]; + $room=Db::name('room')->whereOr($roomWhereOrSql)->select()->toArray(); + foreach ($outStore['room'] as $roomKey=>$roomVo) { + $roomFind=search($room)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + $outStore['room'][$roomKey]['id']=$roomFind['id']; + $roomDuplicate[]=['id'=>$roomFind['id'],'nums'=>$roomVo['nums']]; + } + //4 更新数据 + Db::name('room')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($roomDuplicate); + } + //3 仓储详情 + if(!empty($outStore['roomInfo'])){ + //1 填充数据 + foreach ($outStore['roomInfo'] as $roomInfoKey=>$roomInfoVo) { + $outStore['roomInfo'][$roomInfoKey]['pid']=$outStore['room'][$roomInfoKey]['id']; + } + //2 创建数据 + Db::name('room_info')->insertAll($outStore['roomInfo']); + } + //4 批次号 + if(!empty($outStore['batch'])){ + //1 构造数据 + $batchData=[]; + foreach ($outStore['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $outStore['batch'][$batchKey]['room']=$outStore['room'][$batchKey]['id']; + $batchData[]=$outStore['batch'][$batchKey]; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchData)){ + //1 构造数据 + $batchInsert=[]; + foreach ($batchData as $batchDataKey=>$batchDataVo) { + $batchFind=search($batchList)->where([['room','=',$batchDataVo['room']],['number','=',$batchDataVo['number']],['time','=',$batchDataVo['time']]])->find(); + if(empty($batchFind)){ + $batchDataVo['nums']=0; + $batchInsert[]=$batchDataVo; + } + } + //2 创建数据|去重 + empty($batchInsert)||Db::name('batch')->insertAll(array_unique($batchInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $batchDuplicate=[]; + $batch=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + foreach ($outStore['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $batchFind=search($batch)->where([['room','=',$batchVo['room']],['number','=',$batchVo['number']],['time','=',$batchVo['time']]])->find(); + $outStore['batch'][$batchKey]['id']=$batchFind['id']; + $batchDuplicate[]=['id'=>$batchFind['id'],'nums'=>$batchVo['nums']]; + } + } + //4 更新数据 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($batchDuplicate); + } + } + //5 批次号详情 + if(!empty($outStore['batchInfo'])){ + //1 构造数据 + $batchInfoInstall=[]; + foreach ($outStore['batchInfo'] as $batchInfoKey=>$batchInfoVo) { + if(!empty($batchInfoVo)){ + $batchInfoVo['pid']=$outStore['batch'][$batchInfoKey]['id']; + $batchInfoInstall[]=$batchInfoVo; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchInfoInstall)){ + //创建数据 + Db::name('batch_info')->insertAll($batchInfoInstall); + } + } + //6 序列号 + if(!empty($outStore['serial'])){ + //1 构造数据 + $serialData=[]; + foreach ($outStore['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $outStore['serial'][$serialKey][$itemKey]['room']=$outStore['room'][$serialKey]['id']; + $outStore['serial'][$serialKey][$itemKey]['batch']=empty($outStore['batch'][$serialKey])?0:$outStore['batch'][$serialKey]['id']; + $serialData[]=$outStore['serial'][$serialKey][$itemKey]; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialData)){ + //1 构造数据 + $serialInsert=[]; + foreach ($serialData as $serialDataKey=>$serialDataVo) { + $serialFind=search($serialList)->where([['room','=',$serialDataVo['room']],['batch','=',$serialDataVo['batch']],['number','=',$serialDataVo['number']]])->find(); + if(empty($serialFind)){ + $serialInsert[]=$serialDataVo; + } + } + //2 创建数据 + empty($serialInsert)||Db::name('serial')->insertAll($serialInsert); + //3 匹配主键|构造更新 + $serialDuplicate=[]; + $serial=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + foreach ($outStore['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $serialFind=search($serial)->where([['room','=',$itemVo['room']],['batch','=',$itemVo['batch']],['number','=',$itemVo['number']]])->find(); + $outStore['serial'][$serialKey][$itemKey]['id']=$serialFind['id']; + $serialFind['state']==0&&$serialDuplicate[]=$serialFind['id']; + } + } + } + //4 更新数据|状态变更 + empty($serialDuplicate)||Db::name('serial')->where([['id','in',$serialDuplicate]])->update(['state'=>2]); + } + } + //7 序列号详情 + if(!empty($outStore['serialInfo'])){ + //1 构造数据 + $serialInfoInstall=[]; + foreach ($outStore['serialInfo'] as $serialInfoKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $itemVo['pid']=$outStore['serial'][$serialInfoKey][$itemKey]['id']; + $serialInfoInstall[]=$itemVo; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialInfoInstall)){ + //创建数据 + Db::name('serial_info')->insertAll($serialInfoInstall); + } + } + //8 服务商品 + if(!empty($outStore['serve'])){ + //1 匹配数据|去重 + $serveWhereOrSql=array_unique(array_map(function($item){ + return [['goods','=',$item['goods']],['attr','=',$item['attr']]]; + },$outStore['serve']),SORT_REGULAR); + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + //2 构造数据 + $serveInsert=[]; + foreach ($outStore['serve'] as $serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + if(empty($serveFind)){ + $serveVo['nums']=0; + $serveInsert[]=$serveVo; + } + } + //3 创建数据|去重 + empty($serveInsert)||Db::name('serve')->insertAll(array_unique($serveInsert,SORT_REGULAR)); + //4 匹配主键|构造更新 + $serveDuplicate=[]; + $serve=Db::name('serve')->whereOr($serveWhereOrSql)->select()->toArray(); + foreach ($outStore['serve'] as $serveKey=>$serveVo) { + $serveFind=search($serve)->where([['goods','=',$serveVo['goods']],['attr','=',$serveVo['attr']]])->find(); + $outStore['serve'][$serveKey]['id']=$serveFind['id']; + $serveDuplicate[]=['id'=>$serveFind['id'],'nums'=>$serveVo['nums']]; + } + //5 更新数据 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($serveDuplicate); + } + //9 服务商品详情 + if(!empty($outStore['serveInfo'])){ + //1 填充数据 + foreach ($outStore['serveInfo'] as $serveInfoKey=>$serveInfoVo) { + $outStore['serveInfo'][$serveInfoKey]['pid']=$outStore['serve'][$serveInfoKey]['id']; + } + //2 创建数据 + Db::name('serve_info')->insertAll($outStore['serveInfo']); + } + // --- 调入数据 --- + //10 仓储 + if(!empty($enterStore['room'])){ + //1 构造数据 + $roomInsert=[]; + foreach ($enterStore['room'] as $roomVo) { + $roomFind=search($roomList)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + if(empty($roomFind)){ + $roomVo['nums']=0; + $roomInsert[]=$roomVo; + } + } + //2 创建数据|去重 + empty($roomInsert)||Db::name('room')->insertAll(array_unique($roomInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $roomDuplicate=[]; + $room=Db::name('room')->whereOr($toRoomWhereOrSql)->select()->toArray(); + foreach ($enterStore['room'] as $roomKey=>$roomVo) { + $roomFind=search($room)->where([['warehouse','=',$roomVo['warehouse']],['goods','=',$roomVo['goods']],['attr','=',$roomVo['attr']]])->find(); + $enterStore['room'][$roomKey]['id']=$roomFind['id']; + $roomDuplicate[]=['id'=>$roomFind['id'],'nums'=>$roomVo['nums']]; + } + //4 更新数据 + Db::name('room')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($roomDuplicate); + } + //11 仓储详情 + if(!empty($enterStore['roomInfo'])){ + //1 填充数据 + foreach ($enterStore['roomInfo'] as $roomInfoKey=>$roomInfoVo) { + $enterStore['roomInfo'][$roomInfoKey]['pid']=$enterStore['room'][$roomInfoKey]['id']; + } + //2 创建数据 + Db::name('room_info')->insertAll($enterStore['roomInfo']); + } + //12 批次号 + if(!empty($enterStore['batch'])){ + //1 构造数据 + $batchData=[]; + foreach ($enterStore['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $enterStore['batch'][$batchKey]['room']=$enterStore['room'][$batchKey]['id']; + $batchData[]=$enterStore['batch'][$batchKey]; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchData)){ + //1 构造数据 + $batchInsert=[]; + foreach ($batchData as $batchDataKey=>$batchDataVo) { + $batchFind=search($batchList)->where([['room','=',$batchDataVo['room']],['number','=',$batchDataVo['number']],['time','=',$batchDataVo['time']]])->find(); + if(empty($batchFind)){ + $batchDataVo['nums']=0; + $batchInsert[]=$batchDataVo; + } + } + //2 创建数据|去重 + empty($batchInsert)||Db::name('batch')->insertAll(array_unique($batchInsert,SORT_REGULAR)); + //3 匹配主键|构造更新 + $batchDuplicate=[]; + $batch=Db::name('batch')->where([['number','in',$batchGather]])->select()->toArray(); + foreach ($enterStore['batch'] as $batchKey=>$batchVo) { + if(!empty($batchVo)){ + $batchFind=search($batch)->where([['room','=',$batchVo['room']],['number','=',$batchVo['number']],['time','=',$batchVo['time']]])->find(); + $enterStore['batch'][$batchKey]['id']=$batchFind['id']; + $batchDuplicate[]=['id'=>$batchFind['id'],'nums'=>$batchVo['nums']]; + } + } + //4 更新数据 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($batchDuplicate); + } + } + //13 批次号详情 + if(!empty($enterStore['batchInfo'])){ + //1 构造数据 + $batchInfoInstall=[]; + foreach ($enterStore['batchInfo'] as $batchInfoKey=>$batchInfoVo) { + if(!empty($batchInfoVo)){ + $batchInfoVo['pid']=$enterStore['batch'][$batchInfoKey]['id']; + $batchInfoInstall[]=$batchInfoVo; + } + } + //2 排除数据|[[],[],[]] + if(!empty($batchInfoInstall)){ + //创建数据 + Db::name('batch_info')->insertAll($batchInfoInstall); + } + } + //14 序列号 + if(!empty($enterStore['serial'])){ + //1 构造数据 + $serialInsert=[]; + foreach ($enterStore['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $enterStore['serial'][$serialKey][$itemKey]['room']=$enterStore['room'][$serialKey]['id']; + $enterStore['serial'][$serialKey][$itemKey]['batch']=empty($enterStore['batch'][$serialKey])?0:$enterStore['batch'][$serialKey]['id']; + $serialInsert[]=$enterStore['serial'][$serialKey][$itemKey]; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialInsert)){ + //1 创建数据 + Db::name('serial')->insertAll($serialInsert); + //2 匹配主键 + $serial=Db::name('serial')->where([['number','in',$serialGather]])->select()->toArray(); + foreach ($enterStore['serial'] as $serialKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $serialFind=search($serial)->where([['room','=',$itemVo['room']],['batch','=',$itemVo['batch']],['number','=',$itemVo['number']]])->find(); + $enterStore['serial'][$serialKey][$itemKey]['id']=$serialFind['id']; + } + } + } + } + } + //15 序列号详情 + if(!empty($enterStore['serialInfo'])){ + //1 构造数据 + $serialInfoInstall=[]; + foreach ($enterStore['serialInfo'] as $serialInfoKey=>$item) { + if(!empty($item)){ + foreach ($item as $itemKey=>$itemVo) { + $itemVo['pid']=$enterStore['serial'][$serialInfoKey][$itemKey]['id']; + $serialInfoInstall[]=$itemVo; + } + } + } + //2 排除数据|[[],[],[]] + if(!empty($serialInfoInstall)){ + //创建数据 + Db::name('serial_info')->insertAll($serialInfoInstall); + } + } + + //16 更新单据 + Db::name('swap')->where([['id','=',$class['id']]])->update(['examine'=>1]); + //17 单据记录 + Db::name('record')->insert(['type'=>'swap','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'审核单据']); + //18 收发记录 + $summary=new Summary; + $summary->note('swapOut',$class['id'],true); + $summary->note('swapEnter',$class['id'],true); + //19 记录操作 + pushLog('审核调拨单[ '.$class['number'].' ]');//单据日志 + }else{ + //反审核 + //--- 调出数据 --- + //1 匹配数据 + $roomInfoList=Db::name('room_info')->where([['type','=','swapOut'],['info','in',array_column($info,'id')]])->select()->toArray(); + $batchInfoList=Db::name('batch_info')->where([['type','=','swapOut'],['info','in',array_column($info,'id')]])->select()->toArray(); + $serialInfoList=Db::name('serial_info')->where([['type','=','swapOut'],['info','in',array_column($info,'id')]])->select()->toArray(); + $serveInfoList=Db::name('serve_info')->where([['type','=','swap'],['info','in',array_column($info,'id')]])->select()->toArray(); + //1 仓储 + $roomDuplicate=[]; + foreach ($roomInfoList as $roomInfoVo) { + $roomDuplicate[]=['id'=>$roomInfoVo['pid'],'nums'=>$roomInfoVo['nums']]; + } + //2.1 更新仓储 + Db::name('room')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($roomDuplicate); + //2.2 删除仓储详情 + Db::name('room_info')->where([['id','in',array_column($roomInfoList,'id')]])->delete(); + //2.3 仓储|冗余 + $roomPk=array_unique(array_column($roomInfoList,'pid')); + $roomInfoData=Db::name('room_info')->where([['pid','in',$roomPk]])->select()->toArray(); + $roomDiff=array_diff($roomPk,array_unique(array_column($roomInfoData,'pid'))); + empty($roomDiff)||Db::name('room')->where([['id','in',$roomDiff]])->delete(); + //3 批次号 + if(!empty($batchInfoList)){ + //1 构造数据 + $batchInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$batchInfoList); + //2 更新批次号 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums + VALUES(`nums`)')])->insertAll($batchInfoDuplicate); + //3 删除批次号详情 + Db::name('batch_info')->where([['id','in',array_column($batchInfoList,'id')]])->delete(); + //4 批次号|冗余 + $batchPk=array_unique(array_column($batchInfoList,'pid')); + $batchInfoData=Db::name('batch_info')->where([['pid','in',$batchPk]])->select()->toArray(); + $batchDiff=array_diff($batchPk,array_unique(array_column($batchInfoData,'pid'))); + empty($batchDiff)||Db::name('batch')->where([['id','in',$batchDiff]])->delete(); + } + //4 序列号 + if(!empty($serialInfoList)){ + //1 更新序列号 + Db::name('serial')->where([['id','in',array_column($serialInfoList,'pid')]])->update(['state'=>0]); + //2 删除序列号详情 + Db::name('serial_info')->where([['id','in',array_column($serialInfoList,'id')]])->delete(); + //3 序列号|冗余 + $serialPk=array_unique(array_column($serialInfoList,'pid')); + $serialInfoData=Db::name('serial_info')->where([['pid','in',$serialPk]])->select()->toArray(); + $serialDiff=array_diff($serialPk,array_unique(array_column($serialInfoData,'pid'))); + empty($serialDiff)||Db::name('serial')->where([['id','in',$serialDiff]])->delete(); + } + //5 服务 + if(!empty($serveInfoList)){ + //1 构造数据 + $serveInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$serveInfoList); + //2 更新服务 + Db::name('serve')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($serveInfoDuplicate); + //3 删除服务详情 + Db::name('serve_info')->where([['id','in',array_column($serveInfoList,'id')]])->delete(); + //4 服务|冗余 + $servePk=array_unique(array_column($serveInfoList,'pid')); + $serveInfoData=Db::name('serve_info')->where([['pid','in',$servePk]])->select()->toArray(); + $serveDiff=array_diff($servePk,array_unique(array_column($serveInfoData,'pid'))); + empty($serveDiff)||Db::name('serve')->where([['id','in',$serveDiff]])->delete(); + } + //--- 调入数据 --- + //6 匹配数据 + $roomInfoList=Db::name('room_info')->where([['type','=','swapEnter'],['info','in',array_column($info,'id')]])->select()->toArray(); + $batchInfoList=Db::name('batch_info')->where([['type','=','swapEnter'],['info','in',array_column($info,'id')]])->select()->toArray(); + $serialInfoList=Db::name('serial_info')->where([['type','=','swapEnter'],['info','in',array_column($info,'id')]])->select()->toArray(); + //7 仓储 + $roomDuplicate=[]; + foreach ($roomInfoList as $roomInfoVo) { + $roomDuplicate[]=['id'=>$roomInfoVo['pid'],'nums'=>$roomInfoVo['nums']]; + } + //7.1 更新仓储 + Db::name('room')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($roomDuplicate); + //7.2 删除仓储详情 + Db::name('room_info')->where([['id','in',array_column($roomInfoList,'id')]])->delete(); + //7.3 仓储|冗余 + $roomPk=array_unique(array_column($roomInfoList,'pid')); + $roomInfoData=Db::name('room_info')->where([['pid','in',$roomPk]])->select()->toArray(); + $roomDiff=array_diff($roomPk,array_unique(array_column($roomInfoData,'pid'))); + empty($roomDiff)||Db::name('room')->where([['id','in',$roomDiff]])->delete(); + //8 批次号 + if(!empty($batchInfoList)){ + //1 构造数据 + $batchInfoDuplicate=array_map(function($item){ + return ['id'=>$item['pid'],'nums'=>$item['nums']]; + },$batchInfoList); + //2 更新批次号 + Db::name('batch')->duplicate(['nums'=>Db::raw('nums - VALUES(`nums`)')])->insertAll($batchInfoDuplicate); + //3 删除批次号详情 + Db::name('batch_info')->where([['id','in',array_column($batchInfoList,'id')]])->delete(); + //4 批次号|冗余 + $batchPk=array_unique(array_column($batchInfoList,'pid')); + $batchInfoData=Db::name('batch_info')->where([['pid','in',$batchPk]])->select()->toArray(); + $batchDiff=array_diff($batchPk,array_unique(array_column($batchInfoData,'pid'))); + empty($batchDiff)||Db::name('batch')->where([['id','in',$batchDiff]])->delete(); + } + //9 序列号 + if(!empty($serialInfoList)){ + //1 删除序列号 + Db::name('serial')->where([['id','in',array_column($serialInfoList,'pid')]])->delete(); + //2 删除序列号详情 + Db::name('serial_info')->where([['id','in',array_column($serialInfoList,'id')]])->delete(); + } + //10 更新单据 + Db::name('swap')->where([['id','=',$class['id']]])->update(['examine'=>0]); + //11 单据记录 + Db::name('record')->insert(['type'=>'swap','source'=>$class['id'],'time'=>time(),'user'=>getUserID(),'info'=>'反审核单据']); + //12 收发记录 + $summary=new Summary; + $summary->note('swapOut',$class['id'],false); + $summary->note('swapEnter',$class['id'],false); + //13 记录操作 + pushLog('反审核调拨单[ '.$class['number'].' ]');//单据日志 + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return json(['state'=>'error','info'=>'内部错误,操作已撤销!']); + exit; + } + } + $result=['state'=>'success']; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file = request()->file('file'); + //获取上传文件 + if (empty($file)) { + $result = ['state' => 'error','info' => '传入数据不完整!']; + } else { + //文件限制5MB + try{ + validate(['file'=>['fileSize'=>5*1024*1024,'fileExt'=>'png,gif,jpg,jpeg,txt,doc,docx,rtf,xls,xlsx,ppt,pptx,pdf,zip,rar']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('swap', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result = ['state' => 'error','info' => $e->getMessage()]; + } + } + return json($result); + } + //导入 + public function import(){ + delOverdueFile('static.upload.xlsx');//删除过期文件 + $file=request()->file('file');//获取上传文件 + if(empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + $fun=getSys('fun'); + try{ + validate(['file'=>['fileSize'=>2*1024*1024,'fileExt'=>'xlsx']])->check(['file'=>$file]); + $fileInfo = Filesystem::disk('upload')->putFile('xlsx', $file, 'uniqid'); + $filePath = pathChange('static.upload').$fileInfo; + $data=getXlsx($filePath); + unset($data[1]);//删除标题行 + unset($data[2]);//删除列名行 + //初始化CLASS + //关联人员匹配 + if(empty($data[3]['D'])){ + $people=['id'=>0]; + }else{ + $people=Db::name('people')->where([['name','=',$data[3]['D']]])->find(); + if(empty($people)){ + throw new ValidateException('关联人员[ '.$data[3]['D'].' ]未匹配!'); + } + } + $class=[ + 'frame'=>userInfo(getUserID(),'frame'), + 'time'=>$data[3]['A'], + 'number'=>$data[3]['B'], + 'total'=>0, + 'people'=>$people['id'], + 'logistics'=>["key"=>"auto","name"=>"自动识别","number"=>$data[3]['E']], + 'file'=>[], + 'data'=>$data[3]['F'], + 'more'=>[], + 'examine'=>0, + 'cse'=>0, + 'user'=>getUserID() + ]; + $this->validate($class,'app\validate\Swap');//数据合法性验证 + //初始化INFO + $info=[]; + $goods=Goods::with(['attr'])->where([['name','in',array_column($data,'G')]])->select()->toArray(); + $warehouse=Db::name('warehouse')->where([['name','in',array_column($data,'J')]])->select()->toArray(); + $storehouse=Db::name('warehouse')->where([['name','in',array_column($data,'K')]])->select()->toArray(); + foreach ($data as $dataKey=>$dataVo) { + $record=[ + 'goods'=>$dataVo['G'], + 'attr'=>$dataVo['H'], + 'unit'=>$dataVo['I'], + 'warehouse'=>$dataVo['J'], + 'storehouse'=>$dataVo['K'], + 'batch'=>$dataVo['L'], + 'mfd'=>$dataVo['M'], + 'price'=>$dataVo['N'], + 'nums'=>$dataVo['O'], + 'serial'=>explode(',',$dataVo['P']), + 'total'=>$dataVo['Q'], + 'data'=>$dataVo['R'] + ]; + //商品匹配 + $goodsFind=search($goods)->where([['name','=',$record['goods']]])->find(); + if(empty($goodsFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行商品名称[ '.$record['goods'].' ]未匹配!'); + }else{ + $record['goods']=$goodsFind['id']; + } + //辅助属性匹配 + if(empty($goodsFind['attr'])){ + $record['attr']=''; + }else{ + if(empty($record['attr'])){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性不可为空!'); + }else{ + $attrFind=search($goodsFind['attr'])->where([['name','=',$record['attr']]])->find(); + if(empty($attrFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行辅助属性[ '.$record['attr'].' ]未匹配!'); + } + } + } + //单位匹配 + if($goodsFind['unit']==-1){ + if(empty($record['unit'])){ + throw new ValidateException('模板文件第'.$dataKey.'行单位不可为空!'); + }else{ + $unitFind=search($goodsFind['units'])->where([['name','=',$record['unit']]])->find(); + if(empty($unitFind) && $goodsFind['units'][0]['source']!=$record['unit']){ + throw new ValidateException('模板文件第'.$dataKey.'行单位[ '.$record['unit'].' ]未匹配!'); + } + } + }else{ + $record['unit']=$goodsFind['unit']; + } + //调出仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $warehouseFind=search($warehouse)->where([['name','=',$record['warehouse']]])->find(); + if(empty($warehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行调出仓库[ '.$record['warehouse'].' ]未匹配!'); + }else{ + $record['warehouse']=$warehouseFind['id']; + } + }else{ + //服务产品 + $record['warehouse']=null; + } + //调入仓库匹配 + if(empty($goodsFind['type'])){ + //常规产品 + $storehouseFind=search($storehouse)->where([['name','=',$record['storehouse']]])->find(); + if(empty($storehouseFind)){ + throw new ValidateException('模板文件第'.$dataKey.'行调入仓库[ '.$record['storehouse'].' ]未匹配!'); + }else{ + $record['storehouse']=$storehouseFind['id']; + } + }else{ + //服务产品 + $record['storehouse']=null; + } + //调入调出匹配 + if(empty($goodsFind['type'])){ + if($record['warehouse']==$record['storehouse']){ + throw new ValidateException('模板文件第'.$dataKey.'行调出调入仓库不可相等!'); + } + } + //批次号匹配 + if(empty($goodsFind['batch'])){ + $record['batch']=''; + }else{ + if(empty($record['batch'])){ + throw new ValidateException('模板文件第'.$dataKey.'行批次号不可为空!'); + } + } + //生产日期匹配 + if(empty($goodsFind['validity'])){ + $record['mfd']=''; + }else{ + if(empty($record['mfd'])){ + throw new ValidateException('模板文件第'.$dataKey.'行生产日期不可为空!'); + } + } + //成本匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['money']."})?$/",$record['price'])){ + throw new ValidateException('模板文件第'.$dataKey.'行成本不正确!'); + } + //数量匹配 + if(!preg_match("/^\d+(\.\d{0,".$fun['digit']['nums']."})?$/",$record['nums'])){ + throw new ValidateException('模板文件第'.$dataKey.'行数量不正确!'); + } + //序列号匹配 + if(empty($goodsFind['serial'])){ + $record['serial']=[]; + }else{ + if(count($record['serial'])==1 && empty($record['serial'][0])){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号不可为空!'); + }else{ + if(count($record['serial'])!=$record['nums']){ + throw new ValidateException('模板文件第'.$dataKey.'行序列号个数与数量不符!'); + } + } + } + try{ + $this->validate($record,'app\validate\SwapInfo');//数据合法性验证 + $record['total']=math()->chain($record['price'])->mul($record['nums'])->round($fun['digit']['money'])->done(); + //转存数据 + $class['total']=math()->chain($class['total'])->add($record['total'])->done();//累加单据金额 + $info[]=$record; + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>'模板文件第'.$dataKey.'行'.$e->getMessage()]);//返回错误信息 + exit; + } + } + //序列号重复验证 + $serials=[]; + foreach ($info as $infoVo) { + $serials = array_merge($serials,$infoVo['serial']); + } + if(count($serials)!=count(array_unique($serials))){ + throw new ValidateException('商品信息中存在重复序列号!'); + } + Db::startTrans(); + try { + //新增CLASS + $classData=Swaps::create($class); + //新增INFO + foreach ($info as $infoKey=>$infoVo) { + $info[$infoKey]['pid']=$classData['id']; + } + $model = new SwapInfo; + $model->saveAll($info); + Db::name('record')->insert(['type'=>'swap','source'=>$classData['id'],'time'=>time(),'user'=>getUserID(),'info'=>'导入单据']); + pushLog('导入调拨单[ '.$classData['number'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()];//返回错误信息 + } + } + return json($result); + } + //导出 + public function exports(){ + $input=input('get.'); + if(existFull($input,['scene','parm']) && is_array($input['parm'])){ + pushLog('导出调拨单列表');//日志 + $source=Swaps::with(['frameData','peopleData','userData','recordData'])->where([['id','in',$input['parm']]])->append(['extension'])->order(['id'=>'desc'])->select()->toArray();//查询CLASS数据 + if($input['scene']=='simple'){ + //简易报表 + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'调拨单列表']; + //表格数据 + $field=[ + 'frameData|name'=>'所属组织', + 'time'=>'单据时间', + 'number'=>'单据编号', + 'total'=>'单据成本', + 'cost'=>'单据费用', + 'peopleData|name'=>'关联人员', + 'extension|examine'=>'审核状态', + 'extension|cse'=>'费用状态', + 'userData|name'=>'制单人', + 'data'=>'备注信息' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //统计数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + '总单据成本:'.mathArraySum(array_column($source,'total')), + '总单据费用:'.mathArraySum(array_column($source,'cost')) + ]]; + //导出execl + buildExcel('调拨单列表',$excel); + }else{ + //详细报表 + $files=[];//初始化文件列表 + foreach ($source as $sourceVo) { + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'调拨单']; + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据日期:'.$sourceVo['time'], + '单据编号:'.$sourceVo['number']] + ]; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'goodsData|spec'=>'规格型号', + 'attr'=>'辅助属性', + 'unit'=>'单位', + 'warehouseData|name'=>'调出仓库', + 'storehouseData|name'=>'调入仓库', + 'batch'=>'批次号', + 'mfd'=>'生产日期', + 'price'=>'成本', + 'nums'=>'数量', + 'extension|serial'=>'序列号', + 'total'=>'总成本', + 'data'=>'备注信息' + ]; + //构造表内数据 + $info=SwapInfo::with(['goodsData','warehouseData','storehouseData'])->where([['pid','=',$sourceVo['id']]])->order(['id'=>'asc'])->append(['extension'])->select()->toArray(); + //批次号匹配 + if(empty(search($info)->where([['goodsData|batch','=',true]])->find())){ + unset($field['batch']); + } + //生产日期匹配 + if(empty(search($info)->where([['goodsData|validity','=',true]])->find())){ + unset($field['mfd']); + } + //序列号匹配 + if(empty(search($info)->where([['goodsData|serial','=',true]])->find())){ + unset($field['extension|serial']); + } + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + foreach ($info as $infoVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($infoVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //节点数据 + $excel[]=['type'=>'node','info'=>[ + '单据成本:'.$sourceVo['total'], + '单据费用:'.$sourceVo['cost'], + '关联人员:'.arraySeek($sourceVo,'peopleData|name'), + '物流信息:'.$sourceVo['extension']['logistics'], + '备注信息:'.$sourceVo['data']] + ]; + //生成execl + $files[]=buildExcel($sourceVo['number'],$excel,false); + + } + buildZip('调拨单_'.time(),$files); + } + }else{ + return json(['state'=>'error','info'=>'传入数据不完整!']); + } + } +} \ No newline at end of file diff --git a/serve/app/controller/Sys.php b/serve/app/controller/Sys.php new file mode 100644 index 0000000..0bead33 --- /dev/null +++ b/serve/app/controller/Sys.php @@ -0,0 +1,41 @@ +'success','info'=>getSys()]); + } + //保存 + public function save(){ + $input=input('post.'); + if(is_array($input)){ + $sql=[]; + //查找对应主键 + $keys=array_keys($input); + $sys=Syss::where([['name','in',$keys]])->field(['id','name'])->select(); + //构造数据 + foreach ($sys as $row){ + $sql[]=['id'=>$row['id'],'info'=>$input[$row['name']]]; + } + Db::startTrans(); + try { + //数据处理 + $model=new Syss; + $model->saveAll($sql); + pushLog('修改系统参数'); + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/User.php b/serve/app/controller/User.php new file mode 100644 index 0000000..0d1b5c5 --- /dev/null +++ b/serve/app/controller/User.php @@ -0,0 +1,161 @@ +'name|py'],'fullLike'], + ['user','fullLike'], + ['tel','fullLike'], + ['data','fullLike'] + ]);//构造SQL + $sql=frameScope($sql);//组织数据 + $sql=sqlAuth('user',$sql);//数据鉴权 + $count = Users::where($sql)->count();//获取总条数 + $info = Users::with(['frameData','roleData'])->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + + //构造|验证 + try { + $input['py']=zhToPy($input['name']);//首拼信息 + if(empty($input['id'])){ + $this->validate($input,'app\validate\User'); + }else{ + //设置TOKEN失效 + $input['token']=""; + //判断密码是否修改|留空不修改密码 + if(isset($input['pwd']) && empty($input['pwd'])){ + unset($input['pwd']); + } + $this->validate($input,'app\validate\User.update'); + } + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Users::create($input); + pushLog('新增用户[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Users::update($input); + pushLog('更新用户[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Users::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //关联判断 + $exist=moreTableFind([ + ['table'=>'allot','where'=>[['user','=',$input['id']]]], + ['table'=>'barter','where'=>[['user','=',$input['id']]]], + ['table'=>'bill','where'=>[['user','=',$input['id']]]], + ['table'=>'bor','where'=>[['user','=',$input['id']]]], + ['table'=>'bre','where'=>[['user','=',$input['id']]]], + ['table'=>'buy','where'=>[['user','=',$input['id']]]], + ['table'=>'entry','where'=>[['user','=',$input['id']]]], + ['table'=>'extry','where'=>[['user','=',$input['id']]]], + ['table'=>'ice','where'=>[['user','=',$input['id']]]], + ['table'=>'imy','where'=>[['user','=',$input['id']]]], + ['table'=>'oce','where'=>[['user','=',$input['id']]]], + ['table'=>'omy','where'=>[['user','=',$input['id']]]], + ['table'=>'period','where'=>[['user','=',$input['id']]]], + ['table'=>'sell','where'=>[['user','=',$input['id']]]], + ['table'=>'sor','where'=>[['user','=',$input['id']]]], + ['table'=>'sre','where'=>[['user','=',$input['id']]]], + ['table'=>'swap','where'=>[['user','=',$input['id']]]], + ['table'=>'customer','where'=>[['user','=',$input['id']]]], + ['table'=>'often','where'=>[['user','=',$input['id']]]], + ['table'=>'record','where'=>[['user','=',$input['id']]]], + ['table'=>'supplier','where'=>[['user','=',$input['id']]]], + ]); + if(empty($exist)){ + //逻辑处理 + $find=Db::name('user')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + try { + Db::name('user')->where([['id','=',$input['id']]])->delete(); + Db::name('log')->where([['user','=',$input['id']]])->delete(); + pushLog('删除用户[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //上传 + public function upload(){ + $file=request()->file('file');//获取上传文件 + if (empty($file)){ + $result=['state'=>'error','info'=>'传入数据不完整!']; + }else{ + try{ + validate(['file'=>['fileSize'=>1*1024*1024,'fileExt'=>'png,gif,jpg,jpeg']])->check(['file'=>$file]); + $fileInfo=Filesystem::disk('upload')->putFile('user', $file, 'uniqid'); + $filePath=request()->domain().'/static/upload/'.$fileInfo; + $result=['state'=>'success','info'=>$filePath]; + }catch(ValidateException $e) { + $result=['state'=>'error','info'=>$e->getMessage()]; + } + } + return json($result); + } +} diff --git a/serve/app/controller/Warehouse.php b/serve/app/controller/Warehouse.php new file mode 100644 index 0000000..de215ed --- /dev/null +++ b/serve/app/controller/Warehouse.php @@ -0,0 +1,118 @@ +count();//获取总条数 + $info = Warehouses::with(['frameData'])->where($sql)->page($input['page'],$input['limit'])->order(['id'=>'desc'])->select();//查询分页数据 + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info + ];//返回数据 + return json($result); + } + //新增|更新 + public function save(){ + $input=input('post.'); + if(isset($input['id'])){ + //验证数据 + try { + empty($input['id'])?$this->validate($input,'app\validate\Warehouse'):$this->validate($input,'app\validate\Warehouse.update'); + } catch (ValidateException $e) { + return json(['state'=>'error','info'=>$e->getError()]); + exit; + } + + //处理数据 + Db::startTrans(); + try { + if(empty($input['id'])){ + //创建数据 + Warehouses::create($input); + pushLog('新增仓库[ '.$input['name'].' ]');//日志 + }else{ + //更新数据 + Warehouses::update($input); + pushLog('更新仓库[ '.$input['name'].' ]');//日志 + } + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //获取 + public function get(){ + $input=input('post.'); + if(existFull($input,['id'])){ + $result=[ + 'state'=>'success', + 'info'=>Warehouses::where([['id','=',$input['id']]])->find() + ]; + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //删除 + public function del(){ + $input=input('post.'); + if(existFull($input,['id'])){ + //关联判断 + $exist=moreTableFind([ + ['table'=>'sor_info','where'=>[['warehouse','=',$input['id']]]], + ['table'=>'sell_info','where'=>[['warehouse','=',$input['id']]]], + ['table'=>'sre_info','where'=>[['warehouse','=',$input['id']]]], + ['table'=>'bor_info','where'=>[['warehouse','=',$input['id']]]], + ['table'=>'buy_info','where'=>[['warehouse','=',$input['id']]]], + ['table'=>'bre_info','where'=>[['warehouse','=',$input['id']]]], + ['table'=>'extry_info','where'=>[['warehouse','=',$input['id']]]], + ['table'=>'entry_info','where'=>[['warehouse','=',$input['id']]]], + ['table'=>'swap_info','where'=>[['warehouse|storehouse','=',$input['id']]]], + ['table'=>'deploy','where'=>[['source','like','%"warehouse":'.$input['id'].'%']]] + ]); + if(empty($exist)){ + //逻辑处理 + $find=Db::name('warehouse')->where([['id','=',$input['id']]])->find(); + Db::startTrans(); + try { + Db::name('warehouse')->where([['id','=',$input['id']]])->delete(); + pushLog('删除仓库[ '.$find['name'].' ]');//日志 + + Db::commit(); + $result=['state'=>'success']; + } catch (\Exception $e) { + Db::rollback(); + $result=['state'=>'error','info'=>'内部错误,操作已撤销!']; + } + }else{ + $result=['state'=>'error','info'=>'存在数据关联,删除失败!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Wechat.php b/serve/app/controller/Wechat.php new file mode 100644 index 0000000..ab45955 --- /dev/null +++ b/serve/app/controller/Wechat.php @@ -0,0 +1,169 @@ +appId=$deploy['wechat']['appid']; + $config->merchantId=$deploy['wechat']['mchid']; + $config->key=$deploy['wechat']['mchkey']; + //单据数据 + $order=new \WxPayMicroPay; + $order->SetBody($deploy['wechat']['title']); + $order->SetOut_trade_no($input['number']); + $money=math()->chain($input['money'])->mul(100)->done(); + $order->SetTotal_fee($money); + $order->SetAuth_code($input['code']); + //发送请求 + $result=\WxPayApi::micropay($config,$order); + if($result['return_code']=='SUCCESS'){ + //判断支付状态 + if($result['result_code']=='SUCCESS'){ + //支付成功 + $result=['state'=>'success','info'=>$result['transaction_id']]; + }else{ + //支付失败 + if(in_array($result['err_code'],['SYSTEMERROR','BANKERROR','USERPAYING'])){ + //返回等待信息 + $result=['state'=>'wait','info'=>'等待操作...']; + }else{ + //确认失败,返回错误信息 + $result=['state'=>'wrong','info'=>$result['err_code_des']]; + } + } + }else{ + $result=['state'=>'wrong','info'=>$result['return_msg']]; + } + }else{ + $result=['state'=>'error','info'=>'支付参数不完整!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //查询单据 + public function query(){ + $input=input('post.'); + if(existFull($input,['number'])){ + //读取配置 + $deploy=getFrameDeploy(); + if(!empty($deploy)){ + //微信支付SDK + $wxPayPath=root_path('extend/wechat'); + require_once $wxPayPath."WxPay.Api.php"; + require_once $wxPayPath."WxPay.Config.php"; + //配置数据 + $config=new \WxPayConfig; + $config->appId=$deploy['wechat']['appid']; + $config->merchantId=$deploy['wechat']['mchid']; + $config->key=$deploy['wechat']['mchkey']; + //单据数据 + $order=new \WxPayOrderQuery; + $order->SetOut_trade_no($input['number']); + //发送请求 + $result=\WxPayApi::orderQuery($config,$order); + if($result['return_code']=='SUCCESS'){ + //判断查询状态 + if($result['result_code']=='SUCCESS'){ + //查询成功 + if($result['trade_state']=='SUCCESS'){ + //支付成功 + $result=['state'=>'success','info'=>$result['transaction_id']]; + }elseif($result['trade_state']=='USERPAYING'){ + //用户支付中,返回等待信息 + $result=['state'=>'wait','info'=>'等待操作...']; + }else{ + //其他状态,返回数据 + $result=['state'=>'wrong','info'=>$result['trade_state_desc']]; + } + }else{ + //查询失败 + if($result['err_code']=='SYSTEMERROR'){ + //返回等待信息 + $result=['state'=>'wait','info'=>'等待操作...']; + }else{ + //返回查询错误信息 + $result=['state'=>'wrong','info'=>$result['err_code_des']]; + } + } + }else{ + $result=['state'=>'wrong','info'=>$result['return_msg']]; + } + }else{ + $result=['state'=>'error','info'=>'支付参数不完整!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //撤销单据 + //支付成功退款|未支付关闭单据 + public function cancel(){ + $input=input('post.'); + if(existFull($input,['number'])){ + //读取配置 + $deploy=getFrameDeploy(); + if(!empty($deploy)){ + //微信支付SDK + $wxPayPath=root_path('extend/wechat'); + require_once $wxPayPath."WxPay.Api.php"; + require_once $wxPayPath."WxPay.Config.php"; + $sslCert = tmpfile(); + fwrite($sslCert,$deploy['wechat']['certText']); + $sslKey = tmpfile(); + fwrite($sslKey,$deploy['wechat']['keyText']); + //配置数据 + $config=new \WxPayConfig; + $config->appId=$deploy['wechat']['appid']; + $config->merchantId=$deploy['wechat']['mchid']; + $config->key=$deploy['wechat']['mchkey']; + $config->sslCertPath=stream_get_meta_data($sslCert)['uri']; + $config->sslKeyPath=stream_get_meta_data($sslKey)['uri']; + //单据数据 + $order=new \WxPayReverse; + $order->SetOut_trade_no($input['number']); + //发送请求 + $result=\WxPayApi::reverse($config,$order); + if($result['return_code']=='SUCCESS'){ + //判断查询状态 + if($result['result_code']=='SUCCESS'){ + //撤销成功 + $result=['state'=>'success','info'=>'撤销单据成功!']; + }else{ + //查询失败 + if(in_array($result['err_code'],['SYSTEMERROR','USERPAYING'])){ + //等待信息 + $result=['state'=>'wait','info'=>'等待操作...']; + }else{ + //返回查询错误信息 + $result=['state'=>'wrong','info'=>$result['err_code_des']]; + } + } + }else{ + $result=['state'=>'wrong','info'=>$result['return_msg']]; + } + }else{ + $result=['state'=>'error','info'=>'支付参数不完整!']; + } + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } +} \ No newline at end of file diff --git a/serve/app/controller/Wrf.php b/serve/app/controller/Wrf.php new file mode 100644 index 0000000..f075a62 --- /dev/null +++ b/serve/app/controller/Wrf.php @@ -0,0 +1,641 @@ +where(empty($input['warehouse'])?sqlAuth('warehouse',[]):[['id','in',$input['warehouse']]])->order(['id'=>'desc'])->select()->toArray(); + //构造表头 + $column=[]; + foreach ($warehouse as $vo) { + $column[]=['id'=>$vo['id'],'name'=>$vo['name'],'uct'=>'uct_'.$vo['id'],'uns'=>'uns_'.$vo['id'],'bct'=>'bct_'.$vo['id']]; + } + //匹配数据 + $sql=fastSql($input,[ + ['warehouse','fullIn'], + ['time','endTime'] + ]); + $sql=sqlAuth('summary',$sql); + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['goods','in',$goods]; + } + $count=Summary::where($sql)->group(['goods'])->count(); + $info=Summary::with(['goodsData'])->where($sql)->group(['goods'])->page($input['page'],$input['limit'])->order(['goods'])->select()->toArray(); + foreach ($info as $key=>$vo) { + //查询条件 + $where=fastSql($input,[['time','endTime']]); + $where[]=['goods','=',$vo['goods']]; + //单位数据 + $info[$key]['unit']=$vo['goodsData']['unit']==-1?'多单位':$vo['goodsData']['unit']; + //分仓数据 + $info[$key]['uns']=0; + foreach ($column as $v) { + $wb=Db::name('summary')->where(array_merge($where,[['warehouse','=',$v['id']]]))->order(['id'=>'DESC'])->find(); + + $wb=empty($wb)?['exist'=>[0,0,0,0],'balance'=>[0,0,0,0]]:['exist'=>json_decode($wb['exist']),'balance'=>json_decode($wb['balance'])]; + if(empty($wb['exist'][1]) && empty($wb['balance'][1])){ + $info[$key]['wb_'.$v['id']]=['uct'=>'','uns'=>'','bct'=>'']; + }else{ + $info[$key]['wb_'.$v['id']]=[ + 'uct'=>empty($wb['exist'][1])?0:math()->chain($wb['balance'][1])->div($wb['exist'][1])->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($wb['exist'][1],$vo['goodsData']['units']):$wb['exist'][1], + 'bct'=>$wb['balance'][1] + ]; + } + if(!empty($info[$key]['wb_'.$v['id']]['uns']) && $vo['goodsData']['unit'] != -1){ + $info[$key]['uns']+=$info[$key]['wb_'.$v['id']]['uns']; + }elseif(!empty($info[$key]['wb_'.$v['id']]['uns']) && $vo['goodsData']['unit'] == -1){ + $info[$key]['uns']+-$wb['exist'][1]; + } + + } + //汇总数据 + $balance=Db::name('summary')->where($where)->order(['id'=>'DESC'])->find(); + $balance=['exist'=>json_decode($balance['exist']),'balance'=>json_decode($balance['balance'])]; + $info[$key]['balance']=[]; + $info[$key]['balance']['uct']=empty($balance['exist'][0])?0:math()->chain($balance['balance'][0])->div($balance['exist'][0])->round(2)->done(); + $info[$key]['balance']['uns']=$vo['goodsData']['unit']==-1?unitSwitch($info[$key]['uns'],$vo['goodsData']['units']):$info[$key]['uns']; + $info[$key]['balance']['bct']=math()->chain($info[$key]['balance']['uct'])->mul($info[$key]['balance']['uns'])->round(2)->done(); + + } + + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$info, + 'column'=>$column + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //商品库存余额表-导出 + public function wbsExports(){ + $input=input('get.'); + existFull($input,['warehouse'])||$input['warehouse']=[]; + if(isset($input['warehouse']) && is_array($input['warehouse'])){ + //匹配仓库 + $warehouse = Db::name('warehouse')->where(empty($input['warehouse'])?sqlAuth('warehouse',[]):[['id','in',$input['warehouse']]])->order(['id'=>'desc'])->select()->toArray(); + //构造表头 + $column=[]; + foreach ($warehouse as $vo) { + $column[]=['id'=>$vo['id'],'name'=>$vo['name'],'uct'=>'uct_'.$vo['id'],'uns'=>'uns_'.$vo['id'],'bct'=>'bct_'.$vo['id']]; + } + //匹配数据 + $sql=fastSql($input,[ + ['warehouse','fullIn'], + ['time','endTime'] + ]); + $sql=sqlAuth('summary',$sql); + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['goods','in',$goods]; + } + $count=Summary::where($sql)->group(['goods'])->count(); + $info=Summary::with(['goodsData'])->where($sql)->group(['goods'])->order(['goods'])->select()->toArray(); + foreach ($info as $key=>$vo) { + //查询条件 + $where=fastSql($input,[['time','endTime']]); + $where[]=['goods','=',$vo['goods']]; + //单位数据 + $info[$key]['unit']=$vo['goodsData']['unit']==-1?'多单位':$vo['goodsData']['unit']; + //分仓数据 + foreach ($column as $v) { + $wb=Db::name('summary')->where(array_merge($where,[['warehouse','=',$v['id']]]))->order(['id'=>'DESC'])->find(); + $wb=empty($wb)?['exist'=>[0,0,0,0],'balance'=>[0,0,0,0]]:['exist'=>json_decode($wb['exist']),'balance'=>json_decode($wb['balance'])]; + if(empty($wb['exist'][1]) && empty($wb['balance'][1])){ + $info[$key]['wb_'.$v['id']]=['uct'=>'','uns'=>'','bct'=>'']; + }else{ + $info[$key]['wb_'.$v['id']]=[ + 'uct'=>empty($wb['exist'][1])?0:math()->chain($wb['balance'][1])->div($wb['exist'][1])->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($wb['exist'][1],$vo['goodsData']['units']):$wb['exist'][1], + 'bct'=>$wb['balance'][1] + ]; + } + } + //汇总数据 + $balance=Db::name('summary')->where($where)->order(['id'=>'DESC'])->find(); + $balance=['exist'=>json_decode($balance['exist']),'balance'=>json_decode($balance['balance'])]; + $info[$key]['balance']=[ + 'uct'=>empty($balance['exist'][0])?0:math()->chain($balance['balance'][0])->div($balance['exist'][0])->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($balance['exist'][0],$vo['goodsData']['units']):$balance['exist'][0], + 'bct'=>$balance['balance'][0] + ]; + } + $source=$info; + $columns=[]; + foreach ($column as $v) { + $columns['wb_'.$v['id'].'|uct']=$v['name'].'成本'; + $columns['wb_'.$v['id'].'|uns']=$v['name'].'数量'; + $columns['wb_'.$v['id'].'|bct']=$v['name'].'总成本'; + } + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'商品库存余额表']; + //表格数据 + $field=array_merge( + [ + 'goodsData|name'=>'商品名称', + 'unit'=>'单位' + ], + $columns, + [ + 'balance|uct'=>'汇总成本', + 'balance|uns'=>'汇总数量', + 'balance|bct'=>'汇总总成本' + ] + ); + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + ]]; + //导出execl + buildExcel('商品库存余额表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //商品收发明细表 + public function wds(){ + $input=input('post.'); + $sheet=['buy','bre','sell','sre','swapOut','swapEnter','entry','extry']; + existFull($input,['mold'])||$input['mold']=$sheet; + if(existFull($input,['page','limit']) && is_arrays($input,['warehouse','mold']) && arrayInArray($input['mold'],$sheet)){ + $sql=fastSql($input,[ + ['warehouse','fullIn'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['mold'=>'type'],'fullIn'] + ]); + $sql=sqlAuth('summary',$sql); + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['goods','in',$goods]; + } + //子查询 + $existsSql=[['id','=',Db::raw('summary.class')]]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + //匹配类型|减少查询 + if(in_array($k,$input['mold'])){ + $union[]=Db::name($v)->where([['summary.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $count=Summary::alias('summary')->where($sql)->whereExists($union)->count(); + $source=Summary::with(['sourceData'=>['frameData'],'goodsData','warehouseData'])->alias('summary')->where($sql)->whereExists($union)->page($input['page'],$input['limit'])->order(['goods','id'])->append(['extension'])->select()->toArray(); + //匹配往来单位 + $currentList=['customer'=>[],'supplier'=>[]]; + //匹配客戶 + foreach (search($source)->where([['type','in',['sell','sre','extry']]])->select() as $item) { + $currentList['customer'][]=$item['sourceData']['customer']; + } + empty($currentList['customer'])||$currentList['customer']=Db::name('customer')->where([['id','in',array_unique($currentList['customer'])]])->select()->toArray(); + //匹配供应商 + foreach (search($source)->where([['type','in',['buy','bre','entry']]])->select() as $item) { + $currentList['supplier'][]=$item['sourceData']['supplier']; + } + empty($currentList['supplier'])||$currentList['supplier']=Db::name('supplier')->where([['id','in',array_unique($currentList['supplier'])]])->select()->toArray(); + $data=[]; + $cur=0; + foreach ($source as $vo) { + + if($cur!=$vo['goods']){ + $state=Db::name('summary')->where([['id','<',$vo['id']],['goods','=',$vo['goods']],['warehouse','=',$vo['warehouse']]])->order(['id'=>'DESC'])->find(); + $state=empty($state)?['exist'=>[0,0,0,0],'balance'=>[0,0,0,0]]:['exist'=>json_decode($state['exist']),'balance'=>json_decode($state['balance'])]; + $data[]=[ + 'extension'=>['type'=>'期初余额'], + 'goodsData'=>['name'=>$vo['goodsData']['name']], + 'balance'=>[ + 'uct'=>empty($state['exist'][0])?0:math()->chain($state['balance'][0])->div($state['exist'][0])->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($state['exist'][0],$vo['goodsData']['units']):$state['exist'][0], + 'bct'=>$state['balance'][0] + ] + ]; + $cur=$vo['goods']; + } + $row=$vo; + //往来单位 + if(in_array($vo['type'],['buy','bre','entry'])){ + $row['current']=search($currentList['supplier'])->where([['id','=',$vo['sourceData']['supplier']]])->find(); + }else if(in_array($vo['type'],['sell','sre','extry'])){ + $row['current']=search($currentList['customer'])->where([['id','=',$vo['sourceData']['customer']]])->find(); + }else{ + $row['current']=[]; + } + $row['unit']=$vo['goodsData']['unit']==-1?'多单位':$vo['goodsData']['unit']; + + //出入方向 + $uns=$vo['goodsData']['unit']==-1?unitSwitch($vo['nums'],$vo['goodsData']['units']):$vo['nums']; + if(empty($vo['direction'])){ + //出库 + $row['in']=['uct'=>'','uns'=>'','bct'=>'']; + $row['out']=['uct'=>$vo['uct'],'uns'=>$uns,'bct'=>$vo['bct']]; + }else{ + //入库 + $row['in']=['uct'=>$vo['uct'],'uns'=>$uns,'bct'=>$vo['bct']]; + $row['out']=['uct'=>'','uns'=>'','bct'=>'']; + } + //汇总 + $exist=json_decode($vo['exist']); + $balance=json_decode($vo['balance']); + $row['balance']=[ + 'uct'=>empty($exist[0])?0:math()->chain($balance[0])->div($exist[0])->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($exist[0],$vo['goodsData']['units']):$exist[0], + 'bct'=>$balance[0] + ]; + $data[]=$row; + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //商品收发明细表-导出 + public function wdsExports(){ + $input=input('get.'); + $sheet=['buy','bre','sell','sre','swapOut','swapEnter','entry','extry']; + existFull($input,['warehouse'])||$input['warehouse']=[]; + existFull($input,['mold'])||$input['mold']=$sheet; + if(is_arrays($input,['warehouse','mold']) && arrayInArray($input['mold'],$sheet)){ + $sql=fastSql($input,[ + ['warehouse','fullIn'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'], + [['mold'=>'type'],'fullIn'] + ]); + $sql=sqlAuth('summary',$sql); + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['goods','in',$goods]; + } + //子查询 + $existsSql=[['id','=',Db::raw('summary.class')]]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + //匹配类型|减少查询 + if(in_array($k,$input['mold'])){ + $union[]=Db::name($v)->where([['summary.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $source=Summary::with(['sourceData'=>['frameData'],'goodsData','warehouseData'])->alias('summary')->where($sql)->whereExists($union)->order(['goods','id'])->append(['extension'])->select()->toArray(); + //匹配往来单位 + $currentList=['customer'=>[],'supplier'=>[]]; + //匹配客戶 + foreach (search($source)->where([['type','in',['sell','sre','extry']]])->select() as $item) { + $currentList['customer'][]=$item['sourceData']['customer']; + } + empty($currentList['customer'])||$currentList['customer']=Db::name('customer')->where([['id','in',array_unique($currentList['customer'])]])->select()->toArray(); + //匹配供应商 + foreach (search($source)->where([['type','in',['buy','bre','entry']]])->select() as $item) { + $currentList['supplier'][]=$item['sourceData']['supplier']; + } + empty($currentList['supplier'])||$currentList['supplier']=Db::name('supplier')->where([['id','in',array_unique($currentList['supplier'])]])->select()->toArray(); + $data=[]; + $cur=0; + foreach ($source as $vo) { + if($cur!=$vo['goods']){ + $state=Db::name('summary')->where([['id','<',$vo['id']],['goods','=',$vo['goods']]])->order(['id'=>'DESC'])->find(); + $state=empty($state)?['exist'=>[0,0,0,0],'balance'=>[0,0,0,0]]:['exist'=>json_decode($state['exist']),'balance'=>json_decode($state['balance'])]; + $data[]=[ + 'extension'=>['type'=>'期初余额'], + 'goodsData'=>['name'=>$vo['goodsData']['name']], + 'balance'=>[ + 'uct'=>empty($state['exist'][0])?0:math()->chain($state['balance'][0])->div($state['exist'][0])->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($state['exist'][0],$vo['goodsData']['units']):$state['exist'][0], + 'bct'=>$state['balance'][0] + ] + ]; + $cur=$vo['goods']; + } + $row=$vo; + //往来单位 + if(in_array($vo['type'],['buy','bre','entry'])){ + $row['current']=search($currentList['supplier'])->where([['id','=',$vo['sourceData']['supplier']]])->find(); + }else if(in_array($vo['type'],['sell','sre','extry'])){ + $row['current']=search($currentList['customer'])->where([['id','=',$vo['sourceData']['customer']]])->find(); + }else{ + $row['current']=[]; + } + $row['unit']=$vo['goodsData']['unit']==-1?'多单位':$vo['goodsData']['unit']; + + //出入方向 + $uns=$vo['goodsData']['unit']==-1?unitSwitch($vo['nums'],$vo['goodsData']['units']):$vo['nums']; + if(empty($vo['direction'])){ + //出库 + $row['in']=['uct'=>'','uns'=>'','bct'=>'']; + $row['out']=['uct'=>$vo['uct'],'uns'=>$uns,'bct'=>$vo['bct']]; + }else{ + //入库 + $row['in']=['uct'=>$vo['uct'],'uns'=>$uns,'bct'=>$vo['bct']]; + $row['out']=['uct'=>'','uns'=>'','bct'=>'']; + } + //汇总 + $exist=json_decode($vo['exist']); + $balance=json_decode($vo['balance']); + $row['balance']=[ + 'uct'=>empty($exist[0])?0:math()->chain($balance[0])->div($exist[0])->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($exist[0],$vo['goodsData']['units']):$exist[0], + 'bct'=>$balance[0] + ]; + $data[]=$row; + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'商品收发明细表']; + //表格数据 + $field=[ + 'extension|type'=>'单据类型', + 'sourceData|frameData|name'=>'所属组织', + 'current|name'=>'往来单位', + 'sourceData|time'=>'单据时间', + 'sourceData|number'=>'单据编号', + 'goodsData|name'=>'商品名称', + 'attr'=>'辅助属性', + 'warehouseData|name'=>'仓库', + 'unit'=>'单位', + 'in|uct'=>'入库成本', + 'in|uns'=>'入库数量', + 'in|bct'=>'入库总成本', + 'out|uct'=>'出库成本', + 'out|uns'=>'出库数量', + 'out|bct'=>'出库总成本', + 'balance|uct'=>'汇总成本', + 'balance|uns'=>'汇总数量', + 'balance|bct'=>'汇总总成本' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //导出execl + buildExcel('商品收发明细表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } + //商品收发汇总表 + public function wss(){ + $input=input('post.'); + if(existFull($input,['page','limit']) && is_array($input['warehouse'])){ + $sql=fastSql($input,[ + ['warehouse','fullIn'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql=sqlAuth('summary',$sql); + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['goods','in',$goods]; + } + //子查询 + $existsSql=[['id','=',Db::raw('summary.class')]]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + $union[]=Db::name($v)->where([['summary.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $record=Db::name('summary')->alias('summary')->where($sql)->whereExists($union)->order(['id'])->select()->toArray(); + //分页数据 + $count=Summary::where([['id','in',array_column($record,'id')]])->group(['goods','warehouse'])->count(); + $data=Summary::with(['goodsData','warehouseData'])->where([['id','in',array_column($record,'id')]])->group(['goods','warehouse'])->page($input['page'],$input['limit'])->order(['goods'])->select()->toArray(); + foreach ($data as $key=>$vo) { + $data[$key]['unit']=$vo['goodsData']['unit']==-1?'多单位':$vo['goodsData']['unit']; + //期初 + $scope=search($record)->where([['goods','=',$vo['goods']]])->select(); + $state=Db::name('summary')->where([['id','<',$scope[0]['id']],['goods','=',$vo['goods']]])->order(['id'=>'DESC'])->find(); + $state=empty($state)?['exist'=>[0,0,0,0],'balance'=>[0,0,0,0]]:['exist'=>json_decode($state['exist']),'balance'=>json_decode($state['balance'])]; + $data[$key]['state']=[ + 'uct'=>empty($state['exist'][0])?0:math()->chain($state['balance'][0])->div($state['exist'][0])->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($state['exist'][0],$vo['goodsData']['units']):$state['exist'][0], + 'bct'=>$state['balance'][0] + ]; + $list=search($scope)->where([['goods','=',$vo['goods']],['warehouse','=',$vo['warehouse']]])->select(); + foreach ($table as $t=>$m) { + $group=search($list)->where([['type','=',$t]])->select(); + if(empty($group)){ + $data[$key][$t]=['uct'=>'','uns'=>'','bct'=>'']; + }else{ + $uns=0; + $bct=0; + foreach ($group as $v) { + $uns=math()->chain($uns)->add($v['nums'])->done(); + $bct=math()->chain($bct)->add($v['bct'])->done(); + } + $data[$key][$t]=[ + 'uct'=>math()->chain($bct)->div($uns)->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($uns,$vo['goodsData']['units']):$uns, + 'bct'=>$bct + ]; + } + } + //汇总 + $balance=$scope[count($scope)-1]; + $balance=['exist'=>json_decode($balance['exist']),'balance'=>json_decode($balance['balance'])]; + $sum=Db::name('summary')->where([['goods','=',$vo['goods']],['warehouse','=',$vo['warehouse']]])->order(['id'=>'desc'])->find(); + $data[$key]['balance']=[]; + $data[$key]['balance']['uct']=empty($balance['exist'][0])?0:math()->chain($balance['balance'][0])->div($balance['exist'][0])->round(2)->done(); + $data[$key]['balance']['uns']=$vo['goodsData']['unit']==-1?unitSwitch(json_decode($sum['exist'])[1],$vo['goodsData']['units']):json_decode($sum['exist'])[1]; + $data[$key]['balance']['bct']=math()->chain($data[$key]['balance']['uct'])->mul($data[$key]['balance']['uns'])->round(2)->done(); + + + } + $result=[ + 'state'=>'success', + 'count'=>$count, + 'info'=>$data + ];//返回数据 + }else{ + $result=['state'=>'error','info'=>'传入参数不完整!']; + } + return json($result); + } + //商品收发汇总表-导出 + public function wssExports(){ + $input=input('get.'); + existFull($input,['warehouse'])||$input['warehouse']=[]; + if(is_array($input['warehouse'])){ + $sql=fastSql($input,[ + ['warehouse','fullIn'], + [['startTime'=>'time'],'startTime'], + [['endTime'=>'time'],'endTime'] + ]); + $sql=sqlAuth('summary',$sql); + //商品信息扩展查询 + if(existFull($input,['goods'])){ + $goods=array_column(Db::name('goods')->where([['name|py','like','%'.$input['goods'].'%']])->select()->toArray(),'id'); + $sql[]=['goods','in',$goods]; + } + //子查询 + $existsSql=[['id','=',Db::raw('summary.class')]]; + $existsSql=frameScope($existsSql); + //多源匹配 + $union=[]; + //数据关系表 + $table=['buy'=>'buy','bre'=>'bre','sell'=>'sell','sre'=>'sre','swapOut'=>'swap','swapEnter'=>'swap','entry'=>'entry','extry'=>'extry']; + foreach ($table as $k=>$v) { + $union[]=Db::name($v)->where([['summary.type','=',$k]])->where(array_merge($existsSql,sqlAuth($v,[])))->limit(1)->buildSql(); + } + //合并子查询 + $union=implode(' UNION ALL ',$union); + $record=Db::name('summary')->alias('summary')->where($sql)->whereExists($union)->order(['id'])->select()->toArray(); + //分页数据 + $count=Summary::where([['id','in',array_column($record,'id')]])->group(['goods','warehouse'])->count(); + $data=Summary::with(['goodsData','warehouseData'])->where([['id','in',array_column($record,'id')]])->group(['goods','warehouse'])->order(['goods'])->select()->toArray(); + foreach ($data as $key=>$vo) { + $data[$key]['unit']=$vo['goodsData']['unit']==-1?'多单位':$vo['goodsData']['unit']; + //期初 + $scope=search($record)->where([['goods','=',$vo['goods']]])->select(); + $state=Db::name('summary')->where([['id','<',$scope[0]['id']],['goods','=',$vo['goods']]])->order(['id'=>'DESC'])->find(); + $state=empty($state)?['exist'=>[0,0,0,0],'balance'=>[0,0,0,0]]:['exist'=>json_decode($state['exist']),'balance'=>json_decode($state['balance'])]; + $data[$key]['state']=[ + 'uct'=>empty($state['exist'][0])?0:math()->chain($state['balance'][0])->div($state['exist'][0])->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($state['exist'][0],$vo['goodsData']['units']):$state['exist'][0], + 'bct'=>$state['balance'][0] + ]; + $list=search($scope)->where([['goods','=',$vo['goods']],['warehouse','=',$vo['warehouse']]])->select(); + foreach ($table as $t=>$m) { + $group=search($list)->where([['type','=',$t]])->select(); + if(empty($group)){ + $data[$key][$t]=['uct'=>'','uns'=>'','bct'=>'']; + }else{ + $uns=0; + $bct=0; + foreach ($group as $v) { + $uns=math()->chain($uns)->add($v['nums'])->done(); + $bct=math()->chain($bct)->add($v['bct'])->done(); + } + $data[$key][$t]=[ + 'uct'=>math()->chain($bct)->div($uns)->round(2)->done(), + 'uns'=>$vo['goodsData']['unit']==-1?unitSwitch($uns,$vo['goodsData']['units']):$uns, + 'bct'=>$bct + ]; + } + } + //汇总 + $balance=$scope[count($scope)-1]; + $balance=['exist'=>json_decode($balance['exist']),'balance'=>json_decode($balance['balance'])]; + $sum=Db::name('summary')->where([['goods','=',$vo['goods']],['warehouse','=',$vo['warehouse']]])->order(['id'=>'desc'])->find(); + $data[$key]['balance']=[]; + $data[$key]['balance']['uct']=empty($balance['exist'][0])?0:math()->chain($balance['balance'][0])->div($balance['exist'][0])->round(2)->done(); + $data[$key]['balance']['uns']=$vo['goodsData']['unit']==-1?unitSwitch(json_decode($sum['exist'])[1],$vo['goodsData']['units']):json_decode($sum['exist'])[1]; + $data[$key]['balance']['bct']=math()->chain($data[$key]['balance']['uct'])->mul($data[$key]['balance']['uns'])->round(2)->done(); + } + $source=$data; + //开始构造导出数据 + $excel=[];//初始化导出数据 + //标题数据 + $excel[]=['type'=>'title','info'=>'商品收发汇总表']; + //表格数据 + $field=[ + 'goodsData|name'=>'商品名称', + 'warehouseData|name'=>'仓库', + 'unit'=>'单位', + 'state|uct'=>'期初成本', + 'state|uns'=>'期初数量', + 'state|bct'=>'期初成本', + 'buy|uct'=>'采购成本', + 'buy|uns'=>'采购数量', + 'buy|bct'=>'采购总成本', + 'bre|uct'=>'购退成本', + 'bre|uns'=>'购退数量', + 'bre|bct'=>'购退总成本', + 'sell|uct'=>'销售成本', + 'sell|uns'=>'销售数量', + 'sell|bct'=>'销售总成本', + 'sre|uct'=>'销退成本', + 'sre|uns'=>'销退数量', + 'sre|bct'=>'销退总成本', + 'swapOut|uct'=>'调出成本', + 'swapOut|uns'=>'调出数量', + 'swapOut|bct'=>'调出总成本', + 'swapEnter|uct'=>'调入成本', + 'swapEnter|uns'=>'调入数量', + 'swapEnter|bct'=>'调入总成本', + 'entry|uct'=>'其入成本', + 'entry|uns'=>'其入数量', + 'entry|bct'=>'其入总成本', + 'extry|uct'=>'其出成本', + 'extry|uns'=>'其出数量', + 'extry|bct'=>'其出总成本', + 'balance|uct'=>'汇总成本', + 'balance|uns'=>'汇总数量', + 'balance|bct'=>'汇总总成本' + ]; + $thead=array_values($field);//表格标题 + $tbody=[];//表格内容 + //构造表内数据 + foreach ($source as $sourceVo) { + $rowData=[]; + foreach (array_keys($field) as $fieldVo) { + $rowData[]=arraySeek($sourceVo,$fieldVo);//多键名数据赋值 + } + $tbody[]=$rowData;//加入行数据 + } + $excel[]=['type'=>'table','info'=>['thead'=>$thead,'tbody'=>$tbody]];//表格数据 + //汇总数据 + $excel[]=['type'=>'node','info'=>[ + '总数:'.count($source), + ]]; + //导出execl + buildExcel('商品收发汇总表',$excel); + }else{ + return json(['state'=>'error','info'=>'传入参数不完整!']); + } + } +} diff --git a/serve/app/event.php b/serve/app/event.php new file mode 100644 index 0000000..e9851bb --- /dev/null +++ b/serve/app/event.php @@ -0,0 +1,17 @@ + [ + ], + + 'listen' => [ + 'AppInit' => [], + 'HttpRun' => [], + 'HttpEnd' => [], + 'LogLevel' => [], + 'LogWrite' => [], + ], + + 'subscribe' => [ + ], +]; diff --git a/serve/app/middleware.php b/serve/app/middleware.php new file mode 100644 index 0000000..60b8c09 --- /dev/null +++ b/serve/app/middleware.php @@ -0,0 +1,5 @@ +domain(); + header('Access-Control-Allow-Origin:'.$origin); + header('access-control-allow-credentials:true'); + header('access-control-allow-methods:GET,POST,OPTIONS'); + header('access-control-allow-headers:Accept,X-PINGARUNER,CONTENT-TYPE,X-Requested-With,Token'); + return $request->isOptions()?response('Hello NodCloud',200):$next($request); + } +} \ No newline at end of file diff --git a/serve/app/model/Account.php b/serve/app/model/Account.php new file mode 100644 index 0000000..756a191 --- /dev/null +++ b/serve/app/model/Account.php @@ -0,0 +1,34 @@ +'timestamp:Y-m-d', + ]; + + //组织属性关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //期初余额_读取器 + public function getInitialAttr($val,$data){ + return floatval($val); + } + + //账户余额_读取器 + public function getBalanceAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //实际余额 + $source['money']=math()->chain($data['balance'])->add($data['initial'])->done(); + return $source; + } +} diff --git a/serve/app/model/AccountInfo.php b/serve/app/model/AccountInfo.php new file mode 100644 index 0000000..565607f --- /dev/null +++ b/serve/app/model/AccountInfo.php @@ -0,0 +1,42 @@ +'timestamp:Y-m-d' + ]; + //单据关联 + public function sourceData(){ + return $this->morphTo(['type','class'],[ + 'buy'=>Buy::class, + 'bre'=>Bre::class, + 'sell'=>Sell::class, + 'sre'=>Sre::class, + 'vend'=>Vend::class, + 'vre'=>Vre::class, + 'imy'=>Imy::class, + 'omy'=>Omy::class, + 'allotOut'=>Allot::class, + 'allotEnter'=>Allot::class, + 'ice'=>Ice::class, + 'oce'=>Oce::class, + ]); + } + + //金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=['buy'=>'采购单', 'bre'=>'采购退货单', 'sell'=>'销售单', 'sre'=>'销售退货单', 'vend'=>'零售单', 'vre'=>'零售退货单', 'imy'=>'收款单', 'omy'=>'付款单', 'allotOut'=>'转账单-出', 'allotEnter'=>'转账单-入', 'ice'=>'其它收入单', 'oce'=>'其它支出单'][$data['type']]; + //操作类型 + $source['direction']=["减少","增加"][$data['direction']]; + + return $source; + } +} diff --git a/serve/app/model/Allot.php b/serve/app/model/Allot.php new file mode 100644 index 0000000..cc96f79 --- /dev/null +++ b/serve/app/model/Allot.php @@ -0,0 +1,73 @@ +'timestamp:Y-m-d', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','allot']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/AllotInfo.php b/serve/app/model/AllotInfo.php new file mode 100644 index 0000000..9b0a7cb --- /dev/null +++ b/serve/app/model/AllotInfo.php @@ -0,0 +1,42 @@ +hasOne(Account::class,'id','account'); + } + + //转入账户关联 + public function tatData(){ + return $this->hasOne(Account::class,'id','tat'); + } + + //转出账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //转出账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //转入账户_设置器 + public function setTatAttr($val,$data){ + return empty($val)?0:$val; + } + + //转入账户_读取器 + public function getTatAttr($val,$data){ + return empty($val)?null:$val; + } + + //结算金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + +} diff --git a/serve/app/model/Attr.php b/serve/app/model/Attr.php new file mode 100644 index 0000000..8464a51 --- /dev/null +++ b/serve/app/model/Attr.php @@ -0,0 +1,21 @@ +hasMany(AttributeInfo::class,'pid','id')->visible(['name']); + } +} diff --git a/serve/app/model/AttributeInfo.php b/serve/app/model/AttributeInfo.php new file mode 100644 index 0000000..6fe36e5 --- /dev/null +++ b/serve/app/model/AttributeInfo.php @@ -0,0 +1,7 @@ +'timestamp:Y-m-d' + ]; + + //库存数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } +} diff --git a/serve/app/model/BatchInfo.php b/serve/app/model/BatchInfo.php new file mode 100644 index 0000000..fc52fe4 --- /dev/null +++ b/serve/app/model/BatchInfo.php @@ -0,0 +1,43 @@ +'timestamp:Y-m-d' + ]; + + //单据关联 + public function sourceData(){ + return $this->morphTo(['type','class'],[ + 'buy'=>Buy::class, + 'bre'=>Bre::class, + 'sell'=>Sell::class, + 'sre'=>Sre::class, + 'vend'=>Vend::class, + 'vre'=>Vre::class, + 'barter'=>Barter::class, + 'swapOut'=>Swap::class, + 'swapEnter'=>Swap::class, + 'entry'=>Entry::class, + 'extry'=>Extry::class, + ]); + } + + //基础数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=["buy"=>"采购单","bre"=>"采购退货单","sell"=>"销售单","sre"=>"销售退货单","vend"=>"零售单","vre"=>"零售退货单","barter"=>"积分兑换单","swapOut"=>"调拨单-出","swapEnter"=>"调拨单-入","entry"=>"其它入库单","extry"=>"其它出库单"][$data['type']]; + //操作类型 + $source['direction']=["减少","增加"][$data['direction']]; + + return $source; + } +} diff --git a/serve/app/model/Bill.php b/serve/app/model/Bill.php new file mode 100644 index 0000000..47ed7aa --- /dev/null +++ b/serve/app/model/Bill.php @@ -0,0 +1,109 @@ +'timestamp:Y-m-d', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //客户关联 + public function customerData(){ + return $this->hasOne(Customer::class,'id','customer')->append(['extension']); + } + + //供应商关联 + public function supplierData(){ + return $this->hasOne(Supplier::class,'id','supplier')->append(['extension']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','bill']])->append(['extension'])->order('id desc'); + } + + //客户_设置器 + public function setCustomerAttr($val){ + return empty($val)?0:$val; + } + + //客户_读取器 + public function getCustomerAttr($val){ + return empty($val)?null:$val; + } + + //供应商_设置器 + public function setSupplierAttr($val){ + return empty($val)?0:$val; + } + + //供应商_读取器 + public function getSupplierAttr($val){ + return empty($val)?null:$val; + } + //总核金额_读取器 + public function getPmyAttr($val,$data){ + return floatval($val); + } + + //总销金额_读取器 + public function getSmpAttr($val,$data){ + return floatval($val); + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //核销类型 + $source['type']=[0=>'预收冲应收',1=>'预付冲应付',2=>'应收冲应付',3=>'销退冲销售',4=>'购退冲采购'][$data['type']]; + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/BillInfo.php b/serve/app/model/BillInfo.php new file mode 100644 index 0000000..f2739da --- /dev/null +++ b/serve/app/model/BillInfo.php @@ -0,0 +1,35 @@ +morphTo(['mold','source'],[ + 'imy' => Imy::class, + 'omy' => Omy::class, + 'buy' => Buy::class, + 'bre' => Bre::class, + 'sell' => Sell::class, + 'sre' => Sre::class, + 'ice' => Ice::class, + 'oce' => Oce::class, + ]); + } + + //核销金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //核销类型 + $source['bill']=['cia'=>'预收','pia'=>'预付','re'=>'应收','cw'=>'应付','sre'=>'销退','sell'=>'销售','bre'=>'购退','buy'=>'采购'][$data['bill']]; + //单据类型 + $source['mold']=['imy'=>'收款单','omy'=>'付款单','buy'=>'采购单','bre'=>'采购退货单','sell'=>'销售单','sre'=>'销售退货单','ice'=>'其它收入单','oce'=>'其它支出单'][$data['mold']]; + return $source; + } +} diff --git a/serve/app/model/Bor.php b/serve/app/model/Bor.php new file mode 100644 index 0000000..ba0028a --- /dev/null +++ b/serve/app/model/Bor.php @@ -0,0 +1,96 @@ +'timestamp:Y-m-d', + 'arrival'=>'timestamp:Y-m-d', + 'logistics'=>'json', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //供应商关联 + public function supplierData(){ + return $this->hasOne(Supplier::class,'id','supplier')->append(['extension']); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','bor']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //实际金额_读取器 + public function getActualAttr($val,$data){ + return floatval($val); + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //物流信息 + $logistics=json_decode($data['logistics'],true); + if(empty($logistics['key'])){ + $source['logistics']=''; + }elseif($logistics['key']=='auto'){ + $source['logistics']=$logistics['number']; + }else{ + $source['logistics']=$logistics['name'].'|'.$logistics['number']; + } + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //入库状态 + $source['state']=[0=>'未入库',1=>'部分入库',2=>'已入库',3=>'关闭'][$data['state']]; + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/BorInfo.php b/serve/app/model/BorInfo.php new file mode 100644 index 0000000..29d74e0 --- /dev/null +++ b/serve/app/model/BorInfo.php @@ -0,0 +1,72 @@ +hasOne(Goods::class,'id','goods'); + } + + //仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //仓库_设置器 + public function setWarehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //仓库_读取器 + public function getWarehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //单价_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //折扣率_读取器 + public function getDiscountAttr($val,$data){ + return floatval($val); + } + + //折扣额_读取器 + public function getDscAttr($val,$data){ + return floatval($val); + } + + //金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //税率_读取器 + public function getTaxAttr($val,$data){ + return floatval($val); + } + + //税额_读取器 + public function getTatAttr($val,$data){ + return floatval($val); + } + + //价税合计_读取器 + public function getTptAttr($val,$data){ + return floatval($val); + } + + //入库数量_读取器 + public function getHandleAttr($val,$data){ + return floatval($val); + } + +} diff --git a/serve/app/model/Bre.php b/serve/app/model/Bre.php new file mode 100644 index 0000000..ff0360c --- /dev/null +++ b/serve/app/model/Bre.php @@ -0,0 +1,151 @@ +'timestamp:Y-m-d', + 'logistics'=>'json', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //供应商关联 + public function supplierData(){ + return $this->hasOne(Supplier::class,'id','supplier')->append(['extension']); + } + + //结算账户关联 + public function accountData(){ + return $this->hasOne(Account::class,'id','account'); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //核销关联 + public function billData(){ + return $this->hasMany(BreBill::class,'pid','id')->with(['sourceData'])->visible(['sourceData'=>['id','number']])->append(['extension'])->order('id desc'); + } + + //费用详情关联 + public function costData(){ + return $this->hasMany(Cost::class,'class','id')->with(['ietData'])->where([['type','=','bre']])->append(['extension'])->order('id desc'); + } + + //发票关联 + public function invoiceData(){ + return $this->hasMany(Invoice::class,'class','id')->where([['type','=','bre']])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','bre']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //实际金额_读取器 + public function getActualAttr($val,$data){ + return floatval($val); + } + + //实付金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //单据费用_读取器 + public function getCostAttr($val,$data){ + return floatval($val); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //物流信息 + $logistics=json_decode($data['logistics'],true); + if(empty($logistics['key'])){ + $source['logistics']=''; + }elseif($logistics['key']=='auto'){ + $source['logistics']=$logistics['number']; + }else{ + $source['logistics']=$logistics['name'].'|'.$logistics['number']; + } + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核销状态 + $source['nucleus']=[0=>'未核销',1=>'部分核销',2=>'已核销'][$data['nucleus']]; + //费用状态 + $source['cse']=[0=>'未结算',1=>'部分结算',2=>'已结算',3=>'无需结算'][$data['cse']]; + //发票状态 + $source['invoice']=[0=>'未开具',1=>'部分开具',2=>'已开具',3=>'无需开具'][$data['invoice']]; + //核对状态 + $source['check']=[0=>'未核对',1=>'已核对'][$data['check']]; + //已核销金额 + if($data['nucleus']==0){ + $source['amount']=0; + }else if($data['nucleus']==1){ + $source['amount']=db('bre_bill')->where([['pid','=',$data['id']]])->sum('money'); + }else{ + $source['amount']=floatval($data['actual']); + } + //未核销金额 + $source['anwo']=math()->chain($data['actual'])->sub($source['amount'])->done(); + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/BreBill.php b/serve/app/model/BreBill.php new file mode 100644 index 0000000..25945e9 --- /dev/null +++ b/serve/app/model/BreBill.php @@ -0,0 +1,31 @@ +'timestamp:Y-m-d' + ]; + + //结算账户关联 + public function sourceData(){ + return $this->morphTo(['type','source'],[ + 'bre' => Bre::class, + 'bill' => Bill::class + ]); + } + + //核销金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=['bre'=>'采购退货单','bill'=>'核销单'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/BreInfo.php b/serve/app/model/BreInfo.php new file mode 100644 index 0000000..35b81c7 --- /dev/null +++ b/serve/app/model/BreInfo.php @@ -0,0 +1,88 @@ +'json' + ]; + + //商品关联 + public function goodsData(){ + return $this->hasOne(Goods::class,'id','goods'); + } + + //仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //仓库_设置器 + public function setWarehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //仓库_读取器 + public function getWarehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //生产日期_设置器 + public function setMfdAttr($val,$data){ + return empty($val)?0:strtotime($val); + } + + //生产日期_读取器 + public function getMfdAttr($val,$data){ + return empty($val)?'':date('Y-m-d',$val); + } + + //单价_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //折扣率_读取器 + public function getDiscountAttr($val,$data){ + return floatval($val); + } + + //折扣额_读取器 + public function getDscAttr($val,$data){ + return floatval($val); + } + + //金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //税率_读取器 + public function getTaxAttr($val,$data){ + return floatval($val); + } + + //税额_读取器 + public function getTatAttr($val,$data){ + return floatval($val); + } + + //价税合计_读取器 + public function getTptAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //序列号 + $source['serial']=implode(',',json_decode($data['serial'])); + return $source; + } +} diff --git a/serve/app/model/Buy.php b/serve/app/model/Buy.php new file mode 100644 index 0000000..48708eb --- /dev/null +++ b/serve/app/model/Buy.php @@ -0,0 +1,151 @@ +'timestamp:Y-m-d', + 'logistics'=>'json', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //供应商关联 + public function supplierData(){ + return $this->hasOne(Supplier::class,'id','supplier')->append(['extension']); + } + + //结算账户关联 + public function accountData(){ + return $this->hasOne(Account::class,'id','account'); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //核销关联 + public function billData(){ + return $this->hasMany(BuyBill::class,'pid','id')->with(['sourceData'])->visible(['sourceData'=>['id','number']])->append(['extension'])->order('id desc'); + } + + //费用详情关联 + public function costData(){ + return $this->hasMany(Cost::class,'class','id')->with(['ietData'])->where([['type','=','buy']])->append(['extension'])->order('id desc'); + } + + //发票关联 + public function invoiceData(){ + return $this->hasMany(Invoice::class,'class','id')->where([['type','=','buy']])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','buy']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //实际金额_读取器 + public function getActualAttr($val,$data){ + return floatval($val); + } + + //实付金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //单据费用_读取器 + public function getCostAttr($val,$data){ + return floatval($val); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //物流信息 + $logistics=json_decode($data['logistics'],true); + if(empty($logistics['key'])){ + $source['logistics']=''; + }elseif($logistics['key']=='auto'){ + $source['logistics']=$logistics['number']; + }else{ + $source['logistics']=$logistics['name'].'|'.$logistics['number']; + } + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核销状态 + $source['nucleus']=[0=>'未核销',1=>'部分核销',2=>'已核销'][$data['nucleus']]; + //费用状态 + $source['cse']=[0=>'未结算',1=>'部分结算',2=>'已结算',3=>'无需结算'][$data['cse']]; + //发票状态 + $source['invoice']=[0=>'未开具',1=>'部分开具',2=>'已开具',3=>'无需开具'][$data['invoice']]; + //核对状态 + $source['check']=[0=>'未核对',1=>'已核对'][$data['check']]; + //已核销金额 + if($data['nucleus']==0){ + $source['amount']=0; + }else if($data['nucleus']==1){ + $source['amount']=db('buy_bill')->where([['pid','=',$data['id']]])->sum('money'); + }else{ + $source['amount']=floatval($data['actual']); + } + //未核销金额 + $source['anwo']=math()->chain($data['actual'])->sub($source['amount'])->done(); + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/BuyBill.php b/serve/app/model/BuyBill.php new file mode 100644 index 0000000..944b0b7 --- /dev/null +++ b/serve/app/model/BuyBill.php @@ -0,0 +1,31 @@ +'timestamp:Y-m-d' + ]; + + //核销单据关联 + public function sourceData(){ + return $this->morphTo(['type','source'],[ + 'buy' => Buy::class, + 'bill' => Bill::class + ]); + } + + //核销金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=['buy'=>'采购单','bill'=>'核销单'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/BuyInfo.php b/serve/app/model/BuyInfo.php new file mode 100644 index 0000000..d538433 --- /dev/null +++ b/serve/app/model/BuyInfo.php @@ -0,0 +1,93 @@ +'json' + ]; + + //商品关联 + public function goodsData(){ + return $this->hasOne(Goods::class,'id','goods'); + } + + //仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //仓库_设置器 + public function setWarehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //仓库_读取器 + public function getWarehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //生产日期_设置器 + public function setMfdAttr($val,$data){ + return empty($val)?0:strtotime($val); + } + + //生产日期_读取器 + public function getMfdAttr($val,$data){ + return empty($val)?'':date('Y-m-d',$val); + } + + //单价_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //折扣率_读取器 + public function getDiscountAttr($val,$data){ + return floatval($val); + } + + //折扣额_读取器 + public function getDscAttr($val,$data){ + return floatval($val); + } + + //金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //税率_读取器 + public function getTaxAttr($val,$data){ + return floatval($val); + } + + //税额_读取器 + public function getTatAttr($val,$data){ + return floatval($val); + } + + //价税合计_读取器 + public function getTptAttr($val,$data){ + return floatval($val); + } + + //退货数量_读取器 + public function getRetreatAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //序列号 + $source['serial']=implode(',',json_decode($data['serial'])); + return $source; + } +} diff --git a/serve/app/model/Category.php b/serve/app/model/Category.php new file mode 100644 index 0000000..d7da8bb --- /dev/null +++ b/serve/app/model/Category.php @@ -0,0 +1,6 @@ +'条形码',1=>'二维码'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/Cost.php b/serve/app/model/Cost.php new file mode 100644 index 0000000..57cd0b0 --- /dev/null +++ b/serve/app/model/Cost.php @@ -0,0 +1,52 @@ +'timestamp:Y-m-d' + ]; + + //单据关联 + public function sourceData(){ + return $this->morphTo(['type','class'],[ + 'buy' => Buy::class, + 'bre' => Bre::class, + 'sell' => Sell::class, + 'sre' => Sre::class, + 'vend' => Vend::class, + 'barter' => Barter::class, + 'vre' => Vre::class, + 'swap' => Swap::class, + 'entry' => Entry::class, + 'extry' => Extry::class + + ]); + } + + //收支关联 + public function ietData(){ + return $this->hasOne(Iet::class,'id','iet')->field(['id','name']); + } + + //金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //结算金额_读取器 + public function getSettleAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=['buy'=>'采购单','bre'=>'采购退货单','sell'=>'销售单','sre'=>'销售退货单','vend'=>'零售单','vre'=>'零售退货单','barter'=>'积分兑换单','swap'=>'调拨单','entry'=>'其它入库单','extry'=>'其它出库单'][$data['type']]; + //结算状态 + $source['state']=[0=>'未结算',1=>'部分结算',2=>'已结算'][$data['state']]; + return $source; + } +} diff --git a/serve/app/model/CostInfo.php b/serve/app/model/CostInfo.php new file mode 100644 index 0000000..707a92e --- /dev/null +++ b/serve/app/model/CostInfo.php @@ -0,0 +1,20 @@ +'timestamp:Y-m-d' + ]; + + //单据关联 + public function oceData(){ + return $this->hasOne(Oce::class,'id','oce'); + } + + //结算金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } +} diff --git a/serve/app/model/Customer.php b/serve/app/model/Customer.php new file mode 100644 index 0000000..6eabd3a --- /dev/null +++ b/serve/app/model/Customer.php @@ -0,0 +1,55 @@ + 'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //所属用户关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //应收款余额_读取器 + public function getBalanceAttr($val,$data){ + return floatval($val); + } + + //客户积分_读取器 + public function getIntegralAttr($val,$data){ + return floatval($val); + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //主联系人 + $contact=json_decode($data['contacts'],true); + if(empty($contact)){ + $source['contact']=''; + }else{ + $find=search($contact)->where([['main','=',true]])->find(); + $source['contact']=$find['name'].' | '.$find['tel'].' | '.$find['add']; + } + return $source; + } +} diff --git a/serve/app/model/Deploy.php b/serve/app/model/Deploy.php new file mode 100644 index 0000000..1ab1f1b --- /dev/null +++ b/serve/app/model/Deploy.php @@ -0,0 +1,15 @@ + 'json' + ]; + + //组织属性关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } +} diff --git a/serve/app/model/Entry.php b/serve/app/model/Entry.php new file mode 100644 index 0000000..9015334 --- /dev/null +++ b/serve/app/model/Entry.php @@ -0,0 +1,114 @@ +'timestamp:Y-m-d', + 'logistics'=>'json', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //费用详情关联 + public function costData(){ + return $this->hasMany(Cost::class,'class','id')->with(['ietData'])->where([['type','=','entry']])->append(['extension'])->order('id desc'); + } + + //供应商关联 + public function supplierData(){ + return $this->hasOne(Supplier::class,'id','supplier')->append(['extension']); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','entry']])->append(['extension'])->order('id desc'); + } + + //单据成本_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //单据费用_读取器 + public function getCostAttr($val,$data){ + return floatval($val); + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //供应商_设置器 + public function setSupplierAttr($val){ + return empty($val)?0:$val; + } + + //供应商_读取器 + public function getSupplierAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=[0=>'其它入库单',1=>'盘盈单'][$data['type']]; + //物流信息 + $logistics=json_decode($data['logistics'],true); + if(empty($logistics['key'])){ + $source['logistics']=''; + }elseif($logistics['key']=='auto'){ + $source['logistics']=$logistics['number']; + }else{ + $source['logistics']=$logistics['name'].'|'.$logistics['number']; + } + //费用状态 + $source['cse']=[0=>'未结算',1=>'部分结算',2=>'已结算',3=>'无需结算'][$data['cse']]; + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核对状态 + $source['check']=[0=>'未核对',1=>'已核对'][$data['check']]; + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/EntryInfo.php b/serve/app/model/EntryInfo.php new file mode 100644 index 0000000..cb51deb --- /dev/null +++ b/serve/app/model/EntryInfo.php @@ -0,0 +1,63 @@ +'json' + ]; + + //商品关联 + public function goodsData(){ + return $this->hasOne(Goods::class,'id','goods'); + } + + //仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //仓库_设置器 + public function setWarehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //仓库_读取器 + public function getWarehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //生产日期_设置器 + public function setMfdAttr($val,$data){ + return empty($val)?0:strtotime($val); + } + + //生产日期_读取器 + public function getMfdAttr($val,$data){ + return empty($val)?'':date('Y-m-d',$val); + } + + //成本_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //总成本_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //序列号 + $source['serial']=implode(',',json_decode($data['serial'])); + return $source; + } +} diff --git a/serve/app/model/Extry.php b/serve/app/model/Extry.php new file mode 100644 index 0000000..234fb83 --- /dev/null +++ b/serve/app/model/Extry.php @@ -0,0 +1,114 @@ +'timestamp:Y-m-d', + 'logistics'=>'json', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //费用详情关联 + public function costData(){ + return $this->hasMany(Cost::class,'class','id')->with(['ietData'])->where([['type','=','extry']])->append(['extension'])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','extry']])->append(['extension'])->order('id desc'); + } + + //客户关联 + public function customerData(){ + return $this->hasOne(Customer::class,'id','customer')->append(['extension']); + } + + //单据成本_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //单据费用_读取器 + public function getCostAttr($val,$data){ + return floatval($val); + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //客户_设置器 + public function setCustomerAttr($val){ + return empty($val)?0:$val; + } + + //客户_读取器 + public function getCustomerAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=[0=>'其它出库单',1=>'盘亏单'][$data['type']]; + //物流信息 + $logistics=json_decode($data['logistics'],true); + if(empty($logistics['key'])){ + $source['logistics']=''; + }elseif($logistics['key']=='auto'){ + $source['logistics']=$logistics['number']; + }else{ + $source['logistics']=$logistics['name'].'|'.$logistics['number']; + } + //费用状态 + $source['cse']=[0=>'未结算',1=>'部分结算',2=>'已结算',3=>'无需结算'][$data['cse']]; + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核对状态 + $source['check']=[0=>'未核对',1=>'已核对'][$data['check']]; + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/ExtryInfo.php b/serve/app/model/ExtryInfo.php new file mode 100644 index 0000000..6e0a925 --- /dev/null +++ b/serve/app/model/ExtryInfo.php @@ -0,0 +1,63 @@ +'json' + ]; + + //商品关联 + public function goodsData(){ + return $this->hasOne(Goods::class,'id','goods'); + } + + //仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //仓库_设置器 + public function setWarehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //仓库_读取器 + public function getWarehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //生产日期_设置器 + public function setMfdAttr($val,$data){ + return empty($val)?0:strtotime($val); + } + + //生产日期_读取器 + public function getMfdAttr($val,$data){ + return empty($val)?'':date('Y-m-d',$val); + } + + //成本_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //总成本_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //序列号 + $source['serial']=implode(',',json_decode($data['serial'])); + return $source; + } +} diff --git a/serve/app/model/Field.php b/serve/app/model/Field.php new file mode 100644 index 0000000..541dceb --- /dev/null +++ b/serve/app/model/Field.php @@ -0,0 +1,21 @@ + 'json' + ]; + + + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //模块标识 + $source['key']=["user"=>"用户管理","people"=>"人员管理","customer"=>"客户管理","supplier"=>"供应商管理","goods"=>"商品管理","bor"=>"采购订单","buy"=>"采购单","bre"=>"采购退货单","sor"=>"销售订单","sell"=>"销售单","sre"=>"销售退货单","vend"=>"零售单","vre"=>"零售退货单","barter"=>"积分兑换单","swap"=>"调拨单","entry"=>"其它入库单","extry"=>"其它出库单","imy"=>"收款单","omy"=>"付款单","bill"=>"核销单","allot"=>"转账单","ice"=>"其它收入单","oce"=>"其它支出单"][$data['key']]; + return $source; + } +} diff --git a/serve/app/model/Frame.php b/serve/app/model/Frame.php new file mode 100644 index 0000000..685fb70 --- /dev/null +++ b/serve/app/model/Frame.php @@ -0,0 +1,6 @@ + 'json', + 'units' => 'json', + 'strategy' => 'json', + 'serial' => 'boolean', + 'batch' => 'boolean', + 'validity' => 'boolean' + ]; + + //商品类别关联 + public function categoryData(){ + return $this->hasOne(Category::class,'id','category'); + } + + //辅助属性关联 + public function attr(){ + return $this->hasMany(Attr::class,'pid','id'); + } + + //采购价格_读取器 + public function getBuyAttr($val,$data){ + return floatval($val); + } + + //销售价格_读取器 + public function getSellAttr($val,$data){ + return floatval($val); + } + + //零售价格_读取器 + public function getRetailAttr($val,$data){ + return floatval($val); + } + + //兑换积分_读取器 + public function getIntegralAttr($val,$data){ + return floatval($val); + } + + //库存阈值_读取器 + public function getStockAttr($val,$data){ + return floatval($val); + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //商品单位 + $source['unit']=$data['unit']==-1?'多单位':$data['unit']; + //商品类型 + $source['type']=[0=>'常规商品',1=>'服务商品'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/Ice.php b/serve/app/model/Ice.php new file mode 100644 index 0000000..99fc9d2 --- /dev/null +++ b/serve/app/model/Ice.php @@ -0,0 +1,130 @@ +'timestamp:Y-m-d', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //客户关联 + public function customerData(){ + return $this->hasOne(Customer::class,'id','customer')->append(['extension']); + } + + //资金账户关联 + public function accountData(){ + return $this->hasOne(Account::class,'id','account')->field(['id','name']); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //核销关联 + public function billData(){ + return $this->hasMany(IceBill::class,'pid','id')->with(['sourceData'])->visible(['sourceData'=>['id','number']])->append(['extension'])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','ice']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //实际金额_读取器 + public function getActualAttr($val,$data){ + return floatval($val); + } + + //实收金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //客户_设置器 + public function setCustomerAttr($val){ + return empty($val)?0:$val; + } + + //客户_读取器 + public function getCustomerAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核销状态 + $source['nucleus']=[0=>'未核销',1=>'部分核销',2=>'已核销'][$data['nucleus']]; + //已核销金额 + if($data['nucleus']==0){ + $source['amount']=0; + }else if($data['nucleus']==1){ + $source['amount']=db('ice_bill')->where([['pid','=',$data['id']]])->sum('money'); + }else{ + $source['amount']=floatval($data['actual']); + } + //未核销金额 + $source['anwo']=math()->chain($data['actual'])->sub($source['amount'])->done(); + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/IceBill.php b/serve/app/model/IceBill.php new file mode 100644 index 0000000..912cef9 --- /dev/null +++ b/serve/app/model/IceBill.php @@ -0,0 +1,31 @@ +'timestamp:Y-m-d' + ]; + + //关联单据 + public function sourceData(){ + return $this->morphTo(['type','source'],[ + 'ice' => Ice::class, + 'bill' => Bill::class + ]); + } + + //核销金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=['ice'=>'其它收入单','bill'=>'核销单'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/IceInfo.php b/serve/app/model/IceInfo.php new file mode 100644 index 0000000..afcabcd --- /dev/null +++ b/serve/app/model/IceInfo.php @@ -0,0 +1,32 @@ +hasOne(Iet::class,'id','iet'); + } + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //结算金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + +} diff --git a/serve/app/model/Iet.php b/serve/app/model/Iet.php new file mode 100644 index 0000000..763abe6 --- /dev/null +++ b/serve/app/model/Iet.php @@ -0,0 +1,14 @@ +'收入',1=>'支出'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/Imy.php b/serve/app/model/Imy.php new file mode 100644 index 0000000..9787cd7 --- /dev/null +++ b/serve/app/model/Imy.php @@ -0,0 +1,95 @@ +'timestamp:Y-m-d', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //客户关联 + public function customerData(){ + return $this->hasOne(Customer::class,'id','customer')->append(['extension']); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //核销关联 + public function billData(){ + return $this->hasMany(ImyBill::class,'pid','id')->with(['sourceData'])->visible(['sourceData'=>['id','number']])->append(['extension'])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','imy']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核销状态 + $source['nucleus']=[0=>'未核销',1=>'部分核销',2=>'已核销'][$data['nucleus']]; + //已核销金额 + if($data['nucleus']==0){ + $source['amount']=0; + }else if($data['nucleus']==1){ + $source['amount']=db('imy_bill')->where([['pid','=',$data['id']]])->sum('money'); + }else{ + $source['amount']=floatval($data['total']); + } + //未核销金额 + $source['anwo']=math()->chain($data['total'])->sub($source['amount'])->done(); + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/ImyBill.php b/serve/app/model/ImyBill.php new file mode 100644 index 0000000..5d493d7 --- /dev/null +++ b/serve/app/model/ImyBill.php @@ -0,0 +1,28 @@ +'timestamp:Y-m-d' + ]; + + //关联单据 + public function sourceData(){ + return $this->hasOne(Bill::class,'id','source'); + } + + //核销金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']='核销单'; + return $source; + } +} diff --git a/serve/app/model/ImyInfo.php b/serve/app/model/ImyInfo.php new file mode 100644 index 0000000..2e82fca --- /dev/null +++ b/serve/app/model/ImyInfo.php @@ -0,0 +1,27 @@ +hasOne(Account::class,'id','account'); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //结算金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + +} diff --git a/serve/app/model/Invoice.php b/serve/app/model/Invoice.php new file mode 100644 index 0000000..5498063 --- /dev/null +++ b/serve/app/model/Invoice.php @@ -0,0 +1,29 @@ +'timestamp:Y-m-d', + 'file'=>'json' + ]; + + //单据关联 + public function sourceData(){ + return $this->morphTo(['type','class'],[ + 'buy' => Buy::class, + 'bre' => Bre::class, + 'sell' => Sell::class, + 'sre' => Sre::class, + 'vend' => Vend::class, + 'vre' => Vre::class + ]); + } + + + //开票金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } +} diff --git a/serve/app/model/Log.php b/serve/app/model/Log.php new file mode 100644 index 0000000..060b08e --- /dev/null +++ b/serve/app/model/Log.php @@ -0,0 +1,17 @@ +'timestamp:Y-m-d H:i:s', + ]; + + //用户属性关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + +} diff --git a/serve/app/model/Menu.php b/serve/app/model/Menu.php new file mode 100644 index 0000000..23f2e09 --- /dev/null +++ b/serve/app/model/Menu.php @@ -0,0 +1,16 @@ +'标签模式',1=>'新页模式'][$data['model']]; + //菜单类型 + $source['type']=[0=>'独立菜单',1=>'附属菜单'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/Mould.php b/serve/app/model/Mould.php new file mode 100644 index 0000000..8d9d449 --- /dev/null +++ b/serve/app/model/Mould.php @@ -0,0 +1,10 @@ + 'json' + ]; +} diff --git a/serve/app/model/Oce.php b/serve/app/model/Oce.php new file mode 100644 index 0000000..10ae6d2 --- /dev/null +++ b/serve/app/model/Oce.php @@ -0,0 +1,130 @@ +'timestamp:Y-m-d', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //供应商关联 + public function supplierData(){ + return $this->hasOne(Supplier::class,'id','supplier')->append(['extension']); + } + + //资金账户关联 + public function accountData(){ + return $this->hasOne(Account::class,'id','account')->field(['id','name']); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //核销关联 + public function billData(){ + return $this->hasMany(OceBill::class,'pid','id')->with(['sourceData'])->visible(['sourceData'=>['id','number']])->append(['extension'])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','oce']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //实际金额_读取器 + public function getActualAttr($val,$data){ + return floatval($val); + } + + //实付金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //供应商_设置器 + public function setSupplierAttr($val){ + return empty($val)?0:$val; + } + + //供应商_读取器 + public function getSupplierAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核销状态 + $source['nucleus']=[0=>'未核销',1=>'部分核销',2=>'已核销'][$data['nucleus']]; + //已核销金额 + if($data['nucleus']==0){ + $source['amount']=0; + }else if($data['nucleus']==1){ + $source['amount']=db('oce_bill')->where([['pid','=',$data['id']]])->sum('money'); + }else{ + $source['amount']=floatval($data['actual']); + } + //未核销金额 + $source['anwo']=math()->chain($data['actual'])->sub($source['amount'])->done(); + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/OceBill.php b/serve/app/model/OceBill.php new file mode 100644 index 0000000..14e1bce --- /dev/null +++ b/serve/app/model/OceBill.php @@ -0,0 +1,31 @@ +'timestamp:Y-m-d' + ]; + + //关联单据 + public function sourceData(){ + return $this->morphTo(['type','source'],[ + 'oce' => Oce::class, + 'bill' => Bill::class + ]); + } + + //核销金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=['oce'=>'其它支出单','bill'=>'核销单'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/OceInfo.php b/serve/app/model/OceInfo.php new file mode 100644 index 0000000..77269ed --- /dev/null +++ b/serve/app/model/OceInfo.php @@ -0,0 +1,32 @@ +hasOne(Iet::class,'id','iet'); + } + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //结算金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + +} diff --git a/serve/app/model/Omy.php b/serve/app/model/Omy.php new file mode 100644 index 0000000..2fb8611 --- /dev/null +++ b/serve/app/model/Omy.php @@ -0,0 +1,95 @@ +'timestamp:Y-m-d', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //供应商关联 + public function supplierData(){ + return $this->hasOne(Supplier::class,'id','supplier')->append(['extension']); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //核销关联 + public function billData(){ + return $this->hasMany(OmyBill::class,'pid','id')->with(['sourceData'])->visible(['sourceData'=>['id','number']])->append(['extension'])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','omy']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核销状态 + $source['nucleus']=[0=>'未核销',1=>'部分核销',2=>'已核销'][$data['nucleus']]; + //已核销金额 + if($data['nucleus']==0){ + $source['amount']=0; + }else if($data['nucleus']==1){ + $source['amount']=db('omy_bill')->where([['pid','=',$data['id']]])->sum('money'); + }else{ + $source['amount']=floatval($data['total']); + } + //未核销金额 + $source['anwo']=math()->chain($data['total'])->sub($source['amount'])->done(); + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/OmyBill.php b/serve/app/model/OmyBill.php new file mode 100644 index 0000000..d281750 --- /dev/null +++ b/serve/app/model/OmyBill.php @@ -0,0 +1,28 @@ +'timestamp:Y-m-d' + ]; + + //关联单据 + public function sourceData(){ + return $this->hasOne(Bill::class,'id','source'); + } + + //核销金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']='核销单'; + return $source; + } +} diff --git a/serve/app/model/OmyInfo.php b/serve/app/model/OmyInfo.php new file mode 100644 index 0000000..ac376b6 --- /dev/null +++ b/serve/app/model/OmyInfo.php @@ -0,0 +1,27 @@ +hasOne(Account::class,'id','account'); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //结算金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + +} diff --git a/serve/app/model/People.php b/serve/app/model/People.php new file mode 100644 index 0000000..55fda9f --- /dev/null +++ b/serve/app/model/People.php @@ -0,0 +1,48 @@ + 'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //所属用户关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //应收款余额_读取器 + public function getBalanceAttr($val,$data){ + return floatval($val); + } + + //客户积分_读取器 + public function getIntegralAttr($val,$data){ + return floatval($val); + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + $source['sex']=[0=>'女',1=>'男'][$data['sex']]; + return $source; + } +} diff --git a/serve/app/model/Period.php b/serve/app/model/Period.php new file mode 100644 index 0000000..eb8c004 --- /dev/null +++ b/serve/app/model/Period.php @@ -0,0 +1,18 @@ +'timestamp:Y-m-d', + 'time'=>'timestamp:Y-m-d', + ]; + + //用户属性关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + +} diff --git a/serve/app/model/Record.php b/serve/app/model/Record.php new file mode 100644 index 0000000..3bf1016 --- /dev/null +++ b/serve/app/model/Record.php @@ -0,0 +1,19 @@ +hasOne(User::class,'id','user')->field(['id','name']); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //时间文本 + $source['time']=date('Y-m-d H:i',$data['time']); + return $source; + } +} diff --git a/serve/app/model/Role.php b/serve/app/model/Role.php new file mode 100644 index 0000000..207ec08 --- /dev/null +++ b/serve/app/model/Role.php @@ -0,0 +1,10 @@ + 'json', + 'auth' => 'json' + ]; +} diff --git a/serve/app/model/RoomInfo.php b/serve/app/model/RoomInfo.php new file mode 100644 index 0000000..8516b33 --- /dev/null +++ b/serve/app/model/RoomInfo.php @@ -0,0 +1,48 @@ +'timestamp:Y-m-d' + ]; + + //单据关联 + public function sourceData(){ + return $this->morphTo(['type','class'],[ + 'buy'=>Buy::class, + 'bre'=>Bre::class, + 'sell'=>Sell::class, + 'sre'=>Sre::class, + 'vend'=>Vend::class, + 'vre'=>Vre::class, + 'barter'=>Barter::class, + 'swapOut'=>Swap::class, + 'swapEnter'=>Swap::class, + 'entry'=>Entry::class, + 'extry'=>Extry::class, + ]); + } + + //基础单价_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //基础数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=["buy"=>"采购单","bre"=>"采购退货单","sell"=>"销售单","sre"=>"销售退货单","vend"=>"零售单","vre"=>"零售退货单","barter"=>"积分兑换单","swapOut"=>"调拨单-出","swapEnter"=>"调拨单-入","entry"=>"其它入库单","extry"=>"其它出库单"][$data['type']]; + //操作类型 + $source['direction']=["减少","增加"][$data['direction']]; + + return $source; + } +} diff --git a/serve/app/model/Sell.php b/serve/app/model/Sell.php new file mode 100644 index 0000000..f0f0768 --- /dev/null +++ b/serve/app/model/Sell.php @@ -0,0 +1,151 @@ +'timestamp:Y-m-d', + 'logistics'=>'json', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //客户关联 + public function customerData(){ + return $this->hasOne(Customer::class,'id','customer')->append(['extension']); + } + + //结算账户关联 + public function accountData(){ + return $this->hasOne(Account::class,'id','account'); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //核销关联 + public function billData(){ + return $this->hasMany(SellBill::class,'pid','id')->with(['sourceData'])->visible(['sourceData'=>['id','number']])->append(['extension'])->order('id desc'); + } + + //费用详情关联 + public function costData(){ + return $this->hasMany(Cost::class,'class','id')->with(['ietData'])->where([['type','=','sell']])->append(['extension'])->order('id desc'); + } + + //发票关联 + public function invoiceData(){ + return $this->hasMany(Invoice::class,'class','id')->where([['type','=','sell']])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','sell']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //实际金额_读取器 + public function getActualAttr($val,$data){ + return floatval($val); + } + + //实收金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //单据费用_读取器 + public function getCostAttr($val,$data){ + return floatval($val); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //物流信息 + $logistics=json_decode($data['logistics'],true); + if(empty($logistics['key'])){ + $source['logistics']=''; + }elseif($logistics['key']=='auto'){ + $source['logistics']=$logistics['number']; + }else{ + $source['logistics']=$logistics['name'].'|'.$logistics['number']; + } + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核销状态 + $source['nucleus']=[0=>'未核销',1=>'部分核销',2=>'已核销'][$data['nucleus']]; + //费用状态 + $source['cse']=[0=>'未结算',1=>'部分结算',2=>'已结算',3=>'无需结算'][$data['cse']]; + //发票状态 + $source['invoice']=[0=>'未开具',1=>'部分开具',2=>'已开具',3=>'无需开具'][$data['invoice']]; + //核对状态 + $source['check']=[0=>'未核对',1=>'已核对'][$data['check']]; + //已核销金额 + if($data['nucleus']==0){ + $source['amount']=0; + }else if($data['nucleus']==1){ + $source['amount']=db('sell_bill')->where([['pid','=',$data['id']]])->sum('money'); + }else{ + $source['amount']=floatval($data['actual']); + } + //未核销金额 + $source['anwo']=math()->chain($data['actual'])->sub($source['amount'])->done(); + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/SellBill.php b/serve/app/model/SellBill.php new file mode 100644 index 0000000..5437376 --- /dev/null +++ b/serve/app/model/SellBill.php @@ -0,0 +1,31 @@ +'timestamp:Y-m-d' + ]; + + //关联单据 + public function sourceData(){ + return $this->morphTo(['type','source'],[ + 'sell' => Sell::class, + 'bill' => Bill::class + ]); + } + + //核销金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=['sell'=>'销售单','bill'=>'核销单'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/SellInfo.php b/serve/app/model/SellInfo.php new file mode 100644 index 0000000..58f1a7b --- /dev/null +++ b/serve/app/model/SellInfo.php @@ -0,0 +1,93 @@ +'json' + ]; + + //商品关联 + public function goodsData(){ + return $this->hasOne(Goods::class,'id','goods'); + } + + //仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //仓库_设置器 + public function setWarehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //仓库_读取器 + public function getWarehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //生产日期_设置器 + public function setMfdAttr($val,$data){ + return empty($val)?0:strtotime($val); + } + + //生产日期_读取器 + public function getMfdAttr($val,$data){ + return empty($val)?'':date('Y-m-d',$val); + } + + //单价_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //折扣率_读取器 + public function getDiscountAttr($val,$data){ + return floatval($val); + } + + //折扣额_读取器 + public function getDscAttr($val,$data){ + return floatval($val); + } + + //金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //税率_读取器 + public function getTaxAttr($val,$data){ + return floatval($val); + } + + //税额_读取器 + public function getTatAttr($val,$data){ + return floatval($val); + } + + //价税合计_读取器 + public function getTptAttr($val,$data){ + return floatval($val); + } + + //退货数量_读取器 + public function getRetreatAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //序列号 + $source['serial']=implode(',',json_decode($data['serial'])); + return $source; + } +} diff --git a/serve/app/model/Serial.php b/serve/app/model/Serial.php new file mode 100644 index 0000000..43118b7 --- /dev/null +++ b/serve/app/model/Serial.php @@ -0,0 +1,14 @@ +'未销售',1=>'已销售',2=>'已调拨',3=>'已退货'][$data['state']]; + return $source; + } +} diff --git a/serve/app/model/SerialInfo.php b/serve/app/model/SerialInfo.php new file mode 100644 index 0000000..b63884a --- /dev/null +++ b/serve/app/model/SerialInfo.php @@ -0,0 +1,31 @@ +morphTo(['type','class'],[ + 'buy'=>Buy::class, + 'bre'=>Bre::class, + 'sell'=>Sell::class, + 'sre'=>Sre::class, + 'vend'=>Vend::class, + 'vre'=>Vre::class, + 'barter'=>Barter::class, + 'swapOut'=>Swap::class, + 'swapEnter'=>Swap::class, + 'entry'=>Entry::class, + 'extry'=>Extry::class, + ]); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=["buy"=>"采购单","bre"=>"采购退货单","sell"=>"销售单","sre"=>"销售退货单","vend"=>"零售单","vre"=>"零售退货单","barter"=>"积分兑换单","swapOut"=>"调拨单-出","swapEnter"=>"调拨单-入","entry"=>"其它入库单","extry"=>"其它出库单"][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/Sor.php b/serve/app/model/Sor.php new file mode 100644 index 0000000..a522d5e --- /dev/null +++ b/serve/app/model/Sor.php @@ -0,0 +1,96 @@ +'timestamp:Y-m-d', + 'arrival'=>'timestamp:Y-m-d', + 'logistics'=>'json', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //客户关联 + public function customerData(){ + return $this->hasOne(Customer::class,'id','customer')->append(['extension']); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','sor']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //实际金额_读取器 + public function getActualAttr($val,$data){ + return floatval($val); + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //物流信息 + $logistics=json_decode($data['logistics'],true); + if(empty($logistics['key'])){ + $source['logistics']=''; + }elseif($logistics['key']=='auto'){ + $source['logistics']=$logistics['number']; + }else{ + $source['logistics']=$logistics['name'].'|'.$logistics['number']; + } + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //出库状态 + $source['state']=[0=>'未出库',1=>'部分出库',2=>'已出库',3=>'关闭'][$data['state']]; + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/SorInfo.php b/serve/app/model/SorInfo.php new file mode 100644 index 0000000..be9f714 --- /dev/null +++ b/serve/app/model/SorInfo.php @@ -0,0 +1,72 @@ +hasOne(Goods::class,'id','goods'); + } + + //仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //仓库_设置器 + public function setWarehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //仓库_读取器 + public function getWarehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //单价_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //折扣率_读取器 + public function getDiscountAttr($val,$data){ + return floatval($val); + } + + //折扣额_读取器 + public function getDscAttr($val,$data){ + return floatval($val); + } + + //金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //税率_读取器 + public function getTaxAttr($val,$data){ + return floatval($val); + } + + //税额_读取器 + public function getTatAttr($val,$data){ + return floatval($val); + } + + //价税合计_读取器 + public function getTptAttr($val,$data){ + return floatval($val); + } + + //出库数量_读取器 + public function getHandleAttr($val,$data){ + return floatval($val); + } + +} diff --git a/serve/app/model/Sre.php b/serve/app/model/Sre.php new file mode 100644 index 0000000..aac8169 --- /dev/null +++ b/serve/app/model/Sre.php @@ -0,0 +1,151 @@ +'timestamp:Y-m-d', + 'logistics'=>'json', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //客户关联 + public function customerData(){ + return $this->hasOne(Customer::class,'id','customer')->append(['extension']); + } + + //结算账户关联 + public function accountData(){ + return $this->hasOne(Account::class,'id','account'); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //核销关联 + public function billData(){ + return $this->hasMany(SreBill::class,'pid','id')->with(['sourceData'])->visible(['sourceData'=>['id','number']])->append(['extension'])->order('id desc'); + } + + //费用详情关联 + public function costData(){ + return $this->hasMany(Cost::class,'class','id')->with(['ietData'])->where([['type','=','sre']])->append(['extension'])->order('id desc'); + } + + //发票关联 + public function invoiceData(){ + return $this->hasMany(Invoice::class,'class','id')->where([['type','=','bre']])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','sre']])->append(['extension'])->order('id desc'); + } + + //单据金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //实际金额_读取器 + public function getActualAttr($val,$data){ + return floatval($val); + } + + //实付金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //单据费用_读取器 + public function getCostAttr($val,$data){ + return floatval($val); + } + + //结算账户_设置器 + public function setAccountAttr($val,$data){ + return empty($val)?0:$val; + } + + //结算账户_读取器 + public function getAccountAttr($val,$data){ + return empty($val)?null:$val; + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //物流信息 + $logistics=json_decode($data['logistics'],true); + if(empty($logistics['key'])){ + $source['logistics']=''; + }elseif($logistics['key']=='auto'){ + $source['logistics']=$logistics['number']; + }else{ + $source['logistics']=$logistics['name'].'|'.$logistics['number']; + } + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //核销状态 + $source['nucleus']=[0=>'未核销',1=>'部分核销',2=>'已核销'][$data['nucleus']]; + //费用状态 + $source['cse']=[0=>'未结算',1=>'部分结算',2=>'已结算',3=>'无需结算'][$data['cse']]; + //发票状态 + $source['invoice']=[0=>'未开具',1=>'部分开具',2=>'已开具',3=>'无需开具'][$data['invoice']]; + //核对状态 + $source['check']=[0=>'未核对',1=>'已核对'][$data['check']]; + //已核销金额 + if($data['nucleus']==0){ + $source['amount']=0; + }else if($data['nucleus']==1){ + $source['amount']=db('sre_bill')->where([['pid','=',$data['id']]])->sum('money'); + }else{ + $source['amount']=floatval($data['actual']); + } + //未核销金额 + $source['anwo']=math()->chain($data['actual'])->sub($source['amount'])->done(); + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/SreBill.php b/serve/app/model/SreBill.php new file mode 100644 index 0000000..263293b --- /dev/null +++ b/serve/app/model/SreBill.php @@ -0,0 +1,31 @@ +'timestamp:Y-m-d' + ]; + + //结算账户关联 + public function sourceData(){ + return $this->morphTo(['type','source'],[ + 'sre' => Sre::class, + 'bill' => Bill::class + ]); + } + + //核销金额_读取器 + public function getMoneyAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=['sre'=>'销售退货单','bill'=>'核销单'][$data['type']]; + return $source; + } +} diff --git a/serve/app/model/SreInfo.php b/serve/app/model/SreInfo.php new file mode 100644 index 0000000..37ce690 --- /dev/null +++ b/serve/app/model/SreInfo.php @@ -0,0 +1,88 @@ +'json' + ]; + + //商品关联 + public function goodsData(){ + return $this->hasOne(Goods::class,'id','goods'); + } + + //仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //仓库_设置器 + public function setWarehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //仓库_读取器 + public function getWarehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //生产日期_设置器 + public function setMfdAttr($val,$data){ + return empty($val)?0:strtotime($val); + } + + //生产日期_读取器 + public function getMfdAttr($val,$data){ + return empty($val)?'':date('Y-m-d',$val); + } + + //单价_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //折扣率_读取器 + public function getDiscountAttr($val,$data){ + return floatval($val); + } + + //折扣额_读取器 + public function getDscAttr($val,$data){ + return floatval($val); + } + + //金额_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //税率_读取器 + public function getTaxAttr($val,$data){ + return floatval($val); + } + + //税额_读取器 + public function getTatAttr($val,$data){ + return floatval($val); + } + + //价税合计_读取器 + public function getTptAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //序列号 + $source['serial']=implode(',',json_decode($data['serial'])); + return $source; + } +} diff --git a/serve/app/model/Summary.php b/serve/app/model/Summary.php new file mode 100644 index 0000000..8e7b999 --- /dev/null +++ b/serve/app/model/Summary.php @@ -0,0 +1,68 @@ +'timestamp:Y-m-d' + ]; + + //单据关联 + public function sourceData(){ + return $this->morphTo(['type','class'],[ + 'buy'=>Buy::class, + 'bre'=>Bre::class, + 'sell'=>Sell::class, + 'sre'=>Sre::class, + 'vend'=>Vend::class, + 'vre'=>Vre::class, + 'barter'=>Barter::class, + 'swapOut'=>Swap::class, + 'swapEnter'=>Swap::class, + 'entry'=>Entry::class, + 'extry'=>Extry::class, + ]); + } + + //仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //商品关联 + public function goodsData(){ + return $this->hasOne(Goods::class,'id','goods'); + } + + //基础单价_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //基础数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //单位成本_读取器 + public function getUctAttr($val,$data){ + return floatval($val); + } + + //基础成本_读取器 + public function getBctAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //单据类型 + $source['type']=["buy"=>"采购单","bre"=>"采购退货单","sell"=>"销售单","sre"=>"销售退货单","vend"=>"零售单","vre"=>"零售退货单","barter"=>"积分兑换单","swapOut"=>"调拨单-出","swapEnter"=>"调拨单-入","entry"=>"其它入库单","extry"=>"其它出库单"][$data['type']]; + //操作类型 + $source['direction']=["减少","增加"][$data['direction']]; + + return $source; + } +} diff --git a/serve/app/model/Supplier.php b/serve/app/model/Supplier.php new file mode 100644 index 0000000..860e59e --- /dev/null +++ b/serve/app/model/Supplier.php @@ -0,0 +1,56 @@ + 'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //所属用户关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //增值税税率_读取器 + public function getRateAttr($val,$data){ + return floatval($val); + } + + //应付款余额_读取器 + public function getBalanceAttr($val,$data){ + return floatval($val); + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //主联系人 + $contact=json_decode($data['contacts'],true); + if(empty($contact)){ + $source['contact']=''; + }else{ + $find=search($contact)->where([['main','=',true]])->find(); + $source['contact']=$find['name'].' | '.$find['tel'].' | '.$find['add']; + } + return $source; + } + +} diff --git a/serve/app/model/Swap.php b/serve/app/model/Swap.php new file mode 100644 index 0000000..432379f --- /dev/null +++ b/serve/app/model/Swap.php @@ -0,0 +1,108 @@ +'timestamp:Y-m-d', + 'logistics'=>'json', + 'file'=>'json' + ]; + + //所属组织关联 + public function frameData(){ + return $this->hasOne(Frame::class,'id','frame'); + } + + //关联人员关联 + public function peopleData(){ + return $this->hasOne(People::class,'id','people')->field(['id','name']); + } + + //制单人关联 + public function userData(){ + return $this->hasOne(User::class,'id','user')->field(['id','name']); + } + + //费用详情关联 + public function costData(){ + return $this->hasMany(Cost::class,'class','id')->with(['ietData'])->where([['type','=','swap']])->append(['extension'])->order('id desc'); + } + + //记录关联 + public function recordData(){ + return $this->hasMany(Record::class,'source','id')->with(['userData'])->where([['type','=','swap']])->append(['extension'])->order('id desc'); + } + + //单据成本_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //单据费用_读取器 + public function getCostAttr($val,$data){ + return floatval($val); + } + + //关联人员_设置器 + public function setPeopleAttr($val){ + return empty($val)?0:$val; + } + + //关联人员_读取器 + public function getPeopleAttr($val){ + return empty($val)?null:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //物流信息 + $logistics=json_decode($data['logistics'],true); + if(empty($logistics['key'])){ + $source['logistics']=''; + }elseif($logistics['key']=='auto'){ + $source['logistics']=$logistics['number']; + }else{ + $source['logistics']=$logistics['name'].'|'.$logistics['number']; + } + //审核状态 + $source['examine']=[0=>'未审核',1=>'已审核'][$data['examine']]; + //费用状态 + $source['cse']=[0=>'未结算',1=>'部分结算',2=>'已结算',3=>'无需结算'][$data['cse']]; + //联系信息 + $sceneData=$this->sceneData; + if(empty($sceneData)){ + $source['contact']=''; + }else{ + $contact=$sceneData['contacts']; + if(empty($contact)){ + $source['contact']=''; + }else{ + $find=search($contact)->where([['main','=',true]])->find(); + $source['contact']=$find['name'].' | '.$find['tel'].' | '.$find['add']; + } + } + return $source; + } + + //EVENT|更新前 + public static function onBeforeUpdate($model){ + $source=$model::where([['id','=',$model['id']]])->find(); + if(!empty($source['examine'])){ + exit(json(['state'=>'error','info'=>'[ ERROR ] 单据已审核!'],200)->send()); + } + } +} diff --git a/serve/app/model/SwapInfo.php b/serve/app/model/SwapInfo.php new file mode 100644 index 0000000..00953d2 --- /dev/null +++ b/serve/app/model/SwapInfo.php @@ -0,0 +1,78 @@ +'json' + ]; + + //商品关联 + public function goodsData(){ + return $this->hasOne(Goods::class,'id','goods'); + } + + //调出仓库关联 + public function warehouseData(){ + return $this->hasOne(Warehouse::class,'id','warehouse'); + } + + //调入仓库关联 + public function storehouseData(){ + return $this->hasOne(Warehouse::class,'id','storehouse'); + } + + //调出仓库_设置器 + public function setWarehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //调入仓库_设置器 + public function setStorehouseAttr($val,$data){ + return empty($val)?0:$val; + } + + //调出仓库_读取器 + public function getWarehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //调入仓库_读取器 + public function getStorehouseAttr($val,$data){ + return empty($val)?null:$val; + } + + //生产日期_设置器 + public function setMfdAttr($val,$data){ + return empty($val)?0:strtotime($val); + } + + //生产日期_读取器 + public function getMfdAttr($val,$data){ + return empty($val)?'':date('Y-m-d',$val); + } + + //成本_读取器 + public function getPriceAttr($val,$data){ + return floatval($val); + } + + //数量_读取器 + public function getNumsAttr($val,$data){ + return floatval($val); + } + + //总成本_读取器 + public function getTotalAttr($val,$data){ + return floatval($val); + } + + //数据扩展 + public function getExtensionAttr($val,$data){ + $source=[]; + //序列号 + $source['serial']=implode(',',json_decode($data['serial'])); + return $source; + } +} diff --git a/serve/app/model/Sys.php b/serve/app/model/Sys.php new file mode 100644 index 0000000..1b4a7d4 --- /dev/null +++ b/serve/app/model/Sys.php @@ -0,0 +1,17 @@ +hasOne(Frame::class,'id','frame'); + } + + //所属角色关联 + public function roleData(){ + return $this->hasOne(Role::class,'id','role')->field(['id','name']); + } + + //用户密码_设置器 + public function setPwdAttr($val){ + return md5($val); + } + + //用户角色_设置器 + public function setRoleAttr($val){ + return empty($val)?0:$val; + } + + //扩展信息_设置器 + public function setMoreAttr($val){ + //兼容Api|修复PHP空对象json编码为[] + return json_encode((object)$val); + } + + //扩展信息_读取器 + public function getMoreAttr($val){ + return json_decode($val); + } +} diff --git a/serve/app/model/Warehouse.php b/serve/app/model/Warehouse.php new file mode 100644 index 0000000..61f393d --- /dev/null +++ b/serve/app/model/Warehouse.php @@ -0,0 +1,12 @@ +hasOne(Frame::class,'id','frame'); + } + +} diff --git a/serve/app/provider.php b/serve/app/provider.php new file mode 100644 index 0000000..73d99fa --- /dev/null +++ b/serve/app/provider.php @@ -0,0 +1,9 @@ + Request::class, + 'think\exception\Handle' => ExceptionHandle::class, +]; diff --git a/serve/app/validate/Account.php b/serve/app/validate/Account.php new file mode 100644 index 0000000..6ece8d0 --- /dev/null +++ b/serve/app/validate/Account.php @@ -0,0 +1,32 @@ + ['require'], + 'number' => ['require','unique:account'], + 'frame' => ['require','integer'], + 'time' => ['require','date'], + 'initial' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '账户名称不可为空!', + 'number.require' => '账户编号不可为空!', + 'number.unique' => '账户编号重复!', + 'frame.require' => '所属组织不可为空!', + 'frame.integer' => '所属组织不正确!', + 'time.require' => '余额日期不可为空!', + 'time.date' => '余额日期不正确!', + 'initial.require' => '期初余额不可为空!', + 'initial.float' => '期初余额不正确!', + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','number','frame','time','initial'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Allot.php b/serve/app/validate/Allot.php new file mode 100644 index 0000000..f8d4a8c --- /dev/null +++ b/serve/app/validate/Allot.php @@ -0,0 +1,32 @@ + ['require','date'], + 'number' => ['require','unique:allot'], + 'total' => ['require','float'], + 'people' => ['integer'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'people.integer' => '关联人员不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['time','number','total','people','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/AllotInfo.php b/serve/app/validate/AllotInfo.php new file mode 100644 index 0000000..2bc4fec --- /dev/null +++ b/serve/app/validate/AllotInfo.php @@ -0,0 +1,22 @@ + ['require','integer'], + 'tat' => ['require','integer'], + 'money' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'account.require' => '转入账户不可为空!', + 'account.integer' => '转入账户不正确!', + 'tat.require' => '转出账户不可为空!', + 'tat.integer' => '转出账户不正确!', + 'money.require' => '结算金额不可为空!', + 'money.float' => '结算金额不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Attr.php b/serve/app/validate/Attr.php new file mode 100644 index 0000000..91d8856 --- /dev/null +++ b/serve/app/validate/Attr.php @@ -0,0 +1,29 @@ + ['require'], + 'buy' => ['require','float'], + 'sell' => ['require','float'], + 'retail' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '属性名称不可为空!', + 'buy.require' => '采购价格不可为空!', + 'buy.float' => '采购价格不正确!', + 'sell.require' => '销售价格不可为空!', + 'sell.float' => '销售价格不正确!', + 'retail.require' => '零售价格不可为空!', + 'retail.float' => '零售价格不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','buy','sell','retail'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Attribute.php b/serve/app/validate/Attribute.php new file mode 100644 index 0000000..650b759 --- /dev/null +++ b/serve/app/validate/Attribute.php @@ -0,0 +1,45 @@ + ['require','unique:attribute'], + 'info' => ['require','array','checkInfo'], + 'sort' => ['require','integer'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '属性名称不可为空!', + 'name.unique' => '属性名称重复!', + 'info.require' => '属性内容不可为空!', + 'info.array' => '属性内容不正确!', + 'sort.require' => '属性排序不可为空!', + 'sort.integer' => '属性排序不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','info','sort'] + ]; + + //独立验证器 + protected function checkInfo($value,$rule,$data){ + $column=array_column($value,'name'); + if(count($column)!=count(array_unique($column))){ + $result = '属性内容存在重复!'; + }else if(strpos(json_encode($column),'|')!==false){ + $result = '属性内容不可包含[ | ]保留字符!'; + }else{ + //全局重复判断 + $find=db('attribute_info')->where([['pid','<>',$data['id']],['name','in',$column]])->find(); + if(empty($find)){ + $result=true; + }else{ + $result='属性内容与其他属性内容重复!'; + } + } + return $result; + } +} \ No newline at end of file diff --git a/serve/app/validate/Bill.php b/serve/app/validate/Bill.php new file mode 100644 index 0000000..1552572 --- /dev/null +++ b/serve/app/validate/Bill.php @@ -0,0 +1,42 @@ + ['integer'], + 'supplier' => ['integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:bill'], + 'type' => ['require'], + 'pmy' => ['require','float'], + 'smp' => ['require','float'], + 'people' => ['integer'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'customer.integer' => '客户不正确!', + 'supplier.integer' => '供应商不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'type.require' => '核销类型不可为空!', + 'pmy.require' => '总核金额不可为空!', + 'pmy.float' => '总核金额不正确!', + 'smp.require' => '总销金额不可为空!', + 'smp.float' => '总销金额不正确!', + 'people.integer' => '关联人员不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['customer','supplier','time','number','type','pmy','smp','people','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/BillInfo.php b/serve/app/validate/BillInfo.php new file mode 100644 index 0000000..e1d46ad --- /dev/null +++ b/serve/app/validate/BillInfo.php @@ -0,0 +1,23 @@ + ['require','integer'], + 'bill' => ['require'], + 'mold' => ['require'], + 'money' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联单据不可为空!', + 'source.integer' => '关联单据不正确!', + 'bill.require' => '核销类型不可为空!', + 'mold.require' => '单据类型不可为空!', + 'money.require' => '核销金额不可为空!', + 'money.float' => '核销金额不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Bor.php b/serve/app/validate/Bor.php new file mode 100644 index 0000000..110a8dd --- /dev/null +++ b/serve/app/validate/Bor.php @@ -0,0 +1,43 @@ + ['require','integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:bor'], + 'total' => ['require','float'], + 'actual' => ['require','float'], + 'people' => ['integer'], + 'arrival' => ['date'], + 'logistics' => ['array'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'supplier.require' => '供应商不可为空!', + 'supplier.integer' => '供应商不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'actual.require' => '实际金额不可为空!', + 'actual.float' => '实际金额不正确!', + 'people.integer' => '关联人员不正确!', + 'arrival.date' => '单据日期不正确!', + 'logistics.array' => '物流信息不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!', + ]; + + //场景规则 + protected $scene = [ + 'update' => ['supplier','time','number','total','actual','people','arrival','logistics','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/BorInfo.php b/serve/app/validate/BorInfo.php new file mode 100644 index 0000000..6ccae70 --- /dev/null +++ b/serve/app/validate/BorInfo.php @@ -0,0 +1,42 @@ + ['require','integer'], + 'warehouse' => ['integer'], + 'price' => ['require','float'], + 'nums' => ['require','float'], + 'discount' => ['require','between:0,100'], + 'dsc' => ['require','float'], + 'total' => ['require','float'], + 'tax' => ['require','between:0,100'], + 'tat' => ['require','float'], + 'tpt' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'goods.require' => '商品信息不可为空!', + 'goods.integer' => '商品信息不正确!', + 'warehouse.integer' => '仓库不正确!', + 'price.require' => '单价不可为空!', + 'price.float' => '单价不正确!', + 'nums.require' => '数量不可为空!', + 'nums.float' => '数量不正确!', + 'discount.require' => '折扣率不可为空!', + 'discount.between' => '折扣率不正确!', + 'dsc.require' => '折扣额不可为空!', + 'dsc.float' => '折扣额不正确!', + 'total.require' => '金额不可为空!', + 'total.float' => '金额不正确!', + 'tax.require' => '税率不可为空!', + 'tax.between' => '税率不正确!', + 'tat.require' => '税额不可为空!', + 'tat.float' => '税额不正确!', + 'tpt.require' => '价税合计不可为空!', + 'tpt.float' => '价税合计不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Bre.php b/serve/app/validate/Bre.php new file mode 100644 index 0000000..5ea3b01 --- /dev/null +++ b/serve/app/validate/Bre.php @@ -0,0 +1,49 @@ + ['require','integer'], + 'supplier' => ['require','integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:bre'], + 'total' => ['require','float'], + 'actual' => ['require','float'], + 'money' => ['require','float'], + 'account' => ['requireWith:money'], + 'people' => ['integer'], + 'logistics' => ['array'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联单据不可为空!', + 'source.integer' => '关联单据不正确!', + 'supplier.require' => '供应商不可为空!', + 'supplier.integer' => '供应商不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'actual.require' => '实际金额不可为空!', + 'actual.float' => '实际金额不正确!', + 'money.require' => '实收金额不可为空!', + 'money.float' => '实收金额不正确!', + 'account.requireWith' => '结算账户不可为空!', + 'people.integer' => '关联人员不正确!', + 'logistics.array' => '物流信息不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['source','supplier','time','number','total','actual','money','account','people','logistics','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/BreInfo.php b/serve/app/validate/BreInfo.php new file mode 100644 index 0000000..dea792c --- /dev/null +++ b/serve/app/validate/BreInfo.php @@ -0,0 +1,50 @@ + ['require','integer'], + 'goods' => ['require','integer'], + 'warehouse' => ['integer'], + 'mfd' => ['date'], + 'price' => ['require','float'], + 'nums' => ['require','float'], + 'serial' => ['array'], + 'discount' => ['require','between:0,100'], + 'dsc' => ['require','float'], + 'total' => ['require','float'], + 'tax' => ['require','between:0,100'], + 'tat' => ['require','float'], + 'tpt' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联详情不可为空!', + 'source.integer' => '关联详情不正确!', + 'goods.require' => '商品信息不可为空!', + 'goods.integer' => '商品信息不正确!', + 'warehouse.integer' => '仓库不正确!', + 'mfd.require' => '生产日期不正确!', + 'price.require' => '单价不可为空!', + 'price.float' => '单价不正确!', + 'nums.require' => '数量不可为空!', + 'nums.float' => '数量不正确!', + 'serial.require' => '序列号不可为空!', + 'serial.array' => '序列号不正确!', + 'discount.require' => '折扣率不可为空!', + 'discount.between' => '折扣率不正确!', + 'dsc.require' => '折扣额不可为空!', + 'dsc.float' => '折扣额不正确!', + 'total.require' => '金额不可为空!', + 'total.float' => '金额不正确!', + 'tax.require' => '税率不可为空!', + 'tax.between' => '税率不正确!', + 'tat.require' => '税额不可为空!', + 'tat.float' => '税额不正确!', + 'tpt.require' => '价税合计不可为空!', + 'tpt.float' => '价税合计不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Buy.php b/serve/app/validate/Buy.php new file mode 100644 index 0000000..c51c289 --- /dev/null +++ b/serve/app/validate/Buy.php @@ -0,0 +1,49 @@ + ['require','integer'], + 'supplier' => ['require','integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:buy'], + 'total' => ['require','float'], + 'actual' => ['require','float'], + 'money' => ['require','float'], + 'account' => ['requireWith:money'], + 'people' => ['integer'], + 'logistics' => ['array'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联单据不可为空!', + 'source.integer' => '关联单据不正确!', + 'supplier.require' => '供应商不可为空!', + 'supplier.integer' => '供应商不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'actual.require' => '实际金额不可为空!', + 'actual.float' => '实际金额不正确!', + 'money.require' => '实付金额不可为空!', + 'money.float' => '实付金额不正确!', + 'account.requireWith' => '结算账户不可为空!', + 'people.integer' => '关联人员不正确!', + 'logistics.array' => '物流信息不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['source','supplier','time','number','total','actual','money','account','people','logistics','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/BuyInfo.php b/serve/app/validate/BuyInfo.php new file mode 100644 index 0000000..014ca93 --- /dev/null +++ b/serve/app/validate/BuyInfo.php @@ -0,0 +1,50 @@ + ['require','integer'], + 'goods' => ['require','integer'], + 'warehouse' => ['integer'], + 'mfd' => ['date'], + 'price' => ['require','float'], + 'nums' => ['require','float'], + 'serial' => ['array'], + 'discount' => ['require','between:0,100'], + 'dsc' => ['require','float'], + 'total' => ['require','float'], + 'tax' => ['require','between:0,100'], + 'tat' => ['require','float'], + 'tpt' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联详情不可为空!', + 'source.integer' => '关联详情不正确!', + 'goods.require' => '商品信息不可为空!', + 'goods.integer' => '商品信息不正确!', + 'warehouse.integer' => '仓库不正确!', + 'mfd.require' => '生产日期不正确!', + 'price.require' => '单价不可为空!', + 'price.float' => '单价不正确!', + 'nums.require' => '数量不可为空!', + 'nums.float' => '数量不正确!', + 'serial.require' => '序列号不可为空!', + 'serial.array' => '序列号不正确!', + 'discount.require' => '折扣率不可为空!', + 'discount.between' => '折扣率不正确!', + 'dsc.require' => '折扣额不可为空!', + 'dsc.float' => '折扣额不正确!', + 'total.require' => '金额不可为空!', + 'total.float' => '金额不正确!', + 'tax.require' => '税率不可为空!', + 'tax.between' => '税率不正确!', + 'tat.require' => '税额不可为空!', + 'tat.float' => '税额不正确!', + 'tpt.require' => '价税合计不可为空!', + 'tpt.float' => '价税合计不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Category.php b/serve/app/validate/Category.php new file mode 100644 index 0000000..4f15b3e --- /dev/null +++ b/serve/app/validate/Category.php @@ -0,0 +1,25 @@ + ['require'], + 'pid' => ['require','integer'], + 'sort' => ['require','integer'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '类别名称不可为空!', + 'pid.require' => '所属类别不可为空!', + 'pid.integer' => '所属类别不正确!', + 'sort.require' => '类别排序不可为空!', + 'sort.integer' => '类别排序不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','pid','sort'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Code.php b/serve/app/validate/Code.php new file mode 100644 index 0000000..e6d5f56 --- /dev/null +++ b/serve/app/validate/Code.php @@ -0,0 +1,24 @@ + ['require'], + 'info' => ['require'], + 'type' => ['require','integer'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '条码名称不可为空!', + 'info.require' => '条码内容不可为空!', + 'type.require' => '条码类型不可为空!', + 'type.integer' => '条码类型不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','info','type'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Cost.php b/serve/app/validate/Cost.php new file mode 100644 index 0000000..ebdd2cf --- /dev/null +++ b/serve/app/validate/Cost.php @@ -0,0 +1,19 @@ + ['require','integer'], + 'money' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'iet.require' => '支出类别不可为空!', + 'iet.integer' => '支出类别不正确!', + 'money.require' => '金额不可为空!', + 'money.float' => '金额不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Customer.php b/serve/app/validate/Customer.php new file mode 100644 index 0000000..3eff613 --- /dev/null +++ b/serve/app/validate/Customer.php @@ -0,0 +1,34 @@ + ['require'], + 'number' => ['require','unique:customer'], + 'frame' => ['require','integer'], + 'user' => ['require','integer'], + 'contacts'=>['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '客户名称不可为空!', + 'number.require' => '客户编号不可为空!', + 'number.unique' => '客户编号重复!', + 'frame.require' => '所属组织不可为空!', + 'frame.integer' => '所属组织不正确!', + 'user.require' => '所属用户不可为空!', + 'user.integer' => '所属用户不正确!', + 'contacts.array' => '联系资料不正确!', + 'more.array' => '扩展信息不正确!', + + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','number','frame','user','contacts','more'], + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Deploy.php b/serve/app/validate/Deploy.php new file mode 100644 index 0000000..32f3b73 --- /dev/null +++ b/serve/app/validate/Deploy.php @@ -0,0 +1,24 @@ + ['require','integer','unique:deploy'], + 'source' => ['require','array'] + ]; + + //常规规则提示 + protected $message = [ + 'frame.require' => '关联组织不可为空!', + 'frame.integer' => '关联组织不正确!', + 'frame.unique' => '关联组织重复!', + 'source.require' => '配置信息不可为空!', + 'source.array' => '配置信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['frame','source'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Entry.php b/serve/app/validate/Entry.php new file mode 100644 index 0000000..8522de8 --- /dev/null +++ b/serve/app/validate/Entry.php @@ -0,0 +1,35 @@ + ['require','date'], + 'number' => ['require','unique:entry'], + 'total' => ['require','float'], + 'people' => ['integer'], + 'logistics' => ['array'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据成本不可为空!', + 'total.float' => '单据成本不正确!', + 'people.integer' => '关联人员不正确!', + 'logistics.array' => '物流信息不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['time','number','total','people','logistics','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/EntryInfo.php b/serve/app/validate/EntryInfo.php new file mode 100644 index 0000000..c85d5ac --- /dev/null +++ b/serve/app/validate/EntryInfo.php @@ -0,0 +1,32 @@ + ['require','integer'], + 'warehouse' => ['integer'], + 'mfd' => ['date'], + 'price' => ['require','float'], + 'nums' => ['require','float'], + 'serial' => ['array'], + 'total' => ['require','float'], + ]; + + //常规规则提示 + protected $message = [ + 'goods.require' => '商品信息不可为空!', + 'goods.integer' => '商品信息不正确!', + 'warehouse.integer' => '仓库不正确!', + 'mfd.require' => '生产日期不正确!', + 'price.require' => '成本不可为空!', + 'price.float' => '成本不正确!', + 'nums.require' => '数量不可为空!', + 'nums.float' => '数量不正确!', + 'serial.require' => '序列号不可为空!', + 'serial.array' => '序列号不正确!', + 'total.require' => '总成本不可为空!', + 'total.float' => '总成本不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Extry.php b/serve/app/validate/Extry.php new file mode 100644 index 0000000..3747883 --- /dev/null +++ b/serve/app/validate/Extry.php @@ -0,0 +1,35 @@ + ['require','date'], + 'number' => ['require','unique:extry'], + 'total' => ['require','float'], + 'people' => ['integer'], + 'logistics' => ['array'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据成本不可为空!', + 'total.float' => '单据成本不正确!', + 'people.integer' => '关联人员不正确!', + 'logistics.array' => '物流信息不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['time','number','total','people','logistics','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/ExtryInfo.php b/serve/app/validate/ExtryInfo.php new file mode 100644 index 0000000..738b81f --- /dev/null +++ b/serve/app/validate/ExtryInfo.php @@ -0,0 +1,32 @@ + ['require','integer'], + 'warehouse' => ['integer'], + 'mfd' => ['date'], + 'price' => ['require','float'], + 'nums' => ['require','float'], + 'serial' => ['array'], + 'total' => ['require','float'], + ]; + + //常规规则提示 + protected $message = [ + 'goods.require' => '商品信息不可为空!', + 'goods.integer' => '商品信息不正确!', + 'warehouse.integer' => '仓库不正确!', + 'mfd.require' => '生产日期不正确!', + 'price.require' => '成本不可为空!', + 'price.float' => '成本不正确!', + 'nums.require' => '数量不可为空!', + 'nums.float' => '数量不正确!', + 'serial.require' => '序列号不可为空!', + 'serial.array' => '序列号不正确!', + 'total.require' => '总成本不可为空!', + 'total.float' => '总成本不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Field.php b/serve/app/validate/Field.php new file mode 100644 index 0000000..fe07bea --- /dev/null +++ b/serve/app/validate/Field.php @@ -0,0 +1,24 @@ + ['require'], + 'key' => ['require','unique:field'], + 'fields' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '模块名称不可为空!', + 'key.require' => '模块标识不可为空!', + 'key.unique' => '模块标识重复!', + 'fields.array' => '字段数据不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','key','fields'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Frame.php b/serve/app/validate/Frame.php new file mode 100644 index 0000000..57d02cd --- /dev/null +++ b/serve/app/validate/Frame.php @@ -0,0 +1,25 @@ + ['require'], + 'pid' => ['require','integer'], + 'sort' => ['require','integer'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '组织名称不可为空!', + 'pid.require' => '所属组织不可为空!', + 'pid.integer' => '所属组织不正确!', + 'sort.require' => '组织排序不可为空!', + 'sort.integer' => '组织排序不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','pid','sort'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Goods.php b/serve/app/validate/Goods.php new file mode 100644 index 0000000..dcffe13 --- /dev/null +++ b/serve/app/validate/Goods.php @@ -0,0 +1,58 @@ + ['require','unique:goods'], + 'number' => ['require','unique:goods'], + 'category' => ['require','integer'], + 'buy' => ['require','float'], + 'sell' => ['require','float'], + 'stock' => ['require','float'], + 'type' => ['require','integer'], + 'imgs' => ['array'], + 'units' => ['array'], + 'serial' => ['require','boolean'], + 'batch' => ['require','boolean'], + 'protect' => ['require','integer'], + 'threshold' => ['require','integer'], + 'more' => ['array'], + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '商品名称不可为空!', + 'name.unique' => '商品名称重复!', + 'number.require' => '商品编号不可为空!', + 'number.unique' => '商品编号重复!', + 'category.require' => '商品分类不可为空!', + 'category.integer' => '商品分类不正确!', + 'buy.require' => '采购价格不可为空!', + 'buy.float' => '采购价格不正确!', + 'sell.require' => '销售价格不可为空!', + 'sell.float' => '销售价格不正确!', + 'stock.require' => '库存阈值不可为空!', + 'stock.float' => '库存阈值不正确!', + 'type.require' => '商品类型不可为空!', + 'type.integer' => '商品类型不正确!', + 'imgs.array' => '商品图像不正确!', + 'units.array' => '多单位配置不正确!', + 'serial.require' => '序列商品不可为空!', + 'serial.boolean' => '序列商品不正确!', + 'batch.require' => '批次商品不可为空!', + 'batch.boolean' => '批次商品不正确!', + 'protect.require' => '保质期不可为空!', + 'protect.integer' => '保质期不正确!', + 'threshold.require' => '保质期不可为空!', + 'threshold.integer' => '预警阀值不正确!', + 'more.array' => '扩展信息不正确!', + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','number','category','buy','sell','stock','type','imgs','units','serial','batch','protect','threshold','more'], + 'imports' => ['name','number','buy','sell','stock','type','imgs','units','serial','batch','protect','threshold','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Ice.php b/serve/app/validate/Ice.php new file mode 100644 index 0000000..81bf851 --- /dev/null +++ b/serve/app/validate/Ice.php @@ -0,0 +1,44 @@ +['integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:ice'], + 'total' => ['require','float'], + 'actual' => ['require','float'], + 'money' => ['require','float'], + 'account' => ['requireWith:money'], + 'people' => ['integer'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'customer.integer' => '客户不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'actual.require' => '实际金额不可为空!', + 'actual.float' => '实际金额不正确!', + 'money.require' => '实收金额不可为空!', + 'money.float' => '实收金额不正确!', + 'account.requireWith' => '结算账户不可为空!', + 'account.integer' => '资金账户不正确!', + 'people.integer' => '关联人员不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['customer','time','number','total','actual','money','account','people','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/IceInfo.php b/serve/app/validate/IceInfo.php new file mode 100644 index 0000000..a433731 --- /dev/null +++ b/serve/app/validate/IceInfo.php @@ -0,0 +1,19 @@ + ['require','integer'], + 'money' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'iet.require' => '收入类型不可为空!', + 'iet.integer' => '收入类型不正确!', + 'money.require' => '结算金额不可为空!', + 'money.float' => '结算金额不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Iet.php b/serve/app/validate/Iet.php new file mode 100644 index 0000000..7cdba02 --- /dev/null +++ b/serve/app/validate/Iet.php @@ -0,0 +1,21 @@ + ['require', 'unique:iet'], + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '类别名称不可为空!', + 'name.unique' => '类别名称不可重复!', + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Imy.php b/serve/app/validate/Imy.php new file mode 100644 index 0000000..4d86950 --- /dev/null +++ b/serve/app/validate/Imy.php @@ -0,0 +1,37 @@ + ['require','integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:imy'], + 'total' => ['require','float'], + 'people' => ['integer'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + + 'customer.require' => '客户不可为空!', + 'customer.integer' => '客户不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'people.integer' => '关联人员不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['customer','time','number','total','people','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/ImyInfo.php b/serve/app/validate/ImyInfo.php new file mode 100644 index 0000000..78429b6 --- /dev/null +++ b/serve/app/validate/ImyInfo.php @@ -0,0 +1,19 @@ + ['require','integer'], + 'money' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'account.require' => '结算账户不可为空!', + 'account.integer' => '结算账户不正确!', + 'money.require' => '结算金额不可为空!', + 'money.float' => '结算金额不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Invoice.php b/serve/app/validate/Invoice.php new file mode 100644 index 0000000..f843f87 --- /dev/null +++ b/serve/app/validate/Invoice.php @@ -0,0 +1,30 @@ + ['require'], + 'class' => ['require','integer'], + 'time' => ['require','date'], + 'number' => ['require'], + 'title' => ['require'], + 'money' => ['require','float'], + 'file' => ['array'], + ]; + + //常规规则提示 + protected $message = [ + 'type.require' => '单据类型不可为空!', + 'class.require' => '所属单据不可为空!', + 'class.integer' => '所属单据不正确!', + 'time.require' => '开票时间不可为空!', + 'time.date' => '开票时间不正确!', + 'number.require' => '发票号码不可为空!', + 'title.require' => '发票抬头不可为空!', + 'money.require' => '开票金额不可为空!', + 'money.float' => '开票金额不正确!', + 'file.array' => '发票附件不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Menu.php b/serve/app/validate/Menu.php new file mode 100644 index 0000000..4785ec2 --- /dev/null +++ b/serve/app/validate/Menu.php @@ -0,0 +1,31 @@ + ['require'], + 'key' => ['require','unique:menu'], + 'pid' => ['require','integer'], + 'type' => ['require','integer'], + 'sort' => ['require','integer'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '菜单名称不可为空!', + 'key.require' => '菜单标识不可为空!', + 'key.unique' => '菜单标识重复!', + 'pid.require' => '所属菜单不可为空!', + 'pid.integer' => '所属菜单不正确!', + 'type.require' => '菜单类型不可为空!', + 'type.integer' => '菜单类型不正确!', + 'sort.require' => '菜单排序不可为空!', + 'sort.integer' => '菜单排序不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','key','pid','type','sort'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Mould.php b/serve/app/validate/Mould.php new file mode 100644 index 0000000..7b23eaa --- /dev/null +++ b/serve/app/validate/Mould.php @@ -0,0 +1,30 @@ + ['require'], + 'key' => ['require'], + 'sort' => ['require','integer'], + 'source' => ['require','array'], + 'code' => ['require'], + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '模板名称不可为空!', + 'key.require' => '模板标识不可为空!', + 'sort.require' => '组织排序不可为空!', + 'sort.integer' => '组织排序不正确!', + 'source.require' => '数据源不可为空!', + 'source.array' => '数据源不正确!', + 'code.require' => '模板代码不可为空!', + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','key','sort','source','code'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Oce.php b/serve/app/validate/Oce.php new file mode 100644 index 0000000..574d6d7 --- /dev/null +++ b/serve/app/validate/Oce.php @@ -0,0 +1,44 @@ +['integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:oce'], + 'total' => ['require','float'], + 'actual' => ['require','float'], + 'account' => ['requireWith:money'], + 'account'=>['require','integer'], + 'people' => ['integer'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'supplier.integer' => '供应商不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'actual.require' => '实际金额不可为空!', + 'actual.float' => '实际金额不正确!', + 'money.require' => '实付金额不可为空!', + 'money.float' => '实付金额不正确!', + 'account.requireWith' => '结算账户不可为空!', + 'account.integer' => '资金账户不正确!', + 'people.integer' => '关联人员不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['supplier','time','number','total','actual','money','account','people','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/OceInfo.php b/serve/app/validate/OceInfo.php new file mode 100644 index 0000000..cd8b8a5 --- /dev/null +++ b/serve/app/validate/OceInfo.php @@ -0,0 +1,22 @@ + ['require','integer'], + 'iet' => ['require','integer'], + 'money' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联详情不可为空!', + 'source.integer' => '关联详情不正确!', + 'iet.require' => '收入类型不可为空!', + 'iet.integer' => '收入类型不正确!', + 'money.require' => '结算金额不可为空!', + 'money.float' => '结算金额不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Omy.php b/serve/app/validate/Omy.php new file mode 100644 index 0000000..83e14aa --- /dev/null +++ b/serve/app/validate/Omy.php @@ -0,0 +1,37 @@ + ['require','integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:omy'], + 'total' => ['require','float'], + 'people' => ['integer'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + + 'supplier.require' => '供应商不可为空!', + 'supplier.integer' => '供应商不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'people.integer' => '关联人员不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['supplier','time','number','total','people','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/OmyInfo.php b/serve/app/validate/OmyInfo.php new file mode 100644 index 0000000..647d436 --- /dev/null +++ b/serve/app/validate/OmyInfo.php @@ -0,0 +1,19 @@ + ['require','integer'], + 'money' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'account.require' => '结算账户不可为空!', + 'account.integer' => '结算账户不正确!', + 'money.require' => '结算金额不可为空!', + 'money.float' => '结算金额不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/People.php b/serve/app/validate/People.php new file mode 100644 index 0000000..cba556e --- /dev/null +++ b/serve/app/validate/People.php @@ -0,0 +1,31 @@ + ['require'], + 'number' => ['require','unique:people'], + 'frame' => ['require','integer'], + 'sex' => ['require','integer'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '人员名称不可为空!', + 'number.require' => '人员编号不可为空!', + 'number.unique' => '人员编号重复!', + 'frame.require' => '所属组织不可为空!', + 'frame.integer' => '所属组织不正确!', + 'sex.require' => '性别不可为空!', + 'sex.integer' => '性别不正确!', + 'more.array' => '扩展信息不正确!', + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','number','frame','sex','more'], + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Role.php b/serve/app/validate/Role.php new file mode 100644 index 0000000..5aedc29 --- /dev/null +++ b/serve/app/validate/Role.php @@ -0,0 +1,26 @@ + ['require'], + 'root' => ['require','array'], + 'auth' => ['require','array'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '角色名称不可为空!', + 'root.require' => '功能权限不可为空!', + 'root.array' => '功能权限不正确!', + 'auth.require' => '数据权限不可为空!', + 'auth.array' => '数据权限不正确!', + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','root','auth'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Sell.php b/serve/app/validate/Sell.php new file mode 100644 index 0000000..b33bbab --- /dev/null +++ b/serve/app/validate/Sell.php @@ -0,0 +1,49 @@ + ['require','integer'], + 'customer' => ['require','integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:sell'], + 'total' => ['require','float'], + 'actual' => ['require','float'], + 'money' => ['require','float'], + 'account' => ['requireWith:money'], + 'people' => ['integer'], + 'logistics' => ['array'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联单据不可为空!', + 'source.integer' => '关联单据不正确!', + 'customer.require' => '客户不可为空!', + 'customer.integer' => '客户不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'actual.require' => '实际金额不可为空!', + 'actual.float' => '实际金额不正确!', + 'money.require' => '实收金额不可为空!', + 'money.float' => '实收金额不正确!', + 'account.requireWith' => '结算账户不可为空!', + 'people.integer' => '关联人员不正确!', + 'logistics.array' => '物流信息不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['source','customer','time','number','total','actual','money','account','people','logistics','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/SellInfo.php b/serve/app/validate/SellInfo.php new file mode 100644 index 0000000..e486735 --- /dev/null +++ b/serve/app/validate/SellInfo.php @@ -0,0 +1,50 @@ + ['require','integer'], + 'goods' => ['require','integer'], + 'warehouse' => ['integer'], + 'mfd' => ['date'], + 'price' => ['require','float'], + 'nums' => ['require','float'], + 'serial' => ['array'], + 'discount' => ['require','between:0,100'], + 'dsc' => ['require','float'], + 'total' => ['require','float'], + 'tax' => ['require','between:0,100'], + 'tat' => ['require','float'], + 'tpt' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联详情不可为空!', + 'source.integer' => '关联详情不正确!', + 'goods.require' => '商品信息不可为空!', + 'goods.integer' => '商品信息不正确!', + 'warehouse.integer' => '仓库不正确!', + 'mfd.require' => '生产日期不正确!', + 'price.require' => '单价不可为空!', + 'price.float' => '单价不正确!', + 'nums.require' => '数量不可为空!', + 'nums.float' => '数量不正确!', + 'serial.require' => '序列号不可为空!', + 'serial.array' => '序列号不正确!', + 'discount.require' => '折扣率不可为空!', + 'discount.between' => '折扣率不正确!', + 'dsc.require' => '折扣额不可为空!', + 'dsc.float' => '折扣额不正确!', + 'total.require' => '金额不可为空!', + 'total.float' => '金额不正确!', + 'tax.require' => '税率不可为空!', + 'tax.between' => '税率不正确!', + 'tat.require' => '税额不可为空!', + 'tat.float' => '税额不正确!', + 'tpt.require' => '价税合计不可为空!', + 'tpt.float' => '价税合计不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Sor.php b/serve/app/validate/Sor.php new file mode 100644 index 0000000..db94ec4 --- /dev/null +++ b/serve/app/validate/Sor.php @@ -0,0 +1,41 @@ + ['require','integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:sor'], + 'total' => ['require','float'], + 'actual' => ['require','float'], + 'people' => ['integer'], + 'logistics' => ['array'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'customer.require' => '客户不可为空!', + 'customer.integer' => '客户不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'actual.require' => '实际金额不可为空!', + 'actual.float' => '实际金额不正确!', + 'people.integer' => '关联人员不正确!', + 'logistics.array' => '物流信息不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!', + ]; + + //场景规则 + protected $scene = [ + 'update' => ['customer','time','number','total','actual','people','logistics','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/SorInfo.php b/serve/app/validate/SorInfo.php new file mode 100644 index 0000000..efe63c2 --- /dev/null +++ b/serve/app/validate/SorInfo.php @@ -0,0 +1,42 @@ + ['require','integer'], + 'warehouse' => ['integer'], + 'price' => ['require','float'], + 'nums' => ['require','float'], + 'discount' => ['require','between:0,100'], + 'dsc' => ['require','float'], + 'total' => ['require','float'], + 'tax' => ['require','between:0,100'], + 'tat' => ['require','float'], + 'tpt' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'goods.require' => '商品信息不可为空!', + 'goods.integer' => '商品信息不正确!', + 'warehouse.integer' => '仓库不正确!', + 'price.require' => '单价不可为空!', + 'price.float' => '单价不正确!', + 'nums.require' => '数量不可为空!', + 'nums.float' => '数量不正确!', + 'discount.require' => '折扣率不可为空!', + 'discount.between' => '折扣率不正确!', + 'dsc.require' => '折扣额不可为空!', + 'dsc.float' => '折扣额不正确!', + 'total.require' => '金额不可为空!', + 'total.float' => '金额不正确!', + 'tax.require' => '税率不可为空!', + 'tax.between' => '税率不正确!', + 'tat.require' => '税额不可为空!', + 'tat.float' => '税额不正确!', + 'tpt.require' => '价税合计不可为空!', + 'tpt.float' => '价税合计不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Sre.php b/serve/app/validate/Sre.php new file mode 100644 index 0000000..ea953c8 --- /dev/null +++ b/serve/app/validate/Sre.php @@ -0,0 +1,49 @@ + ['require','integer'], + 'customer' => ['require','integer'], + 'time' => ['require','date'], + 'number' => ['require','unique:sre'], + 'total' => ['require','float'], + 'actual' => ['require','float'], + 'money' => ['require','float'], + 'account' => ['requireWith:money'], + 'people' => ['integer'], + 'logistics' => ['array'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联单据不可为空!', + 'source.integer' => '关联单据不正确!', + 'customer.require' => '客户不可为空!', + 'customer.integer' => '客户不正确!', + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'total.require' => '单据金额不可为空!', + 'total.float' => '单据金额不正确!', + 'actual.require' => '实际金额不可为空!', + 'actual.float' => '实际金额不正确!', + 'money.require' => '实付金额不可为空!', + 'money.float' => '实付金额不正确!', + 'account.requireWith' => '结算账户不可为空!', + 'people.integer' => '关联人员不正确!', + 'logistics.array' => '物流信息不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['source','customer','time','number','total','actual','money','account','people','logistics','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/SreInfo.php b/serve/app/validate/SreInfo.php new file mode 100644 index 0000000..fad7d6d --- /dev/null +++ b/serve/app/validate/SreInfo.php @@ -0,0 +1,50 @@ + ['require','integer'], + 'goods' => ['require','integer'], + 'warehouse' => ['integer'], + 'mfd' => ['date'], + 'price' => ['require','float'], + 'nums' => ['require','float'], + 'serial' => ['array'], + 'discount' => ['require','between:0,100'], + 'dsc' => ['require','float'], + 'total' => ['require','float'], + 'tax' => ['require','between:0,100'], + 'tat' => ['require','float'], + 'tpt' => ['require','float'] + ]; + + //常规规则提示 + protected $message = [ + 'source.require' => '关联详情不可为空!', + 'source.integer' => '关联详情不正确!', + 'goods.require' => '商品信息不可为空!', + 'goods.integer' => '商品信息不正确!', + 'warehouse.integer' => '仓库不正确!', + 'mfd.require' => '生产日期不正确!', + 'price.require' => '单价不可为空!', + 'price.float' => '单价不正确!', + 'nums.require' => '数量不可为空!', + 'nums.float' => '数量不正确!', + 'serial.require' => '序列号不可为空!', + 'serial.array' => '序列号不正确!', + 'discount.require' => '折扣率不可为空!', + 'discount.between' => '折扣率不正确!', + 'dsc.require' => '折扣额不可为空!', + 'dsc.float' => '折扣额不正确!', + 'total.require' => '金额不可为空!', + 'total.float' => '金额不正确!', + 'tax.require' => '税率不可为空!', + 'tax.between' => '税率不正确!', + 'tat.require' => '税额不可为空!', + 'tat.float' => '税额不正确!', + 'tpt.require' => '价税合计不可为空!', + 'tpt.float' => '价税合计不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Supplier.php b/serve/app/validate/Supplier.php new file mode 100644 index 0000000..202fba7 --- /dev/null +++ b/serve/app/validate/Supplier.php @@ -0,0 +1,37 @@ + ['require'], + 'number' => ['require','unique:supplier'], + 'frame' => ['require','integer'], + 'user' => ['require','integer'], + 'rate' => ['require','between:0,100'], + 'contacts'=>['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '供应商名称不可为空!', + 'number.require' => '供应商编号不可为空!', + 'number.unique' => '供应商编号重复!', + 'frame.require' => '所属组织不可为空!', + 'frame.integer' => '所属组织不正确!', + 'user.require' => '所属用户不可为空!', + 'user.integer' => '所属用户不正确!', + 'rate.require' => '增值税税率不可为空!', + 'rate.between' => '增值税税率不正确!', + 'contacts.array' => '联系资料不正确!', + 'more.array' => '扩展信息不正确!', + + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','number','frame','user','rate','contacts','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Swap.php b/serve/app/validate/Swap.php new file mode 100644 index 0000000..8ea056a --- /dev/null +++ b/serve/app/validate/Swap.php @@ -0,0 +1,32 @@ + ['require','date'], + 'number' => ['require','unique:swap'], + 'people' => ['integer'], + 'logistics' => ['array'], + 'file' => ['array'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'time.require' => '单据日期不可为空!', + 'time.date' => '单据日期不正确!', + 'number.require' => '单据编号不可为空!', + 'number.unique' => '单据编号重复!', + 'people.integer' => '关联人员不正确!', + 'logistics.array' => '物流信息不正确!', + 'file.array' => '单据附件不正确!', + 'more.array' => '扩展信息不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['time','number','people','logistics','file','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/SwapInfo.php b/serve/app/validate/SwapInfo.php new file mode 100644 index 0000000..304931f --- /dev/null +++ b/serve/app/validate/SwapInfo.php @@ -0,0 +1,31 @@ + ['require','integer'], + 'warehouse' => ['integer'], + 'storehouse' => ['integer'], + 'mfd' => ['date'], + 'price' => ['require','float'], + 'nums' => ['require','float'], + 'serial' => ['array'], + ]; + + //常规规则提示 + protected $message = [ + 'goods.require' => '商品信息不可为空!', + 'goods.integer' => '商品信息不正确!', + 'warehouse.integer' => '调出仓库不正确!', + 'storehouse.integer' => '调入仓库不正确!', + 'mfd.require' => '生产日期不正确!', + 'price.require' => '单价不可为空!', + 'price.float' => '单价不正确!', + 'nums.require' => '数量不可为空!', + 'nums.float' => '数量不正确!', + 'serial.require' => '序列号不可为空!', + 'serial.array' => '序列号不正确!' + ]; +} \ No newline at end of file diff --git a/serve/app/validate/User.php b/serve/app/validate/User.php new file mode 100644 index 0000000..29323e2 --- /dev/null +++ b/serve/app/validate/User.php @@ -0,0 +1,35 @@ + ['require'], + 'frame' => ['require','integer'], + 'role' => ['integer'], + 'user' => ['require','unique:user'], + 'tel' => ['require','unique:user'], + 'pwd' => ['require'], + 'more' => ['array'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '用户名称不可为空!', + 'frame.require' => '所属组织不可为空!', + 'frame.integer' => '所属组织不正确!', + 'role.integer' => '用户角色不正确!', + 'user.require' => '用户账号不可为空!', + 'user.unique' => '用户账号重复!', + 'tel.require' => '手机号码不可为空!', + 'tel.unique' => '手机号码重复!', + 'pwd.require' => '用户密码不可为空!', + 'more.array' => '扩展信息不正确!', + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','frame','role','user','tel','more'] + ]; +} \ No newline at end of file diff --git a/serve/app/validate/Warehouse.php b/serve/app/validate/Warehouse.php new file mode 100644 index 0000000..ff46ca6 --- /dev/null +++ b/serve/app/validate/Warehouse.php @@ -0,0 +1,26 @@ + ['require','unique:warehouse'], + 'number' => ['require','unique:warehouse'], + 'frame' => ['require','integer'] + ]; + + //常规规则提示 + protected $message = [ + 'name.require' => '仓库名称不可为空!', + 'name.unique' => '仓库名称重复!', + 'number.require' => '仓库编号不可为空!', + 'number.unique' => '仓库编号重复!', + 'frame.require' => '所属组织不可为空!', + 'frame.integer' => '所属组织不正确!' + ]; + + //场景规则 + protected $scene = [ + 'update' => ['name','number','frame'] + ]; +} \ No newline at end of file diff --git a/serve/app/view/index/index.html b/serve/app/view/index/index.html new file mode 100644 index 0000000..09fa5e1 --- /dev/null +++ b/serve/app/view/index/index.html @@ -0,0 +1 @@ +点可云进销存软件
\ No newline at end of file diff --git a/serve/composer.json b/serve/composer.json new file mode 100644 index 0000000..1c26a63 --- /dev/null +++ b/serve/composer.json @@ -0,0 +1,61 @@ +{ + "name": "topthink/think", + "description": "the new thinkphp framework", + "type": "project", + "keywords": [ + "framework", + "thinkphp", + "ORM" + ], + "homepage": "http://thinkphp.cn/", + "license": "Apache-2.0", + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0", + "topthink/think-orm": "^2.0", + "ezyang/htmlpurifier": "^4.11", + "phpoffice/phpspreadsheet": "^1.9", + "endroid/qr-code": "^3.7", + "barcode-bakery/barcode-common": "*", + "barcode-bakery/barcode-1d": "*", + "alipaysdk/easysdk": "^2.0", + "topthink/think-view": "^1.0" + }, + "repositories": [ + { + "type": "path", + "url": "vendor/packages/barcode-common" + }, + { + "type": "path", + "url": "vendor/packages/barcode-1d" + } + ], + "require-dev": { + "symfony/var-dumper": "^4.2", + "topthink/think-trace": "^1.0" + }, + "autoload": { + "psr-4": { + "app\\": "app" + }, + "psr-0": { + "": "extend/" + } + }, + "config": { + "preferred-install": "dist" + }, + "scripts": { + "post-autoload-dump": [ + "@php think service:discover", + "@php think vendor:publish" + ] + } +} diff --git a/serve/composer.lock b/serve/composer.lock new file mode 100644 index 0000000..c916131 --- /dev/null +++ b/serve/composer.lock @@ -0,0 +1,3525 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "48dc658954150aad85085b97433b801a", + "packages": [ + { + "name": "adbario/php-dot-notation", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/adbario/php-dot-notation.git", + "reference": "eee4fc81296531e6aafba4c2bbccfc5adab1676e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/eee4fc81296531e6aafba4c2bbccfc5adab1676e", + "reference": "eee4fc81296531e6aafba4c2bbccfc5adab1676e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0|^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Adbar\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Riku Särkinen", + "email": "riku@adbar.io" + } + ], + "description": "PHP dot notation access to arrays", + "homepage": "https://github.com/adbario/php-dot-notation", + "keywords": [ + "ArrayAccess", + "dotnotation" + ], + "support": { + "issues": "https://github.com/adbario/php-dot-notation/issues", + "source": "https://github.com/adbario/php-dot-notation/tree/2.x" + }, + "time": "2019-01-01T23:59:15+00:00" + }, + { + "name": "alibabacloud/tea", + "version": "3.1.21", + "source": { + "type": "git", + "url": "https://github.com/aliyun/tea-php.git", + "reference": "379faffe240ee97134cf3f796cb28059f9fb7fa9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/tea-php/zipball/379faffe240ee97134cf3f796cb28059f9fb7fa9", + "reference": "379faffe240ee97134cf3f796cb28059f9fb7fa9", + "shasum": "" + }, + "require": { + "adbario/php-dot-notation": "^2.2", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "*", + "symfony/dotenv": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com", + "homepage": "http://www.alibabacloud.com" + } + ], + "description": "Client of Tea for PHP", + "homepage": "https://www.alibabacloud.com/", + "keywords": [ + "alibabacloud", + "client", + "cloud", + "tea" + ], + "support": { + "issues": "https://github.com/aliyun/tea-php/issues", + "source": "https://github.com/aliyun/tea-php" + }, + "time": "2021-03-15T03:31:41+00:00" + }, + { + "name": "alibabacloud/tea-fileform", + "version": "0.3.4", + "source": { + "type": "git", + "url": "https://github.com/alibabacloud-sdk-php/tea-fileform.git", + "reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alibabacloud-sdk-php/tea-fileform/zipball/4bf0c75a045c8115aa8cb1a394bd08d8bb833181", + "reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181", + "shasum": "" + }, + "require": { + "alibabacloud/tea": "^3.0", + "php": ">5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\FileForm\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "description": "Alibaba Cloud Tea File Library for PHP", + "support": { + "issues": "https://github.com/alibabacloud-sdk-php/tea-fileform/issues", + "source": "https://github.com/alibabacloud-sdk-php/tea-fileform/tree/0.3.4" + }, + "time": "2020-12-01T07:24:35+00:00" + }, + { + "name": "alipaysdk/easysdk", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/alipay/alipay-easysdk.git", + "reference": "7a1cfa83c7e140bded957498ea072c77611e6480" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alipay/alipay-easysdk/zipball/7a1cfa83c7e140bded957498ea072c77611e6480", + "reference": "7a1cfa83c7e140bded957498ea072c77611e6480", + "shasum": "" + }, + "require": { + "adbario/php-dot-notation": "^2.2", + "alibabacloud/tea": "^3.1", + "alibabacloud/tea-fileform": "^0.3.2", + "danielstjules/stringy": "^3.1", + "ext-ctype": "*", + "ext-curl": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": ">=6.3", + "mtdowling/jmespath.php": "^2.4", + "php": ">=7.0", + "pimple/pimple": "^3.0", + "psr/log": "^1.1", + "songshenzong/support": "^2.0", + "xin/container": "^2.0.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Alipay\\EasySDK\\": "php/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "junying.wjy", + "email": "junying.wjy@antfin.com" + } + ], + "description": "支付宝官方 Alipay Easy SDK", + "support": { + "issues": "https://github.com/alipay/alipay-easysdk/issues", + "source": "https://github.com/alipay/alipay-easysdk/tree/v2.2.0" + }, + "time": "2021-01-19T07:30:32+00:00" + }, + { + "name": "bacon/bacon-qr-code", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "3e9d791b67d0a2912922b7b7c7312f4b37af41e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/3e9d791b67d0a2912922b7b7c7312f4b37af41e4", + "reference": "3e9d791b67d0a2912922b7b7c7312f4b37af41e4", + "shasum": "" + }, + "require": { + "dasprid/enum": "^1.0.3", + "ext-iconv": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phly/keep-a-changelog": "^1.4", + "phpunit/phpunit": "^7 | ^8 | ^9", + "squizlabs/php_codesniffer": "^3.4" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "type": "library", + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "support": { + "issues": "https://github.com/Bacon/BaconQrCode/issues", + "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.3" + }, + "time": "2020-10-30T02:02:47+00:00" + }, + { + "name": "barcode-bakery/barcode-1d", + "version": "6.0.0", + "dist": { + "type": "path", + "url": "vendor/packages/barcode-1d", + "reference": "cd8c30d754d6595bfda13a0fa88e5033179d71f2" + }, + "require": { + "ext-gd": "*", + "php": ">=5.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "BarcodeBakery\\Barcode\\": "src" + } + }, + "license": [ + "Commercial", + "CC-BY-NC-ND-4.0" + ], + "authors": [ + { + "name": "Jean-Sébastien Goupil", + "email": "contact@barcodebakery.com" + } + ], + "description": "Generates 1D barcodes from a PHP server to a file or HTML document.", + "homepage": "http://www.barcodebakery.com", + "keywords": [ + "bakery", + "barcode", + "codabar", + "code11", + "code128", + "code39", + "code39extended", + "code93", + "ean-13", + "ean-8", + "ean13", + "ean8", + "generator", + "i25", + "isbn", + "msi", + "s25", + "upc-a", + "upc-e", + "upcext2", + "upcext5" + ], + "support": { + "email": "contact@barcodebakery.com", + "docs": "http://www.barcodebakery.com" + }, + "transport-options": { + "relative": true + } + }, + { + "name": "barcode-bakery/barcode-common", + "version": "6.0.0", + "dist": { + "type": "path", + "url": "vendor/packages/barcode-common", + "reference": "289043a2fd5fc8e18c28f1565b50bfd21a712fbd" + }, + "require": { + "ext-gd": "*", + "php": ">=5.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "BarcodeBakery\\Common\\": "src" + } + }, + "license": [ + "Commercial", + "CC-BY-NC-ND-4.0" + ], + "authors": [ + { + "name": "Jean-Sébastien Goupil", + "email": "contact@barcodebakery.com" + } + ], + "description": "Base code for generating barcode with the Barcode Bakery library. See barcode-bakery/barcode-1d.", + "homepage": "http://www.barcodebakery.com", + "support": { + "email": "contact@barcodebakery.com", + "docs": "http://www.barcodebakery.com" + }, + "transport-options": { + "relative": true + } + }, + { + "name": "danielstjules/stringy", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/danielstjules/Stringy.git", + "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", + "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Stringy\\": "src/" + }, + "files": [ + "src/Create.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel St. Jules", + "email": "danielst.jules@gmail.com", + "homepage": "http://www.danielstjules.com" + } + ], + "description": "A string manipulation library with multibyte support", + "homepage": "https://github.com/danielstjules/Stringy", + "keywords": [ + "UTF", + "helpers", + "manipulation", + "methods", + "multibyte", + "string", + "utf-8", + "utility", + "utils" + ], + "support": { + "issues": "https://github.com/danielstjules/Stringy/issues", + "source": "https://github.com/danielstjules/Stringy" + }, + "time": "2017-06-12T01:10:27+00:00" + }, + { + "name": "dasprid/enum", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "5abf82f213618696dda8e3bf6f64dd042d8542b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/5abf82f213618696dda8e3bf6f64dd042d8542b2", + "reference": "5abf82f213618696dda8e3bf6f64dd042d8542b2", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "^7 | ^8 | ^9", + "squizlabs/php_codesniffer": "^3.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "support": { + "issues": "https://github.com/DASPRiD/Enum/issues", + "source": "https://github.com/DASPRiD/Enum/tree/1.0.3" + }, + "time": "2020-10-02T16:03:48+00:00" + }, + { + "name": "endroid/qr-code", + "version": "3.9.7", + "source": { + "type": "git", + "url": "https://github.com/endroid/qr-code.git", + "reference": "94563d7b3105288e6ac53a67ae720e3669fac1f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/endroid/qr-code/zipball/94563d7b3105288e6ac53a67ae720e3669fac1f6", + "reference": "94563d7b3105288e6ac53a67ae720e3669fac1f6", + "shasum": "" + }, + "require": { + "bacon/bacon-qr-code": "^2.0", + "khanamiryan/qrcode-detector-decoder": "^1.0.5", + "myclabs/php-enum": "^1.5", + "php": "^7.3||^8.0", + "symfony/options-resolver": "^3.4||^4.4||^5.0", + "symfony/property-access": "^3.4||^4.4||^5.0" + }, + "require-dev": { + "endroid/quality": "^1.5.2", + "setasign/fpdf": "^1.8" + }, + "suggest": { + "ext-gd": "Required for generating PNG images", + "roave/security-advisories": "Avoids installation of package versions with vulnerabilities", + "setasign/fpdf": "Required to use the FPDF writer.", + "symfony/security-checker": "Checks your composer.lock for vulnerabilities" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Endroid\\QrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeroen van den Enden", + "email": "info@endroid.nl" + } + ], + "description": "Endroid QR Code", + "homepage": "https://github.com/endroid/qr-code", + "keywords": [ + "bundle", + "code", + "endroid", + "php", + "qr", + "qrcode" + ], + "support": { + "issues": "https://github.com/endroid/qr-code/issues", + "source": "https://github.com/endroid/qr-code/tree/3.9.7" + }, + "funding": [ + { + "url": "https://github.com/endroid", + "type": "github" + } + ], + "time": "2021-04-20T19:10:54+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.13.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "require-dev": { + "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" + }, + "type": "library", + "autoload": { + "psr-0": { + "HTMLPurifier": "library/" + }, + "files": [ + "library/HTMLPurifier.composer.php" + ], + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/master" + }, + "time": "2020-06-29T00:56:53+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "7008573787b430c1c1f650e3722d9bba59967628" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7008573787b430c1c1f650e3722d9bba59967628", + "reference": "7008573787b430c1c1f650e3722d9bba59967628", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.4", + "guzzlehttp/psr7": "^1.7 || ^2.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", + "psr/log": "^1.1" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.3-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://github.com/alexeyshockov", + "type": "github" + }, + { + "url": "https://github.com/gmponos", + "type": "github" + } + ], + "time": "2021-03-23T11:33:13+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.4.1" + }, + "time": "2021-03-07T09:25:29+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.8.2" + }, + "time": "2021-04-26T09:17:50+00:00" + }, + { + "name": "khanamiryan/qrcode-detector-decoder", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/khanamiryan/php-qrcode-detector-decoder.git", + "reference": "6c8c23003a87ecd7458807cd49372b1fb590d1f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/khanamiryan/php-qrcode-detector-decoder/zipball/6c8c23003a87ecd7458807cd49372b1fb590d1f5", + "reference": "6c8c23003a87ecd7458807cd49372b1fb590d1f5", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 | ^7.5 | ^8.0 | ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Zxing\\": "lib/" + }, + "files": [ + "lib/Common/customFunctions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ashot Khanamiryan", + "email": "a.khanamiryan@gmail.com", + "homepage": "https://github.com/khanamiryan", + "role": "Developer" + } + ], + "description": "QR code decoder / reader", + "homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder/", + "keywords": [ + "barcode", + "qr", + "zxing" + ], + "support": { + "issues": "https://github.com/khanamiryan/php-qrcode-detector-decoder/issues", + "source": "https://github.com/khanamiryan/php-qrcode-detector-decoder/tree/1.0.5" + }, + "time": "2021-04-20T18:34:35+00:00" + }, + { + "name": "league/flysystem", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "9be3b16c877d477357c015cec057548cf9b2a14a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/9be3b16c877d477357c015cec057548cf9b2a14a", + "reference": "9be3b16c877d477357c015cec057548cf9b2a14a", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.x" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "time": "2020-08-23T07:39:11+00:00" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "support": { + "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues", + "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master" + }, + "time": "2020-07-25T15:56:04+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.18", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.7.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2021-01-18T20:58:21+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/c4c5803cc1f93df3d2448478ef79394a5981cc58", + "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58", + "shasum": "" + }, + "require": { + "myclabs/php-enum": "^1.5", + "php": ">= 7.1", + "psr/http-message": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "ext-zip": "*", + "guzzlehttp/guzzle": ">= 6.3", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": ">= 7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/master" + }, + "funding": [ + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], + "time": "2020-05-30T13:11:16+00:00" + }, + { + "name": "markbaker/complex", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "9999f1432fae467bc93c53f357105b4c31bb994c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/9999f1432fae467bc93c53f357105b4c31bb994c", + "reference": "9999f1432fae467bc93c53f357105b4c31bb994c", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "phpcompatibility/php-compatibility": "^9.0", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + }, + "files": [ + "classes/src/functions/abs.php", + "classes/src/functions/acos.php", + "classes/src/functions/acosh.php", + "classes/src/functions/acot.php", + "classes/src/functions/acoth.php", + "classes/src/functions/acsc.php", + "classes/src/functions/acsch.php", + "classes/src/functions/argument.php", + "classes/src/functions/asec.php", + "classes/src/functions/asech.php", + "classes/src/functions/asin.php", + "classes/src/functions/asinh.php", + "classes/src/functions/atan.php", + "classes/src/functions/atanh.php", + "classes/src/functions/conjugate.php", + "classes/src/functions/cos.php", + "classes/src/functions/cosh.php", + "classes/src/functions/cot.php", + "classes/src/functions/coth.php", + "classes/src/functions/csc.php", + "classes/src/functions/csch.php", + "classes/src/functions/exp.php", + "classes/src/functions/inverse.php", + "classes/src/functions/ln.php", + "classes/src/functions/log2.php", + "classes/src/functions/log10.php", + "classes/src/functions/negative.php", + "classes/src/functions/pow.php", + "classes/src/functions/rho.php", + "classes/src/functions/sec.php", + "classes/src/functions/sech.php", + "classes/src/functions/sin.php", + "classes/src/functions/sinh.php", + "classes/src/functions/sqrt.php", + "classes/src/functions/tan.php", + "classes/src/functions/tanh.php", + "classes/src/functions/theta.php", + "classes/src/operations/add.php", + "classes/src/operations/subtract.php", + "classes/src/operations/multiply.php", + "classes/src/operations/divideby.php", + "classes/src/operations/divideinto.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/PHP8" + }, + "time": "2020-08-26T10:42:07+00:00" + }, + { + "name": "markbaker/matrix", + "version": "2.1.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/361c0f545c3172ee26c3d596a0aa03f0cef65e6a", + "reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "phpcompatibility/php-compatibility": "^9.0", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + }, + "files": [ + "classes/src/Functions/adjoint.php", + "classes/src/Functions/antidiagonal.php", + "classes/src/Functions/cofactors.php", + "classes/src/Functions/determinant.php", + "classes/src/Functions/diagonal.php", + "classes/src/Functions/identity.php", + "classes/src/Functions/inverse.php", + "classes/src/Functions/minors.php", + "classes/src/Functions/trace.php", + "classes/src/Functions/transpose.php", + "classes/src/Operations/add.php", + "classes/src/Operations/directsum.php", + "classes/src/Operations/subtract.php", + "classes/src/Operations/multiply.php", + "classes/src/Operations/divideby.php", + "classes/src/Operations/divideinto.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/2.1.2" + }, + "time": "2021-01-23T16:37:31+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/42dae2cbd13154083ca6d70099692fef8ca84bfb", + "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^1.4", + "phpunit/phpunit": "^4.8.36 || ^7.5.15" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-4": { + "JmesPath\\": "src/" + }, + "files": [ + "src/JmesPath.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.6.0" + }, + "time": "2020-07-31T21:01:56+00:00" + }, + { + "name": "myclabs/php-enum", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "46cf3d8498b095bd33727b13fd5707263af99421" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/46cf3d8498b095bd33727b13fd5707263af99421", + "reference": "46cf3d8498b095bd33727b13fd5707263af99421", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^4.5.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "http://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "support": { + "issues": "https://github.com/myclabs/php-enum/issues", + "source": "https://github.com/myclabs/php-enum/tree/1.8.0" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "time": "2021-02-15T16:11:48+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.17.1", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "c55269cb06911575a126dc225a05c0e4626e5fb4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/c55269cb06911575a126dc225a05c0e4626e5fb4", + "reference": "c55269cb06911575a126dc225a05c0e4626e5fb4", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.13", + "maennchen/zipstream-php": "^2.1", + "markbaker/complex": "^1.5||^2.0", + "markbaker/matrix": "^1.2||^2.0", + "php": "^7.2||^8.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0" + }, + "require-dev": { + "dompdf/dompdf": "^0.8.5", + "friendsofphp/php-cs-fixer": "^2.18", + "jpgraph/jpgraph": "^4.0", + "mpdf/mpdf": "^8.0", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^8.5||^9.3", + "squizlabs/php_codesniffer": "^3.5", + "tecnickcom/tcpdf": "^6.3" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)", + "jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.17.1" + }, + "time": "2021-03-02T17:54:11+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "86406047271859ffc13424a048541f4531f53601" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/86406047271859ffc13424a048541f4531f53601", + "reference": "86406047271859ffc13424a048541f4531f53601", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "https://pimple.symfony.com", + "keywords": [ + "container", + "dependency injection" + ], + "support": { + "source": "https://github.com/silexphp/Pimple/tree/v3.4.0" + }, + "time": "2021-03-06T08:28:00+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, + "time": "2021-03-05T17:36:06+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.3" + }, + "time": "2020-03-23T09:12:05+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "songshenzong/support", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/songshenzong/support.git", + "reference": "34973c04ffcf226e503f1c3a69d30ac49f7621f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/songshenzong/support/zipball/34973c04ffcf226e503f1c3a69d30ac49f7621f6", + "reference": "34973c04ffcf226e503f1c3a69d30ac49f7621f6", + "shasum": "" + }, + "require": { + "danielstjules/stringy": "^3.1", + "ext-json": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "php": ">=5.5" + }, + "require-dev": { + "laravel/framework": "^5.8", + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Songshenzong\\Support\\StringsServiceProvider" + ], + "aliases": { + "Strings": "Songshenzong\\Support\\StringsFacade" + } + } + }, + "autoload": { + "psr-4": { + "Songshenzong\\Support\\": "src/" + }, + "files": [ + "src/StringsHelpers.php", + "src/BashEchoHelpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Songshenzong", + "email": "i@songshenzong.com" + } + ], + "description": "The Songshenzong Support package.", + "homepage": "http://songshenzong.com", + "keywords": [ + "laravel", + "support", + "tools", + "web" + ], + "support": { + "issues": "https://github.com/songshenzong/support/issues", + "source": "https://github.com/songshenzong/support" + }, + "time": "2019-08-29T01:59:12+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-03-23T23:28:01+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v5.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.15" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-27T12:56:27+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5601e09b69f26c1828b13b6bb87cb07cddba3170", + "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-22T09:19:47+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-22T09:19:47+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-22T09:19:47+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" + }, + { + "name": "symfony/property-access", + "version": "v5.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "3af8ed262bd3217512a13b023981fe68f36ad5f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/3af8ed262bd3217512a13b023981fe68f36ad5f3", + "reference": "3af8ed262bd3217512a13b023981fe68f36ad5f3", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15", + "symfony/property-info": "^5.2" + }, + "require-dev": { + "symfony/cache": "^4.4|^5.0" + }, + "suggest": { + "psr/cache-implementation": "To cache access methods." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v5.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-27T10:15:41+00:00" + }, + { + "name": "symfony/property-info", + "version": "v5.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "7185bbc74e6f49c3f1b5936b4d9e4ca133921189" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/7185bbc74e6f49c3f1b5936b4d9e4ca133921189", + "reference": "7185bbc74e6f49c3f1b5936b4d9e4ca133921189", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15", + "symfony/string": "^5.1" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/cache": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "suggest": { + "phpdocumentor/reflection-docblock": "To use the PHPDoc", + "psr/cache-implementation": "To cache results", + "symfony/doctrine-bridge": "To use Doctrine metadata", + "symfony/serializer": "To use Serializer metadata" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v5.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-17T15:24:54+00:00" + }, + { + "name": "symfony/string", + "version": "v5.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", + "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-03-17T17:12:15+00:00" + }, + { + "name": "topthink/framework", + "version": "v6.0.8", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "4789343672aef06d571d556da369c0e156609bce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/4789343672aef06d571d556da369c0e156609bce", + "reference": "4789343672aef06d571d556da369c0e156609bce", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "league/flysystem": "^1.0", + "league/flysystem-cached-adapter": "^1.0", + "php": ">=7.1.0", + "psr/container": "~1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1.1", + "topthink/think-orm": "^2.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP Framework.", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "support": { + "issues": "https://github.com/top-think/framework/issues", + "source": "https://github.com/top-think/framework/tree/v6.0.8" + }, + "time": "2021-04-27T00:41:08+00:00" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.4", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "c28d37743bda4a0455286ca85b17b5791d626e10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/c28d37743bda4a0455286ca85b17b5791d626e10", + "reference": "c28d37743bda4a0455286ca85b17b5791d626e10", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "src/helper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/3.0" + }, + "time": "2019-11-08T08:01:10+00:00" + }, + { + "name": "topthink/think-orm", + "version": "v2.0.40", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "1119d979b850849f3725856460cf108eec1c3eb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/1119d979b850849f3725856460cf108eec1c3eb8", + "reference": "1119d979b850849f3725856460cf108eec1c3eb8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pdo": "*", + "php": ">=7.1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "stubs/load_stubs.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "think orm", + "keywords": [ + "database", + "orm" + ], + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v2.0.40" + }, + "time": "2021-04-19T13:29:37+00:00" + }, + { + "name": "topthink/think-template", + "version": "v2.0.8", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-template.git", + "reference": "abfc293f74f9ef5127b5c416310a01fe42e59368" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-template/zipball/abfc293f74f9ef5127b5c416310a01fe42e59368", + "reference": "abfc293f74f9ef5127b5c416310a01fe42e59368", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "psr/simple-cache": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "the php template engine", + "support": { + "issues": "https://github.com/top-think/think-template/issues", + "source": "https://github.com/top-think/think-template/tree/v2.0.8" + }, + "time": "2020-12-10T07:52:03+00:00" + }, + { + "name": "topthink/think-view", + "version": "v1.0.14", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-view.git", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-view/zipball/edce0ae2c9551ab65f9e94a222604b0dead3576d", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/think-template": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\view\\driver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp template driver", + "support": { + "issues": "https://github.com/top-think/think-view/issues", + "source": "https://github.com/top-think/think-view/tree/v1.0.14" + }, + "time": "2019-11-06T11:40:13+00:00" + }, + { + "name": "xin/container", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://gitee.com/liuxiaojinla/php-container", + "reference": "97bb67f87dd851545938a1f2fe0ffbd379e3ff81" + }, + "require": { + "ext-ctype": "*", + "ext-iconv": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "psr/container": "^1.0", + "xin/helper": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "xin\\container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "晋", + "email": "657306123@qq.com" + } + ], + "description": "严格基于PSR11规范实现基础的容器和依赖注入", + "time": "2019-10-21T03:51:25+00:00" + }, + { + "name": "xin/helper", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://gitee.com/liuxiaojinla/php-helper", + "reference": "02a58132dae2aea2d1c0b8e66f55125969224747" + }, + "require": { + "ext-ctype": "*", + "ext-iconv": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "xin\\helper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "晋", + "email": "1540175452@qq.com" + } + ], + "description": "PHP项目日常开发必备基础库,数组工具类、字符串工具类、数字工具类、函数工具类、服务器工具类、加密工具类", + "time": "2019-06-22T08:28:23+00:00" + } + ], + "packages-dev": [ + { + "name": "symfony/polyfill-php72", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0da0e174f728996f5d5072d6a9f0a42259dbc806", + "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-03-27T19:49:03+00:00" + }, + { + "name": "topthink/think-trace", + "version": "v1.4", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-trace.git", + "reference": "9a9fa8f767b6c66c5a133ad21ca1bc96ad329444" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-trace/zipball/9a9fa8f767b6c66c5a133ad21ca1bc96ad329444", + "reference": "9a9fa8f767b6c66c5a133ad21ca1bc96ad329444", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\trace\\Service" + ], + "config": { + "trace": "src/config.php" + } + } + }, + "autoload": { + "psr-4": { + "think\\trace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp debug trace", + "support": { + "issues": "https://github.com/top-think/think-trace/issues", + "source": "https://github.com/top-think/think-trace/tree/v1.4" + }, + "time": "2020-06-29T05:27:28+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1.0" + }, + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/serve/config/app.php b/serve/config/app.php new file mode 100644 index 0000000..3bba167 --- /dev/null +++ b/serve/config/app.php @@ -0,0 +1,36 @@ + Env::get('app.host', ''), + // 应用的命名空间 + 'app_namespace' => '', + // 是否启用路由 + 'with_route' => true, + // 是否启用事件 + 'with_event' => true, + // 默认应用 + 'default_app' => 'index', + // 默认时区 + 'default_timezone' => 'Asia/Shanghai', + + // 应用映射(自动多应用模式有效) + 'app_map' => [], + // 域名绑定(自动多应用模式有效) + 'domain_bind' => [], + // 禁止URL访问的应用列表(自动多应用模式有效) + 'deny_app_list' => [], + + // 异常页面的模板文件 + 'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl', + + // 错误显示信息,非调试模式有效 + 'error_message' => '页面错误!请稍后再试~', + // 显示错误信息 + 'show_error_msg' => false, +]; diff --git a/serve/config/cache.php b/serve/config/cache.php new file mode 100644 index 0000000..65e8150 --- /dev/null +++ b/serve/config/cache.php @@ -0,0 +1,30 @@ + Env::get('cache.driver', 'file'), + + // 缓存连接方式配置 + 'stores' => [ + 'file' => [ + // 驱动方式 + 'type' => 'File', + // 缓存保存目录 + 'path' => '', + // 缓存前缀 + 'prefix' => '', + // 缓存有效期 + 'expire' => 2*60*60, + // 缓存标签前缀 + 'tag_prefix' => 'tag:', + // 序列化机制 例如 ['serialize', 'unserialize'] + 'serialize' => [], + ], + // 更多的缓存连接 + ], +]; diff --git a/serve/config/captcha.php b/serve/config/captcha.php new file mode 100644 index 0000000..9bbf529 --- /dev/null +++ b/serve/config/captcha.php @@ -0,0 +1,39 @@ + 5, + // 验证码字符集合 + 'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY', + // 验证码过期时间 + 'expire' => 1800, + // 是否使用中文验证码 + 'useZh' => false, + // 是否使用算术验证码 + 'math' => false, + // 是否使用背景图 + 'useImgBg' => false, + //验证码字符大小 + 'fontSize' => 25, + // 是否使用混淆曲线 + 'useCurve' => true, + //是否添加杂点 + 'useNoise' => true, + // 验证码字体 不设置则随机 + 'fontttf' => '', + //背景颜色 + 'bg' => [243, 251, 254], + // 验证码图片高度 + 'imageH' => 0, + // 验证码图片宽度 + 'imageW' => 0, + + // 添加额外的验证码设置 + // verify => [ + // 'length'=>4, + // ... + //], +]; diff --git a/serve/config/console.php b/serve/config/console.php new file mode 100644 index 0000000..a818a98 --- /dev/null +++ b/serve/config/console.php @@ -0,0 +1,9 @@ + [ + ], +]; diff --git a/serve/config/cookie.php b/serve/config/cookie.php new file mode 100644 index 0000000..bde814c --- /dev/null +++ b/serve/config/cookie.php @@ -0,0 +1,21 @@ + 0, + // cookie 保存路径 + 'path' => '/', + // cookie 有效域名 + 'domain' => '', + // cookie 启用安全传输 + 'secure' => true, + // httponly设置 + 'httponly' => false, + // 是否使用 setcookie + 'setcookie' => true, + // 是否使用 samesite + // Chrome|CORS|PHP7.3+ + 'samesite' => 'None' +]; diff --git a/serve/config/filesystem.php b/serve/config/filesystem.php new file mode 100644 index 0000000..bac2e0f --- /dev/null +++ b/serve/config/filesystem.php @@ -0,0 +1,35 @@ + Env::get('filesystem.driver', 'local'), + // 磁盘列表 + 'disks' => [ + 'local' => [ + 'type' => 'local', + 'root' => app()->getRuntimePath() . 'storage', + ], + 'public' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/storage', + // 磁盘路径对应的外部URL路径 + 'url' => '/storage', + // 可见性 + 'visibility' => 'public', + ], + 'upload' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'static/upload', + // 磁盘路径对应的外部URL路径 + 'url' => 'static/upload', + // 可见性 + 'visibility' => 'public', + ] + ], +]; diff --git a/serve/config/lang.php b/serve/config/lang.php new file mode 100644 index 0000000..33232bd --- /dev/null +++ b/serve/config/lang.php @@ -0,0 +1,27 @@ + Env::get('lang.default_lang', 'zh-cn'), + // 允许的语言列表 + 'allow_lang_list' => [], + // 多语言自动侦测变量名 + 'detect_var' => 'lang', + // 是否使用Cookie记录 + 'use_cookie' => true, + // 多语言cookie变量 + 'cookie_var' => 'think_lang', + // 扩展语言包 + 'extend_list' => [], + // Accept-Language转义为对应语言包名称 + 'accept_language' => [ + 'zh-hans-cn' => 'zh-cn', + ], + // 是否支持语言分组 + 'allow_group' => false, +]; diff --git a/serve/config/log.php b/serve/config/log.php new file mode 100644 index 0000000..5f7afcb --- /dev/null +++ b/serve/config/log.php @@ -0,0 +1,46 @@ + Env::get('log.channel', 'file'), + // 日志记录级别 + 'level' => [], + // 日志类型记录的通道 ['error'=>'email',...] + 'type_channel' => [], + // 关闭全局日志写入 + 'close' => false, + // 全局日志处理 支持闭包 + 'processor' => null, + + // 日志通道列表 + 'channels' => [ + 'file' => [ + // 日志记录方式 + 'type' => 'File', + // 日志保存目录 + 'path' => '', + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => [], + // 最大日志文件数量 + 'max_files' => 0, + // 使用JSON格式记录 + 'json' => false, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => false, + ], + // 其它日志通道配置 + ], + +]; diff --git a/serve/config/middleware.php b/serve/config/middleware.php new file mode 100644 index 0000000..7e1972f --- /dev/null +++ b/serve/config/middleware.php @@ -0,0 +1,8 @@ + [], + // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行 + 'priority' => [], +]; diff --git a/serve/config/route.php b/serve/config/route.php new file mode 100644 index 0000000..955eeec --- /dev/null +++ b/serve/config/route.php @@ -0,0 +1,45 @@ + '/', + // URL伪静态后缀 + 'url_html_suffix' => 'html', + // URL普通方式参数 用于自动生成 + 'url_common_param' => true, + // 是否开启路由延迟解析 + 'url_lazy_route' => false, + // 是否强制使用路由 + 'url_route_must' => false, + // 合并路由规则 + 'route_rule_merge' => false, + // 路由是否完全匹配 + 'route_complete_match' => false, + // 访问控制器层名称 + 'controller_layer' => 'controller', + // 空控制器名 + 'empty_controller' => 'Error', + // 是否使用控制器后缀 + 'controller_suffix' => false, + // 默认的路由变量规则 + 'default_route_pattern' => '[\w\.]+', + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 + 'request_cache' => false, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + // 默认控制器名 + 'default_controller' => 'Index', + // 默认操作名 + 'default_action' => 'index', + // 操作方法后缀 + 'action_suffix' => '', + // 默认JSONP格式返回的处理方法 + 'default_jsonp_handler' => 'jsonpReturn', + // 默认JSONP处理方法 + 'var_jsonp_handler' => 'callback', +]; diff --git a/serve/config/session.php b/serve/config/session.php new file mode 100644 index 0000000..c1ef6e1 --- /dev/null +++ b/serve/config/session.php @@ -0,0 +1,19 @@ + 'PHPSESSID', + // SESSION_ID的提交变量,解决flash上传跨域 + 'var_session_id' => '', + // 驱动方式 支持file cache + 'type' => 'file', + // 存储连接标识 当type使用cache的时候有效 + 'store' => null, + // 过期时间 + 'expire' => 1440, + // 前缀 + 'prefix' => '', +]; diff --git a/serve/config/soft.php b/serve/config/soft.php new file mode 100644 index 0000000..1b8f7a0 --- /dev/null +++ b/serve/config/soft.php @@ -0,0 +1,10 @@ + 'erp', + 'edition' => 'develop', + 'version' => '7.4.1' +]; \ No newline at end of file diff --git a/serve/config/trace.php b/serve/config/trace.php new file mode 100644 index 0000000..fad2392 --- /dev/null +++ b/serve/config/trace.php @@ -0,0 +1,10 @@ + 'Html', + // 读取的日志通道名 + 'channel' => '', +]; diff --git a/serve/config/view.php b/serve/config/view.php new file mode 100644 index 0000000..01259a0 --- /dev/null +++ b/serve/config/view.php @@ -0,0 +1,25 @@ + 'Think', + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 + 'auto_rule' => 1, + // 模板目录名 + 'view_dir_name' => 'view', + // 模板后缀 + 'view_suffix' => 'html', + // 模板文件名分隔符 + 'view_depr' => DIRECTORY_SEPARATOR, + // 模板引擎普通标签开始标记 + 'tpl_begin' => '{', + // 模板引擎普通标签结束标记 + 'tpl_end' => '}', + // 标签库标签开始标记 + 'taglib_begin' => '{', + // 标签库标签结束标记 + 'taglib_end' => '}', +]; diff --git a/serve/extend/org/BakSql.php b/serve/extend/org/BakSql.php new file mode 100644 index 0000000..963377f --- /dev/null +++ b/serve/extend/org/BakSql.php @@ -0,0 +1,325 @@ +config = $config; + $this->begin = microtime(true); + header("Content-type: text/html;charset=utf-8"); + $this->connect(); + } + //首次进行pdo连接 + private function connect() { + try{ + $this->handler =new \PDO("{$this->config['type']}:host={$this->config['hostname']};port={$this->config['hostport']};dbname={$this->config['database']};", + $this->config['username'], + $this->config['password'], + array( + \PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES {$this->config['charset']};", + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC + )); + }catch (PDOException $e) { + die ("Error!: " . $e->getMessage() . "
"); + } + } + /** + * 查询 + * @param string $sql + * @return mixed + */ + private function query($sql = '') + { + $stmt = $this->handler->query($sql); + $stmt->setFetchMode(\PDO::FETCH_NUM); + $list = $stmt->fetchAll(); + return $list; + } + /** + * 获取全部表 + * @param string $dbName + * @return array + */ + private function get_dbname($dbName = '*') { + $sql = 'SHOW TABLES'; + $list = $this->query($sql); + $tables = array(); + foreach ($list as $value) + { + $tables[] = $value[0]; + } + return $tables; + } + /** + * 获取表定义语句 + * @param string $table + * @return mixed + */ + private function get_dbhead($table = '') + { + $sql = "SHOW CREATE TABLE `{$table}`"; + $ddl = $this->query($sql)[0][1] . ';'; + return $ddl; + } + /** + * 获取表数据 + * @param string $table + * @return mixed + */ + private function get_dbdata($table = '') + { + $sql = "SHOW COLUMNS FROM `{$table}`"; + $list = $this->query($sql); + //字段 + $columns = ''; + //需要返回的SQL + $query = ''; + foreach ($list as $value) + { + $columns .= "`{$value[0]}`,"; + } + $columns = substr($columns, 0, -1); + $data = $this->query("SELECT * FROM `{$table}`"); + foreach ($data as $value) + { + $dataSql = ''; + foreach ($value as $v) + { + $dataSql .= "'".addslashes($v)."',"; + } + $dataSql = substr($dataSql, 0, -1); + $query .= "INSERT INTO `{$table}` ({$columns}) VALUES ({$dataSql});\r\n"; + } + return $query; + } + /** + * 写入文件 + * @param array $tables + * @param array $ddl + * @param array $data + */ + private function writeToFile($tables = array(), $ddl = array(), $data = array()) + { + $str = "/*\r\nMySQL Database Backup Tools - NODCLOUD.COM\r\n"; + $str .= "Server:{$this->config['hostname']}:{$this->config['hostport']}\r\n"; + $str .= "Database:{$this->config['database']}\r\n"; + $str .= "Data:" . date('Y-m-d H:i:s', time()) . "\r\n*/\r\n"; + $str .= "SET NAMES utf8;\r\n"; + $str .= "SET FOREIGN_KEY_CHECKS=0;\r\n"; + $str .= "SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';\r\n"; + $i = 0; + foreach ($tables as $table) + { + $str .= "-- ----------------------------\r\n"; + $str .= "-- Table structure for {$table}\r\n"; + $str .= "-- ----------------------------\r\n"; + $str .= "DROP TABLE IF EXISTS `{$table}`;\r\n"; + $str .= $ddl[$i] . "\r\n"; + $str .= "-- ----------------------------\r\n"; + $str .= "-- Records of {$table}\r\n"; + $str .= "-- ----------------------------\r\n"; + $str .= $data[$i] . "\r\n"; + $i++; + } + if(!file_exists($this->config['path'])){mkdir($this->config['path']);} + return file_put_contents($this->config['path'].$this->config['sqlbakname'], $str) ? 'success' : 'error'; + } + /** + * 设置要备份的表 + * @param array $tables + */ + private function setTables($tables = array()) + { + if (!empty($tables) && is_array($tables)) + { + //备份指定表 + $this->tables = $tables; + } + else + { + //备份全部表 + $this->tables = $this->get_dbname(); + } + } + /** + * 备份 + * @param array $tables + * @return bool + */ + public function backup($tables = array()) + { + //存储表定义语句的数组 + $ddl = array(); + //存储数据的数组 + $data = array(); + $this->setTables($tables); + if (!empty($this->tables)) + { + foreach ($this->tables as $table) + { + $ddl[] = $this->get_dbhead($table); + $data[] = $this->get_dbdata($table); + } + + //开始写入 + return $this->writeToFile($this->tables, $ddl, $data); + } + else + { + $this->error = '数据库中没有表!'; + return false; + } + } + /** + * 错误信息 + * @return mixed + */ + public function getError() + { + return $this->error; + } + //还原数据库 + public function restore($filename = '') + { + $path=$this->config['path'].$filename; + if (!file_exists($path)) + { + $this->error('SQL文件不存在!'); + return false; + } + else + { + $sql = $this->parseSQL($path); + try + { + $this->handler->exec($sql); + return 'success'; + } + catch (PDOException $e) + { + $this->error = $e->getMessage(); + return false; + } + } + } + + /** + * 解析SQL文件为SQL语句数组 + * @param string $path + * @return array|mixed|string + */ + private function parseSQL($path = '') + { + $sql = file_get_contents($path); + $sql = explode("\r\n", $sql); + //先消除--注释 + $sql = array_filter($sql, function ($data) + { + if (empty($data) || preg_match('/^--.*/', $data)) + { + return false; + } + else + { + return true; + } + }); + $sql = implode('', $sql); + //删除/**/注释 + $sql = preg_replace('/\/\*.*\*\//', '', $sql); + return $sql; + } + /** + * 下载备份 + * @param string $fileName + * @return array|mixed|string + */ + public function downloadFile($fileName) { + $fileName=$this->config['path'].$fileName; + if (file_exists($fileName)){ + ob_end_clean(); + header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + header('Content-Length: ' . filesize($fileName)); + header('Content-Disposition: attachment; filename=' . basename($fileName)); + readfile($fileName); + }else{ + $this->error="文件有错误!"; + } + + } + /** + * 获取文件是时间 + * @param string $file + * @return string + */ + private function getfiletime($file){ + $path=$this->config['path'].$file; + $a = filemtime($path); + $time = date("Y-m-d H:i:s", $a); + return $time; + } + /** + * 获取文件是大小 + * @param string $file + * @return string + */ + private function getfilesize($file){ + $perms=stat($this->config['path'].$file); + $size = $perms['size']; + $a = ['B', 'KB', 'MB', 'GB', 'TB']; + $pos = 0; + while ($size >= 1024) { + $size /= 1024; + $pos++; + } + return round($size, 2). $a[$pos]; + } + + /** + * 获取文件列表 + * @param string $Order 级别 + * @return array + */ + public function get_filelist($Order = 0) { + $FilePath=$this->config['path']; + $FilePath = opendir($FilePath); + $FileAndFolderAyy=array(); + $i=1; + while (false !== ($filename = readdir($FilePath))) { + if ($filename!="." && $filename!=".."){ + $i++; + $FileAndFolderAyy[$i]['name'] = $filename; + $FileAndFolderAyy[$i]['time'] = $this->getfiletime($filename); + $FileAndFolderAyy[$i]['size'] = $this->getfilesize($filename); + } + } + $Order == 0 ? sort($FileAndFolderAyy) : rsort($FileAndFolderAyy); + return array_reverse($FileAndFolderAyy);//返回反转数组 + } + public function delfilename($filename){ + $path=$this->config['path'].$filename; + if (@unlink($path)) {return 'success';} + } +} +?> \ No newline at end of file diff --git a/serve/extend/org/Captcha.php b/serve/extend/org/Captcha.php new file mode 100644 index 0000000..d4e1b97 --- /dev/null +++ b/serve/extend/org/Captcha.php @@ -0,0 +1,139 @@ +join("",$code), + 'data'=>"data:image/png;base64,".base64_encode($imageData) + ]; + } + + /** + * 画一条由两条连在一起构成的随机正弦函数曲线作干扰线(你可以改成更帅的曲线函数) + * + * 高中的数学公式咋都忘了涅,写出来 + * 正弦型函数解析式:y=Asin(ωx+φ)+b + * 各常数值对函数图像的影响: + * A:决定峰值(即纵向拉伸压缩的倍数) + * b:表示波形在Y轴的位置关系或纵向移动距离(上加下减) + * φ:决定波形与X轴位置关系或横向移动距离(左加右减) + * ω:决定周期(最小正周期T=2π/∣ω∣) + * + */ + protected static function _writeCurve() { + $A = mt_rand(1, self::$imageH/2); // 振幅 + $b = mt_rand(-self::$imageH/4, self::$imageH/4); // Y轴方向偏移量 + $f = mt_rand(-self::$imageH/4, self::$imageH/4); // X轴方向偏移量 + $T = mt_rand(self::$imageH*1.5, self::$imageL*2); // 周期 + $w = (2* M_PI)/$T; + $px1 = 0; // 曲线横坐标起始位置 + $px2 = mt_rand(self::$imageL/2, self::$imageL * 0.667); // 曲线横坐标结束位置 + for ($px=$px1; $px<=$px2; $px=$px+ 0.9) { + if ($w!=0) { + $py = $A * sin($w*$px + $f)+ $b + self::$imageH/2; // y = Asin(ωx+φ) + b + $i = (int) ((self::$fontSize - 6)/4); + while ($i > 0) { + imagesetpixel(self::$_image, $px + $i, $py + $i, self::$_color); // 这里画像素点比imagettftext和imagestring性能要好很多 + $i--; + } + } + } + $A = mt_rand(1, self::$imageH/2); // 振幅 + $f = mt_rand(-self::$imageH/4, self::$imageH/4); // X轴方向偏移量 + $T = mt_rand(self::$imageH*1.5, self::$imageL*2); // 周期 + $w = (2* M_PI)/$T; + $b = $py - $A * sin($w*$px + $f) - self::$imageH/2; + $px1 = $px2; + $px2 = self::$imageL; + for ($px=$px1; $px<=$px2; $px=$px+ 0.9) { + if ($w!=0) { + $py = $A * sin($w*$px + $f)+ $b + self::$imageH/2; // y = Asin(ωx+φ) + b + $i = (int) ((self::$fontSize - 8)/4); + while ($i > 0) { + imagesetpixel(self::$_image, $px + $i, $py + $i, self::$_color); // 这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出(不用这while循环)性能要好很多 + $i--; + } + } + } + } + + /** + * 画杂点 + * 往图片上写不同颜色的字母或数字 + */ + protected static function _writeNoise() { + for($i = 0; $i < 10; $i++){ + //杂点颜色 + $noiseColor = imagecolorallocate( + self::$_image, + mt_rand(150,225), + mt_rand(150,225), + mt_rand(150,225) + ); + for($j = 0; $j < 5; $j++) { + // 绘杂点 + imagestring( + self::$_image, + 5, + mt_rand(-10, self::$imageL), + mt_rand(-10, self::$imageH), + self::$codeSet[mt_rand(0, 27)], // 杂点文本为随机的字母或数字 + $noiseColor + ); + } + } + } +} \ No newline at end of file diff --git a/serve/extend/org/Core.php b/serve/extend/org/Core.php new file mode 100644 index 0000000..e69de29 diff --git a/serve/extend/org/Math.php b/serve/extend/org/Math.php new file mode 100644 index 0000000..d521d4a --- /dev/null +++ b/serve/extend/org/Math.php @@ -0,0 +1,57 @@ +base=$number; + return $this; + } + //加法运算 + public function add($number) { + $this->base=bcadd($this->base,$number); + return $this; + } + //减法运算 + public function sub($number) { + $this->base=bcsub($this->base,$number); + return $this; + } + //乘法运算 + public function mul($number) { + $this->base=bcmul($this->base,$number); + return $this; + } + //除法运算 + public function div($number) { + $this->base=bcdiv($this->base,$number); + return $this; + } + //取余运算 + public function mod($number) { + $this->base=bcmod($this->base,$number); + return $this; + } + //四舍五入 + public function round($digit) { + $this->base=round($this->base,$digit); + return $this; + } + //四舍五入 + public function abs() { + $this->base=abs($this->base); + return $this; + } + //返回结果 + public function done() { + return floatval($this->base); + } +} diff --git a/serve/extend/org/Search.php b/serve/extend/org/Search.php new file mode 100644 index 0000000..80acc34 --- /dev/null +++ b/serve/extend/org/Search.php @@ -0,0 +1,90 @@ +source=$source; + return $this; + } + + //搜索条件 + //[['key|key1','=|<>|in|like|between','val']] + public function where($condition,$retain=false) { + $recode=[]; + foreach ($this->source as $sourcekey=>$sourceVo) { + $state=true; + foreach ($condition as $conditionVo){ + //处理多层键名 + $row=$this->arraySeek($sourceVo,$conditionVo[0]); + //条件判断 + if($conditionVo[1]=='='){ + //相等判断 + $row==$conditionVo[2]||($state=false); + }elseif($conditionVo[1]=='<>'){ + //不相等判断 + $row==$conditionVo[2]&&($state=false); + }elseif($conditionVo[1]=='in'){ + //包含判断 + in_array($row,$conditionVo[2])||($state=false); + }elseif($conditionVo[1]=='like'){ + //模糊匹配判断 + strstr($row,$conditionVo[2])==false&&($state=false); + }elseif($conditionVo[1]=='between'){ + //区间判断 + ($row>=$conditionVo[2][0] && $row<=$conditionVo[2][1])||($state=false); + }else{ + die('匹配规则失败!'); + } + } + if($state){ + $retain&&$sourceVo['rowKey']=$sourcekey; + $recode[]=$sourceVo; + } + } + $this->source=$recode; + return $this; + } + //处理数据 + public function loop($fun){ + foreach ($this->source as $key=>$vo) { + $this->source[$key]=$fun($vo,$key); + } + return $this; + } + + //单组数据 + public function find() { + return empty($this->source)?[]:$this->source[0]; + } + + //多组数据 + public function select() { + return $this->source; + } + + //数据统计 + public function count() { + return count($this->source); + } + + //多层键名匹配 + private function arraySeek($data,$rule){ + $recode=$data; + is_array($rule)||($rule=explode('|',$rule)); + foreach ($rule as $ruleVo) { + if(is_array($recode) && isset($recode[$ruleVo])){ + $recode=$recode[$ruleVo]; + }else{ + $recode=''; + break; + } + } + return $recode; + } +} diff --git a/serve/extend/org/Tree.php b/serve/extend/org/Tree.php new file mode 100644 index 0000000..89a9b7a --- /dev/null +++ b/serve/extend/org/Tree.php @@ -0,0 +1,40 @@ + &$v) { + if(!empty($v['sub'])){ + $v['sub']=self::sort($v['sub'],$cols); + } + $sort[$k]=$v[$cols]; + } + if(isset($sort)) + array_multisort($sort,SORT_ASC,$arr); + return $arr; + } + //横向分类树 + static public function hTree($arr,$pid=0){ + foreach($arr as $k => $v){ + if($v['pid']==$pid){ + $v['sub']=self::hTree($arr,$v['id']); + $data[]=$v; + } + } + return isset($data)?$data:[]; + } + //纵向分类树 + static public function vTree($arr,$pid=0,$state=true){ + static $data=[]; + $state&&$data=[]; + foreach($arr as $k => $v){ + if($v['pid']==$pid){ + $data[]=$v; + self::vTree($arr,$v['id'],false); + } + } + return $data; + } +} \ No newline at end of file diff --git a/serve/extend/org/ZhToPy.php b/serve/extend/org/ZhToPy.php new file mode 100644 index 0000000..276e5e8 --- /dev/null +++ b/serve/extend/org/ZhToPy.php @@ -0,0 +1,50 @@ +'yi','乁'=>'yi','乂'=>'yi','义'=>'yi','乙'=>'yi','亄'=>'yi','亦'=>'yi','亿'=>'yi','仡'=>'yi','以'=>'yi','仪'=>'yi','伇'=>'yi','伊'=>'yi','伿'=>'yi','佁'=>'yi','佚'=>'yi','佾'=>'yi','侇'=>'yi','依'=>'yi','俋'=>'yi','倚'=>'yi','偯'=>'yi','儀'=>'yi','億'=>'yi','兿'=>'yi','冝'=>'yi','刈'=>'yi','劓'=>'yi','劮'=>'yi','勚'=>'yi','勩'=>'yi','匇'=>'yi','匜'=>'yi','医'=>'yi','吚'=>'yi','呓'=>'yi','呭'=>'yi','呹'=>'yi','咦'=>'yi','咿'=>'yi','唈'=>'yi','噫'=>'yi','囈'=>'yi','圛'=>'yi','圯'=>'yi','坄'=>'yi','垼'=>'yi','埶'=>'yi','埸'=>'yi','墿'=>'yi','壱'=>'yi','壹'=>'yi','夁'=>'yi','夷'=>'yi','奕'=>'yi','妷'=>'yi','姨'=>'yi','媐'=>'yi','嫕'=>'yi','嫛'=>'yi','嬄'=>'yi','嬑'=>'yi','嬟'=>'yi','宐'=>'yi','宜'=>'yi','宧'=>'yi','寱'=>'yi','寲'=>'yi','屹'=>'yi','峄'=>'yi','峓'=>'yi','崺'=>'yi','嶧'=>'yi','嶬'=>'yi','嶷'=>'yi','已'=>'yi','巸'=>'yi','帟'=>'yi','帠'=>'yi','幆'=>'yi','庡'=>'yi','廙'=>'yi','异'=>'yi','弈'=>'yi','弋'=>'yi','弌'=>'yi','弬'=>'yi','彛'=>'yi','彜'=>'yi','彝'=>'yi','彞'=>'yi','役'=>'yi','忆'=>'yi','忔'=>'yi','怈'=>'yi','怡'=>'yi','怿'=>'yi','恞'=>'yi','悒'=>'yi','悘'=>'yi','悥'=>'yi','意'=>'yi','憶'=>'yi','懌'=>'yi','懿'=>'yi','扅'=>'yi','扆'=>'yi','抑'=>'yi','挹'=>'yi','揖'=>'yi','撎'=>'yi','攺'=>'yi','敡'=>'yi','敼'=>'yi','斁'=>'yi','旑'=>'yi','旖'=>'yi','易'=>'yi','晹'=>'yi','暆'=>'yi','曀'=>'yi','曎'=>'yi','曵'=>'yi','杙'=>'yi','杝'=>'yi','枍'=>'yi','枻'=>'yi','柂'=>'yi','栘'=>'yi','栧'=>'yi','栺'=>'yi','桋'=>'yi','棭'=>'yi','椅'=>'yi','椬'=>'yi','椸'=>'yi','榏'=>'yi','槸'=>'yi','檍'=>'yi','檥'=>'yi','檹'=>'yi','欭'=>'yi','欹'=>'yi','歝'=>'yi','殔'=>'yi','殪'=>'yi','殹'=>'yi','毅'=>'yi','毉'=>'yi','沂'=>'yi','沶'=>'yi','泆'=>'yi','洢'=>'yi','浂'=>'yi','浥'=>'yi','浳'=>'yi','湙'=>'yi','溢'=>'yi','漪'=>'yi','潩'=>'yi','澺'=>'yi','瀷'=>'yi','炈'=>'yi','焲'=>'yi','熠'=>'yi','熤'=>'yi','熪'=>'yi','熼'=>'yi','燚'=>'yi','燡'=>'yi','燱'=>'yi','狋'=>'yi','猗'=>'yi','獈'=>'yi','玴'=>'yi','瑿'=>'yi','瓵'=>'yi','畩'=>'yi','異'=>'yi','疑'=>'yi','疫'=>'yi','痍'=>'yi','痬'=>'yi','瘗'=>'yi','瘞'=>'yi','瘱'=>'yi','癔'=>'yi','益'=>'yi','眙'=>'yi','瞖'=>'yi','矣'=>'yi','礒'=>'yi','祎'=>'yi','禕'=>'yi','秇'=>'yi','移'=>'yi','稦'=>'yi','穓'=>'yi','竩'=>'yi','笖'=>'yi','簃'=>'yi','籎'=>'yi','縊'=>'yi','繄'=>'yi','繶'=>'yi','繹'=>'yi','绎'=>'yi','缢'=>'yi','羛'=>'yi','羠'=>'yi','義'=>'yi','羿'=>'yi','翊'=>'yi','翌'=>'yi','翳'=>'yi','翼'=>'yi','耴'=>'yi','肄'=>'yi','肊'=>'yi','胰'=>'yi','膉'=>'yi','臆'=>'yi','舣'=>'yi','艗'=>'yi','艤'=>'yi','艺'=>'yi','芅'=>'yi','苅'=>'yi','苡'=>'yi','苢'=>'yi','荑'=>'yi','萓'=>'yi','萟'=>'yi','蓺'=>'yi','薏'=>'yi','藙'=>'yi','藝'=>'yi','蘙'=>'yi','虉'=>'yi','蚁'=>'yi','蛜'=>'yi','蛡'=>'yi','蛦'=>'yi','蜴'=>'yi','螔'=>'yi','螘'=>'yi','螠'=>'yi','蟻'=>'yi','衣'=>'yi','衤'=>'yi','衪'=>'yi','衵'=>'yi','袘'=>'yi','袣'=>'yi','裔'=>'yi','裛'=>'yi','褹'=>'yi','襼'=>'yi','觺'=>'yi','訲'=>'yi','訳'=>'yi','詍'=>'yi','詒'=>'yi','詣'=>'yi','誃'=>'yi','誼'=>'yi','謻'=>'yi','譩'=>'yi','譯'=>'yi','議'=>'yi','讉'=>'yi','讛'=>'yi','议'=>'yi','译'=>'yi','诒'=>'yi','诣'=>'yi','谊'=>'yi','豙'=>'yi','豛'=>'yi','豷'=>'yi','貖'=>'yi','貤'=>'yi','貽'=>'yi','贀'=>'yi','贻'=>'yi','跇'=>'yi','跠'=>'yi','軼'=>'yi','輢'=>'yi','轙'=>'yi','轶'=>'yi','辷'=>'yi','迆'=>'yi','迤'=>'yi','迻'=>'yi','逘'=>'yi','逸'=>'yi','遗'=>'yi','遺'=>'yi','邑'=>'yi','郼'=>'yi','酏'=>'yi','醫'=>'yi','醳'=>'yi','醷'=>'yi','釔'=>'yi','釴'=>'yi','鈘'=>'yi','鈠'=>'yi','鉯'=>'yi','銥'=>'yi','鎰'=>'yi','鏔'=>'yi','鐿'=>'yi','钇'=>'yi','铱'=>'yi','镒'=>'yi','镱'=>'yi','阣'=>'yi','陭'=>'yi','隿'=>'yi','霬'=>'yi','靾'=>'yi','頉'=>'yi','頤'=>'yi','頥'=>'yi','顊'=>'yi','顗'=>'yi','颐'=>'yi','飴'=>'yi','饐'=>'yi','饴'=>'yi','駅'=>'yi','驛'=>'yi','驿'=>'yi','骮'=>'yi','鮧'=>'yi','鮨'=>'yi','鯣'=>'yi','鳦'=>'yi','鶂'=>'yi','鶃'=>'yi','鶍'=>'yi','鷁'=>'yi','鷊'=>'yi','鷖'=>'yi','鷧'=>'yi','鷾'=>'yi','鸃'=>'yi','鹝'=>'yi','鹢'=>'yi','鹥'=>'yi','黓'=>'yi','黟'=>'yi','黳'=>'yi','齮'=>'yi','齸'=>'yi','㐹'=>'yi','㑊'=>'yi','㑜'=>'yi','㑥'=>'yi','㓷'=>'yi','㔴'=>'yi','㕥'=>'yi','㖂'=>'yi','㘁'=>'yi','㘈'=>'yi','㘊'=>'yi','㘦'=>'yi','㙠'=>'yi','㙯'=>'yi','㚤'=>'yi','㚦'=>'yi','㛕'=>'yi','㜋'=>'yi','㜒'=>'yi','㝖'=>'yi','㞔'=>'yi','㠯'=>'yi','㡫'=>'yi','㡼'=>'yi','㢞'=>'yi','㣂'=>'yi','㣻'=>'yi','㥴'=>'yi','㦉'=>'yi','㦤'=>'yi','㦾'=>'yi','㩘'=>'yi','㫊'=>'yi','㰘'=>'yi','㰝'=>'yi','㰻'=>'yi','㱅'=>'yi','㱲'=>'yi','㲼'=>'yi','㳑'=>'yi','㴁'=>'yi','㴒'=>'yi','㵝'=>'yi','㵩'=>'yi','㶠'=>'yi','㹓'=>'yi','㹭'=>'yi','㺿'=>'yi','㽈'=>'yi','䄁'=>'yi','䄬'=>'yi','䄿'=>'yi','䆿'=>'yi','䇩'=>'yi','䇵'=>'yi','䉨'=>'yi','䋚'=>'yi','䋵'=>'yi','䌻'=>'yi','䎈'=>'yi','䐅'=>'yi','䐖'=>'yi','䓃'=>'yi','䓈'=>'yi','䓹'=>'yi','䔬'=>'yi','䕍'=>'yi','䖁'=>'yi','䖊'=>'yi','䗑'=>'yi','䗟'=>'yi','䗷'=>'yi','䘝'=>'yi','䘸'=>'yi','䝘'=>'yi','䝝'=>'yi','䝯'=>'yi','䞅'=>'yi','䢃'=>'yi','䣧'=>'yi','䦴'=>'yi','䧧'=>'yi','䩟'=>'yi','䬁'=>'yi','䬥'=>'yi','䬮'=>'yi','䭂'=>'yi','䭇'=>'yi','䭞'=>'yi','䭿'=>'yi','䮊'=>'yi','䯆'=>'yi','䰙'=>'yi','䱌'=>'yi','䱒'=>'yi','䲑'=>'yi','䴊'=>'yi','䴬'=>'yi','丁'=>'ding','仃'=>'ding','叮'=>'ding','啶'=>'ding','奵'=>'ding','定'=>'ding','嵿'=>'ding','帄'=>'ding','忊'=>'ding','椗'=>'ding','玎'=>'ding','甼'=>'ding','疔'=>'ding','盯'=>'ding','矴'=>'ding','碇'=>'ding','碠'=>'ding','磸'=>'ding','耵'=>'ding','聢'=>'ding','聣'=>'ding','腚'=>'ding','萣'=>'ding','薡'=>'ding','訂'=>'ding','订'=>'ding','酊'=>'ding','釘'=>'ding','錠'=>'ding','鐤'=>'ding','钉'=>'ding','锭'=>'ding','靪'=>'ding','頂'=>'ding','顁'=>'ding','顶'=>'ding','飣'=>'ding','饤'=>'ding','鼎'=>'ding','鼑'=>'ding','㝎'=>'ding','㫀'=>'ding','㴿'=>'ding','㼗'=>'ding','丂'=>'kao','尻'=>'kao','拷'=>'kao','攷'=>'kao','栲'=>'kao','洘'=>'kao','烤'=>'kao','犒'=>'kao','考'=>'kao','銬'=>'kao','铐'=>'kao','靠'=>'kao','髛'=>'kao','鮳'=>'kao','鯌'=>'kao','鲓'=>'kao','䐧'=>'kao','䯪'=>'kao','七'=>'qi','乞'=>'qi','亓'=>'qi','亝'=>'qi','企'=>'qi','倛'=>'qi','僛'=>'qi','其'=>'qi','凄'=>'qi','剘'=>'qi','启'=>'qi','呇'=>'qi','呮'=>'qi','咠'=>'qi','唘'=>'qi','唭'=>'qi','啓'=>'qi','啔'=>'qi','啟'=>'qi','嘁'=>'qi','噐'=>'qi','器'=>'qi','圻'=>'qi','埼'=>'qi','夡'=>'qi','奇'=>'qi','契'=>'qi','妻'=>'qi','娸'=>'qi','婍'=>'qi','屺'=>'qi','岂'=>'qi','岐'=>'qi','岓'=>'qi','崎'=>'qi','嵜'=>'qi','帺'=>'qi','弃'=>'qi','忯'=>'qi','恓'=>'qi','悽'=>'qi','愒'=>'qi','愭'=>'qi','慼'=>'qi','慽'=>'qi','憇'=>'qi','憩'=>'qi','懠'=>'qi','戚'=>'qi','捿'=>'qi','掑'=>'qi','摖'=>'qi','斉'=>'qi','斊'=>'qi','旂'=>'qi','旗'=>'qi','晵'=>'qi','暣'=>'qi','朞'=>'qi','期'=>'qi','杞'=>'qi','柒'=>'qi','栔'=>'qi','栖'=>'qi','桤'=>'qi','桼'=>'qi','棄'=>'qi','棊'=>'qi','棋'=>'qi','棨'=>'qi','棲'=>'qi','榿'=>'qi','槭'=>'qi','檱'=>'qi','櫀'=>'qi','欫'=>'qi','欺'=>'qi','歧'=>'qi','气'=>'qi','気'=>'qi','氣'=>'qi','汔'=>'qi','汽'=>'qi','沏'=>'qi','泣'=>'qi','淇'=>'qi','淒'=>'qi','渏'=>'qi','湆'=>'qi','湇'=>'qi','漆'=>'qi','濝'=>'qi','炁'=>'qi','猉'=>'qi','玂'=>'qi','玘'=>'qi','琦'=>'qi','琪'=>'qi','璂'=>'qi','甈'=>'qi','畦'=>'qi','疧'=>'qi','盀'=>'qi','盵'=>'qi','矵'=>'qi','砌'=>'qi','碁'=>'qi','碕'=>'qi','碛'=>'qi','碶'=>'qi','磎'=>'qi','磜'=>'qi','磧'=>'qi','磩'=>'qi','礘'=>'qi','祁'=>'qi','祇'=>'qi','祈'=>'qi','祺'=>'qi','禥'=>'qi','竒'=>'qi','簯'=>'qi','簱'=>'qi','籏'=>'qi','粸'=>'qi','紪'=>'qi','綥'=>'qi','綦'=>'qi','綨'=>'qi','綮'=>'qi','綺'=>'qi','緀'=>'qi','緕'=>'qi','纃'=>'qi','绮'=>'qi','缼'=>'qi','罊'=>'qi','耆'=>'qi','肵'=>'qi','脐'=>'qi','臍'=>'qi','艩'=>'qi','芑'=>'qi','芞'=>'qi','芪'=>'qi','荠'=>'qi','萁'=>'qi','萋'=>'qi','葺'=>'qi','蕲'=>'qi','薺'=>'qi','藄'=>'qi','蘄'=>'qi','蚑'=>'qi','蚔'=>'qi','蚚'=>'qi','蛴'=>'qi','蜝'=>'qi','蜞'=>'qi','螧'=>'qi','蟿'=>'qi','蠐'=>'qi','裿'=>'qi','褀'=>'qi','褄'=>'qi','訖'=>'qi','諆'=>'qi','諬'=>'qi','諿'=>'qi','讫'=>'qi','豈'=>'qi','起'=>'qi','跂'=>'qi','踑'=>'qi','踦'=>'qi','蹊'=>'qi','軝'=>'qi','迄'=>'qi','迉'=>'qi','邔'=>'qi','郪'=>'qi','釮'=>'qi','錡'=>'qi','鏚'=>'qi','锜'=>'qi','闙'=>'qi','霋'=>'qi','頎'=>'qi','颀'=>'qi','騎'=>'qi','騏'=>'qi','騹'=>'qi','骐'=>'qi','骑'=>'qi','鬐'=>'qi','鬾'=>'qi','鬿'=>'qi','魌'=>'qi','魕'=>'qi','鯕'=>'qi','鰭'=>'qi','鲯'=>'qi','鳍'=>'qi','鵸'=>'qi','鶀'=>'qi','鶈'=>'qi','麒'=>'qi','麡'=>'qi','齊'=>'qi','齐'=>'qi','㒅'=>'qi','㓞'=>'qi','㜎'=>'qi','㞓'=>'qi','㞚'=>'qi','㟓'=>'qi','㟚'=>'qi','㟢'=>'qi','㣬'=>'qi','㥓'=>'qi','㩩'=>'qi','㩽'=>'qi','㫓'=>'qi','㮑'=>'qi','㯦'=>'qi','㼤'=>'qi','㾨'=>'qi','䀈'=>'qi','䀙'=>'qi','䁈'=>'qi','䁉'=>'qi','䄎'=>'qi','䄢'=>'qi','䄫'=>'qi','䅤'=>'qi','䅲'=>'qi','䉝'=>'qi','䉻'=>'qi','䋯'=>'qi','䌌'=>'qi','䎢'=>'qi','䏅'=>'qi','䏌'=>'qi','䏠'=>'qi','䏿'=>'qi','䐡'=>'qi','䑴'=>'qi','䒗'=>'qi','䒻'=>'qi','䓅'=>'qi','䔇'=>'qi','䙄'=>'qi','䚉'=>'qi','䚍'=>'qi','䛴'=>'qi','䞚'=>'qi','䟄'=>'qi','䟚'=>'qi','䡋'=>'qi','䡔'=>'qi','䢀'=>'qi','䧘'=>'qi','䧵'=>'qi','䩓'=>'qi','䫔'=>'qi','䬣'=>'qi','䭫'=>'qi','䭬'=>'qi','䭶'=>'qi','䭼'=>'qi','䰇'=>'qi','䰴'=>'qi','䱈'=>'qi','䲬'=>'qi','䳢'=>'qi','䶒'=>'qi','䶞'=>'qi','丄'=>'shang','上'=>'shang','仩'=>'shang','伤'=>'shang','傷'=>'shang','商'=>'shang','垧'=>'shang','墒'=>'shang','尙'=>'shang','尚'=>'shang','恦'=>'shang','愓'=>'shang','慯'=>'shang','扄'=>'shang','晌'=>'shang','殇'=>'shang','殤'=>'shang','滳'=>'shang','漡'=>'shang','熵'=>'shang','緔'=>'shang','绱'=>'shang','蔏'=>'shang','螪'=>'shang','裳'=>'shang','觞'=>'shang','觴'=>'shang','謪'=>'shang','賞'=>'shang','赏'=>'shang','鑜'=>'shang','鬺'=>'shang','䬕'=>'shang','丅'=>'xia','下'=>'xia','侠'=>'xia','俠'=>'xia','傄'=>'xia','匣'=>'xia','厦'=>'xia','吓'=>'xia','呷'=>'xia','嚇'=>'xia','圷'=>'xia','夏'=>'xia','夓'=>'xia','峡'=>'xia','峽'=>'xia','廈'=>'xia','懗'=>'xia','搳'=>'xia','敮'=>'xia','暇'=>'xia','柙'=>'xia','梺'=>'xia','溊'=>'xia','炠'=>'xia','烚'=>'xia','煆'=>'xia','狎'=>'xia','狭'=>'xia','狹'=>'xia','珨'=>'xia','瑕'=>'xia','疜'=>'xia','疨'=>'xia','睱'=>'xia','瞎'=>'xia','硖'=>'xia','硤'=>'xia','碬'=>'xia','磍'=>'xia','祫'=>'xia','笚'=>'xia','筪'=>'xia','縀'=>'xia','縖'=>'xia','罅'=>'xia','翈'=>'xia','舝'=>'xia','舺'=>'xia','蕸'=>'xia','虾'=>'xia','蝦'=>'xia','諕'=>'xia','谺'=>'xia','赮'=>'xia','轄'=>'xia','辖'=>'xia','遐'=>'xia','鍜'=>'xia','鎋'=>'xia','鏬'=>'xia','閕'=>'xia','閜'=>'xia','陜'=>'xia','陿'=>'xia','霞'=>'xia','颬'=>'xia','騢'=>'xia','魻'=>'xia','鰕'=>'xia','鶷'=>'xia','黠'=>'xia','㗇'=>'xia','㗿'=>'xia','㘡'=>'xia','㙤'=>'xia','㰺'=>'xia','㽠'=>'xia','䖎'=>'xia','䖖'=>'xia','䘥'=>'xia','䛅'=>'xia','䦖'=>'xia','䪗'=>'xia','䫗'=>'xia','丆'=>'mu','亩'=>'mu','仫'=>'mu','凩'=>'mu','募'=>'mu','坶'=>'mu','墓'=>'mu','墲'=>'mu','姆'=>'mu','娒'=>'mu','峔'=>'mu','幕'=>'mu','幙'=>'mu','慔'=>'mu','慕'=>'mu','拇'=>'mu','旀'=>'mu','暮'=>'mu','木'=>'mu','椧'=>'mu','楘'=>'mu','樢'=>'mu','母'=>'mu','毣'=>'mu','毪'=>'mu','氁'=>'mu','沐'=>'mu','炑'=>'mu','牡'=>'mu','牧'=>'mu','牳'=>'mu','狇'=>'mu','獏'=>'mu','畆'=>'mu','畒'=>'mu','畝'=>'mu','畞'=>'mu','畮'=>'mu','目'=>'mu','睦'=>'mu','砪'=>'mu','穆'=>'mu','胟'=>'mu','艒'=>'mu','苜'=>'mu','莯'=>'mu','萺'=>'mu','蚞'=>'mu','踇'=>'mu','鉧'=>'mu','鉬'=>'mu','钼'=>'mu','雮'=>'mu','霂'=>'mu','鞪'=>'mu','㒇'=>'mu','㜈'=>'mu','㣎'=>'mu','㧅'=>'mu','㾇'=>'mu','䀲'=>'mu','䊾'=>'mu','䑵'=>'mu','䥈'=>'mu','䧔'=>'mu','䱯'=>'mu','万'=>'wan','丸'=>'wan','乛'=>'wan','倇'=>'wan','刓'=>'wan','剜'=>'wan','卍'=>'wan','卐'=>'wan','唍'=>'wan','埦'=>'wan','塆'=>'wan','壪'=>'wan','妧'=>'wan','婉'=>'wan','婠'=>'wan','完'=>'wan','宛'=>'wan','岏'=>'wan','帵'=>'wan','弯'=>'wan','彎'=>'wan','忨'=>'wan','惋'=>'wan','抏'=>'wan','挽'=>'wan','捖'=>'wan','捥'=>'wan','晚'=>'wan','晩'=>'wan','晼'=>'wan','杤'=>'wan','梚'=>'wan','椀'=>'wan','汍'=>'wan','涴'=>'wan','湾'=>'wan','潫'=>'wan','灣'=>'wan','烷'=>'wan','玩'=>'wan','琓'=>'wan','琬'=>'wan','畹'=>'wan','皖'=>'wan','盌'=>'wan','睕'=>'wan','碗'=>'wan','笂'=>'wan','紈'=>'wan','綩'=>'wan','綰'=>'wan','纨'=>'wan','绾'=>'wan','翫'=>'wan','脘'=>'wan','腕'=>'wan','芄'=>'wan','莞'=>'wan','菀'=>'wan','萬'=>'wan','薍'=>'wan','蜿'=>'wan','豌'=>'wan','貦'=>'wan','贃'=>'wan','贎'=>'wan','踠'=>'wan','輓'=>'wan','邜'=>'wan','鋄'=>'wan','鋔'=>'wan','錽'=>'wan','鍐'=>'wan','鎫'=>'wan','頑'=>'wan','顽'=>'wan','㜶'=>'wan','㝴'=>'wan','㸘'=>'wan','㽜'=>'wan','㿸'=>'wan','䂺'=>'wan','䅋'=>'wan','䖤'=>'wan','䗕'=>'wan','䘼'=>'wan','䛷'=>'wan','䝹'=>'wan','䥑'=>'wan','䩊'=>'wan','䯈'=>'wan','䳃'=>'wan','丈'=>'zhang','仉'=>'zhang','仗'=>'zhang','傽'=>'zhang','墇'=>'zhang','嫜'=>'zhang','嶂'=>'zhang','帐'=>'zhang','帳'=>'zhang','幛'=>'zhang','幥'=>'zhang','张'=>'zhang','弡'=>'zhang','張'=>'zhang','彰'=>'zhang','慞'=>'zhang','扙'=>'zhang','掌'=>'zhang','暲'=>'zhang','杖'=>'zhang','樟'=>'zhang','涨'=>'zhang','涱'=>'zhang','漲'=>'zhang','漳'=>'zhang','獐'=>'zhang','璋'=>'zhang','痮'=>'zhang','瘬'=>'zhang','瘴'=>'zhang','瞕'=>'zhang','礃'=>'zhang','章'=>'zhang','粀'=>'zhang','粻'=>'zhang','胀'=>'zhang','脹'=>'zhang','蔁'=>'zhang','蟑'=>'zhang','賬'=>'zhang','账'=>'zhang','遧'=>'zhang','鄣'=>'zhang','鏱'=>'zhang','鐣'=>'zhang','障'=>'zhang','鞝'=>'zhang','餦'=>'zhang','騿'=>'zhang','鱆'=>'zhang','麞'=>'zhang','㕩'=>'zhang','㙣'=>'zhang','㽴'=>'zhang','䍤'=>'zhang','三'=>'san','伞'=>'san','俕'=>'san','傘'=>'san','厁'=>'san','叁'=>'san','壭'=>'san','弎'=>'san','散'=>'san','橵'=>'san','毵'=>'san','毶'=>'san','毿'=>'san','犙'=>'san','糁'=>'san','糂'=>'san','糝'=>'san','糣'=>'san','糤'=>'san','繖'=>'san','鏒'=>'san','閐'=>'san','饊'=>'san','馓'=>'san','鬖'=>'san','㤾'=>'san','㧲'=>'san','㪔'=>'san','㪚'=>'san','䀐'=>'san','䉈'=>'san','䊉'=>'san','䫅'=>'san','䫩'=>'san',''=>'','丌'=>'ji','丮'=>'ji','乩'=>'ji','亟'=>'ji','亼'=>'ji','伋'=>'ji','伎'=>'ji','佶'=>'ji','偈'=>'ji','偮'=>'ji','僟'=>'ji','兾'=>'ji','冀'=>'ji','几'=>'ji','击'=>'ji','刉'=>'ji','刏'=>'ji','剂'=>'ji','剞'=>'ji','剤'=>'ji','劑'=>'ji','勣'=>'ji','卙'=>'ji','即'=>'ji','卽'=>'ji','及'=>'ji','叝'=>'ji','叽'=>'ji','吉'=>'ji','咭'=>'ji','哜'=>'ji','唧'=>'ji','喞'=>'ji','嗘'=>'ji','嘰'=>'ji','嚌'=>'ji','圾'=>'ji','坖'=>'ji','垍'=>'ji','基'=>'ji','塉'=>'ji','墍'=>'ji','墼'=>'ji','妀'=>'ji','妓'=>'ji','姞'=>'ji','姬'=>'ji','嫉'=>'ji','季'=>'ji','寂'=>'ji','寄'=>'ji','屐'=>'ji','岌'=>'ji','峜'=>'ji','嵆'=>'ji','嵇'=>'ji','嵴'=>'ji','嶯'=>'ji','己'=>'ji','幾'=>'ji','庴'=>'ji','廭'=>'ji','彐'=>'ji','彑'=>'ji','彶'=>'ji','徛'=>'ji','忌'=>'ji','忣'=>'ji','急'=>'ji','悸'=>'ji','惎'=>'ji','愱'=>'ji','憿'=>'ji','懻'=>'ji','戟'=>'ji','戢'=>'ji','技'=>'ji','挤'=>'ji','掎'=>'ji','揤'=>'ji','撃'=>'ji','撠'=>'ji','擊'=>'ji','擠'=>'ji','攲'=>'ji','敧'=>'ji','旡'=>'ji','既'=>'ji','旣'=>'ji','暨'=>'ji','暩'=>'ji','曁'=>'ji','机'=>'ji','极'=>'ji','枅'=>'ji','梞'=>'ji','棘'=>'ji','楖'=>'ji','楫'=>'ji','極'=>'ji','槉'=>'ji','槣'=>'ji','樭'=>'ji','機'=>'ji','橶'=>'ji','檕'=>'ji','檝'=>'ji','檵'=>'ji','櫅'=>'ji','殛'=>'ji','毄'=>'ji','汲'=>'ji','泲'=>'ji','洎'=>'ji','济'=>'ji','済'=>'ji','湒'=>'ji','漃'=>'ji','漈'=>'ji','潗'=>'ji','激'=>'ji','濈'=>'ji','濟'=>'ji','瀱'=>'ji','焏'=>'ji','犄'=>'ji','犱'=>'ji','狤'=>'ji','玑'=>'ji','璣'=>'ji','璾'=>'ji','畸'=>'ji','畿'=>'ji','疾'=>'ji','痵'=>'ji','瘠'=>'ji','癠'=>'ji','癪'=>'ji','皍'=>'ji','矶'=>'ji','磯'=>'ji','祭'=>'ji','禝'=>'ji','禨'=>'ji','积'=>'ji','稘'=>'ji','稩'=>'ji','稷'=>'ji','稽'=>'ji','穄'=>'ji','穊'=>'ji','積'=>'ji','穖'=>'ji','穧'=>'ji','笄'=>'ji','笈'=>'ji','筓'=>'ji','箕'=>'ji','箿'=>'ji','簊'=>'ji','籍'=>'ji','糭'=>'ji','紀'=>'ji','紒'=>'ji','級'=>'ji','継'=>'ji','緝'=>'ji','縘'=>'ji','績'=>'ji','繋'=>'ji','繫'=>'ji','繼'=>'ji','级'=>'ji','纪'=>'ji','继'=>'ji','绩'=>'ji','缉'=>'ji','罽'=>'ji','羁'=>'ji','羇'=>'ji','羈'=>'ji','耤'=>'ji','耭'=>'ji','肌'=>'ji','脊'=>'ji','脨'=>'ji','膌'=>'ji','臮'=>'ji','艥'=>'ji','芨'=>'ji','芰'=>'ji','芶'=>'ji','茍'=>'ji','萕'=>'ji','葪'=>'ji','蒺'=>'ji','蓟'=>'ji','蔇'=>'ji','蕀'=>'ji','蕺'=>'ji','薊'=>'ji','蘎'=>'ji','蘮'=>'ji','蘻'=>'ji','虀'=>'ji','虮'=>'ji','蝍'=>'ji','螏'=>'ji','蟣'=>'ji','裚'=>'ji','襀'=>'ji','襋'=>'ji','覉'=>'ji','覊'=>'ji','覬'=>'ji','觊'=>'ji','觙'=>'ji','觭'=>'ji','計'=>'ji','記'=>'ji','誋'=>'ji','諅'=>'ji','譏'=>'ji','譤'=>'ji','计'=>'ji','讥'=>'ji','记'=>'ji','谻'=>'ji','賫'=>'ji','賷'=>'ji','赍'=>'ji','趌'=>'ji','跡'=>'ji','跻'=>'ji','跽'=>'ji','踖'=>'ji','蹐'=>'ji','蹟'=>'ji','躋'=>'ji','躤'=>'ji','躸'=>'ji','輯'=>'ji','轚'=>'ji','辑'=>'ji','迹'=>'ji','郆'=>'ji','鄿'=>'ji','銈'=>'ji','銡'=>'ji','錤'=>'ji','鍓'=>'ji','鏶'=>'ji','鐖'=>'ji','鑇'=>'ji','鑙'=>'ji','际'=>'ji','際'=>'ji','隮'=>'ji','集'=>'ji','雞'=>'ji','雦'=>'ji','雧'=>'ji','霁'=>'ji','霵'=>'ji','霽'=>'ji','鞊'=>'ji','鞿'=>'ji','韲'=>'ji','飢'=>'ji','饑'=>'ji','饥'=>'ji','驥'=>'ji','骥'=>'ji','髻'=>'ji','魢'=>'ji','鮆'=>'ji','鯚'=>'ji','鯽'=>'ji','鰶'=>'ji','鰿'=>'ji','鱀'=>'ji','鱭'=>'ji','鱾'=>'ji','鲚'=>'ji','鲫'=>'ji','鳮'=>'ji','鵋'=>'ji','鶏'=>'ji','鶺'=>'ji','鷄'=>'ji','鷑'=>'ji','鸄'=>'ji','鸡'=>'ji','鹡'=>'ji','麂'=>'ji','齌'=>'ji','齎'=>'ji','齏'=>'ji','齑'=>'ji','㑧'=>'ji','㒫'=>'ji','㔕'=>'ji','㖢'=>'ji','㗊'=>'ji','㗱'=>'ji','㘍'=>'ji','㙨'=>'ji','㙫'=>'ji','㚡'=>'ji','㞃'=>'ji','㞆'=>'ji','㞛'=>'ji','㞦'=>'ji','㠍'=>'ji','㠎'=>'ji','㠖'=>'ji','㠱'=>'ji','㡇'=>'ji','㡭'=>'ji','㡮'=>'ji','㡶'=>'ji','㤂'=>'ji','㥍'=>'ji','㥛'=>'ji','㦸'=>'ji','㧀'=>'ji','㨈'=>'ji','㪠'=>'ji','㭰'=>'ji','㭲'=>'ji','㮟'=>'ji','㮨'=>'ji','㰟'=>'ji','㱞'=>'ji','㲅'=>'ji','㲺'=>'ji','㳵'=>'ji','㴉'=>'ji','㴕'=>'ji','㸄'=>'ji','㹄'=>'ji','㻑'=>'ji','㻷'=>'ji','㽺'=>'ji','㾊'=>'ji','㾒'=>'ji','㾵'=>'ji','䁒'=>'ji','䋟'=>'ji','䐀'=>'ji','䐕'=>'ji','䐚'=>'ji','䒁'=>'ji','䓫'=>'ji','䓽'=>'ji','䗁'=>'ji','䚐'=>'ji','䜞'=>'ji','䝸'=>'ji','䞘'=>'ji','䟌'=>'ji','䠏'=>'ji','䢋'=>'ji','䢳'=>'ji','䣢'=>'ji','䤒'=>'ji','䤠'=>'ji','䦇'=>'ji','䨖'=>'ji','䩯'=>'ji','䮺'=>'ji','䯂'=>'ji','䰏'=>'ji','䲯'=>'ji','䳭'=>'ji','䶓'=>'ji','䶩'=>'ji','不'=>'bu','佈'=>'bu','勏'=>'bu','卟'=>'bu','吥'=>'bu','咘'=>'bu','哺'=>'bu','埗'=>'bu','埠'=>'bu','峬'=>'bu','布'=>'bu','庯'=>'bu','廍'=>'bu','怖'=>'bu','悑'=>'bu','捗'=>'bu','晡'=>'bu','步'=>'bu','歨'=>'bu','歩'=>'bu','獛'=>'bu','瓿'=>'bu','篰'=>'bu','簿'=>'bu','荹'=>'bu','蔀'=>'bu','补'=>'bu','補'=>'bu','誧'=>'bu','踄'=>'bu','轐'=>'bu','逋'=>'bu','部'=>'bu','郶'=>'bu','醭'=>'bu','鈈'=>'bu','鈽'=>'bu','钚'=>'bu','钸'=>'bu','餔'=>'bu','餢'=>'bu','鳪'=>'bu','鵏'=>'bu','鸔'=>'bu','㘵'=>'bu','㙛'=>'bu','㚴'=>'bu','㨐'=>'bu','㳍'=>'bu','㻉'=>'bu','㾟'=>'bu','䀯'=>'bu','䊇'=>'bu','䋠'=>'bu','䍌'=>'bu','䏽'=>'bu','䑰'=>'bu','䒈'=>'bu','䝵'=>'bu','䪁'=>'bu','䪔'=>'bu','䬏'=>'bu','䳝'=>'bu','䴝'=>'bu','䴺'=>'bu','与'=>'yu','予'=>'yu','于'=>'yu','亐'=>'yu','伃'=>'yu','伛'=>'yu','余'=>'yu','俁'=>'yu','俞'=>'yu','俣'=>'yu','俼'=>'yu','偊'=>'yu','傴'=>'yu','儥'=>'yu','兪'=>'yu','匬'=>'yu','吁'=>'yu','唹'=>'yu','喅'=>'yu','喐'=>'yu','喩'=>'yu','喻'=>'yu','噊'=>'yu','噳'=>'yu','圄'=>'yu','圉'=>'yu','圫'=>'yu','域'=>'yu','堉'=>'yu','堣'=>'yu','堬'=>'yu','妤'=>'yu','妪'=>'yu','娛'=>'yu','娯'=>'yu','娱'=>'yu','媀'=>'yu','嫗'=>'yu','嬩'=>'yu','宇'=>'yu','寓'=>'yu','寙'=>'yu','屿'=>'yu','峪'=>'yu','峿'=>'yu','崳'=>'yu','嵎'=>'yu','嵛'=>'yu','嶎'=>'yu','嶼'=>'yu','庽'=>'yu','庾'=>'yu','彧'=>'yu','御'=>'yu','忬'=>'yu','悆'=>'yu','惐'=>'yu','愈'=>'yu','愉'=>'yu','愚'=>'yu','慾'=>'yu','懙'=>'yu','戫'=>'yu','扜'=>'yu','扵'=>'yu','挧'=>'yu','揄'=>'yu','敔'=>'yu','斔'=>'yu','斞'=>'yu','於'=>'yu','旟'=>'yu','昱'=>'yu','杅'=>'yu','栯'=>'yu','棛'=>'yu','棜'=>'yu','棫'=>'yu','楀'=>'yu','楡'=>'yu','楰'=>'yu','榆'=>'yu','櫲'=>'yu','欎'=>'yu','欝'=>'yu','欤'=>'yu','欲'=>'yu','歈'=>'yu','歟'=>'yu','歶'=>'yu','毓'=>'yu','浴'=>'yu','淢'=>'yu','淤'=>'yu','淯'=>'yu','渔'=>'yu','渝'=>'yu','湡'=>'yu','滪'=>'yu','漁'=>'yu','澞'=>'yu','澦'=>'yu','灪'=>'yu','焴'=>'yu','煜'=>'yu','燏'=>'yu','燠'=>'yu','爩'=>'yu','牏'=>'yu','狱'=>'yu','狳'=>'yu','獄'=>'yu','玉'=>'yu','玗'=>'yu','玙'=>'yu','琙'=>'yu','瑀'=>'yu','瑜'=>'yu','璵'=>'yu','畬'=>'yu','畭'=>'yu','瘀'=>'yu','瘉'=>'yu','瘐'=>'yu','癒'=>'yu','盂'=>'yu','盓'=>'yu','睮'=>'yu','矞'=>'yu','砡'=>'yu','硢'=>'yu','礇'=>'yu','礖'=>'yu','礜'=>'yu','祤'=>'yu','禦'=>'yu','禹'=>'yu','禺'=>'yu','秗'=>'yu','稢'=>'yu','稶'=>'yu','穥'=>'yu','穻'=>'yu','窬'=>'yu','窳'=>'yu','竽'=>'yu','箊'=>'yu','篽'=>'yu','籅'=>'yu','籞'=>'yu','籲'=>'yu','紆'=>'yu','緎'=>'yu','繘'=>'yu','纡'=>'yu','罭'=>'yu','羭'=>'yu','羽'=>'yu','聿'=>'yu','育'=>'yu','腴'=>'yu','臾'=>'yu','舁'=>'yu','舆'=>'yu','與'=>'yu','艅'=>'yu','芋'=>'yu','芌'=>'yu','茟'=>'yu','茰'=>'yu','荢'=>'yu','萭'=>'yu','萮'=>'yu','萸'=>'yu','蒮'=>'yu','蓣'=>'yu','蓹'=>'yu','蕍'=>'yu','蕷'=>'yu','薁'=>'yu','蘌'=>'yu','蘛'=>'yu','虞'=>'yu','虶'=>'yu','蜟'=>'yu','蜮'=>'yu','蝓'=>'yu','螸'=>'yu','衧'=>'yu','袬'=>'yu','裕'=>'yu','褕'=>'yu','覦'=>'yu','觎'=>'yu','誉'=>'yu','語'=>'yu','諛'=>'yu','諭'=>'yu','謣'=>'yu','譽'=>'yu','语'=>'yu','谀'=>'yu','谕'=>'yu','豫'=>'yu','貐'=>'yu','踰'=>'yu','軉'=>'yu','輍'=>'yu','輿'=>'yu','轝'=>'yu','迃'=>'yu','逳'=>'yu','逾'=>'yu','遇'=>'yu','遹'=>'yu','邘'=>'yu','郁'=>'yu','鄅'=>'yu','酑'=>'yu','醧'=>'yu','釪'=>'yu','鈺'=>'yu','銉'=>'yu','鋊'=>'yu','鋙'=>'yu','錥'=>'yu','鍝'=>'yu','鐭'=>'yu','钰'=>'yu','铻'=>'yu','閾'=>'yu','阈'=>'yu','陓'=>'yu','隃'=>'yu','隅'=>'yu','隩'=>'yu','雓'=>'yu','雨'=>'yu','雩'=>'yu','霱'=>'yu','預'=>'yu','预'=>'yu','飫'=>'yu','餘'=>'yu','饇'=>'yu','饫'=>'yu','馀'=>'yu','馭'=>'yu','騟'=>'yu','驈'=>'yu','驭'=>'yu','骬'=>'yu','髃'=>'yu','鬰'=>'yu','鬱'=>'yu','鬻'=>'yu','魊'=>'yu','魚'=>'yu','魣'=>'yu','鮽'=>'yu','鯲'=>'yu','鰅'=>'yu','鱊'=>'yu','鱼'=>'yu','鳿'=>'yu','鴥'=>'yu','鴧'=>'yu','鴪'=>'yu','鵒'=>'yu','鷠'=>'yu','鷸'=>'yu','鸆'=>'yu','鸒'=>'yu','鹆'=>'yu','鹬'=>'yu','麌'=>'yu','齬'=>'yu','龉'=>'yu','㑨'=>'yu','㒁'=>'yu','㒜'=>'yu','㔱'=>'yu','㙑'=>'yu','㚥'=>'yu','㝢'=>'yu','㠘'=>'yu','㠨'=>'yu','㡰'=>'yu','㣃'=>'yu','㤤'=>'yu','㥔'=>'yu','㥚'=>'yu','㥥'=>'yu','㦛'=>'yu','㪀'=>'yu','㬂'=>'yu','㬰'=>'yu','㲾'=>'yu','㳚'=>'yu','㳛'=>'yu','㶛'=>'yu','㷒'=>'yu','㺄'=>'yu','㺞'=>'yu','㺮'=>'yu','㼌'=>'yu','㼶'=>'yu','㽣'=>'yu','䁌'=>'yu','䁩'=>'yu','䂊'=>'yu','䂛'=>'yu','䃋'=>'yu','䄏'=>'yu','䄨'=>'yu','䆷'=>'yu','䈅'=>'yu','䉛'=>'yu','䋖'=>'yu','䍂'=>'yu','䍞'=>'yu','䏸'=>'yu','䐳'=>'yu','䔡'=>'yu','䖇'=>'yu','䗨'=>'yu','䘘'=>'yu','䘱'=>'yu','䛕'=>'yu','䜽'=>'yu','䢓'=>'yu','䢩'=>'yu','䣁'=>'yu','䥏'=>'yu','䨒'=>'yu','䨞'=>'yu','䩒'=>'yu','䬄'=>'yu','䮇'=>'yu','䮙'=>'yu','䰻'=>'yu','䱷'=>'yu','䲣'=>'yu','䴁'=>'yu','䵫'=>'yu','丏'=>'mian','俛'=>'mian','偭'=>'mian','免'=>'mian','冕'=>'mian','勉'=>'mian','勔'=>'mian','喕'=>'mian','娩'=>'mian','婂'=>'mian','媔'=>'mian','嬵'=>'mian','宀'=>'mian','愐'=>'mian','棉'=>'mian','檰'=>'mian','櫋'=>'mian','汅'=>'mian','沔'=>'mian','湎'=>'mian','眄'=>'mian','眠'=>'mian','矈'=>'mian','矊'=>'mian','矏'=>'mian','糆'=>'mian','綿'=>'mian','緜'=>'mian','緬'=>'mian','绵'=>'mian','缅'=>'mian','腼'=>'mian','臱'=>'mian','芇'=>'mian','葂'=>'mian','蝒'=>'mian','面'=>'mian','靣'=>'mian','鮸'=>'mian','麪'=>'mian','麫'=>'mian','麵'=>'mian','麺'=>'mian','黾'=>'mian','㒙'=>'mian','㛯'=>'mian','㝰'=>'mian','㤁'=>'mian','㬆'=>'mian','㮌'=>'mian','㰃'=>'mian','㴐'=>'mian','㻰'=>'mian','䀎'=>'mian','䃇'=>'mian','䏃'=>'mian','䤄'=>'mian','䫵'=>'mian','䰓'=>'mian','丐'=>'gai','乢'=>'gai','侅'=>'gai','匃'=>'gai','匄'=>'gai','垓'=>'gai','姟'=>'gai','峐'=>'gai','忋'=>'gai','戤'=>'gai','摡'=>'gai','改'=>'gai','晐'=>'gai','杚'=>'gai','概'=>'gai','槩'=>'gai','槪'=>'gai','溉'=>'gai','漑'=>'gai','瓂'=>'gai','畡'=>'gai','盖'=>'gai','祴'=>'gai','絠'=>'gai','絯'=>'gai','荄'=>'gai','葢'=>'gai','蓋'=>'gai','該'=>'gai','该'=>'gai','豥'=>'gai','賅'=>'gai','賌'=>'gai','赅'=>'gai','郂'=>'gai','鈣'=>'gai','鎅'=>'gai','钙'=>'gai','陔'=>'gai','隑'=>'gai','㕢'=>'gai','㧉'=>'gai','㮣'=>'gai','䏗'=>'gai','䪱'=>'gai','丑'=>'chou','丒'=>'chou','仇'=>'chou','侴'=>'chou','俦'=>'chou','偢'=>'chou','儔'=>'chou','吜'=>'chou','嬦'=>'chou','帱'=>'chou','幬'=>'chou','惆'=>'chou','愁'=>'chou','懤'=>'chou','抽'=>'chou','搊'=>'chou','杽'=>'chou','栦'=>'chou','椆'=>'chou','殠'=>'chou','燽'=>'chou','犨'=>'chou','犫'=>'chou','畴'=>'chou','疇'=>'chou','瘳'=>'chou','皗'=>'chou','瞅'=>'chou','矁'=>'chou','稠'=>'chou','筹'=>'chou','篘'=>'chou','籌'=>'chou','紬'=>'chou','絒'=>'chou','綢'=>'chou','绸'=>'chou','臭'=>'chou','臰'=>'chou','菗'=>'chou','薵'=>'chou','裯'=>'chou','詶'=>'chou','讎'=>'chou','讐'=>'chou','踌'=>'chou','躊'=>'chou','遚'=>'chou','酧'=>'chou','酬'=>'chou','醜'=>'chou','醻'=>'chou','雔'=>'chou','雠'=>'chou','魗'=>'chou','㐜'=>'chou','㛶'=>'chou','㤽'=>'chou','㦞'=>'chou','㨶'=>'chou','㵞'=>'chou','㿧'=>'chou','䇺'=>'chou','䊭'=>'chou','䌧'=>'chou','䌷'=>'chou','䓓'=>'chou','䔏'=>'chou','䛬'=>'chou','䥒'=>'chou','䪮'=>'chou','䲖'=>'chou','专'=>'zhuan','僎'=>'zhuan','叀'=>'zhuan','啭'=>'zhuan','囀'=>'zhuan','堟'=>'zhuan','嫥'=>'zhuan','孨'=>'zhuan','専'=>'zhuan','專'=>'zhuan','撰'=>'zhuan','灷'=>'zhuan','瑑'=>'zhuan','瑼'=>'zhuan','甎'=>'zhuan','砖'=>'zhuan','磚'=>'zhuan','竱'=>'zhuan','篆'=>'zhuan','籑'=>'zhuan','縳'=>'zhuan','膞'=>'zhuan','蒃'=>'zhuan','蟤'=>'zhuan','襈'=>'zhuan','諯'=>'zhuan','譔'=>'zhuan','賺'=>'zhuan','赚'=>'zhuan','転'=>'zhuan','轉'=>'zhuan','转'=>'zhuan','鄟'=>'zhuan','顓'=>'zhuan','颛'=>'zhuan','饌'=>'zhuan','馔'=>'zhuan','鱄'=>'zhuan','䉵'=>'zhuan','䡱'=>'zhuan','且'=>'qie','倿'=>'qie','切'=>'qie','匧'=>'qie','厒'=>'qie','妾'=>'qie','怯'=>'qie','悏'=>'qie','惬'=>'qie','愜'=>'qie','挈'=>'qie','朅'=>'qie','洯'=>'qie','淁'=>'qie','癿'=>'qie','穕'=>'qie','窃'=>'qie','竊'=>'qie','笡'=>'qie','箧'=>'qie','篋'=>'qie','籡'=>'qie','緁'=>'qie','聺'=>'qie','苆'=>'qie','茄'=>'qie','藒'=>'qie','蛪'=>'qie','踥'=>'qie','鍥'=>'qie','鐑'=>'qie','锲'=>'qie','魥'=>'qie','鯜'=>'qie','㓶'=>'qie','㗫'=>'qie','㚗'=>'qie','㛍'=>'qie','㛙'=>'qie','㤲'=>'qie','㥦'=>'qie','㫸'=>'qie','㰰'=>'qie','㰼'=>'qie','㹤'=>'qie','㾀'=>'qie','㾜'=>'qie','䟙'=>'qie','䤿'=>'qie','䦧'=>'qie','䬊'=>'qie','丕'=>'pi','仳'=>'pi','伓'=>'pi','伾'=>'pi','僻'=>'pi','劈'=>'pi','匹'=>'pi','啤'=>'pi','噼'=>'pi','噽'=>'pi','嚊'=>'pi','嚭'=>'pi','圮'=>'pi','坯'=>'pi','埤'=>'pi','壀'=>'pi','媲'=>'pi','嫓'=>'pi','屁'=>'pi','岯'=>'pi','崥'=>'pi','庀'=>'pi','怶'=>'pi','悂'=>'pi','憵'=>'pi','批'=>'pi','披'=>'pi','抷'=>'pi','揊'=>'pi','擗'=>'pi','旇'=>'pi','朇'=>'pi','枇'=>'pi','椑'=>'pi','榌'=>'pi','毗'=>'pi','毘'=>'pi','毞'=>'pi','淠'=>'pi','渒'=>'pi','潎'=>'pi','澼'=>'pi','炋'=>'pi','焷'=>'pi','狉'=>'pi','狓'=>'pi','琵'=>'pi','甓'=>'pi','疈'=>'pi','疲'=>'pi','痞'=>'pi','癖'=>'pi','皮'=>'pi','睤'=>'pi','睥'=>'pi','砒'=>'pi','磇'=>'pi','礔'=>'pi','礕'=>'pi','秛'=>'pi','秠'=>'pi','笓'=>'pi','篺'=>'pi','簲'=>'pi','紕'=>'pi','纰'=>'pi','罴'=>'pi','羆'=>'pi','翍'=>'pi','耚'=>'pi','肶'=>'pi','脴'=>'pi','脾'=>'pi','腗'=>'pi','膍'=>'pi','芘'=>'pi','苉'=>'pi','蚍'=>'pi','蚽'=>'pi','蜱'=>'pi','螷'=>'pi','蠯'=>'pi','諀'=>'pi','譬'=>'pi','豼'=>'pi','豾'=>'pi','貔'=>'pi','邳'=>'pi','郫'=>'pi','釽'=>'pi','鈚'=>'pi','鈹'=>'pi','鉟'=>'pi','銔'=>'pi','銢'=>'pi','錃'=>'pi','錍'=>'pi','铍'=>'pi','闢'=>'pi','阰'=>'pi','陴'=>'pi','隦'=>'pi','霹'=>'pi','駓'=>'pi','髬'=>'pi','魮'=>'pi','魾'=>'pi','鮍'=>'pi','鲏'=>'pi','鴄'=>'pi','鵧'=>'pi','鷿'=>'pi','鸊'=>'pi','鼙'=>'pi','㔥'=>'pi','㨽'=>'pi','㯅'=>'pi','㿙'=>'pi','䏘'=>'pi','䑀'=>'pi','䑄'=>'pi','䚰'=>'pi','䚹'=>'pi','䠘'=>'pi','䡟'=>'pi','䤏'=>'pi','䤨'=>'pi','䫌'=>'pi','䰦'=>'pi','䴙'=>'pi','世'=>'shi','丗'=>'shi','乨'=>'shi','亊'=>'shi','事'=>'shi','什'=>'shi','仕'=>'shi','佦'=>'shi','使'=>'shi','侍'=>'shi','兘'=>'shi','兙'=>'shi','冟'=>'shi','势'=>'shi','勢'=>'shi','十'=>'shi','卋'=>'shi','叓'=>'shi','史'=>'shi','呞'=>'shi','呩'=>'shi','嗜'=>'shi','噬'=>'shi','埘'=>'shi','塒'=>'shi','士'=>'shi','失'=>'shi','奭'=>'shi','始'=>'shi','姼'=>'shi','嬕'=>'shi','实'=>'shi','実'=>'shi','室'=>'shi','宩'=>'shi','寔'=>'shi','實'=>'shi','尸'=>'shi','屍'=>'shi','屎'=>'shi','峕'=>'shi','崼'=>'shi','嵵'=>'shi','市'=>'shi','师'=>'shi','師'=>'shi','式'=>'shi','弑'=>'shi','弒'=>'shi','徥'=>'shi','忕'=>'shi','恀'=>'shi','恃'=>'shi','戺'=>'shi','拭'=>'shi','拾'=>'shi','揓'=>'shi','施'=>'shi','时'=>'shi','旹'=>'shi','是'=>'shi','昰'=>'shi','時'=>'shi','枾'=>'shi','柹'=>'shi','柿'=>'shi','栻'=>'shi','榁'=>'shi','榯'=>'shi','檡'=>'shi','氏'=>'shi','浉'=>'shi','湜'=>'shi','湤'=>'shi','湿'=>'shi','溡'=>'shi','溮'=>'shi','溼'=>'shi','澨'=>'shi','濕'=>'shi','炻'=>'shi','烒'=>'shi','煶'=>'shi','狮'=>'shi','獅'=>'shi','瑡'=>'shi','瓧'=>'shi','眂'=>'shi','眎'=>'shi','眡'=>'shi','睗'=>'shi','矢'=>'shi','石'=>'shi','示'=>'shi','礻'=>'shi','祏'=>'shi','竍'=>'shi','笶'=>'shi','笹'=>'shi','筮'=>'shi','箷'=>'shi','篒'=>'shi','簭'=>'shi','籂'=>'shi','籭'=>'shi','絁'=>'shi','舐'=>'shi','舓'=>'shi','莳'=>'shi','葹'=>'shi','蒒'=>'shi','蒔'=>'shi','蓍'=>'shi','虱'=>'shi','虲'=>'shi','蚀'=>'shi','蝕'=>'shi','蝨'=>'shi','螫'=>'shi','褆'=>'shi','褷'=>'shi','襫'=>'shi','襹'=>'shi','視'=>'shi','视'=>'shi','觢'=>'shi','試'=>'shi','詩'=>'shi','誓'=>'shi','諟'=>'shi','諡'=>'shi','謚'=>'shi','識'=>'shi','识'=>'shi','试'=>'shi','诗'=>'shi','谥'=>'shi','豕'=>'shi','貰'=>'shi','贳'=>'shi','軾'=>'shi','轼'=>'shi','辻'=>'shi','适'=>'shi','逝'=>'shi','遈'=>'shi','適'=>'shi','遾'=>'shi','邿'=>'shi','酾'=>'shi','釃'=>'shi','釈'=>'shi','释'=>'shi','釋'=>'shi','釶'=>'shi','鈰'=>'shi','鉂'=>'shi','鉃'=>'shi','鉇'=>'shi','鉐'=>'shi','鉽'=>'shi','銴'=>'shi','鍦'=>'shi','铈'=>'shi','食'=>'shi','飠'=>'shi','飾'=>'shi','餝'=>'shi','饣'=>'shi','饰'=>'shi','駛'=>'shi','驶'=>'shi','鮖'=>'shi','鯴'=>'shi','鰘'=>'shi','鰣'=>'shi','鰤'=>'shi','鲥'=>'shi','鲺'=>'shi','鳲'=>'shi','鳾'=>'shi','鶳'=>'shi','鸤'=>'shi','鼫'=>'shi','鼭'=>'shi','齛'=>'shi','㒾'=>'shi','㔺'=>'shi','㕜'=>'shi','㖷'=>'shi','㫑'=>'shi','㮶'=>'shi','㱁'=>'shi','㵓'=>'shi','㸷'=>'shi','㹝'=>'shi','㹬'=>'shi','㹷'=>'shi','䁺'=>'shi','䂖'=>'shi','䊓'=>'shi','䏡'=>'shi','䒨'=>'shi','䖨'=>'shi','䛈'=>'shi','䟗'=>'shi','䤱'=>'shi','䦠'=>'shi','䦹'=>'shi','䩃'=>'shi','䭄'=>'shi','䰄'=>'shi','䴓'=>'shi','䶡'=>'shi','丘'=>'qiu','丠'=>'qiu','俅'=>'qiu','叴'=>'qiu','唒'=>'qiu','囚'=>'qiu','坵'=>'qiu','媝'=>'qiu','寈'=>'qiu','崷'=>'qiu','巯'=>'qiu','巰'=>'qiu','恘'=>'qiu','扏'=>'qiu','搝'=>'qiu','朹'=>'qiu','梂'=>'qiu','楸'=>'qiu','殏'=>'qiu','毬'=>'qiu','求'=>'qiu','汓'=>'qiu','泅'=>'qiu','浗'=>'qiu','渞'=>'qiu','湭'=>'qiu','煪'=>'qiu','犰'=>'qiu','玌'=>'qiu','球'=>'qiu','璆'=>'qiu','皳'=>'qiu','盚'=>'qiu','秋'=>'qiu','秌'=>'qiu','穐'=>'qiu','篍'=>'qiu','糗'=>'qiu','紌'=>'qiu','絿'=>'qiu','緧'=>'qiu','肍'=>'qiu','莍'=>'qiu','萩'=>'qiu','蓲'=>'qiu','蘒'=>'qiu','虬'=>'qiu','虯'=>'qiu','蚯'=>'qiu','蛷'=>'qiu','蝤'=>'qiu','蝵'=>'qiu','蟗'=>'qiu','蠤'=>'qiu','裘'=>'qiu','觓'=>'qiu','觩'=>'qiu','訄'=>'qiu','訅'=>'qiu','賕'=>'qiu','赇'=>'qiu','趥'=>'qiu','逎'=>'qiu','逑'=>'qiu','遒'=>'qiu','邱'=>'qiu','酋'=>'qiu','醔'=>'qiu','釚'=>'qiu','釻'=>'qiu','銶'=>'qiu','鞦'=>'qiu','鞧'=>'qiu','鮂'=>'qiu','鯄'=>'qiu','鰌'=>'qiu','鰍'=>'qiu','鰽'=>'qiu','鱃'=>'qiu','鳅'=>'qiu','鵭'=>'qiu','鶖'=>'qiu','鹙'=>'qiu','鼽'=>'qiu','龝'=>'qiu','㐀'=>'qiu','㐤'=>'qiu','㕤'=>'qiu','㞗'=>'qiu','㟈'=>'qiu','㤹'=>'qiu','㥢'=>'qiu','㧨'=>'qiu','㭝'=>'qiu','㷕'=>'qiu','㺫'=>'qiu','㼒'=>'qiu','䆋'=>'qiu','䊵'=>'qiu','䎿'=>'qiu','䜪'=>'qiu','䞭'=>'qiu','䟬'=>'qiu','䟵'=>'qiu','䠗'=>'qiu','䣇'=>'qiu','䤛'=>'qiu','丙'=>'bing','並'=>'bing','仌'=>'bing','併'=>'bing','倂'=>'bing','偋'=>'bing','傡'=>'bing','兵'=>'bing','冫'=>'bing','冰'=>'bing','垪'=>'bing','寎'=>'bing','并'=>'bing','幷'=>'bing','庰'=>'bing','怲'=>'bing','抦'=>'bing','掤'=>'bing','摒'=>'bing','昞'=>'bing','昺'=>'bing','柄'=>'bing','栟'=>'bing','栤'=>'bing','梹'=>'bing','棅'=>'bing','檳'=>'bing','氷'=>'bing','炳'=>'bing','燷'=>'bing','病'=>'bing','眪'=>'bing','禀'=>'bing','秉'=>'bing','窉'=>'bing','竝'=>'bing','苪'=>'bing','蛃'=>'bing','誁'=>'bing','邴'=>'bing','鈵'=>'bing','鉼'=>'bing','鋲'=>'bing','陃'=>'bing','靐'=>'bing','鞆'=>'bing','餅'=>'bing','餠'=>'bing','饼'=>'bing','鮩'=>'bing','㓈'=>'bing','㨀'=>'bing','䈂'=>'bing','䋑'=>'bing','䓑'=>'bing','䗒'=>'bing','䴵'=>'bing','业'=>'ye','也'=>'ye','亪'=>'ye','亱'=>'ye','倻'=>'ye','偞'=>'ye','僷'=>'ye','冶'=>'ye','叶'=>'ye','吔'=>'ye','嘢'=>'ye','噎'=>'ye','嚈'=>'ye','埜'=>'ye','堨'=>'ye','墷'=>'ye','壄'=>'ye','夜'=>'ye','嶪'=>'ye','嶫'=>'ye','抴'=>'ye','捓'=>'ye','捙'=>'ye','掖'=>'ye','揶'=>'ye','擖'=>'ye','擛'=>'ye','擨'=>'ye','擪'=>'ye','擫'=>'ye','晔'=>'ye','暍'=>'ye','曄'=>'ye','曅'=>'ye','曗'=>'ye','曳'=>'ye','枼'=>'ye','枽'=>'ye','椰'=>'ye','楪'=>'ye','業'=>'ye','歋'=>'ye','殗'=>'ye','洂'=>'ye','液'=>'ye','漜'=>'ye','潱'=>'ye','澲'=>'ye','烨'=>'ye','燁'=>'ye','爗'=>'ye','爷'=>'ye','爺'=>'ye','皣'=>'ye','瞱'=>'ye','瞸'=>'ye','礏'=>'ye','耶'=>'ye','腋'=>'ye','葉'=>'ye','蠮'=>'ye','謁'=>'ye','谒'=>'ye','邺'=>'ye','鄓'=>'ye','鄴'=>'ye','野'=>'ye','釾'=>'ye','鋣'=>'ye','鍱'=>'ye','鎁'=>'ye','鎑'=>'ye','铘'=>'ye','靥'=>'ye','靨'=>'ye','頁'=>'ye','页'=>'ye','餣'=>'ye','饁'=>'ye','馌'=>'ye','驜'=>'ye','鵺'=>'ye','鸈'=>'ye','㐖'=>'ye','㖡'=>'ye','㖶'=>'ye','㗼'=>'ye','㙒'=>'ye','㙪'=>'ye','㝣'=>'ye','㥷'=>'ye','㩎'=>'ye','㪑'=>'ye','㱉'=>'ye','㸣'=>'ye','䈎'=>'ye','䓉'=>'ye','䤳'=>'ye','䤶'=>'ye','䥟'=>'ye','䥡'=>'ye','䥺'=>'ye','䧨'=>'ye','䭟'=>'ye','䲜'=>'ye','丛'=>'cong','从'=>'cong','匆'=>'cong','叢'=>'cong','囪'=>'cong','囱'=>'cong','婃'=>'cong','孮'=>'cong','従'=>'cong','徖'=>'cong','從'=>'cong','忩'=>'cong','怱'=>'cong','悤'=>'cong','悰'=>'cong','慒'=>'cong','憁'=>'cong','暰'=>'cong','枞'=>'cong','棇'=>'cong','楤'=>'cong','樅'=>'cong','樬'=>'cong','樷'=>'cong','欉'=>'cong','淙'=>'cong','漎'=>'cong','漗'=>'cong','潀'=>'cong','潈'=>'cong','潨'=>'cong','灇'=>'cong','焧'=>'cong','熜'=>'cong','爜'=>'cong','琮'=>'cong','瑽'=>'cong','璁'=>'cong','瞛'=>'cong','篵'=>'cong','緫'=>'cong','繱'=>'cong','聡'=>'cong','聦'=>'cong','聪'=>'cong','聰'=>'cong','苁'=>'cong','茐'=>'cong','葱'=>'cong','蓯'=>'cong','蔥'=>'cong','藂'=>'cong','蟌'=>'cong','誴'=>'cong','謥'=>'cong','賨'=>'cong','賩'=>'cong','鏦'=>'cong','騘'=>'cong','驄'=>'cong','骢'=>'cong','㼻'=>'cong','䉘'=>'cong','䕺'=>'cong','䧚'=>'cong','䳷'=>'cong','东'=>'dong','侗'=>'dong','倲'=>'dong','働'=>'dong','冬'=>'dong','冻'=>'dong','凍'=>'dong','动'=>'dong','動'=>'dong','咚'=>'dong','垌'=>'dong','埬'=>'dong','墥'=>'dong','姛'=>'dong','娻'=>'dong','嬞'=>'dong','岽'=>'dong','峒'=>'dong','峝'=>'dong','崠'=>'dong','崬'=>'dong','恫'=>'dong','懂'=>'dong','戙'=>'dong','挏'=>'dong','昸'=>'dong','東'=>'dong','栋'=>'dong','棟'=>'dong','氡'=>'dong','氭'=>'dong','洞'=>'dong','涷'=>'dong','湩'=>'dong','硐'=>'dong','笗'=>'dong','箽'=>'dong','胨'=>'dong','胴'=>'dong','腖'=>'dong','苳'=>'dong','菄'=>'dong','董'=>'dong','蕫'=>'dong','蝀'=>'dong','詷'=>'dong','諌'=>'dong','迵'=>'dong','霘'=>'dong','駧'=>'dong','鮗'=>'dong','鯟'=>'dong','鶇'=>'dong','鶫'=>'dong','鸫'=>'dong','鼕'=>'dong','㑈'=>'dong','㓊'=>'dong','㖦'=>'dong','㗢'=>'dong','㜱'=>'dong','㢥'=>'dong','㨂'=>'dong','㼯'=>'dong','䂢'=>'dong','䅍'=>'dong','䍶'=>'dong','䞒'=>'dong','䵔'=>'dong','丝'=>'si','乺'=>'si','亖'=>'si','伺'=>'si','似'=>'si','佀'=>'si','価'=>'si','俟'=>'si','俬'=>'si','儩'=>'si','兕'=>'si','凘'=>'si','厮'=>'si','厶'=>'si','司'=>'si','咝'=>'si','嗣'=>'si','嘶'=>'si','噝'=>'si','四'=>'si','姒'=>'si','娰'=>'si','媤'=>'si','孠'=>'si','寺'=>'si','巳'=>'si','廝'=>'si','思'=>'si','恖'=>'si','撕'=>'si','斯'=>'si','枱'=>'si','柶'=>'si','梩'=>'si','楒'=>'si','榹'=>'si','死'=>'si','汜'=>'si','泀'=>'si','泗'=>'si','泤'=>'si','洍'=>'si','涘'=>'si','澌'=>'si','瀃'=>'si','燍'=>'si','牭'=>'si','磃'=>'si','祀'=>'si','禗'=>'si','禠'=>'si','禩'=>'si','私'=>'si','竢'=>'si','笥'=>'si','糹'=>'si','絲'=>'si','緦'=>'si','纟'=>'si','缌'=>'si','罒'=>'si','罳'=>'si','耜'=>'si','肂'=>'si','肆'=>'si','蕬'=>'si','蕼'=>'si','虒'=>'si','蛳'=>'si','蜤'=>'si','螄'=>'si','螦'=>'si','蟖'=>'si','蟴'=>'si','覗'=>'si','貄'=>'si','釲'=>'si','鈻'=>'si','鉰'=>'si','銯'=>'si','鋖'=>'si','鍶'=>'si','鐁'=>'si','锶'=>'si','颸'=>'si','飔'=>'si','飤'=>'si','飼'=>'si','饲'=>'si','駟'=>'si','騃'=>'si','騦'=>'si','驷'=>'si','鷥'=>'si','鸶'=>'si','鼶'=>'si','㐌'=>'si','㕽'=>'si','㚶'=>'si','㣈'=>'si','㭒'=>'si','㸻'=>'si','㹑'=>'si','㾅'=>'si','䇃'=>'si','䎣'=>'si','䏤'=>'si','䦙'=>'si','丞'=>'cheng','乗'=>'cheng','乘'=>'cheng','侱'=>'cheng','偁'=>'cheng','呈'=>'cheng','城'=>'cheng','埕'=>'cheng','堘'=>'cheng','塍'=>'cheng','塖'=>'cheng','娍'=>'cheng','宬'=>'cheng','峸'=>'cheng','庱'=>'cheng','徎'=>'cheng','悜'=>'cheng','惩'=>'cheng','憆'=>'cheng','憕'=>'cheng','懲'=>'cheng','成'=>'cheng','承'=>'cheng','挰'=>'cheng','掁'=>'cheng','摚'=>'cheng','撐'=>'cheng','撑'=>'cheng','朾'=>'cheng','枨'=>'cheng','柽'=>'cheng','棖'=>'cheng','棦'=>'cheng','椉'=>'cheng','橕'=>'cheng','橙'=>'cheng','檉'=>'cheng','檙'=>'cheng','泟'=>'cheng','洆'=>'cheng','浾'=>'cheng','溗'=>'cheng','澂'=>'cheng','澄'=>'cheng','瀓'=>'cheng','爯'=>'cheng','牚'=>'cheng','珵'=>'cheng','珹'=>'cheng','琤'=>'cheng','畻'=>'cheng','睈'=>'cheng','瞠'=>'cheng','碀'=>'cheng','秤'=>'cheng','称'=>'cheng','程'=>'cheng','穪'=>'cheng','窚'=>'cheng','竀'=>'cheng','筬'=>'cheng','絾'=>'cheng','緽'=>'cheng','脀'=>'cheng','脭'=>'cheng','荿'=>'cheng','虰'=>'cheng','蛏'=>'cheng','蟶'=>'cheng','裎'=>'cheng','誠'=>'cheng','诚'=>'cheng','赪'=>'cheng','赬'=>'cheng','逞'=>'cheng','郕'=>'cheng','酲'=>'cheng','鋮'=>'cheng','鏳'=>'cheng','鏿'=>'cheng','鐺'=>'cheng','铖'=>'cheng','铛'=>'cheng','阷'=>'cheng','靗'=>'cheng','頳'=>'cheng','饓'=>'cheng','騁'=>'cheng','騬'=>'cheng','骋'=>'cheng','鯎'=>'cheng','㐼'=>'cheng','㞼'=>'cheng','㨃'=>'cheng','㲂'=>'cheng','㼩'=>'cheng','䀕'=>'cheng','䁎'=>'cheng','䄇'=>'cheng','䆑'=>'cheng','䆵'=>'cheng','䆸'=>'cheng','䇸'=>'cheng','䔲'=>'cheng','䗊'=>'cheng','䞓'=>'cheng','䧕'=>'cheng','䫆'=>'cheng','䮪'=>'cheng','丟'=>'diu','丢'=>'diu','銩'=>'diu','铥'=>'diu','颩'=>'diu','両'=>'liang','两'=>'liang','亮'=>'liang','俍'=>'liang','兩'=>'liang','凉'=>'liang','哴'=>'liang','唡'=>'liang','啢'=>'liang','喨'=>'liang','墚'=>'liang','掚'=>'liang','晾'=>'liang','梁'=>'liang','椋'=>'liang','樑'=>'liang','涼'=>'liang','湸'=>'liang','煷'=>'liang','簗'=>'liang','粮'=>'liang','粱'=>'liang','糧'=>'liang','綡'=>'liang','緉'=>'liang','脼'=>'liang','良'=>'liang','蜽'=>'liang','裲'=>'liang','諒'=>'liang','谅'=>'liang','踉'=>'liang','輌'=>'liang','輛'=>'liang','輬'=>'liang','辆'=>'liang','辌'=>'liang','量'=>'liang','鍄'=>'liang','魉'=>'liang','魎'=>'liang','㒳'=>'liang','㔝'=>'liang','㹁'=>'liang','䓣'=>'liang','䝶'=>'liang','䠃'=>'liang','䣼'=>'liang','䩫'=>'liang','䭪'=>'liang','丣'=>'you','亴'=>'you','优'=>'you','佑'=>'you','侑'=>'you','偤'=>'you','優'=>'you','卣'=>'you','又'=>'you','友'=>'you','右'=>'you','呦'=>'you','哊'=>'you','唀'=>'you','嚘'=>'you','囿'=>'you','姷'=>'you','孧'=>'you','宥'=>'you','尢'=>'you','尤'=>'you','峟'=>'you','峳'=>'you','幼'=>'you','幽'=>'you','庮'=>'you','忧'=>'you','怞'=>'you','怣'=>'you','怮'=>'you','悠'=>'you','憂'=>'you','懮'=>'you','攸'=>'you','斿'=>'you','有'=>'you','柚'=>'you','梄'=>'you','梎'=>'you','楢'=>'you','槱'=>'you','櫌'=>'you','櫾'=>'you','沋'=>'you','油'=>'you','泑'=>'you','浟'=>'you','游'=>'you','湵'=>'you','滺'=>'you','瀀'=>'you','牖'=>'you','牗'=>'you','牰'=>'you','犹'=>'you','狖'=>'you','猶'=>'you','猷'=>'you','由'=>'you','疣'=>'you','祐'=>'you','禉'=>'you','秞'=>'you','糿'=>'you','纋'=>'you','羐'=>'you','羑'=>'you','耰'=>'you','聈'=>'you','肬'=>'you','脜'=>'you','苃'=>'you','莜'=>'you','莠'=>'you','莤'=>'you','莸'=>'you','蒏'=>'you','蕕'=>'you','蚰'=>'you','蚴'=>'you','蜏'=>'you','蝣'=>'you','訧'=>'you','誘'=>'you','诱'=>'you','貁'=>'you','輏'=>'you','輶'=>'you','迂'=>'you','迶'=>'you','逌'=>'you','逰'=>'you','遊'=>'you','邎'=>'you','邮'=>'you','郵'=>'you','鄾'=>'you','酉'=>'you','酭'=>'you','釉'=>'you','鈾'=>'you','銪'=>'you','铀'=>'you','铕'=>'you','駀'=>'you','魷'=>'you','鮋'=>'you','鱿'=>'you','鲉'=>'you','麀'=>'you','黝'=>'you','鼬'=>'you','㒡'=>'you','㓜'=>'you','㕗'=>'you','㕱'=>'you','㘥'=>'you','㚭'=>'you','㛜'=>'you','㤑'=>'you','㫍'=>'you','㮋'=>'you','㰶'=>'you','㳺'=>'you','㹨'=>'you','㺠'=>'you','㻀'=>'you','㽕'=>'you','㾞'=>'you','䀁'=>'you','䅎'=>'you','䆜'=>'you','䑻'=>'you','䒴'=>'you','䖻'=>'you','䚃'=>'you','䛻'=>'you','䞥'=>'you','䢊'=>'you','䢟'=>'you','䬀'=>'you','䱂'=>'you','䳑'=>'you','严'=>'yan','乵'=>'yan','俨'=>'yan','偃'=>'yan','偐'=>'yan','偣'=>'yan','傿'=>'yan','儼'=>'yan','兖'=>'yan','兗'=>'yan','円'=>'yan','剦'=>'yan','匽'=>'yan','厌'=>'yan','厣'=>'yan','厭'=>'yan','厳'=>'yan','厴'=>'yan','咽'=>'yan','唁'=>'yan','喭'=>'yan','噞'=>'yan','嚥'=>'yan','嚴'=>'yan','堰'=>'yan','塩'=>'yan','墕'=>'yan','壛'=>'yan','壧'=>'yan','夵'=>'yan','奄'=>'yan','妍'=>'yan','妟'=>'yan','姲'=>'yan','姸'=>'yan','娫'=>'yan','娮'=>'yan','嫣'=>'yan','嬊'=>'yan','嬮'=>'yan','嬿'=>'yan','孍'=>'yan','宴'=>'yan','岩'=>'yan','崦'=>'yan','嵃'=>'yan','嵒'=>'yan','嵓'=>'yan','嶖'=>'yan','巌'=>'yan','巖'=>'yan','巗'=>'yan','巘'=>'yan','巚'=>'yan','延'=>'yan','弇'=>'yan','彥'=>'yan','彦'=>'yan','恹'=>'yan','愝'=>'yan','懕'=>'yan','戭'=>'yan','扊'=>'yan','抁'=>'yan','掞'=>'yan','掩'=>'yan','揅'=>'yan','揜'=>'yan','敥'=>'yan','昖'=>'yan','晏'=>'yan','暥'=>'yan','曕'=>'yan','曮'=>'yan','棪'=>'yan','椻'=>'yan','椼'=>'yan','楌'=>'yan','樮'=>'yan','檐'=>'yan','檿'=>'yan','櫩'=>'yan','欕'=>'yan','沇'=>'yan','沿'=>'yan','淹'=>'yan','渰'=>'yan','渷'=>'yan','湮'=>'yan','滟'=>'yan','演'=>'yan','漹'=>'yan','灎'=>'yan','灔'=>'yan','灧'=>'yan','灩'=>'yan','炎'=>'yan','烟'=>'yan','焉'=>'yan','焔'=>'yan','焰'=>'yan','焱'=>'yan','煙'=>'yan','熖'=>'yan','燄'=>'yan','燕'=>'yan','爓'=>'yan','牪'=>'yan','狿'=>'yan','猒'=>'yan','珚'=>'yan','琂'=>'yan','琰'=>'yan','甗'=>'yan','盐'=>'yan','眼'=>'yan','研'=>'yan','砚'=>'yan','硏'=>'yan','硯'=>'yan','硽'=>'yan','碞'=>'yan','礹'=>'yan','筵'=>'yan','篶'=>'yan','簷'=>'yan','綖'=>'yan','縯'=>'yan','罨'=>'yan','胭'=>'yan','腌'=>'yan','臙'=>'yan','艳'=>'yan','艶'=>'yan','艷'=>'yan','芫'=>'yan','莚'=>'yan','菸'=>'yan','萒'=>'yan','葕'=>'yan','蔅'=>'yan','虤'=>'yan','蜒'=>'yan','蝘'=>'yan','衍'=>'yan','裺'=>'yan','褗'=>'yan','覎'=>'yan','觃'=>'yan','觾'=>'yan','言'=>'yan','訁'=>'yan','訮'=>'yan','詽'=>'yan','諺'=>'yan','讌'=>'yan','讞'=>'yan','讠'=>'yan','谚'=>'yan','谳'=>'yan','豓'=>'yan','豔'=>'yan','贋'=>'yan','贗'=>'yan','贘'=>'yan','赝'=>'yan','躽'=>'yan','軅'=>'yan','遃'=>'yan','郔'=>'yan','郾'=>'yan','鄢'=>'yan','酀'=>'yan','酓'=>'yan','酽'=>'yan','醃'=>'yan','醶'=>'yan','醼'=>'yan','釅'=>'yan','閆'=>'yan','閹'=>'yan','閻'=>'yan','闫'=>'yan','阉'=>'yan','阎'=>'yan','隁'=>'yan','隒'=>'yan','雁'=>'yan','顏'=>'yan','顔'=>'yan','顩'=>'yan','颜'=>'yan','餍'=>'yan','饜'=>'yan','騐'=>'yan','験'=>'yan','騴'=>'yan','驗'=>'yan','驠'=>'yan','验'=>'yan','鬳'=>'yan','魇'=>'yan','魘'=>'yan','鰋'=>'yan','鳫'=>'yan','鴈'=>'yan','鴳'=>'yan','鶠'=>'yan','鷃'=>'yan','鷰'=>'yan','鹽'=>'yan','麙'=>'yan','麣'=>'yan','黡'=>'yan','黤'=>'yan','黫'=>'yan','黬'=>'yan','黭'=>'yan','黶'=>'yan','鼴'=>'yan','鼹'=>'yan','齞'=>'yan','齴'=>'yan','龑'=>'yan','㓧'=>'yan','㕣'=>'yan','㗴'=>'yan','㘖'=>'yan','㘙'=>'yan','㚧'=>'yan','㛪'=>'yan','㢂'=>'yan','㢛'=>'yan','㦔'=>'yan','㫃'=>'yan','㫟'=>'yan','㬫'=>'yan','㭺'=>'yan','㳂'=>'yan','㶄'=>'yan','㷔'=>'yan','㷳'=>'yan','㷼'=>'yan','㿕'=>'yan','㿼'=>'yan','䀋'=>'yan','䀽'=>'yan','䁙'=>'yan','䂩'=>'yan','䂴'=>'yan','䄋'=>'yan','䅧'=>'yan','䊙'=>'yan','䊻'=>'yan','䌪'=>'yan','䎦'=>'yan','䑍'=>'yan','䓂'=>'yan','䕾'=>'yan','䖗'=>'yan','䗡'=>'yan','䗺'=>'yan','䜩'=>'yan','䢥'=>'yan','䢭'=>'yan','䣍'=>'yan','䤷'=>'yan','䨄'=>'yan','䭘'=>'yan','䱲'=>'yan','䲓'=>'yan','䳛'=>'yan','䳺'=>'yan','䴏'=>'yan','䶮'=>'yan','丧'=>'sang','喪'=>'sang','嗓'=>'sang','搡'=>'sang','桑'=>'sang','桒'=>'sang','槡'=>'sang','磉'=>'sang','褬'=>'sang','鎟'=>'sang','顙'=>'sang','颡'=>'sang','䡦'=>'sang','䫙'=>'sang','丨'=>'gun','惃'=>'gun','棍'=>'gun','棞'=>'gun','滚'=>'gun','滾'=>'gun','璭'=>'gun','睔'=>'gun','睴'=>'gun','磙'=>'gun','緄'=>'gun','緷'=>'gun','绲'=>'gun','蓘'=>'gun','蔉'=>'gun','衮'=>'gun','袞'=>'gun','裷'=>'gun','謴'=>'gun','輥'=>'gun','辊'=>'gun','鮌'=>'gun','鯀'=>'gun','鲧'=>'gun','㙥'=>'gun','㫎'=>'gun','㯻'=>'gun','䃂'=>'gun','䎾'=>'gun','䜇'=>'gun','䵪'=>'gun','丩'=>'jiu','久'=>'jiu','乆'=>'jiu','九'=>'jiu','乣'=>'jiu','倃'=>'jiu','僦'=>'jiu','勼'=>'jiu','匓'=>'jiu','匛'=>'jiu','匶'=>'jiu','厩'=>'jiu','咎'=>'jiu','啾'=>'jiu','奺'=>'jiu','就'=>'jiu','廄'=>'jiu','廏'=>'jiu','廐'=>'jiu','慦'=>'jiu','揂'=>'jiu','揪'=>'jiu','揫'=>'jiu','摎'=>'jiu','救'=>'jiu','旧'=>'jiu','朻'=>'jiu','杦'=>'jiu','柩'=>'jiu','柾'=>'jiu','桕'=>'jiu','樛'=>'jiu','欍'=>'jiu','殧'=>'jiu','汣'=>'jiu','灸'=>'jiu','牞'=>'jiu','玖'=>'jiu','畂'=>'jiu','疚'=>'jiu','究'=>'jiu','糺'=>'jiu','糾'=>'jiu','紤'=>'jiu','纠'=>'jiu','臼'=>'jiu','舅'=>'jiu','舊'=>'jiu','舏'=>'jiu','萛'=>'jiu','赳'=>'jiu','酒'=>'jiu','镹'=>'jiu','阄'=>'jiu','韭'=>'jiu','韮'=>'jiu','鬏'=>'jiu','鬮'=>'jiu','鯦'=>'jiu','鳩'=>'jiu','鷲'=>'jiu','鸠'=>'jiu','鹫'=>'jiu','麔'=>'jiu','齨'=>'jiu','㠇'=>'jiu','㡱'=>'jiu','㧕'=>'jiu','㩆'=>'jiu','㲃'=>'jiu','㶭'=>'jiu','㺩'=>'jiu','㺵'=>'jiu','䅢'=>'jiu','䆒'=>'jiu','䊆'=>'jiu','䊘'=>'jiu','䓘'=>'jiu','䛮'=>'jiu','䡂'=>'jiu','䳎'=>'jiu','䳔'=>'jiu','个'=>'ge','佮'=>'ge','個'=>'ge','割'=>'ge','匌'=>'ge','各'=>'ge','呄'=>'ge','哥'=>'ge','哿'=>'ge','嗝'=>'ge','圪'=>'ge','塥'=>'ge','彁'=>'ge','愅'=>'ge','戈'=>'ge','戓'=>'ge','戨'=>'ge','挌'=>'ge','搁'=>'ge','搿'=>'ge','擱'=>'ge','敋'=>'ge','格'=>'ge','槅'=>'ge','櫊'=>'ge','歌'=>'ge','滆'=>'ge','滒'=>'ge','牫'=>'ge','牱'=>'ge','犵'=>'ge','獦'=>'ge','疙'=>'ge','硌'=>'ge','箇'=>'ge','紇'=>'ge','纥'=>'ge','肐'=>'ge','胳'=>'ge','膈'=>'ge','臵'=>'ge','舸'=>'ge','茖'=>'ge','葛'=>'ge','虼'=>'ge','蛒'=>'ge','蛤'=>'ge','袼'=>'ge','裓'=>'ge','觡'=>'ge','諽'=>'ge','謌'=>'ge','輵'=>'ge','轕'=>'ge','鉻'=>'ge','鎘'=>'ge','鎶'=>'ge','铬'=>'ge','镉'=>'ge','閣'=>'ge','閤'=>'ge','阁'=>'ge','隔'=>'ge','革'=>'ge','鞈'=>'ge','鞷'=>'ge','韐'=>'ge','韚'=>'ge','騔'=>'ge','骼'=>'ge','鬲'=>'ge','鮯'=>'ge','鰪'=>'ge','鴐'=>'ge','鴚'=>'ge','鴿'=>'ge','鸽'=>'ge','㗆'=>'ge','㝓'=>'ge','㠷'=>'ge','㦴'=>'ge','㨰'=>'ge','㪾'=>'ge','㵧'=>'ge','㷴'=>'ge','䆟'=>'ge','䈓'=>'ge','䐙'=>'ge','䕻'=>'ge','䗘'=>'ge','䘁'=>'ge','䛋'=>'ge','䛿'=>'ge','䢔'=>'ge','䧄'=>'ge','䨣'=>'ge','䩐'=>'ge','䪂'=>'ge','䪺'=>'ge','䫦'=>'ge','丫'=>'ya','亚'=>'ya','亜'=>'ya','亞'=>'ya','伢'=>'ya','俹'=>'ya','劜'=>'ya','厊'=>'ya','压'=>'ya','厓'=>'ya','呀'=>'ya','哑'=>'ya','唖'=>'ya','啞'=>'ya','圔'=>'ya','圠'=>'ya','垭'=>'ya','埡'=>'ya','堐'=>'ya','壓'=>'ya','娅'=>'ya','婭'=>'ya','孲'=>'ya','岈'=>'ya','崕'=>'ya','崖'=>'ya','庌'=>'ya','庘'=>'ya','押'=>'ya','挜'=>'ya','掗'=>'ya','揠'=>'ya','枒'=>'ya','桠'=>'ya','椏'=>'ya','氩'=>'ya','氬'=>'ya','涯'=>'ya','漄'=>'ya','牙'=>'ya','犽'=>'ya','猚'=>'ya','猰'=>'ya','玡'=>'ya','琊'=>'ya','瑘'=>'ya','疋'=>'ya','痖'=>'ya','瘂'=>'ya','睚'=>'ya','砑'=>'ya','稏'=>'ya','穵'=>'ya','窫'=>'ya','笌'=>'ya','聐'=>'ya','芽'=>'ya','蕥'=>'ya','蚜'=>'ya','衙'=>'ya','襾'=>'ya','訝'=>'ya','讶'=>'ya','迓'=>'ya','錏'=>'ya','鐚'=>'ya','铔'=>'ya','雅'=>'ya','鴉'=>'ya','鴨'=>'ya','鵶'=>'ya','鸦'=>'ya','鸭'=>'ya','齖'=>'ya','齾'=>'ya','㝞'=>'ya','㧎'=>'ya','㰳'=>'ya','㿿'=>'ya','䄰'=>'ya','䅉'=>'ya','䊦'=>'ya','䝟'=>'ya','䢝'=>'ya','䦪'=>'ya','䪵'=>'ya','䯉'=>'ya','䰲'=>'ya','䵝'=>'ya','丬'=>'zhuang','壮'=>'zhuang','壯'=>'zhuang','壵'=>'zhuang','妆'=>'zhuang','妝'=>'zhuang','娤'=>'zhuang','庄'=>'zhuang','庒'=>'zhuang','戅'=>'zhuang','撞'=>'zhuang','桩'=>'zhuang','梉'=>'zhuang','樁'=>'zhuang','湷'=>'zhuang','焋'=>'zhuang','状'=>'zhuang','狀'=>'zhuang','粧'=>'zhuang','糚'=>'zhuang','荘'=>'zhuang','莊'=>'zhuang','装'=>'zhuang','裝'=>'zhuang','中'=>'zhong','仲'=>'zhong','伀'=>'zhong','众'=>'zhong','偅'=>'zhong','冢'=>'zhong','刣'=>'zhong','喠'=>'zhong','堹'=>'zhong','塚'=>'zhong','妐'=>'zhong','妕'=>'zhong','媑'=>'zhong','尰'=>'zhong','幒'=>'zhong','彸'=>'zhong','忠'=>'zhong','柊'=>'zhong','歱'=>'zhong','汷'=>'zhong','泈'=>'zhong','炂'=>'zhong','煄'=>'zhong','狆'=>'zhong','瘇'=>'zhong','盅'=>'zhong','眾'=>'zhong','祌'=>'zhong','祍'=>'zhong','种'=>'zhong','種'=>'zhong','筗'=>'zhong','籦'=>'zhong','終'=>'zhong','终'=>'zhong','肿'=>'zhong','腫'=>'zhong','舯'=>'zhong','茽'=>'zhong','蔠'=>'zhong','蚛'=>'zhong','螤'=>'zhong','螽'=>'zhong','衆'=>'zhong','衳'=>'zhong','衶'=>'zhong','衷'=>'zhong','諥'=>'zhong','踵'=>'zhong','蹱'=>'zhong','迚'=>'zhong','重'=>'zhong','鈡'=>'zhong','鍾'=>'zhong','鐘'=>'zhong','钟'=>'zhong','锺'=>'zhong','鴤'=>'zhong','鼨'=>'zhong','㐺'=>'zhong','㣫'=>'zhong','㲴'=>'zhong','䱰'=>'zhong','丯'=>'jie','介'=>'jie','借'=>'jie','倢'=>'jie','偼'=>'jie','傑'=>'jie','刦'=>'jie','刧'=>'jie','刼'=>'jie','劫'=>'jie','劼'=>'jie','卩'=>'jie','卪'=>'jie','吤'=>'jie','喈'=>'jie','嗟'=>'jie','堦'=>'jie','堺'=>'jie','姐'=>'jie','婕'=>'jie','媎'=>'jie','媘'=>'jie','媫'=>'jie','嫅'=>'jie','孑'=>'jie','尐'=>'jie','屆'=>'jie','届'=>'jie','岊'=>'jie','岕'=>'jie','崨'=>'jie','嵥'=>'jie','嶻'=>'jie','巀'=>'jie','幯'=>'jie','庎'=>'jie','徣'=>'jie','忦'=>'jie','悈'=>'jie','戒'=>'jie','截'=>'jie','拮'=>'jie','捷'=>'jie','接'=>'jie','掲'=>'jie','揭'=>'jie','擑'=>'jie','擮'=>'jie','擳'=>'jie','斺'=>'jie','昅'=>'jie','杰'=>'jie','桀'=>'jie','桔'=>'jie','桝'=>'jie','椄'=>'jie','楐'=>'jie','楬'=>'jie','楶'=>'jie','榤'=>'jie','檞'=>'jie','櫭'=>'jie','毑'=>'jie','洁'=>'jie','湝'=>'jie','滐'=>'jie','潔'=>'jie','煯'=>'jie','犗'=>'jie','玠'=>'jie','琾'=>'jie','界'=>'jie','畍'=>'jie','疌'=>'jie','疖'=>'jie','疥'=>'jie','痎'=>'jie','癤'=>'jie','皆'=>'jie','睫'=>'jie','砎'=>'jie','碣'=>'jie','礍'=>'jie','秸'=>'jie','稭'=>'jie','竭'=>'jie','節'=>'jie','結'=>'jie','繲'=>'jie','结'=>'jie','羯'=>'jie','脻'=>'jie','节'=>'jie','芥'=>'jie','莭'=>'jie','菨'=>'jie','蓵'=>'jie','藉'=>'jie','蚧'=>'jie','蛣'=>'jie','蛶'=>'jie','蜐'=>'jie','蝔'=>'jie','蠘'=>'jie','蠞'=>'jie','蠽'=>'jie','街'=>'jie','衱'=>'jie','衸'=>'jie','袺'=>'jie','褯'=>'jie','解'=>'jie','觧'=>'jie','訐'=>'jie','詰'=>'jie','誡'=>'jie','誱'=>'jie','讦'=>'jie','诘'=>'jie','诫'=>'jie','踕'=>'jie','迼'=>'jie','鉣'=>'jie','鍻'=>'jie','阶'=>'jie','階'=>'jie','鞂'=>'jie','頡'=>'jie','颉'=>'jie','飷'=>'jie','骱'=>'jie','魝'=>'jie','魪'=>'jie','鮚'=>'jie','鲒'=>'jie','鶛'=>'jie','㑘'=>'jie','㓗'=>'jie','㓤'=>'jie','㔾'=>'jie','㘶'=>'jie','㛃'=>'jie','㝌'=>'jie','㝏'=>'jie','㞯'=>'jie','㠹'=>'jie','㦢'=>'jie','㨗'=>'jie','㨩'=>'jie','㮞'=>'jie','㮮'=>'jie','㸅'=>'jie','㾏'=>'jie','㿍'=>'jie','䀷'=>'jie','䀹'=>'jie','䁓'=>'jie','䂒'=>'jie','䂝'=>'jie','䂶'=>'jie','䅥'=>'jie','䇒'=>'jie','䌖'=>'jie','䔿'=>'jie','䕙'=>'jie','䗻'=>'jie','䛺'=>'jie','䣠'=>'jie','䥛'=>'jie','䯰'=>'jie','䰺'=>'jie','䱄'=>'jie','䲙'=>'jie','䲸'=>'jie','丰'=>'feng','仹'=>'feng','俸'=>'feng','偑'=>'feng','僼'=>'feng','冯'=>'feng','凤'=>'feng','凨'=>'feng','凬'=>'feng','凮'=>'feng','唪'=>'feng','堸'=>'feng','夆'=>'feng','奉'=>'feng','妦'=>'feng','寷'=>'feng','封'=>'feng','峯'=>'feng','峰'=>'feng','崶'=>'feng','捀'=>'feng','摓'=>'feng','枫'=>'feng','桻'=>'feng','楓'=>'feng','檒'=>'feng','沣'=>'feng','沨'=>'feng','浲'=>'feng','渢'=>'feng','湗'=>'feng','溄'=>'feng','灃'=>'feng','烽'=>'feng','焨'=>'feng','煈'=>'feng','犎'=>'feng','猦'=>'feng','琒'=>'feng','瓰'=>'feng','甮'=>'feng','疯'=>'feng','瘋'=>'feng','盽'=>'feng','砜'=>'feng','碸'=>'feng','篈'=>'feng','綘'=>'feng','縫'=>'feng','缝'=>'feng','艂'=>'feng','葑'=>'feng','蘕'=>'feng','蘴'=>'feng','蜂'=>'feng','覂'=>'feng','諷'=>'feng','讽'=>'feng','豐'=>'feng','賵'=>'feng','赗'=>'feng','逢'=>'feng','鄷'=>'feng','酆'=>'feng','鋒'=>'feng','鎽'=>'feng','鏠'=>'feng','锋'=>'feng','靊'=>'feng','風'=>'feng','飌'=>'feng','风'=>'feng','馮'=>'feng','鳯'=>'feng','鳳'=>'feng','鴌'=>'feng','麷'=>'feng','㡝'=>'feng','㦀'=>'feng','㵯'=>'feng','䏎'=>'feng','䙜'=>'feng','䟪'=>'feng','䩼'=>'feng','丱'=>'guan','倌'=>'guan','关'=>'guan','冠'=>'guan','卝'=>'guan','官'=>'guan','悹'=>'guan','悺'=>'guan','惯'=>'guan','慣'=>'guan','掼'=>'guan','摜'=>'guan','棺'=>'guan','樌'=>'guan','毌'=>'guan','泴'=>'guan','涫'=>'guan','潅'=>'guan','灌'=>'guan','爟'=>'guan','琯'=>'guan','瓘'=>'guan','痯'=>'guan','瘝'=>'guan','癏'=>'guan','盥'=>'guan','矔'=>'guan','礶'=>'guan','祼'=>'guan','窤'=>'guan','筦'=>'guan','管'=>'guan','罆'=>'guan','罐'=>'guan','舘'=>'guan','萖'=>'guan','蒄'=>'guan','覌'=>'guan','観'=>'guan','觀'=>'guan','观'=>'guan','貫'=>'guan','贯'=>'guan','躀'=>'guan','輨'=>'guan','遦'=>'guan','錧'=>'guan','鏆'=>'guan','鑵'=>'guan','関'=>'guan','闗'=>'guan','關'=>'guan','雚'=>'guan','館'=>'guan','馆'=>'guan','鰥'=>'guan','鱞'=>'guan','鱹'=>'guan','鳏'=>'guan','鳤'=>'guan','鸛'=>'guan','鹳'=>'guan','㮡'=>'guan','㴦'=>'guan','䌯'=>'guan','䎚'=>'guan','䏓'=>'guan','䗆'=>'guan','䗰'=>'guan','䘾'=>'guan','䙛'=>'guan','䙮'=>'guan','䝺'=>'guan','䦎'=>'guan','䩪'=>'guan','䪀'=>'guan','䲘'=>'guan','串'=>'chuan','传'=>'chuan','傳'=>'chuan','僢'=>'chuan','剶'=>'chuan','喘'=>'chuan','圌'=>'chuan','巛'=>'chuan','川'=>'chuan','暷'=>'chuan','椽'=>'chuan','歂'=>'chuan','氚'=>'chuan','汌'=>'chuan','猭'=>'chuan','玔'=>'chuan','瑏'=>'chuan','穿'=>'chuan','篅'=>'chuan','舛'=>'chuan','舡'=>'chuan','舩'=>'chuan','船'=>'chuan','荈'=>'chuan','賗'=>'chuan','輲'=>'chuan','遄'=>'chuan','釧'=>'chuan','钏'=>'chuan','镩'=>'chuan','鶨'=>'chuan','㯌'=>'chuan','㱛'=>'chuan','㼷'=>'chuan','䁣'=>'chuan','丳'=>'chan','产'=>'chan','僝'=>'chan','儃'=>'chan','儳'=>'chan','冁'=>'chan','刬'=>'chan','剗'=>'chan','剷'=>'chan','劖'=>'chan','嚵'=>'chan','囅'=>'chan','壥'=>'chan','婵'=>'chan','嬋'=>'chan','孱'=>'chan','嵼'=>'chan','巉'=>'chan','幝'=>'chan','幨'=>'chan','廛'=>'chan','忏'=>'chan','懴'=>'chan','懺'=>'chan','掺'=>'chan','搀'=>'chan','摌'=>'chan','摲'=>'chan','摻'=>'chan','攙'=>'chan','旵'=>'chan','梴'=>'chan','棎'=>'chan','欃'=>'chan','毚'=>'chan','浐'=>'chan','湹'=>'chan','滻'=>'chan','潹'=>'chan','潺'=>'chan','瀍'=>'chan','瀺'=>'chan','灛'=>'chan','煘'=>'chan','燀'=>'chan','獑'=>'chan','產'=>'chan','産'=>'chan','硟'=>'chan','磛'=>'chan','禅'=>'chan','禪'=>'chan','簅'=>'chan','緾'=>'chan','繟'=>'chan','繵'=>'chan','纏'=>'chan','纒'=>'chan','缠'=>'chan','羼'=>'chan','艬'=>'chan','蒇'=>'chan','蕆'=>'chan','蝉'=>'chan','蝊'=>'chan','蟬'=>'chan','蟾'=>'chan','裧'=>'chan','襜'=>'chan','覘'=>'chan','觇'=>'chan','誗'=>'chan','諂'=>'chan','譂'=>'chan','讇'=>'chan','讒'=>'chan','谄'=>'chan','谗'=>'chan','躔'=>'chan','辿'=>'chan','鄽'=>'chan','酁'=>'chan','醦'=>'chan','鋋'=>'chan','鋓'=>'chan','鏟'=>'chan','鑱'=>'chan','铲'=>'chan','镡'=>'chan','镵'=>'chan','閳'=>'chan','闡'=>'chan','阐'=>'chan','韂'=>'chan','顫'=>'chan','颤'=>'chan','饞'=>'chan','馋'=>'chan','㔆'=>'chan','㙴'=>'chan','㙻'=>'chan','㢆'=>'chan','㢟'=>'chan','㦃'=>'chan','㬄'=>'chan','㯆'=>'chan','㵌'=>'chan','㶣'=>'chan','㸥'=>'chan','㹌'=>'chan','㹽'=>'chan','㺥'=>'chan','䀡'=>'chan','䂁'=>'chan','䊲'=>'chan','䐮'=>'chan','䑎'=>'chan','䜛'=>'chan','䠨'=>'chan','䡪'=>'chan','䡲'=>'chan','䣑'=>'chan','䤘'=>'chan','䤫'=>'chan','䥀'=>'chan','䧯'=>'chan','䩶'=>'chan','䪜'=>'chan','䮭'=>'chan','䱿'=>'chan','䴼'=>'chan','䵐'=>'chan','临'=>'lin','亃'=>'lin','僯'=>'lin','凛'=>'lin','凜'=>'lin','厸'=>'lin','吝'=>'lin','啉'=>'lin','壣'=>'lin','崊'=>'lin','嶙'=>'lin','廩'=>'lin','廪'=>'lin','恡'=>'lin','悋'=>'lin','惏'=>'lin','懍'=>'lin','懔'=>'lin','拎'=>'lin','撛'=>'lin','斴'=>'lin','晽'=>'lin','暽'=>'lin','林'=>'lin','橉'=>'lin','檁'=>'lin','檩'=>'lin','淋'=>'lin','潾'=>'lin','澟'=>'lin','瀶'=>'lin','焛'=>'lin','燐'=>'lin','獜'=>'lin','琳'=>'lin','璘'=>'lin','甐'=>'lin','疄'=>'lin','痳'=>'lin','癛'=>'lin','癝'=>'lin','瞵'=>'lin','碄'=>'lin','磷'=>'lin','稟'=>'lin','箖'=>'lin','粦'=>'lin','粼'=>'lin','繗'=>'lin','翷'=>'lin','膦'=>'lin','臨'=>'lin','菻'=>'lin','蔺'=>'lin','藺'=>'lin','賃'=>'lin','赁'=>'lin','蹸'=>'lin','躏'=>'lin','躙'=>'lin','躪'=>'lin','轔'=>'lin','轥'=>'lin','辚'=>'lin','遴'=>'lin','邻'=>'lin','鄰'=>'lin','鏻'=>'lin','閵'=>'lin','隣'=>'lin','霖'=>'lin','顲'=>'lin','驎'=>'lin','鱗'=>'lin','鳞'=>'lin','麐'=>'lin','麟'=>'lin','㐭'=>'lin','㔂'=>'lin','㖁'=>'lin','㝝'=>'lin','㨆'=>'lin','㷠'=>'lin','䉮'=>'lin','䕲'=>'lin','䗲'=>'lin','䚬'=>'lin','䢯'=>'lin','䫐'=>'lin','䫰'=>'lin','䮼'=>'lin','丵'=>'zhuo','倬'=>'zhuo','劅'=>'zhuo','卓'=>'zhuo','叕'=>'zhuo','啄'=>'zhuo','啅'=>'zhuo','圴'=>'zhuo','妰'=>'zhuo','娺'=>'zhuo','彴'=>'zhuo','拙'=>'zhuo','捉'=>'zhuo','撯'=>'zhuo','擆'=>'zhuo','擢'=>'zhuo','斀'=>'zhuo','斫'=>'zhuo','斮'=>'zhuo','斱'=>'zhuo','斲'=>'zhuo','斵'=>'zhuo','晫'=>'zhuo','桌'=>'zhuo','梲'=>'zhuo','棁'=>'zhuo','棳'=>'zhuo','椓'=>'zhuo','槕'=>'zhuo','櫡'=>'zhuo','浊'=>'zhuo','浞'=>'zhuo','涿'=>'zhuo','濁'=>'zhuo','濯'=>'zhuo','灂'=>'zhuo','灼'=>'zhuo','炪'=>'zhuo','烵'=>'zhuo','犳'=>'zhuo','琢'=>'zhuo','琸'=>'zhuo','着'=>'zhuo','硺'=>'zhuo','禚'=>'zhuo','穛'=>'zhuo','穱'=>'zhuo','窡'=>'zhuo','窧'=>'zhuo','篧'=>'zhuo','籗'=>'zhuo','籱'=>'zhuo','罬'=>'zhuo','茁'=>'zhuo','蠗'=>'zhuo','蠿'=>'zhuo','諁'=>'zhuo','諑'=>'zhuo','謶'=>'zhuo','诼'=>'zhuo','酌'=>'zhuo','鋜'=>'zhuo','鐯'=>'zhuo','鐲'=>'zhuo','镯'=>'zhuo','鵫'=>'zhuo','鷟'=>'zhuo','㑁'=>'zhuo','㣿'=>'zhuo','㪬'=>'zhuo','㭬'=>'zhuo','㺟'=>'zhuo','䅵'=>'zhuo','䕴'=>'zhuo','䶂'=>'zhuo','丶'=>'zhu','主'=>'zhu','伫'=>'zhu','佇'=>'zhu','住'=>'zhu','侏'=>'zhu','劚'=>'zhu','助'=>'zhu','劯'=>'zhu','嘱'=>'zhu','囑'=>'zhu','坾'=>'zhu','墸'=>'zhu','壴'=>'zhu','孎'=>'zhu','宔'=>'zhu','屬'=>'zhu','嵀'=>'zhu','拄'=>'zhu','斸'=>'zhu','曯'=>'zhu','朱'=>'zhu','杼'=>'zhu','柱'=>'zhu','柷'=>'zhu','株'=>'zhu','槠'=>'zhu','樦'=>'zhu','橥'=>'zhu','櫧'=>'zhu','櫫'=>'zhu','欘'=>'zhu','殶'=>'zhu','泏'=>'zhu','注'=>'zhu','洙'=>'zhu','渚'=>'zhu','潴'=>'zhu','濐'=>'zhu','瀦'=>'zhu','灟'=>'zhu','炢'=>'zhu','炷'=>'zhu','烛'=>'zhu','煑'=>'zhu','煮'=>'zhu','燭'=>'zhu','爥'=>'zhu','猪'=>'zhu','珠'=>'zhu','疰'=>'zhu','瘃'=>'zhu','眝'=>'zhu','瞩'=>'zhu','矚'=>'zhu','砫'=>'zhu','硃'=>'zhu','祝'=>'zhu','祩'=>'zhu','秼'=>'zhu','窋'=>'zhu','竚'=>'zhu','竹'=>'zhu','竺'=>'zhu','笁'=>'zhu','笜'=>'zhu','筑'=>'zhu','筯'=>'zhu','箸'=>'zhu','築'=>'zhu','篫'=>'zhu','紵'=>'zhu','紸'=>'zhu','絑'=>'zhu','纻'=>'zhu','罜'=>'zhu','羜'=>'zhu','翥'=>'zhu','舳'=>'zhu','芧'=>'zhu','苎'=>'zhu','苧'=>'zhu','茱'=>'zhu','茿'=>'zhu','莇'=>'zhu','著'=>'zhu','蓫'=>'zhu','藸'=>'zhu','蛀'=>'zhu','蛛'=>'zhu','蝫'=>'zhu','蠋'=>'zhu','蠩'=>'zhu','蠾'=>'zhu','袾'=>'zhu','註'=>'zhu','詝'=>'zhu','誅'=>'zhu','諸'=>'zhu','诛'=>'zhu','诸'=>'zhu','豬'=>'zhu','貯'=>'zhu','贮'=>'zhu','跓'=>'zhu','跦'=>'zhu','躅'=>'zhu','軴'=>'zhu','迬'=>'zhu','逐'=>'zhu','邾'=>'zhu','鉒'=>'zhu','銖'=>'zhu','鋳'=>'zhu','鑄'=>'zhu','钃'=>'zhu','铢'=>'zhu','铸'=>'zhu','陼'=>'zhu','霔'=>'zhu','飳'=>'zhu','馵'=>'zhu','駐'=>'zhu','駯'=>'zhu','驻'=>'zhu','鮢'=>'zhu','鯺'=>'zhu','鱁'=>'zhu','鴸'=>'zhu','麆'=>'zhu','麈'=>'zhu','鼄'=>'zhu','㑏'=>'zhu','㔉'=>'zhu','㝉'=>'zhu','㤖'=>'zhu','㧣'=>'zhu','㫂'=>'zhu','㵭'=>'zhu','㹥'=>'zhu','㺛'=>'zhu','㾻'=>'zhu','㿾'=>'zhu','䇡'=>'zhu','䇧'=>'zhu','䌵'=>'zhu','䍆'=>'zhu','䎷'=>'zhu','䐢'=>'zhu','䕽'=>'zhu','䘚'=>'zhu','䘢'=>'zhu','䝒'=>'zhu','䝬'=>'zhu','䟉'=>'zhu','䥮'=>'zhu','䬡'=>'zhu','䭖'=>'zhu','䮱'=>'zhu','䰞'=>'zhu','丷'=>'ha','哈'=>'ha','妎'=>'ha','鉿'=>'ha','铪'=>'ha','丹'=>'dan','亶'=>'dan','伔'=>'dan','但'=>'dan','僤'=>'dan','儋'=>'dan','刐'=>'dan','勯'=>'dan','匰'=>'dan','单'=>'dan','単'=>'dan','啖'=>'dan','啗'=>'dan','啿'=>'dan','單'=>'dan','嘾'=>'dan','噉'=>'dan','嚪'=>'dan','妉'=>'dan','媅'=>'dan','帎'=>'dan','弹'=>'dan','彈'=>'dan','惮'=>'dan','憚'=>'dan','憺'=>'dan','担'=>'dan','掸'=>'dan','撣'=>'dan','擔'=>'dan','旦'=>'dan','柦'=>'dan','殚'=>'dan','殫'=>'dan','氮'=>'dan','沊'=>'dan','泹'=>'dan','淡'=>'dan','澸'=>'dan','澹'=>'dan','狚'=>'dan','玬'=>'dan','瓭'=>'dan','甔'=>'dan','疍'=>'dan','疸'=>'dan','瘅'=>'dan','癉'=>'dan','癚'=>'dan','眈'=>'dan','砃'=>'dan','禫'=>'dan','窞'=>'dan','箪'=>'dan','簞'=>'dan','紞'=>'dan','耼'=>'dan','耽'=>'dan','聃'=>'dan','聸'=>'dan','胆'=>'dan','腅'=>'dan','膽'=>'dan','萏'=>'dan','蛋'=>'dan','蜑'=>'dan','衴'=>'dan','褝'=>'dan','襌'=>'dan','觛'=>'dan','訑'=>'dan','誕'=>'dan','诞'=>'dan','贉'=>'dan','躭'=>'dan','郸'=>'dan','鄲'=>'dan','酖'=>'dan','霮'=>'dan','頕'=>'dan','餤'=>'dan','饏'=>'dan','馾'=>'dan','駳'=>'dan','髧'=>'dan','鴠'=>'dan','黕'=>'dan','㔊'=>'dan','㕪'=>'dan','㗖'=>'dan','㡺'=>'dan','㫜'=>'dan','㱽'=>'dan','㲷'=>'dan','㵅'=>'dan','㺗'=>'dan','㽎'=>'dan','䃫'=>'dan','䄷'=>'dan','䉞'=>'dan','䉷'=>'dan','䨢'=>'dan','䨵'=>'dan','䩥'=>'dan','䭛'=>'dan','䮰'=>'dan','䱋'=>'dan','䳉'=>'dan','为'=>'wei','亹'=>'wei','伟'=>'wei','伪'=>'wei','位'=>'wei','偉'=>'wei','偎'=>'wei','偽'=>'wei','僞'=>'wei','儰'=>'wei','卫'=>'wei','危'=>'wei','厃'=>'wei','叞'=>'wei','味'=>'wei','唯'=>'wei','喂'=>'wei','喡'=>'wei','喴'=>'wei','囗'=>'wei','围'=>'wei','圍'=>'wei','圩'=>'wei','墛'=>'wei','壝'=>'wei','委'=>'wei','威'=>'wei','娓'=>'wei','媁'=>'wei','媙'=>'wei','媦'=>'wei','寪'=>'wei','尉'=>'wei','尾'=>'wei','峗'=>'wei','峞'=>'wei','崣'=>'wei','嵔'=>'wei','嵬'=>'wei','嶶'=>'wei','巍'=>'wei','帏'=>'wei','帷'=>'wei','幃'=>'wei','廆'=>'wei','徫'=>'wei','微'=>'wei','惟'=>'wei','愄'=>'wei','愇'=>'wei','慰'=>'wei','懀'=>'wei','捤'=>'wei','揋'=>'wei','揻'=>'wei','斖'=>'wei','昷'=>'wei','暐'=>'wei','未'=>'wei','桅'=>'wei','梶'=>'wei','椲'=>'wei','椳'=>'wei','楲'=>'wei','沩'=>'wei','洈'=>'wei','洧'=>'wei','浘'=>'wei','涠'=>'wei','渨'=>'wei','渭'=>'wei','湋'=>'wei','溈'=>'wei','溦'=>'wei','潍'=>'wei','潙'=>'wei','潿'=>'wei','濊'=>'wei','濰'=>'wei','濻'=>'wei','瀢'=>'wei','炜'=>'wei','為'=>'wei','烓'=>'wei','煀'=>'wei','煒'=>'wei','煟'=>'wei','煨'=>'wei','熭'=>'wei','燰'=>'wei','爲'=>'wei','犚'=>'wei','犩'=>'wei','猥'=>'wei','猬'=>'wei','玮'=>'wei','琟'=>'wei','瑋'=>'wei','璏'=>'wei','畏'=>'wei','痏'=>'wei','痿'=>'wei','癐'=>'wei','癓'=>'wei','硊'=>'wei','硙'=>'wei','碨'=>'wei','磑'=>'wei','維'=>'wei','緭'=>'wei','緯'=>'wei','縅'=>'wei','纬'=>'wei','维'=>'wei','罻'=>'wei','胃'=>'wei','腲'=>'wei','艉'=>'wei','芛'=>'wei','苇'=>'wei','苿'=>'wei','荱'=>'wei','菋'=>'wei','萎'=>'wei','葦'=>'wei','葨'=>'wei','葳'=>'wei','蒍'=>'wei','蓶'=>'wei','蔚'=>'wei','蔿'=>'wei','薇'=>'wei','薳'=>'wei','藯'=>'wei','蘶'=>'wei','蜲'=>'wei','蜼'=>'wei','蝛'=>'wei','蝟'=>'wei','螱'=>'wei','衛'=>'wei','衞'=>'wei','褽'=>'wei','覣'=>'wei','覹'=>'wei','詴'=>'wei','諉'=>'wei','謂'=>'wei','讆'=>'wei','讏'=>'wei','诿'=>'wei','谓'=>'wei','踓'=>'wei','躗'=>'wei','躛'=>'wei','軎'=>'wei','轊'=>'wei','违'=>'wei','逶'=>'wei','違'=>'wei','鄬'=>'wei','醀'=>'wei','錗'=>'wei','鍏'=>'wei','鍡'=>'wei','鏏'=>'wei','闈'=>'wei','闱'=>'wei','隇'=>'wei','隈'=>'wei','隗'=>'wei','霨'=>'wei','霺'=>'wei','霻'=>'wei','韋'=>'wei','韑'=>'wei','韙'=>'wei','韡'=>'wei','韦'=>'wei','韪'=>'wei','頠'=>'wei','颹'=>'wei','餧'=>'wei','餵'=>'wei','饖'=>'wei','骩'=>'wei','骪'=>'wei','骫'=>'wei','魏'=>'wei','鮇'=>'wei','鮠'=>'wei','鮪'=>'wei','鰃'=>'wei','鰄'=>'wei','鲔'=>'wei','鳂'=>'wei','鳚'=>'wei','㕒'=>'wei','㖐'=>'wei','㞇'=>'wei','㞑'=>'wei','㟪'=>'wei','㠕'=>'wei','㢻'=>'wei','㣲'=>'wei','㥜'=>'wei','㦣'=>'wei','㧑'=>'wei','㨊'=>'wei','㬙'=>'wei','㭏'=>'wei','㱬'=>'wei','㷉'=>'wei','䃬'=>'wei','䈧'=>'wei','䉠'=>'wei','䑊'=>'wei','䔺'=>'wei','䗽'=>'wei','䘙'=>'wei','䙿'=>'wei','䜅'=>'wei','䜜'=>'wei','䝐'=>'wei','䞔'=>'wei','䡺'=>'wei','䥩'=>'wei','䧦'=>'wei','䪋'=>'wei','䪘'=>'wei','䬐'=>'wei','䬑'=>'wei','䬿'=>'wei','䭳'=>'wei','䮹'=>'wei','䲁'=>'wei','䵋'=>'wei','䵳'=>'wei','丼'=>'jing','井'=>'jing','京'=>'jing','亰'=>'jing','俓'=>'jing','倞'=>'jing','傹'=>'jing','儆'=>'jing','兢'=>'jing','净'=>'jing','凈'=>'jing','刭'=>'jing','剄'=>'jing','坓'=>'jing','坕'=>'jing','坙'=>'jing','境'=>'jing','妌'=>'jing','婙'=>'jing','婛'=>'jing','婧'=>'jing','宑'=>'jing','巠'=>'jing','幜'=>'jing','弪'=>'jing','弳'=>'jing','径'=>'jing','徑'=>'jing','惊'=>'jing','憬'=>'jing','憼'=>'jing','敬'=>'jing','旌'=>'jing','旍'=>'jing','景'=>'jing','晶'=>'jing','暻'=>'jing','曔'=>'jing','桱'=>'jing','梷'=>'jing','橸'=>'jing','汫'=>'jing','汬'=>'jing','泾'=>'jing','浄'=>'jing','涇'=>'jing','淨'=>'jing','瀞'=>'jing','燝'=>'jing','燞'=>'jing','猄'=>'jing','獍'=>'jing','璄'=>'jing','璟'=>'jing','璥'=>'jing','痉'=>'jing','痙'=>'jing','睛'=>'jing','秔'=>'jing','稉'=>'jing','穽'=>'jing','竞'=>'jing','竟'=>'jing','竧'=>'jing','竫'=>'jing','競'=>'jing','竸'=>'jing','粳'=>'jing','精'=>'jing','経'=>'jing','經'=>'jing','经'=>'jing','聙'=>'jing','肼'=>'jing','胫'=>'jing','脛'=>'jing','腈'=>'jing','茎'=>'jing','荆'=>'jing','荊'=>'jing','莖'=>'jing','菁'=>'jing','蟼'=>'jing','誩'=>'jing','警'=>'jing','踁'=>'jing','迳'=>'jing','逕'=>'jing','鏡'=>'jing','镜'=>'jing','阱'=>'jing','靓'=>'jing','靖'=>'jing','静'=>'jing','靚'=>'jing','靜'=>'jing','頚'=>'jing','頸'=>'jing','颈'=>'jing','驚'=>'jing','鯨'=>'jing','鲸'=>'jing','鵛'=>'jing','鶁'=>'jing','鶄'=>'jing','麖'=>'jing','麠'=>'jing','鼱'=>'jing','㕋'=>'jing','㘫'=>'jing','㢣'=>'jing','㣏'=>'jing','㬌'=>'jing','㵾'=>'jing','㹵'=>'jing','䔔'=>'jing','䜘'=>'jing','䡖'=>'jing','䴖'=>'jing','䵞'=>'jing','丽'=>'li','例'=>'li','俐'=>'li','俚'=>'li','俪'=>'li','傈'=>'li','儮'=>'li','儷'=>'li','凓'=>'li','刕'=>'li','利'=>'li','剓'=>'li','剺'=>'li','劙'=>'li','力'=>'li','励'=>'li','勵'=>'li','历'=>'li','厉'=>'li','厘'=>'li','厤'=>'li','厯'=>'li','厲'=>'li','吏'=>'li','呖'=>'li','哩'=>'li','唎'=>'li','唳'=>'li','喱'=>'li','嚟'=>'li','嚦'=>'li','囄'=>'li','囇'=>'li','坜'=>'li','塛'=>'li','壢'=>'li','娌'=>'li','娳'=>'li','婯'=>'li','嫠'=>'li','孋'=>'li','孷'=>'li','屴'=>'li','岦'=>'li','峛'=>'li','峲'=>'li','巁'=>'li','廲'=>'li','悡'=>'li','悧'=>'li','悷'=>'li','慄'=>'li','戾'=>'li','搮'=>'li','攊'=>'li','攦'=>'li','攭'=>'li','斄'=>'li','暦'=>'li','曆'=>'li','曞'=>'li','朸'=>'li','李'=>'li','枥'=>'li','栃'=>'li','栎'=>'li','栗'=>'li','栛'=>'li','栵'=>'li','梨'=>'li','梸'=>'li','棃'=>'li','棙'=>'li','樆'=>'li','檪'=>'li','櫔'=>'li','櫟'=>'li','櫪'=>'li','欐'=>'li','欚'=>'li','歴'=>'li','歷'=>'li','氂'=>'li','沥'=>'li','沴'=>'li','浬'=>'li','涖'=>'li','溧'=>'li','漓'=>'li','澧'=>'li','濿'=>'li','瀝'=>'li','灕'=>'li','爄'=>'li','爏'=>'li','犁'=>'li','犂'=>'li','犛'=>'li','犡'=>'li','狸'=>'li','猁'=>'li','珕'=>'li','理'=>'li','琍'=>'li','瑮'=>'li','璃'=>'li','瓅'=>'li','瓈'=>'li','瓑'=>'li','瓥'=>'li','疠'=>'li','疬'=>'li','痢'=>'li','癘'=>'li','癧'=>'li','皪'=>'li','盠'=>'li','盭'=>'li','睝'=>'li','砅'=>'li','砺'=>'li','砾'=>'li','磿'=>'li','礪'=>'li','礫'=>'li','礰'=>'li','礼'=>'li','禮'=>'li','禲'=>'li','离'=>'li','秝'=>'li','穲'=>'li','立'=>'li','竰'=>'li','笠'=>'li','筣'=>'li','篥'=>'li','篱'=>'li','籬'=>'li','粒'=>'li','粝'=>'li','粴'=>'li','糎'=>'li','糲'=>'li','綟'=>'li','縭'=>'li','缡'=>'li','罹'=>'li','艃'=>'li','苈'=>'li','苙'=>'li','茘'=>'li','荔'=>'li','荲'=>'li','莅'=>'li','莉'=>'li','菞'=>'li','蒚'=>'li','蒞'=>'li','蓠'=>'li','蔾'=>'li','藜'=>'li','藶'=>'li','蘺'=>'li','蚸'=>'li','蛎'=>'li','蛠'=>'li','蜊'=>'li','蜧'=>'li','蟍'=>'li','蟸'=>'li','蠇'=>'li','蠡'=>'li','蠣'=>'li','蠫'=>'li','裏'=>'li','裡'=>'li','褵'=>'li','詈'=>'li','謧'=>'li','讈'=>'li','豊'=>'li','貍'=>'li','赲'=>'li','跞'=>'li','躒'=>'li','轢'=>'li','轣'=>'li','轹'=>'li','逦'=>'li','邌'=>'li','邐'=>'li','郦'=>'li','酈'=>'li','醨'=>'li','醴'=>'li','里'=>'li','釐'=>'li','鉝'=>'li','鋫'=>'li','鋰'=>'li','錅'=>'li','鏫'=>'li','鑗'=>'li','锂'=>'li','隶'=>'li','隷'=>'li','隸'=>'li','離'=>'li','雳'=>'li','靂'=>'li','靋'=>'li','驪'=>'li','骊'=>'li','鬁'=>'li','鯉'=>'li','鯏'=>'li','鯬'=>'li','鱧'=>'li','鱱'=>'li','鱺'=>'li','鲡'=>'li','鲤'=>'li','鳢'=>'li','鳨'=>'li','鴗'=>'li','鵹'=>'li','鷅'=>'li','鸝'=>'li','鹂'=>'li','麗'=>'li','麜'=>'li','黎'=>'li','黧'=>'li','㑦'=>'li','㒧'=>'li','㒿'=>'li','㓯'=>'li','㔏'=>'li','㕸'=>'li','㗚'=>'li','㘑'=>'li','㟳'=>'li','㠟'=>'li','㡂'=>'li','㤡'=>'li','㤦'=>'li','㦒'=>'li','㧰'=>'li','㬏'=>'li','㮚'=>'li','㯤'=>'li','㰀'=>'li','㰚'=>'li','㱹'=>'li','㴝'=>'li','㷰'=>'li','㸚'=>'li','㹈'=>'li','㺡'=>'li','㻎'=>'li','㻺'=>'li','㼖'=>'li','㽁'=>'li','㽝'=>'li','㾐'=>'li','㾖'=>'li','㿛'=>'li','㿨'=>'li','䁻'=>'li','䃯'=>'li','䄜'=>'li','䅄'=>'li','䅻'=>'li','䇐'=>'li','䉫'=>'li','䊍'=>'li','䊪'=>'li','䋥'=>'li','䍠'=>'li','䍦'=>'li','䍽'=>'li','䓞'=>'li','䔁'=>'li','䔆'=>'li','䔉'=>'li','䔣'=>'li','䔧'=>'li','䖥'=>'li','䖽'=>'li','䖿'=>'li','䗍'=>'li','䘈'=>'li','䙰'=>'li','䚕'=>'li','䟏'=>'li','䟐'=>'li','䡃'=>'li','䣓'=>'li','䣫'=>'li','䤙'=>'li','䤚'=>'li','䥶'=>'li','䧉'=>'li','䬅'=>'li','䬆'=>'li','䮋'=>'li','䮥'=>'li','䰛'=>'li','䰜'=>'li','䱘'=>'li','䲞'=>'li','䴄'=>'li','䴡'=>'li','䴻'=>'li','䵓'=>'li','䵩'=>'li','䶘'=>'li','举'=>'ju','侷'=>'ju','俱'=>'ju','倨'=>'ju','倶'=>'ju','僪'=>'ju','具'=>'ju','冣'=>'ju','凥'=>'ju','剧'=>'ju','劇'=>'ju','勮'=>'ju','匊'=>'ju','句'=>'ju','咀'=>'ju','圧'=>'ju','埧'=>'ju','埾'=>'ju','壉'=>'ju','姖'=>'ju','娵'=>'ju','婅'=>'ju','婮'=>'ju','寠'=>'ju','局'=>'ju','居'=>'ju','屦'=>'ju','屨'=>'ju','岠'=>'ju','崌'=>'ju','巈'=>'ju','巨'=>'ju','弆'=>'ju','怇'=>'ju','怚'=>'ju','惧'=>'ju','愳'=>'ju','懅'=>'ju','懼'=>'ju','抅'=>'ju','拒'=>'ju','拘'=>'ju','拠'=>'ju','挙'=>'ju','挶'=>'ju','捄'=>'ju','据'=>'ju','掬'=>'ju','據'=>'ju','擧'=>'ju','昛'=>'ju','梮'=>'ju','椇'=>'ju','椈'=>'ju','椐'=>'ju','榉'=>'ju','榘'=>'ju','橘'=>'ju','檋'=>'ju','櫸'=>'ju','欅'=>'ju','歫'=>'ju','毩'=>'ju','毱'=>'ju','沮'=>'ju','泃'=>'ju','泦'=>'ju','洰'=>'ju','涺'=>'ju','淗'=>'ju','湨'=>'ju','澽'=>'ju','炬'=>'ju','焗'=>'ju','焣'=>'ju','爠'=>'ju','犋'=>'ju','犑'=>'ju','狊'=>'ju','狙'=>'ju','琚'=>'ju','疽'=>'ju','痀'=>'ju','眗'=>'ju','瞿'=>'ju','矩'=>'ju','砠'=>'ju','秬'=>'ju','窭'=>'ju','窶'=>'ju','筥'=>'ju','簴'=>'ju','粔'=>'ju','粷'=>'ju','罝'=>'ju','耟'=>'ju','聚'=>'ju','聥'=>'ju','腒'=>'ju','舉'=>'ju','艍'=>'ju','苣'=>'ju','苴'=>'ju','莒'=>'ju','菊'=>'ju','蒟'=>'ju','蓻'=>'ju','蘜'=>'ju','虡'=>'ju','蚷'=>'ju','蜛'=>'ju','袓'=>'ju','裾'=>'ju','襷'=>'ju','詎'=>'ju','諊'=>'ju','讵'=>'ju','豦'=>'ju','貗'=>'ju','趄'=>'ju','趜'=>'ju','跔'=>'ju','跙'=>'ju','距'=>'ju','跼'=>'ju','踘'=>'ju','踞'=>'ju','踽'=>'ju','蹫'=>'ju','躆'=>'ju','躹'=>'ju','輂'=>'ju','遽'=>'ju','邭'=>'ju','郹'=>'ju','醵'=>'ju','鉅'=>'ju','鋦'=>'ju','鋸'=>'ju','鐻'=>'ju','钜'=>'ju','锔'=>'ju','锯'=>'ju','閰'=>'ju','陱'=>'ju','雎'=>'ju','鞠'=>'ju','鞫'=>'ju','颶'=>'ju','飓'=>'ju','駏'=>'ju','駒'=>'ju','駶'=>'ju','驧'=>'ju','驹'=>'ju','鮈'=>'ju','鮔'=>'ju','鴡'=>'ju','鵙'=>'ju','鵴'=>'ju','鶋'=>'ju','鶪'=>'ju','鼰'=>'ju','鼳'=>'ju','齟'=>'ju','龃'=>'ju','㘌'=>'ju','㘲'=>'ju','㜘'=>'ju','㞐'=>'ju','㞫'=>'ju','㠪'=>'ju','㥌'=>'ju','㨿'=>'ju','㩀'=>'ju','㩴'=>'ju','㬬'=>'ju','㮂'=>'ju','㳥'=>'ju','㽤'=>'ju','䃊'=>'ju','䄔'=>'ju','䅓'=>'ju','䆽'=>'ju','䈮'=>'ju','䋰'=>'ju','䏱'=>'ju','䕮'=>'ju','䗇'=>'ju','䛯'=>'ju','䜯'=>'ju','䡞'=>'ju','䢹'=>'ju','䣰'=>'ju','䤎'=>'ju','䪕'=>'ju','䰬'=>'ju','䱟'=>'ju','䱡'=>'ju','䴗'=>'ju','䵕'=>'ju','䶙'=>'ju','䶥'=>'ju','丿'=>'pie','嫳'=>'pie','撆'=>'pie','撇'=>'pie','暼'=>'pie','氕'=>'pie','瞥'=>'pie','苤'=>'pie','鐅'=>'pie','䥕'=>'pie','乀'=>'fu','付'=>'fu','伏'=>'fu','伕'=>'fu','俌'=>'fu','俘'=>'fu','俯'=>'fu','偩'=>'fu','傅'=>'fu','冨'=>'fu','冹'=>'fu','凫'=>'fu','刜'=>'fu','副'=>'fu','匐'=>'fu','呋'=>'fu','呒'=>'fu','咈'=>'fu','咐'=>'fu','哹'=>'fu','坿'=>'fu','垘'=>'fu','复'=>'fu','夫'=>'fu','妇'=>'fu','妋'=>'fu','姇'=>'fu','娐'=>'fu','婏'=>'fu','婦'=>'fu','媍'=>'fu','孚'=>'fu','孵'=>'fu','富'=>'fu','尃'=>'fu','岪'=>'fu','峊'=>'fu','巿'=>'fu','帗'=>'fu','幅'=>'fu','幞'=>'fu','府'=>'fu','弗'=>'fu','弣'=>'fu','彿'=>'fu','復'=>'fu','怤'=>'fu','怫'=>'fu','懯'=>'fu','扶'=>'fu','抚'=>'fu','拂'=>'fu','拊'=>'fu','捬'=>'fu','撫'=>'fu','敷'=>'fu','斧'=>'fu','旉'=>'fu','服'=>'fu','枎'=>'fu','枹'=>'fu','柎'=>'fu','柫'=>'fu','栿'=>'fu','桴'=>'fu','棴'=>'fu','椨'=>'fu','椱'=>'fu','榑'=>'fu','氟'=>'fu','泭'=>'fu','洑'=>'fu','浮'=>'fu','涪'=>'fu','滏'=>'fu','澓'=>'fu','炥'=>'fu','烰'=>'fu','焤'=>'fu','父'=>'fu','猤'=>'fu','玞'=>'fu','玸'=>'fu','琈'=>'fu','甫'=>'fu','甶'=>'fu','畉'=>'fu','畐'=>'fu','畗'=>'fu','癁'=>'fu','盙'=>'fu','砆'=>'fu','砩'=>'fu','祓'=>'fu','祔'=>'fu','福'=>'fu','禣'=>'fu','秿'=>'fu','稃'=>'fu','稪'=>'fu','竎'=>'fu','符'=>'fu','笰'=>'fu','筟'=>'fu','箙'=>'fu','簠'=>'fu','粰'=>'fu','糐'=>'fu','紨'=>'fu','紱'=>'fu','紼'=>'fu','絥'=>'fu','綍'=>'fu','綒'=>'fu','緮'=>'fu','縛'=>'fu','绂'=>'fu','绋'=>'fu','缚'=>'fu','罘'=>'fu','罦'=>'fu','翇'=>'fu','肤'=>'fu','胕'=>'fu','脯'=>'fu','腐'=>'fu','腑'=>'fu','腹'=>'fu','膚'=>'fu','艀'=>'fu','艴'=>'fu','芙'=>'fu','芣'=>'fu','芾'=>'fu','苻'=>'fu','茀'=>'fu','茯'=>'fu','荂'=>'fu','荴'=>'fu','莩'=>'fu','菔'=>'fu','萯'=>'fu','葍'=>'fu','蕧'=>'fu','虙'=>'fu','蚥'=>'fu','蚨'=>'fu','蚹'=>'fu','蛗'=>'fu','蜅'=>'fu','蜉'=>'fu','蝜'=>'fu','蝠'=>'fu','蝮'=>'fu','衭'=>'fu','袝'=>'fu','袱'=>'fu','複'=>'fu','褔'=>'fu','襆'=>'fu','襥'=>'fu','覄'=>'fu','覆'=>'fu','訃'=>'fu','詂'=>'fu','諨'=>'fu','讣'=>'fu','豧'=>'fu','負'=>'fu','賦'=>'fu','賻'=>'fu','负'=>'fu','赋'=>'fu','赙'=>'fu','赴'=>'fu','趺'=>'fu','跗'=>'fu','踾'=>'fu','輔'=>'fu','輹'=>'fu','輻'=>'fu','辅'=>'fu','辐'=>'fu','邞'=>'fu','郙'=>'fu','郛'=>'fu','鄜'=>'fu','酜'=>'fu','釜'=>'fu','釡'=>'fu','鈇'=>'fu','鉘'=>'fu','鉜'=>'fu','鍑'=>'fu','鍢'=>'fu','阜'=>'fu','阝'=>'fu','附'=>'fu','陚'=>'fu','韍'=>'fu','韨'=>'fu','颫'=>'fu','馥'=>'fu','駙'=>'fu','驸'=>'fu','髴'=>'fu','鬴'=>'fu','鮄'=>'fu','鮒'=>'fu','鮲'=>'fu','鰒'=>'fu','鲋'=>'fu','鳆'=>'fu','鳧'=>'fu','鳬'=>'fu','鳺'=>'fu','鴔'=>'fu','鵩'=>'fu','鶝'=>'fu','麩'=>'fu','麬'=>'fu','麱'=>'fu','麸'=>'fu','黻'=>'fu','黼'=>'fu','㓡'=>'fu','㕮'=>'fu','㙏'=>'fu','㚆'=>'fu','㚕'=>'fu','㜑'=>'fu','㟊'=>'fu','㠅'=>'fu','㤔'=>'fu','㤱'=>'fu','㪄'=>'fu','㫙'=>'fu','㬼'=>'fu','㳇'=>'fu','㵗'=>'fu','㽬'=>'fu','㾈'=>'fu','䂤'=>'fu','䃽'=>'fu','䋨'=>'fu','䋹'=>'fu','䌗'=>'fu','䌿'=>'fu','䍖'=>'fu','䎅'=>'fu','䑧'=>'fu','䒀'=>'fu','䒇'=>'fu','䓛'=>'fu','䔰'=>'fu','䕎'=>'fu','䗄'=>'fu','䘀'=>'fu','䘄'=>'fu','䘠'=>'fu','䝾'=>'fu','䞜'=>'fu','䞞'=>'fu','䞯'=>'fu','䞸'=>'fu','䟔'=>'fu','䟮'=>'fu','䠵'=>'fu','䡍'=>'fu','䦣'=>'fu','䧞'=>'fu','䨗'=>'fu','䨱'=>'fu','䩉'=>'fu','䪙'=>'fu','䫍'=>'fu','䫝'=>'fu','䭸'=>'fu','䮛'=>'fu','䯱'=>'fu','䯽'=>'fu','䵗'=>'fu','䵾'=>'fu','乃'=>'nai','倷'=>'nai','奈'=>'nai','奶'=>'nai','妳'=>'nai','嬭'=>'nai','孻'=>'nai','廼'=>'nai','摨'=>'nai','柰'=>'nai','氖'=>'nai','渿'=>'nai','熋'=>'nai','疓'=>'nai','耐'=>'nai','腉'=>'nai','艿'=>'nai','萘'=>'nai','螚'=>'nai','褦'=>'nai','迺'=>'nai','釢'=>'nai','錼'=>'nai','鼐'=>'nai','㮈'=>'nai','㮏'=>'nai','㲡'=>'nai','㾍'=>'nai','䍲'=>'nai','䘅'=>'nai','䯮'=>'nai','乄'=>'wu','乌'=>'wu','五'=>'wu','仵'=>'wu','伆'=>'wu','伍'=>'wu','侮'=>'wu','俉'=>'wu','倵'=>'wu','儛'=>'wu','兀'=>'wu','剭'=>'wu','务'=>'wu','務'=>'wu','勿'=>'wu','午'=>'wu','吳'=>'wu','吴'=>'wu','吾'=>'wu','呉'=>'wu','呜'=>'wu','唔'=>'wu','啎'=>'wu','嗚'=>'wu','圬'=>'wu','坞'=>'wu','塢'=>'wu','奦'=>'wu','妩'=>'wu','娪'=>'wu','娬'=>'wu','婺'=>'wu','嫵'=>'wu','寤'=>'wu','屋'=>'wu','屼'=>'wu','岉'=>'wu','嵍'=>'wu','嵨'=>'wu','巫'=>'wu','庑'=>'wu','廡'=>'wu','弙'=>'wu','忢'=>'wu','忤'=>'wu','怃'=>'wu','悞'=>'wu','悟'=>'wu','悮'=>'wu','憮'=>'wu','戊'=>'wu','扤'=>'wu','捂'=>'wu','摀'=>'wu','敄'=>'wu','无'=>'wu','旿'=>'wu','晤'=>'wu','杇'=>'wu','杌'=>'wu','梧'=>'wu','橆'=>'wu','歍'=>'wu','武'=>'wu','毋'=>'wu','汙'=>'wu','汚'=>'wu','污'=>'wu','洖'=>'wu','洿'=>'wu','浯'=>'wu','溩'=>'wu','潕'=>'wu','烏'=>'wu','焐'=>'wu','焑'=>'wu','無'=>'wu','熃'=>'wu','熓'=>'wu','物'=>'wu','牾'=>'wu','玝'=>'wu','珷'=>'wu','珸'=>'wu','瑦'=>'wu','璑'=>'wu','甒'=>'wu','痦'=>'wu','矹'=>'wu','碔'=>'wu','祦'=>'wu','禑'=>'wu','窏'=>'wu','窹'=>'wu','箼'=>'wu','粅'=>'wu','舞'=>'wu','芜'=>'wu','芴'=>'wu','茣'=>'wu','莁'=>'wu','蕪'=>'wu','蘁'=>'wu','蜈'=>'wu','螐'=>'wu','誈'=>'wu','誣'=>'wu','誤'=>'wu','诬'=>'wu','误'=>'wu','趶'=>'wu','躌'=>'wu','迕'=>'wu','逜'=>'wu','邬'=>'wu','郚'=>'wu','鄔'=>'wu','釫'=>'wu','鋈'=>'wu','錻'=>'wu','鎢'=>'wu','钨'=>'wu','阢'=>'wu','隖'=>'wu','雾'=>'wu','霚'=>'wu','霧'=>'wu','靰'=>'wu','騖'=>'wu','骛'=>'wu','鯃'=>'wu','鰞'=>'wu','鴮'=>'wu','鵐'=>'wu','鵡'=>'wu','鶩'=>'wu','鷡'=>'wu','鹀'=>'wu','鹉'=>'wu','鹜'=>'wu','鼯'=>'wu','鼿'=>'wu','齀'=>'wu','㐅'=>'wu','㐳'=>'wu','㑄'=>'wu','㡔'=>'wu','㬳'=>'wu','㵲'=>'wu','㷻'=>'wu','㹳'=>'wu','㻍'=>'wu','㽾'=>'wu','䃖'=>'wu','䍢'=>'wu','䎸'=>'wu','䑁'=>'wu','䒉'=>'wu','䛩'=>'wu','䟼'=>'wu','䡧'=>'wu','䦍'=>'wu','䦜'=>'wu','䫓'=>'wu','䮏'=>'wu','䳇'=>'wu','䳱'=>'wu','乇'=>'tuo','佗'=>'tuo','侂'=>'tuo','侻'=>'tuo','咃'=>'tuo','唾'=>'tuo','坨'=>'tuo','堶'=>'tuo','妥'=>'tuo','媠'=>'tuo','嫷'=>'tuo','岮'=>'tuo','庹'=>'tuo','彵'=>'tuo','托'=>'tuo','扡'=>'tuo','拓'=>'tuo','拕'=>'tuo','拖'=>'tuo','挩'=>'tuo','捝'=>'tuo','撱'=>'tuo','杔'=>'tuo','柁'=>'tuo','柝'=>'tuo','椭'=>'tuo','楕'=>'tuo','槖'=>'tuo','橐'=>'tuo','橢'=>'tuo','毤'=>'tuo','毻'=>'tuo','汑'=>'tuo','沰'=>'tuo','沱'=>'tuo','涶'=>'tuo','狏'=>'tuo','砣'=>'tuo','砤'=>'tuo','碢'=>'tuo','箨'=>'tuo','籜'=>'tuo','紽'=>'tuo','脫'=>'tuo','脱'=>'tuo','莌'=>'tuo','萚'=>'tuo','蘀'=>'tuo','袉'=>'tuo','袥'=>'tuo','託'=>'tuo','詑'=>'tuo','讬'=>'tuo','跅'=>'tuo','跎'=>'tuo','踻'=>'tuo','迱'=>'tuo','酡'=>'tuo','陀'=>'tuo','陁'=>'tuo','飥'=>'tuo','饦'=>'tuo','馱'=>'tuo','馲'=>'tuo','駄'=>'tuo','駝'=>'tuo','駞'=>'tuo','騨'=>'tuo','驒'=>'tuo','驝'=>'tuo','驮'=>'tuo','驼'=>'tuo','魠'=>'tuo','鮀'=>'tuo','鰖'=>'tuo','鴕'=>'tuo','鵎'=>'tuo','鸵'=>'tuo','鼉'=>'tuo','鼍'=>'tuo','鼧'=>'tuo','㟎'=>'tuo','㸰'=>'tuo','㸱'=>'tuo','㼠'=>'tuo','㾃'=>'tuo','䍫'=>'tuo','䓕'=>'tuo','䡐'=>'tuo','䪑'=>'tuo','䭾'=>'tuo','䰿'=>'tuo','䲊'=>'tuo','䴱'=>'tuo','么'=>'me','嚒'=>'me','嚰'=>'me','庅'=>'me','濹'=>'me','癦'=>'me','乊'=>'ho','乥'=>'ho','之'=>'zhi','乿'=>'zhi','侄'=>'zhi','俧'=>'zhi','倁'=>'zhi','値'=>'zhi','值'=>'zhi','偫'=>'zhi','傂'=>'zhi','儨'=>'zhi','凪'=>'zhi','制'=>'zhi','劕'=>'zhi','劧'=>'zhi','卮'=>'zhi','厔'=>'zhi','只'=>'zhi','吱'=>'zhi','咫'=>'zhi','址'=>'zhi','坁'=>'zhi','坧'=>'zhi','垁'=>'zhi','埴'=>'zhi','執'=>'zhi','墆'=>'zhi','墌'=>'zhi','夂'=>'zhi','姪'=>'zhi','娡'=>'zhi','嬂'=>'zhi','寘'=>'zhi','峙'=>'zhi','崻'=>'zhi','巵'=>'zhi','帋'=>'zhi','帙'=>'zhi','帜'=>'zhi','幟'=>'zhi','庢'=>'zhi','庤'=>'zhi','廌'=>'zhi','彘'=>'zhi','徏'=>'zhi','徔'=>'zhi','徝'=>'zhi','志'=>'zhi','忮'=>'zhi','恉'=>'zhi','慹'=>'zhi','憄'=>'zhi','懥'=>'zhi','懫'=>'zhi','戠'=>'zhi','执'=>'zhi','扺'=>'zhi','扻'=>'zhi','抧'=>'zhi','挃'=>'zhi','指'=>'zhi','挚'=>'zhi','掷'=>'zhi','搘'=>'zhi','搱'=>'zhi','摭'=>'zhi','摯'=>'zhi','擲'=>'zhi','擿'=>'zhi','支'=>'zhi','旘'=>'zhi','旨'=>'zhi','晊'=>'zhi','智'=>'zhi','枝'=>'zhi','枳'=>'zhi','柣'=>'zhi','栀'=>'zhi','栉'=>'zhi','桎'=>'zhi','梔'=>'zhi','梽'=>'zhi','植'=>'zhi','椥'=>'zhi','榰'=>'zhi','槜'=>'zhi','樴'=>'zhi','櫍'=>'zhi','櫛'=>'zhi','止'=>'zhi','殖'=>'zhi','汁'=>'zhi','汥'=>'zhi','汦'=>'zhi','沚'=>'zhi','治'=>'zhi','洔'=>'zhi','洷'=>'zhi','淽'=>'zhi','滍'=>'zhi','滞'=>'zhi','滯'=>'zhi','漐'=>'zhi','潌'=>'zhi','潪'=>'zhi','瀄'=>'zhi','炙'=>'zhi','熫'=>'zhi','狾'=>'zhi','猘'=>'zhi','瓆'=>'zhi','瓡'=>'zhi','畤'=>'zhi','疐'=>'zhi','疷'=>'zhi','疻'=>'zhi','痔'=>'zhi','痣'=>'zhi','瘈'=>'zhi','直'=>'zhi','知'=>'zhi','砋'=>'zhi','礩'=>'zhi','祉'=>'zhi','祑'=>'zhi','祗'=>'zhi','祬'=>'zhi','禃'=>'zhi','禔'=>'zhi','禵'=>'zhi','秓'=>'zhi','秖'=>'zhi','秩'=>'zhi','秪'=>'zhi','秲'=>'zhi','秷'=>'zhi','稙'=>'zhi','稚'=>'zhi','稺'=>'zhi','穉'=>'zhi','窒'=>'zhi','筫'=>'zhi','紙'=>'zhi','紩'=>'zhi','絷'=>'zhi','綕'=>'zhi','緻'=>'zhi','縶'=>'zhi','織'=>'zhi','纸'=>'zhi','织'=>'zhi','置'=>'zhi','翐'=>'zhi','聀'=>'zhi','聁'=>'zhi','职'=>'zhi','職'=>'zhi','肢'=>'zhi','胑'=>'zhi','胝'=>'zhi','脂'=>'zhi','膣'=>'zhi','膱'=>'zhi','至'=>'zhi','致'=>'zhi','臸'=>'zhi','芖'=>'zhi','芝'=>'zhi','芷'=>'zhi','茋'=>'zhi','藢'=>'zhi','蘵'=>'zhi','蛭'=>'zhi','蜘'=>'zhi','螲'=>'zhi','蟙'=>'zhi','衹'=>'zhi','衼'=>'zhi','袟'=>'zhi','袠'=>'zhi','製'=>'zhi','襧'=>'zhi','覟'=>'zhi','觗'=>'zhi','觯'=>'zhi','觶'=>'zhi','訨'=>'zhi','誌'=>'zhi','謢'=>'zhi','豑'=>'zhi','豒'=>'zhi','豸'=>'zhi','貭'=>'zhi','質'=>'zhi','贄'=>'zhi','质'=>'zhi','贽'=>'zhi','趾'=>'zhi','跖'=>'zhi','跱'=>'zhi','踬'=>'zhi','踯'=>'zhi','蹠'=>'zhi','蹢'=>'zhi','躑'=>'zhi','躓'=>'zhi','軄'=>'zhi','軹'=>'zhi','輊'=>'zhi','轵'=>'zhi','轾'=>'zhi','郅'=>'zhi','酯'=>'zhi','釞'=>'zhi','銍'=>'zhi','鋕'=>'zhi','鑕'=>'zhi','铚'=>'zhi','锧'=>'zhi','阤'=>'zhi','阯'=>'zhi','陟'=>'zhi','隲'=>'zhi','隻'=>'zhi','雉'=>'zhi','馶'=>'zhi','馽'=>'zhi','駤'=>'zhi','騭'=>'zhi','騺'=>'zhi','驇'=>'zhi','骘'=>'zhi','鯯'=>'zhi','鳷'=>'zhi','鴙'=>'zhi','鴲'=>'zhi','鷙'=>'zhi','鸷'=>'zhi','黹'=>'zhi','鼅'=>'zhi','㕄'=>'zhi','㗌'=>'zhi','㗧'=>'zhi','㘉'=>'zhi','㙷'=>'zhi','㛿'=>'zhi','㜼'=>'zhi','㝂'=>'zhi','㣥'=>'zhi','㧻'=>'zhi','㨁'=>'zhi','㨖'=>'zhi','㮹'=>'zhi','㲛'=>'zhi','㴛'=>'zhi','䄺'=>'zhi','䅩'=>'zhi','䆈'=>'zhi','䇛'=>'zhi','䇽'=>'zhi','䉅'=>'zhi','䉜'=>'zhi','䌤'=>'zhi','䎺'=>'zhi','䏄'=>'zhi','䏯'=>'zhi','䐈'=>'zhi','䐭'=>'zhi','䑇'=>'zhi','䓌'=>'zhi','䕌'=>'zhi','䚦'=>'zhi','䛗'=>'zhi','䝷'=>'zhi','䞃'=>'zhi','䟈'=>'zhi','䡹'=>'zhi','䥍'=>'zhi','䦯'=>'zhi','䫕'=>'zhi','䬹'=>'zhi','䭁'=>'zhi','䱥'=>'zhi','䱨'=>'zhi','䳅'=>'zhi','䵂'=>'zhi','乍'=>'zha','偧'=>'zha','劄'=>'zha','厏'=>'zha','吒'=>'zha','咋'=>'zha','咤'=>'zha','哳'=>'zha','喳'=>'zha','奓'=>'zha','宱'=>'zha','扎'=>'zha','抯'=>'zha','挓'=>'zha','揸'=>'zha','搩'=>'zha','搾'=>'zha','摣'=>'zha','札'=>'zha','柤'=>'zha','柵'=>'zha','栅'=>'zha','楂'=>'zha','榨'=>'zha','樝'=>'zha','渣'=>'zha','溠'=>'zha','灹'=>'zha','炸'=>'zha','煠'=>'zha','牐'=>'zha','甴'=>'zha','痄'=>'zha','皶'=>'zha','皻'=>'zha','皼'=>'zha','眨'=>'zha','砟'=>'zha','箚'=>'zha','膪'=>'zha','苲'=>'zha','蚱'=>'zha','蚻'=>'zha','觰'=>'zha','詐'=>'zha','譇'=>'zha','譗'=>'zha','诈'=>'zha','踷'=>'zha','軋'=>'zha','轧'=>'zha','迊'=>'zha','醡'=>'zha','鍘'=>'zha','铡'=>'zha','閘'=>'zha','闸'=>'zha','霅'=>'zha','鮓'=>'zha','鮺'=>'zha','鲊'=>'zha','鲝'=>'zha','齄'=>'zha','齇'=>'zha','㒀'=>'zha','㡸'=>'zha','㱜'=>'zha','㴙'=>'zha','㷢'=>'zha','䋾'=>'zha','䕢'=>'zha','䖳'=>'zha','䛽'=>'zha','䞢'=>'zha','䥷'=>'zha','䵙'=>'zha','䵵'=>'zha','乎'=>'hu','乕'=>'hu','互'=>'hu','冱'=>'hu','冴'=>'hu','匢'=>'hu','匫'=>'hu','呼'=>'hu','唬'=>'hu','唿'=>'hu','喖'=>'hu','嘑'=>'hu','嘝'=>'hu','嚛'=>'hu','囫'=>'hu','垀'=>'hu','壶'=>'hu','壷'=>'hu','壺'=>'hu','婟'=>'hu','媩'=>'hu','嫭'=>'hu','嫮'=>'hu','寣'=>'hu','岵'=>'hu','帍'=>'hu','幠'=>'hu','弖'=>'hu','弧'=>'hu','忽'=>'hu','怙'=>'hu','恗'=>'hu','惚'=>'hu','戶'=>'hu','户'=>'hu','戸'=>'hu','戽'=>'hu','扈'=>'hu','抇'=>'hu','护'=>'hu','搰'=>'hu','摢'=>'hu','斛'=>'hu','昈'=>'hu','昒'=>'hu','曶'=>'hu','枑'=>'hu','楜'=>'hu','槲'=>'hu','槴'=>'hu','歑'=>'hu','汻'=>'hu','沍'=>'hu','沪'=>'hu','泘'=>'hu','浒'=>'hu','淴'=>'hu','湖'=>'hu','滬'=>'hu','滸'=>'hu','滹'=>'hu','瀫'=>'hu','烀'=>'hu','焀'=>'hu','煳'=>'hu','熩'=>'hu','狐'=>'hu','猢'=>'hu','琥'=>'hu','瑚'=>'hu','瓠'=>'hu','瓳'=>'hu','祜'=>'hu','笏'=>'hu','箎'=>'hu','箶'=>'hu','簄'=>'hu','粐'=>'hu','糊'=>'hu','絗'=>'hu','綔'=>'hu','縠'=>'hu','胡'=>'hu','膴'=>'hu','芐'=>'hu','苸'=>'hu','萀'=>'hu','葫'=>'hu','蔛'=>'hu','蔰'=>'hu','虍'=>'hu','虎'=>'hu','虖'=>'hu','虝'=>'hu','蝴'=>'hu','螜'=>'hu','衚'=>'hu','觳'=>'hu','謼'=>'hu','護'=>'hu','軤'=>'hu','轷'=>'hu','鄠'=>'hu','醐'=>'hu','錿'=>'hu','鍙'=>'hu','鍸'=>'hu','雐'=>'hu','雽'=>'hu','韄'=>'hu','頀'=>'hu','頶'=>'hu','餬'=>'hu','鬍'=>'hu','魱'=>'hu','鯱'=>'hu','鰗'=>'hu','鱯'=>'hu','鳠'=>'hu','鳸'=>'hu','鶘'=>'hu','鶦'=>'hu','鶮'=>'hu','鸌'=>'hu','鹕'=>'hu','鹱'=>'hu','㕆'=>'hu','㗅'=>'hu','㦿'=>'hu','㨭'=>'hu','㪶'=>'hu','㫚'=>'hu','㯛'=>'hu','㸦'=>'hu','㹱'=>'hu','㺉'=>'hu','㾰'=>'hu','㿥'=>'hu','䁫'=>'hu','䇘'=>'hu','䈸'=>'hu','䉉'=>'hu','䉿'=>'hu','䊀'=>'hu','䍓'=>'hu','䎁'=>'hu','䔯'=>'hu','䕶'=>'hu','䗂'=>'hu','䚛'=>'hu','䛎'=>'hu','䞱'=>'hu','䠒'=>'hu','䧼'=>'hu','䨥'=>'hu','䨼'=>'hu','䩴'=>'hu','䪝'=>'hu','䭅'=>'hu','䭌'=>'hu','䭍'=>'hu','䮸'=>'hu','䲵'=>'hu','乏'=>'fa','伐'=>'fa','佱'=>'fa','傠'=>'fa','发'=>'fa','垡'=>'fa','姂'=>'fa','彂'=>'fa','栰'=>'fa','橃'=>'fa','沷'=>'fa','法'=>'fa','灋'=>'fa','珐'=>'fa','琺'=>'fa','疺'=>'fa','発'=>'fa','發'=>'fa','瞂'=>'fa','砝'=>'fa','筏'=>'fa','罚'=>'fa','罰'=>'fa','罸'=>'fa','茷'=>'fa','藅'=>'fa','醗'=>'fa','鍅'=>'fa','閥'=>'fa','阀'=>'fa','髪'=>'fa','髮'=>'fa','㕹'=>'fa','㘺'=>'fa','㛲'=>'fa','䂲'=>'fa','䇅'=>'fa','䒥'=>'fa','䣹'=>'fa','乐'=>'le','仂'=>'le','勒'=>'le','叻'=>'le','忇'=>'le','扐'=>'le','楽'=>'le','樂'=>'le','氻'=>'le','泐'=>'le','玏'=>'le','砳'=>'le','竻'=>'le','簕'=>'le','艻'=>'le','阞'=>'le','韷'=>'le','餎'=>'le','饹'=>'le','鰳'=>'le','鳓'=>'le','㔹'=>'le','㖀'=>'le','㦡'=>'le','乑'=>'yin','乚'=>'yin','侌'=>'yin','冘'=>'yin','凐'=>'yin','印'=>'yin','吟'=>'yin','吲'=>'yin','唫'=>'yin','喑'=>'yin','噖'=>'yin','噾'=>'yin','嚚'=>'yin','囙'=>'yin','因'=>'yin','圁'=>'yin','垔'=>'yin','垠'=>'yin','垽'=>'yin','堙'=>'yin','夤'=>'yin','姻'=>'yin','婣'=>'yin','婬'=>'yin','寅'=>'yin','尹'=>'yin','峾'=>'yin','崟'=>'yin','崯'=>'yin','嶾'=>'yin','廕'=>'yin','廴'=>'yin','引'=>'yin','愔'=>'yin','慇'=>'yin','慭'=>'yin','憖'=>'yin','憗'=>'yin','懚'=>'yin','斦'=>'yin','朄'=>'yin','栶'=>'yin','檃'=>'yin','檭'=>'yin','檼'=>'yin','櫽'=>'yin','歅'=>'yin','殥'=>'yin','殷'=>'yin','氤'=>'yin','泿'=>'yin','洇'=>'yin','洕'=>'yin','淫'=>'yin','淾'=>'yin','湚'=>'yin','溵'=>'yin','滛'=>'yin','濥'=>'yin','濦'=>'yin','烎'=>'yin','犾'=>'yin','狺'=>'yin','猌'=>'yin','珢'=>'yin','璌'=>'yin','瘖'=>'yin','瘾'=>'yin','癊'=>'yin','癮'=>'yin','碒'=>'yin','磤'=>'yin','禋'=>'yin','秵'=>'yin','筃'=>'yin','粌'=>'yin','絪'=>'yin','緸'=>'yin','胤'=>'yin','苂'=>'yin','茚'=>'yin','茵'=>'yin','荫'=>'yin','荶'=>'yin','蒑'=>'yin','蔩'=>'yin','蔭'=>'yin','蘟'=>'yin','蚓'=>'yin','螾'=>'yin','蟫'=>'yin','裀'=>'yin','訔'=>'yin','訚'=>'yin','訡'=>'yin','誾'=>'yin','諲'=>'yin','讔'=>'yin','趛'=>'yin','鄞'=>'yin','酳'=>'yin','釿'=>'yin','鈏'=>'yin','鈝'=>'yin','銀'=>'yin','銦'=>'yin','铟'=>'yin','银'=>'yin','闉'=>'yin','阥'=>'yin','阴'=>'yin','陰'=>'yin','陻'=>'yin','隂'=>'yin','隐'=>'yin','隠'=>'yin','隱'=>'yin','霒'=>'yin','霠'=>'yin','霪'=>'yin','靷'=>'yin','鞇'=>'yin','音'=>'yin','韾'=>'yin','飮'=>'yin','飲'=>'yin','饮'=>'yin','駰'=>'yin','骃'=>'yin','鮣'=>'yin','鷣'=>'yin','齗'=>'yin','齦'=>'yin','龂'=>'yin','龈'=>'yin','㐆'=>'yin','㕂'=>'yin','㖗'=>'yin','㙬'=>'yin','㝙'=>'yin','㞤'=>'yin','㡥'=>'yin','㣧'=>'yin','㥯'=>'yin','㥼'=>'yin','㦩'=>'yin','㧈'=>'yin','㪦'=>'yin','㱃'=>'yin','㴈'=>'yin','㸒'=>'yin','㹜'=>'yin','㹞'=>'yin','㼉'=>'yin','㾙'=>'yin','䇙'=>'yin','䌥'=>'yin','䒡'=>'yin','䓄'=>'yin','䕃'=>'yin','䖜'=>'yin','䚿'=>'yin','䡛'=>'yin','䤃'=>'yin','䤺'=>'yin','䨸'=>'yin','䪩'=>'yin','䲟'=>'yin','乒'=>'ping','俜'=>'ping','凭'=>'ping','凴'=>'ping','呯'=>'ping','坪'=>'ping','塀'=>'ping','娦'=>'ping','屏'=>'ping','屛'=>'ping','岼'=>'ping','帡'=>'ping','帲'=>'ping','幈'=>'ping','平'=>'ping','慿'=>'ping','憑'=>'ping','枰'=>'ping','檘'=>'ping','洴'=>'ping','涄'=>'ping','淜'=>'ping','焩'=>'ping','玶'=>'ping','瓶'=>'ping','甁'=>'ping','甹'=>'ping','砯'=>'ping','竮'=>'ping','箳'=>'ping','簈'=>'ping','缾'=>'ping','聠'=>'ping','艵'=>'ping','苹'=>'ping','荓'=>'ping','萍'=>'ping','蓱'=>'ping','蘋'=>'ping','蚲'=>'ping','蛢'=>'ping','評'=>'ping','评'=>'ping','軿'=>'ping','輧'=>'ping','郱'=>'ping','頩'=>'ping','鮃'=>'ping','鲆'=>'ping','㺸'=>'ping','㻂'=>'ping','䍈'=>'ping','䶄'=>'ping','乓'=>'pang','厐'=>'pang','嗙'=>'pang','嫎'=>'pang','庞'=>'pang','旁'=>'pang','汸'=>'pang','沗'=>'pang','滂'=>'pang','炐'=>'pang','篣'=>'pang','耪'=>'pang','肨'=>'pang','胖'=>'pang','胮'=>'pang','膖'=>'pang','舽'=>'pang','螃'=>'pang','蠭'=>'pang','覫'=>'pang','逄'=>'pang','雱'=>'pang','霶'=>'pang','髈'=>'pang','鰟'=>'pang','鳑'=>'pang','龎'=>'pang','龐'=>'pang','㜊'=>'pang','㤶'=>'pang','㥬'=>'pang','㫄'=>'pang','䅭'=>'pang','䒍'=>'pang','䨦'=>'pang','䮾'=>'pang','乔'=>'qiao','侨'=>'qiao','俏'=>'qiao','僑'=>'qiao','僺'=>'qiao','劁'=>'qiao','喬'=>'qiao','嘺'=>'qiao','墝'=>'qiao','墽'=>'qiao','嫶'=>'qiao','峭'=>'qiao','嵪'=>'qiao','巧'=>'qiao','帩'=>'qiao','幧'=>'qiao','悄'=>'qiao','愀'=>'qiao','憔'=>'qiao','撬'=>'qiao','撽'=>'qiao','敲'=>'qiao','桥'=>'qiao','槗'=>'qiao','樵'=>'qiao','橇'=>'qiao','橋'=>'qiao','殼'=>'qiao','燆'=>'qiao','犞'=>'qiao','癄'=>'qiao','睄'=>'qiao','瞧'=>'qiao','硗'=>'qiao','硚'=>'qiao','碻'=>'qiao','磽'=>'qiao','礄'=>'qiao','窍'=>'qiao','竅'=>'qiao','繑'=>'qiao','繰'=>'qiao','缲'=>'qiao','翘'=>'qiao','翹'=>'qiao','荍'=>'qiao','荞'=>'qiao','菬'=>'qiao','蕎'=>'qiao','藮'=>'qiao','誚'=>'qiao','譙'=>'qiao','诮'=>'qiao','谯'=>'qiao','趫'=>'qiao','趬'=>'qiao','跷'=>'qiao','踍'=>'qiao','蹺'=>'qiao','蹻'=>'qiao','躈'=>'qiao','郻'=>'qiao','鄗'=>'qiao','鄡'=>'qiao','鄥'=>'qiao','釥'=>'qiao','鍫'=>'qiao','鍬'=>'qiao','鐈'=>'qiao','鐰'=>'qiao','锹'=>'qiao','陗'=>'qiao','鞒'=>'qiao','鞘'=>'qiao','鞩'=>'qiao','鞽'=>'qiao','韒'=>'qiao','頝'=>'qiao','顦'=>'qiao','骹'=>'qiao','髚'=>'qiao','髜'=>'qiao','㚁'=>'qiao','㚽'=>'qiao','㝯'=>'qiao','㡑'=>'qiao','㢗'=>'qiao','㤍'=>'qiao','㪣'=>'qiao','㴥'=>'qiao','䀉'=>'qiao','䃝'=>'qiao','䆻'=>'qiao','䇌'=>'qiao','䎗'=>'qiao','䩌'=>'qiao','䱁'=>'qiao','䲾'=>'qiao','乖'=>'guai','叏'=>'guai','夬'=>'guai','怪'=>'guai','恠'=>'guai','拐'=>'guai','枴'=>'guai','柺'=>'guai','箉'=>'guai','㧔'=>'guai','㷇'=>'guai','㽇'=>'guai','䂯'=>'guai','䊽'=>'guai','乜'=>'mie','吀'=>'mie','咩'=>'mie','哶'=>'mie','孭'=>'mie','幭'=>'mie','懱'=>'mie','搣'=>'mie','櫗'=>'mie','滅'=>'mie','瀎'=>'mie','灭'=>'mie','瓱'=>'mie','篾'=>'mie','蔑'=>'mie','薎'=>'mie','蠛'=>'mie','衊'=>'mie','覕'=>'mie','鑖'=>'mie','鱴'=>'mie','鴓'=>'mie','㒝'=>'mie','䁾'=>'mie','䈼'=>'mie','䘊'=>'mie','䩏'=>'mie','习'=>'xi','係'=>'xi','俙'=>'xi','傒'=>'xi','僖'=>'xi','兮'=>'xi','凞'=>'xi','匸'=>'xi','卌'=>'xi','卥'=>'xi','厀'=>'xi','吸'=>'xi','呬'=>'xi','咥'=>'xi','唏'=>'xi','唽'=>'xi','喜'=>'xi','嘻'=>'xi','噏'=>'xi','嚱'=>'xi','塈'=>'xi','壐'=>'xi','夕'=>'xi','奚'=>'xi','娭'=>'xi','媳'=>'xi','嬆'=>'xi','嬉'=>'xi','屃'=>'xi','屖'=>'xi','屗'=>'xi','屣'=>'xi','嵠'=>'xi','嶍'=>'xi','巇'=>'xi','希'=>'xi','席'=>'xi','徆'=>'xi','徙'=>'xi','徚'=>'xi','徯'=>'xi','忚'=>'xi','忥'=>'xi','怬'=>'xi','怸'=>'xi','恄'=>'xi','息'=>'xi','悉'=>'xi','悕'=>'xi','惁'=>'xi','惜'=>'xi','慀'=>'xi','憘'=>'xi','憙'=>'xi','戏'=>'xi','戯'=>'xi','戱'=>'xi','戲'=>'xi','扸'=>'xi','昔'=>'xi','晞'=>'xi','晰'=>'xi','晳'=>'xi','暿'=>'xi','曦'=>'xi','杫'=>'xi','析'=>'xi','枲'=>'xi','桸'=>'xi','椞'=>'xi','椺'=>'xi','榽'=>'xi','槢'=>'xi','樨'=>'xi','橀'=>'xi','橲'=>'xi','檄'=>'xi','欯'=>'xi','欷'=>'xi','歖'=>'xi','歙'=>'xi','歚'=>'xi','氥'=>'xi','汐'=>'xi','洗'=>'xi','浠'=>'xi','淅'=>'xi','渓'=>'xi','溪'=>'xi','滊'=>'xi','漇'=>'xi','漝'=>'xi','潝'=>'xi','潟'=>'xi','澙'=>'xi','烯'=>'xi','焁'=>'xi','焈'=>'xi','焟'=>'xi','焬'=>'xi','煕'=>'xi','熂'=>'xi','熄'=>'xi','熈'=>'xi','熙'=>'xi','熹'=>'xi','熺'=>'xi','熻'=>'xi','燨'=>'xi','爔'=>'xi','牺'=>'xi','犀'=>'xi','犔'=>'xi','犠'=>'xi','犧'=>'xi','狶'=>'xi','玺'=>'xi','琋'=>'xi','璽'=>'xi','瘜'=>'xi','皙'=>'xi','盻'=>'xi','睎'=>'xi','瞦'=>'xi','矖'=>'xi','矽'=>'xi','硒'=>'xi','磶'=>'xi','礂'=>'xi','禊'=>'xi','禧'=>'xi','稀'=>'xi','稧'=>'xi','穸'=>'xi','窸'=>'xi','粞'=>'xi','系'=>'xi','細'=>'xi','綌'=>'xi','緆'=>'xi','縰'=>'xi','繥'=>'xi','纚'=>'xi','细'=>'xi','绤'=>'xi','羲'=>'xi','習'=>'xi','翕'=>'xi','翖'=>'xi','肸'=>'xi','肹'=>'xi','膝'=>'xi','舄'=>'xi','舾'=>'xi','莃'=>'xi','菥'=>'xi','葈'=>'xi','葸'=>'xi','蒠'=>'xi','蒵'=>'xi','蓆'=>'xi','蓰'=>'xi','蕮'=>'xi','薂'=>'xi','虩'=>'xi','蜥'=>'xi','蝷'=>'xi','螅'=>'xi','螇'=>'xi','蟋'=>'xi','蟢'=>'xi','蠵'=>'xi','衋'=>'xi','袭'=>'xi','襲'=>'xi','西'=>'xi','覀'=>'xi','覡'=>'xi','覤'=>'xi','觋'=>'xi','觹'=>'xi','觽'=>'xi','觿'=>'xi','誒'=>'xi','諰'=>'xi','謑'=>'xi','謵'=>'xi','譆'=>'xi','诶'=>'xi','谿'=>'xi','豀'=>'xi','豨'=>'xi','豯'=>'xi','貕'=>'xi','赥'=>'xi','赩'=>'xi','趇'=>'xi','趘'=>'xi','蹝'=>'xi','躧'=>'xi','郄'=>'xi','郋'=>'xi','郗'=>'xi','郤'=>'xi','鄎'=>'xi','酅'=>'xi','醯'=>'xi','釳'=>'xi','釸'=>'xi','鈢'=>'xi','銑'=>'xi','錫'=>'xi','鎴'=>'xi','鏭'=>'xi','鑴'=>'xi','铣'=>'xi','锡'=>'xi','闟'=>'xi','阋'=>'xi','隙'=>'xi','隟'=>'xi','隰'=>'xi','隵'=>'xi','雟'=>'xi','霫'=>'xi','霼'=>'xi','飁'=>'xi','餏'=>'xi','餙'=>'xi','餼'=>'xi','饩'=>'xi','饻'=>'xi','騱'=>'xi','騽'=>'xi','驨'=>'xi','鬩'=>'xi','鯑'=>'xi','鰼'=>'xi','鱚'=>'xi','鳛'=>'xi','鵗'=>'xi','鸂'=>'xi','黖'=>'xi','鼷'=>'xi','㑶'=>'xi','㔒'=>'xi','㗩'=>'xi','㙾'=>'xi','㚛'=>'xi','㞒'=>'xi','㠄'=>'xi','㣟'=>'xi','㤴'=>'xi','㤸'=>'xi','㥡'=>'xi','㦻'=>'xi','㩗'=>'xi','㭡'=>'xi','㳧'=>'xi','㵿'=>'xi','㸍'=>'xi','㹫'=>'xi','㽯'=>'xi','㿇'=>'xi','䀘'=>'xi','䂀'=>'xi','䈪'=>'xi','䊠'=>'xi','䏮'=>'xi','䐼'=>'xi','䓇'=>'xi','䙽'=>'xi','䚷'=>'xi','䛥'=>'xi','䜁'=>'xi','䢄'=>'xi','䧍'=>'xi','䨳'=>'xi','䩤'=>'xi','䫣'=>'xi','䮎'=>'xi','䲪'=>'xi','乡'=>'xiang','享'=>'xiang','亯'=>'xiang','佭'=>'xiang','像'=>'xiang','勨'=>'xiang','厢'=>'xiang','向'=>'xiang','响'=>'xiang','啌'=>'xiang','嚮'=>'xiang','姠'=>'xiang','嶑'=>'xiang','巷'=>'xiang','庠'=>'xiang','廂'=>'xiang','忀'=>'xiang','想'=>'xiang','晑'=>'xiang','曏'=>'xiang','栙'=>'xiang','楿'=>'xiang','橡'=>'xiang','欀'=>'xiang','湘'=>'xiang','珦'=>'xiang','瓖'=>'xiang','瓨'=>'xiang','相'=>'xiang','祥'=>'xiang','箱'=>'xiang','絴'=>'xiang','緗'=>'xiang','缃'=>'xiang','缿'=>'xiang','翔'=>'xiang','膷'=>'xiang','芗'=>'xiang','萫'=>'xiang','葙'=>'xiang','薌'=>'xiang','蚃'=>'xiang','蟓'=>'xiang','蠁'=>'xiang','襄'=>'xiang','襐'=>'xiang','詳'=>'xiang','详'=>'xiang','象'=>'xiang','跭'=>'xiang','郷'=>'xiang','鄉'=>'xiang','鄊'=>'xiang','鄕'=>'xiang','銄'=>'xiang','鐌'=>'xiang','鑲'=>'xiang','镶'=>'xiang','響'=>'xiang','項'=>'xiang','项'=>'xiang','飨'=>'xiang','餉'=>'xiang','饗'=>'xiang','饟'=>'xiang','饷'=>'xiang','香'=>'xiang','驤'=>'xiang','骧'=>'xiang','鮝'=>'xiang','鯗'=>'xiang','鱌'=>'xiang','鱜'=>'xiang','鱶'=>'xiang','鲞'=>'xiang','麘'=>'xiang','㐮'=>'xiang','㗽'=>'xiang','㟄'=>'xiang','㟟'=>'xiang','䊑'=>'xiang','䐟'=>'xiang','䔗'=>'xiang','䖮'=>'xiang','䜶'=>'xiang','䢽'=>'xiang','乤'=>'hai','亥'=>'hai','咍'=>'hai','嗐'=>'hai','嗨'=>'hai','嚡'=>'hai','塰'=>'hai','孩'=>'hai','害'=>'hai','氦'=>'hai','海'=>'hai','烸'=>'hai','胲'=>'hai','酼'=>'hai','醢'=>'hai','餀'=>'hai','饚'=>'hai','駭'=>'hai','駴'=>'hai','骇'=>'hai','骸'=>'hai','㜾'=>'hai','㤥'=>'hai','㦟'=>'hai','㧡'=>'hai','㨟'=>'hai','㺔'=>'hai','䇋'=>'hai','䠽'=>'hai','䯐'=>'hai','䱺'=>'hai','书'=>'shu','侸'=>'shu','倏'=>'shu','倐'=>'shu','儵'=>'shu','叔'=>'shu','咰'=>'shu','塾'=>'shu','墅'=>'shu','姝'=>'shu','婌'=>'shu','孰'=>'shu','尌'=>'shu','尗'=>'shu','属'=>'shu','庶'=>'shu','庻'=>'shu','怷'=>'shu','恕'=>'shu','戍'=>'shu','抒'=>'shu','掓'=>'shu','摅'=>'shu','攄'=>'shu','数'=>'shu','數'=>'shu','暏'=>'shu','暑'=>'shu','曙'=>'shu','書'=>'shu','朮'=>'shu','术'=>'shu','束'=>'shu','杸'=>'shu','枢'=>'shu','柕'=>'shu','树'=>'shu','梳'=>'shu','樞'=>'shu','樹'=>'shu','橾'=>'shu','殊'=>'shu','殳'=>'shu','毹'=>'shu','毺'=>'shu','沭'=>'shu','淑'=>'shu','漱'=>'shu','潄'=>'shu','潻'=>'shu','澍'=>'shu','濖'=>'shu','瀭'=>'shu','焂'=>'shu','熟'=>'shu','瑹'=>'shu','璹'=>'shu','疎'=>'shu','疏'=>'shu','癙'=>'shu','秫'=>'shu','竖'=>'shu','竪'=>'shu','籔'=>'shu','糬'=>'shu','紓'=>'shu','絉'=>'shu','綀'=>'shu','纾'=>'shu','署'=>'shu','腧'=>'shu','舒'=>'shu','荗'=>'shu','菽'=>'shu','蒁'=>'shu','蔬'=>'shu','薥'=>'shu','薯'=>'shu','藷'=>'shu','虪'=>'shu','蜀'=>'shu','蠴'=>'shu','術'=>'shu','裋'=>'shu','襡'=>'shu','襩'=>'shu','豎'=>'shu','贖'=>'shu','赎'=>'shu','跾'=>'shu','踈'=>'shu','軗'=>'shu','輸'=>'shu','输'=>'shu','述'=>'shu','鄃'=>'shu','鉥'=>'shu','錰'=>'shu','鏣'=>'shu','陎'=>'shu','鮛'=>'shu','鱪'=>'shu','鱰'=>'shu','鵨'=>'shu','鶐'=>'shu','鶑'=>'shu','鸀'=>'shu','黍'=>'shu','鼠'=>'shu','鼡'=>'shu','㒔'=>'shu','㛸'=>'shu','㜐'=>'shu','㟬'=>'shu','㣽'=>'shu','㯮'=>'shu','㳆'=>'shu','㶖'=>'shu','㷂'=>'shu','㻿'=>'shu','㽰'=>'shu','㾁'=>'shu','䃞'=>'shu','䆝'=>'shu','䉀'=>'shu','䎉'=>'shu','䘤'=>'shu','䜹'=>'shu','䝂'=>'shu','䝪'=>'shu','䞖'=>'shu','䠱'=>'shu','䢤'=>'shu','䩱'=>'shu','䩳'=>'shu','䴰'=>'shu','乧'=>'dou','兜'=>'dou','兠'=>'dou','剅'=>'dou','吺'=>'dou','唗'=>'dou','抖'=>'dou','斗'=>'dou','斣'=>'dou','枓'=>'dou','梪'=>'dou','橷'=>'dou','毭'=>'dou','浢'=>'dou','痘'=>'dou','窦'=>'dou','竇'=>'dou','篼'=>'dou','脰'=>'dou','艔'=>'dou','荳'=>'dou','蔸'=>'dou','蚪'=>'dou','豆'=>'dou','逗'=>'dou','郖'=>'dou','酘'=>'dou','鈄'=>'dou','鋀'=>'dou','钭'=>'dou','閗'=>'dou','闘'=>'dou','阧'=>'dou','陡'=>'dou','餖'=>'dou','饾'=>'dou','鬥'=>'dou','鬦'=>'dou','鬪'=>'dou','鬬'=>'dou','鬭'=>'dou','㛒'=>'dou','㞳'=>'dou','㢄'=>'dou','㨮'=>'dou','㪷'=>'dou','㷆'=>'dou','䄈'=>'dou','䕆'=>'dou','䕱'=>'dou','䛠'=>'dou','䬦'=>'dou','乪'=>'nang','儾'=>'nang','嚢'=>'nang','囊'=>'nang','囔'=>'nang','擃'=>'nang','攮'=>'nang','曩'=>'nang','欜'=>'nang','灢'=>'nang','蠰'=>'nang','饢'=>'nang','馕'=>'nang','鬞'=>'nang','齉'=>'nang','㒄'=>'nang','㶞'=>'nang','䂇'=>'nang','乫'=>'kai','凯'=>'kai','凱'=>'kai','剀'=>'kai','剴'=>'kai','勓'=>'kai','嘅'=>'kai','垲'=>'kai','塏'=>'kai','奒'=>'kai','开'=>'kai','忾'=>'kai','恺'=>'kai','愷'=>'kai','愾'=>'kai','慨'=>'kai','揩'=>'kai','暟'=>'kai','楷'=>'kai','欬'=>'kai','炌'=>'kai','炏'=>'kai','烗'=>'kai','蒈'=>'kai','衉'=>'kai','輆'=>'kai','鍇'=>'kai','鎎'=>'kai','鎧'=>'kai','鐦'=>'kai','铠'=>'kai','锎'=>'kai','锴'=>'kai','開'=>'kai','闓'=>'kai','闿'=>'kai','颽'=>'kai','㡁'=>'kai','㲉'=>'kai','䁗'=>'kai','䐩'=>'kai','䒓'=>'kai','䡷'=>'kai','乬'=>'keng','劥'=>'keng','厼'=>'keng','吭'=>'keng','唟'=>'keng','坈'=>'keng','坑'=>'keng','巪'=>'keng','怾'=>'keng','挳'=>'keng','牼'=>'keng','硁'=>'keng','硜'=>'keng','硻'=>'keng','誙'=>'keng','銵'=>'keng','鍞'=>'keng','鏗'=>'keng','铿'=>'keng','䡰'=>'keng','乭'=>'ting','亭'=>'ting','侹'=>'ting','停'=>'ting','厅'=>'ting','厛'=>'ting','听'=>'ting','圢'=>'ting','娗'=>'ting','婷'=>'ting','嵉'=>'ting','庁'=>'ting','庭'=>'ting','廰'=>'ting','廳'=>'ting','廷'=>'ting','挺'=>'ting','桯'=>'ting','梃'=>'ting','楟'=>'ting','榳'=>'ting','汀'=>'ting','涏'=>'ting','渟'=>'ting','濎'=>'ting','烃'=>'ting','烴'=>'ting','烶'=>'ting','珽'=>'ting','町'=>'ting','筳'=>'ting','綎'=>'ting','耓'=>'ting','聤'=>'ting','聴'=>'ting','聼'=>'ting','聽'=>'ting','脡'=>'ting','艇'=>'ting','艈'=>'ting','艼'=>'ting','莛'=>'ting','葶'=>'ting','蜓'=>'ting','蝏'=>'ting','誔'=>'ting','諪'=>'ting','邒'=>'ting','鋌'=>'ting','铤'=>'ting','閮'=>'ting','霆'=>'ting','鞓'=>'ting','頲'=>'ting','颋'=>'ting','鼮'=>'ting','㹶'=>'ting','䋼'=>'ting','䗴'=>'ting','䦐'=>'ting','䱓'=>'ting','䵺'=>'ting','乮'=>'mo','劘'=>'mo','劰'=>'mo','嗼'=>'mo','嚤'=>'mo','嚩'=>'mo','圽'=>'mo','塻'=>'mo','墨'=>'mo','妺'=>'mo','嫫'=>'mo','嫼'=>'mo','寞'=>'mo','尛'=>'mo','帓'=>'mo','帞'=>'mo','怽'=>'mo','懡'=>'mo','抹'=>'mo','摩'=>'mo','摸'=>'mo','摹'=>'mo','擵'=>'mo','昩'=>'mo','暯'=>'mo','末'=>'mo','枺'=>'mo','模'=>'mo','橅'=>'mo','歾'=>'mo','歿'=>'mo','殁'=>'mo','沫'=>'mo','漠'=>'mo','爅'=>'mo','瘼'=>'mo','皌'=>'mo','眜'=>'mo','眽'=>'mo','眿'=>'mo','瞐'=>'mo','瞙'=>'mo','砞'=>'mo','磨'=>'mo','礳'=>'mo','秣'=>'mo','粖'=>'mo','糢'=>'mo','絈'=>'mo','縸'=>'mo','纆'=>'mo','耱'=>'mo','膜'=>'mo','茉'=>'mo','莈'=>'mo','莫'=>'mo','蓦'=>'mo','藦'=>'mo','蘑'=>'mo','蛨'=>'mo','蟔'=>'mo','袹'=>'mo','謨'=>'mo','謩'=>'mo','譕'=>'mo','谟'=>'mo','貃'=>'mo','貊'=>'mo','貘'=>'mo','銆'=>'mo','鏌'=>'mo','镆'=>'mo','陌'=>'mo','靺'=>'mo','饃'=>'mo','饝'=>'mo','馍'=>'mo','驀'=>'mo','髍'=>'mo','魔'=>'mo','魩'=>'mo','魹'=>'mo','麼'=>'mo','麽'=>'mo','麿'=>'mo','默'=>'mo','黙'=>'mo','㱄'=>'mo','㱳'=>'mo','㷬'=>'mo','㷵'=>'mo','㹮'=>'mo','䁼'=>'mo','䁿'=>'mo','䃺'=>'mo','䉑'=>'mo','䏞'=>'mo','䒬'=>'mo','䘃'=>'mo','䜆'=>'mo','䩋'=>'mo','䬴'=>'mo','䮬'=>'mo','䯢'=>'mo','䱅'=>'mo','䳮'=>'mo','䴲'=>'mo','乯'=>'ou','偶'=>'ou','吘'=>'ou','呕'=>'ou','嘔'=>'ou','噢'=>'ou','塸'=>'ou','夞'=>'ou','怄'=>'ou','慪'=>'ou','櫙'=>'ou','欧'=>'ou','歐'=>'ou','殴'=>'ou','毆'=>'ou','毮'=>'ou','沤'=>'ou','漚'=>'ou','熰'=>'ou','瓯'=>'ou','甌'=>'ou','筽'=>'ou','耦'=>'ou','腢'=>'ou','膒'=>'ou','蕅'=>'ou','藕'=>'ou','藲'=>'ou','謳'=>'ou','讴'=>'ou','鏂'=>'ou','鞰'=>'ou','鴎'=>'ou','鷗'=>'ou','鸥'=>'ou','齵'=>'ou','㒖'=>'ou','㛏'=>'ou','㼴'=>'ou','䌂'=>'ou','䌔'=>'ou','䚆'=>'ou','䯚'=>'ou','买'=>'mai','佅'=>'mai','劢'=>'mai','勱'=>'mai','卖'=>'mai','嘪'=>'mai','埋'=>'mai','売'=>'mai','脈'=>'mai','脉'=>'mai','荬'=>'mai','蕒'=>'mai','薶'=>'mai','衇'=>'mai','買'=>'mai','賣'=>'mai','迈'=>'mai','邁'=>'mai','霡'=>'mai','霢'=>'mai','霾'=>'mai','鷶'=>'mai','麥'=>'mai','麦'=>'mai','㜥'=>'mai','㼮'=>'mai','䁲'=>'mai','䈿'=>'mai','䘑'=>'mai','䚑'=>'mai','䜕'=>'mai','䨪'=>'mai','䨫'=>'mai','䮮'=>'mai','乱'=>'luan','亂'=>'luan','卵'=>'luan','圝'=>'luan','圞'=>'luan','奱'=>'luan','孌'=>'luan','孪'=>'luan','孿'=>'luan','峦'=>'luan','巒'=>'luan','挛'=>'luan','攣'=>'luan','曫'=>'luan','栾'=>'luan','欒'=>'luan','滦'=>'luan','灓'=>'luan','灤'=>'luan','癴'=>'luan','癵'=>'luan','羉'=>'luan','脔'=>'luan','臠'=>'luan','虊'=>'luan','釠'=>'luan','銮'=>'luan','鑾'=>'luan','鵉'=>'luan','鸞'=>'luan','鸾'=>'luan','㝈'=>'luan','㡩'=>'luan','㱍'=>'luan','䖂'=>'luan','䜌'=>'luan','乲'=>'cai','倸'=>'cai','偲'=>'cai','埰'=>'cai','婇'=>'cai','寀'=>'cai','彩'=>'cai','戝'=>'cai','才'=>'cai','採'=>'cai','材'=>'cai','棌'=>'cai','猜'=>'cai','睬'=>'cai','綵'=>'cai','縩'=>'cai','纔'=>'cai','菜'=>'cai','蔡'=>'cai','裁'=>'cai','財'=>'cai','财'=>'cai','跴'=>'cai','踩'=>'cai','采'=>'cai','㒲'=>'cai','㥒'=>'cai','䌨'=>'cai','䌽'=>'cai','䐆'=>'cai','䣋'=>'cai','䰂'=>'cai','䴭'=>'cai','乳'=>'ru','侞'=>'ru','儒'=>'ru','入'=>'ru','嗕'=>'ru','嚅'=>'ru','如'=>'ru','媷'=>'ru','嬬'=>'ru','孺'=>'ru','嶿'=>'ru','帤'=>'ru','扖'=>'ru','擩'=>'ru','曘'=>'ru','杁'=>'ru','桇'=>'ru','汝'=>'ru','洳'=>'ru','渪'=>'ru','溽'=>'ru','濡'=>'ru','燸'=>'ru','筎'=>'ru','縟'=>'ru','繻'=>'ru','缛'=>'ru','肗'=>'ru','茹'=>'ru','蒘'=>'ru','蓐'=>'ru','蕠'=>'ru','薷'=>'ru','蠕'=>'ru','袽'=>'ru','褥'=>'ru','襦'=>'ru','辱'=>'ru','込'=>'ru','邚'=>'ru','鄏'=>'ru','醹'=>'ru','銣'=>'ru','铷'=>'ru','顬'=>'ru','颥'=>'ru','鱬'=>'ru','鳰'=>'ru','鴑'=>'ru','鴽'=>'ru','㦺'=>'ru','㨎'=>'ru','㹘'=>'ru','䋈'=>'ru','䰰'=>'ru','乴'=>'xue','吷'=>'xue','坹'=>'xue','学'=>'xue','學'=>'xue','岤'=>'xue','峃'=>'xue','嶨'=>'xue','怴'=>'xue','斈'=>'xue','桖'=>'xue','樰'=>'xue','泧'=>'xue','泶'=>'xue','澩'=>'xue','瀥'=>'xue','烕'=>'xue','燢'=>'xue','狘'=>'xue','疦'=>'xue','疶'=>'xue','穴'=>'xue','膤'=>'xue','艝'=>'xue','茓'=>'xue','蒆'=>'xue','薛'=>'xue','血'=>'xue','袕'=>'xue','觷'=>'xue','謔'=>'xue','谑'=>'xue','趐'=>'xue','踅'=>'xue','轌'=>'xue','辥'=>'xue','雤'=>'xue','雪'=>'xue','靴'=>'xue','鞾'=>'xue','鱈'=>'xue','鳕'=>'xue','鷽'=>'xue','鸴'=>'xue','㖸'=>'xue','㞽'=>'xue','㡜'=>'xue','㧒'=>'xue','㶅'=>'xue','㿱'=>'xue','䎀'=>'xue','䤕'=>'xue','䨮'=>'xue','䫻'=>'xue','䫼'=>'xue','䬂'=>'xue','䭥'=>'xue','䱑'=>'xue','乶'=>'peng','倗'=>'peng','傰'=>'peng','剻'=>'peng','匉'=>'peng','喸'=>'peng','嘭'=>'peng','堋'=>'peng','塜'=>'peng','塳'=>'peng','巼'=>'peng','弸'=>'peng','彭'=>'peng','怦'=>'peng','恲'=>'peng','憉'=>'peng','抨'=>'peng','挷'=>'peng','捧'=>'peng','掽'=>'peng','搒'=>'peng','朋'=>'peng','梈'=>'peng','棚'=>'peng','椖'=>'peng','椪'=>'peng','槰'=>'peng','樥'=>'peng','泙'=>'peng','浌'=>'peng','淎'=>'peng','漨'=>'peng','漰'=>'peng','澎'=>'peng','烹'=>'peng','熢'=>'peng','皏'=>'peng','砰'=>'peng','硑'=>'peng','硼'=>'peng','碰'=>'peng','磞'=>'peng','稝'=>'peng','竼'=>'peng','篷'=>'peng','纄'=>'peng','胓'=>'peng','膨'=>'peng','芃'=>'peng','莑'=>'peng','蓬'=>'peng','蟚'=>'peng','蟛'=>'peng','踫'=>'peng','軯'=>'peng','輣'=>'peng','錋'=>'peng','鑝'=>'peng','閛'=>'peng','闏'=>'peng','韸'=>'peng','韼'=>'peng','駍'=>'peng','騯'=>'peng','髼'=>'peng','鬅'=>'peng','鬔'=>'peng','鵬'=>'peng','鹏'=>'peng','㛔'=>'peng','㥊'=>'peng','㼞'=>'peng','䄘'=>'peng','䡫'=>'peng','䰃'=>'peng','䴶'=>'peng','乷'=>'sha','倽'=>'sha','傻'=>'sha','儍'=>'sha','刹'=>'sha','唦'=>'sha','唼'=>'sha','啥'=>'sha','喢'=>'sha','帹'=>'sha','挱'=>'sha','杀'=>'sha','榝'=>'sha','樧'=>'sha','歃'=>'sha','殺'=>'sha','沙'=>'sha','煞'=>'sha','猀'=>'sha','痧'=>'sha','砂'=>'sha','硰'=>'sha','箑'=>'sha','粆'=>'sha','紗'=>'sha','繌'=>'sha','繺'=>'sha','纱'=>'sha','翜'=>'sha','翣'=>'sha','莎'=>'sha','萐'=>'sha','蔱'=>'sha','裟'=>'sha','鎩'=>'sha','铩'=>'sha','閯'=>'sha','閷'=>'sha','霎'=>'sha','魦'=>'sha','鯊'=>'sha','鯋'=>'sha','鲨'=>'sha','㚫'=>'sha','㛼'=>'sha','㰱'=>'sha','䈉'=>'sha','䝊'=>'sha','䮜'=>'sha','䵘'=>'sha','䶎'=>'sha','乸'=>'na','吶'=>'na','呐'=>'na','哪'=>'na','嗱'=>'na','妠'=>'na','娜'=>'na','拏'=>'na','拿'=>'na','挐'=>'na','捺'=>'na','笝'=>'na','納'=>'na','纳'=>'na','肭'=>'na','蒳'=>'na','衲'=>'na','袦'=>'na','誽'=>'na','豽'=>'na','貀'=>'na','軜'=>'na','那'=>'na','鈉'=>'na','鎿'=>'na','钠'=>'na','镎'=>'na','雫'=>'na','靹'=>'na','魶'=>'na','㗙'=>'na','㨥'=>'na','㴸'=>'na','䀑'=>'na','䅞'=>'na','䇣'=>'na','䇱'=>'na','䈫'=>'na','䎎'=>'na','䏧'=>'na','䖓'=>'na','䖧'=>'na','䛔'=>'na','䟜'=>'na','䪏'=>'na','䫱'=>'na','䱹'=>'na','乹'=>'qian','乾'=>'qian','仟'=>'qian','仱'=>'qian','伣'=>'qian','佥'=>'qian','俔'=>'qian','倩'=>'qian','偂'=>'qian','傔'=>'qian','僉'=>'qian','儙'=>'qian','凵'=>'qian','刋'=>'qian','前'=>'qian','千'=>'qian','嗛'=>'qian','圱'=>'qian','圲'=>'qian','堑'=>'qian','塹'=>'qian','墘'=>'qian','壍'=>'qian','奷'=>'qian','婜'=>'qian','媊'=>'qian','嬱'=>'qian','孯'=>'qian','岍'=>'qian','岒'=>'qian','嵌'=>'qian','嵰'=>'qian','忴'=>'qian','悓'=>'qian','悭'=>'qian','愆'=>'qian','慊'=>'qian','慳'=>'qian','扦'=>'qian','扲'=>'qian','拑'=>'qian','拪'=>'qian','掔'=>'qian','掮'=>'qian','揵'=>'qian','搴'=>'qian','摼'=>'qian','撁'=>'qian','攐'=>'qian','攑'=>'qian','攓'=>'qian','杄'=>'qian','棈'=>'qian','椠'=>'qian','榩'=>'qian','槏'=>'qian','槧'=>'qian','橬'=>'qian','檶'=>'qian','櫏'=>'qian','欠'=>'qian','欦'=>'qian','歉'=>'qian','歬'=>'qian','汘'=>'qian','汧'=>'qian','浅'=>'qian','淺'=>'qian','潛'=>'qian','潜'=>'qian','濳'=>'qian','灊'=>'qian','牵'=>'qian','牽'=>'qian','皘'=>'qian','竏'=>'qian','签'=>'qian','箝'=>'qian','箞'=>'qian','篏'=>'qian','篟'=>'qian','簽'=>'qian','籖'=>'qian','籤'=>'qian','粁'=>'qian','綪'=>'qian','縴'=>'qian','繾'=>'qian','缱'=>'qian','羬'=>'qian','肷'=>'qian','膁'=>'qian','臤'=>'qian','芊'=>'qian','芡'=>'qian','茜'=>'qian','茾'=>'qian','荨'=>'qian','蒨'=>'qian','蔳'=>'qian','蕁'=>'qian','虔'=>'qian','蚈'=>'qian','蜸'=>'qian','褰'=>'qian','諐'=>'qian','謙'=>'qian','譴'=>'qian','谦'=>'qian','谴'=>'qian','谸'=>'qian','軡'=>'qian','輤'=>'qian','迁'=>'qian','遣'=>'qian','遷'=>'qian','釺'=>'qian','鈆'=>'qian','鈐'=>'qian','鉆'=>'qian','鉗'=>'qian','鉛'=>'qian','銭'=>'qian','錢'=>'qian','鎆'=>'qian','鏲'=>'qian','鐱'=>'qian','鑓'=>'qian','钎'=>'qian','钤'=>'qian','钱'=>'qian','钳'=>'qian','铅'=>'qian','阡'=>'qian','雃'=>'qian','韆'=>'qian','顅'=>'qian','騚'=>'qian','騝'=>'qian','騫'=>'qian','骞'=>'qian','鬜'=>'qian','鬝'=>'qian','鰬'=>'qian','鵮'=>'qian','鹐'=>'qian','黔'=>'qian','黚'=>'qian','㐸'=>'qian','㜞'=>'qian','㟻'=>'qian','㡨'=>'qian','㦮'=>'qian','㧄'=>'qian','㨜'=>'qian','㩮'=>'qian','㯠'=>'qian','㸫'=>'qian','䁮'=>'qian','䈤'=>'qian','䈴'=>'qian','䊴'=>'qian','䍉'=>'qian','䖍'=>'qian','䥅'=>'qian','䦲'=>'qian','䨿'=>'qian','䪈'=>'qian','䫡'=>'qian','䭤'=>'qian','乻'=>'er','二'=>'er','仒'=>'er','佴'=>'er','侕'=>'er','儿'=>'er','児'=>'er','兒'=>'er','刵'=>'er','咡'=>'er','唲'=>'er','尒'=>'er','尓'=>'er','尔'=>'er','峏'=>'er','弍'=>'er','弐'=>'er','旕'=>'er','栭'=>'er','栮'=>'er','樲'=>'er','毦'=>'er','洏'=>'er','洱'=>'er','爾'=>'er','珥'=>'er','粫'=>'er','而'=>'er','耏'=>'er','耳'=>'er','聏'=>'er','胹'=>'er','荋'=>'er','薾'=>'er','衈'=>'er','袻'=>'er','誀'=>'er','貮'=>'er','貳'=>'er','贰'=>'er','趰'=>'er','輀'=>'er','轜'=>'er','迩'=>'er','邇'=>'er','鉺'=>'er','铒'=>'er','陑'=>'er','隭'=>'er','餌'=>'er','饵'=>'er','駬'=>'er','髵'=>'er','鮞'=>'er','鲕'=>'er','鴯'=>'er','鸸'=>'er','㒃'=>'er','㖇'=>'er','㚷'=>'er','㛅'=>'er','㜨'=>'er','㢽'=>'er','㧫'=>'er','㮕'=>'er','䋙'=>'er','䋩'=>'er','䌺'=>'er','䎟'=>'er','䎠'=>'er','䎶'=>'er','䏪'=>'er','䣵'=>'er','䮘'=>'er','乼'=>'cui','伜'=>'cui','倅'=>'cui','催'=>'cui','凗'=>'cui','啐'=>'cui','啛'=>'cui','墔'=>'cui','崔'=>'cui','嶉'=>'cui','忰'=>'cui','悴'=>'cui','慛'=>'cui','摧'=>'cui','榱'=>'cui','槯'=>'cui','毳'=>'cui','淬'=>'cui','漼'=>'cui','焠'=>'cui','獕'=>'cui','璀'=>'cui','疩'=>'cui','瘁'=>'cui','皠'=>'cui','磪'=>'cui','竁'=>'cui','粹'=>'cui','紣'=>'cui','綷'=>'cui','縗'=>'cui','缞'=>'cui','翆'=>'cui','翠'=>'cui','脃'=>'cui','脆'=>'cui','膬'=>'cui','膵'=>'cui','臎'=>'cui','萃'=>'cui','襊'=>'cui','趡'=>'cui','鏙'=>'cui','顇'=>'cui','㝮'=>'cui','㥞'=>'cui','㧘'=>'cui','㯔'=>'cui','㯜'=>'cui','㱖'=>'cui','㳃'=>'cui','㵏'=>'cui','㷃'=>'cui','㷪'=>'cui','䂱'=>'cui','䃀'=>'cui','䄟'=>'cui','䆊'=>'cui','䊫'=>'cui','䧽'=>'cui','乽'=>'ceng','噌'=>'ceng','层'=>'ceng','層'=>'ceng','岾'=>'ceng','嶒'=>'ceng','猠'=>'ceng','硛'=>'ceng','硳'=>'ceng','竲'=>'ceng','蹭'=>'ceng','驓'=>'ceng','㣒'=>'ceng','㬝'=>'ceng','䁬'=>'ceng','䉕'=>'ceng','亀'=>'gui','佹'=>'gui','刽'=>'gui','刿'=>'gui','劊'=>'gui','劌'=>'gui','匦'=>'gui','匭'=>'gui','厬'=>'gui','圭'=>'gui','垝'=>'gui','妫'=>'gui','姽'=>'gui','媯'=>'gui','嫢'=>'gui','嬀'=>'gui','宄'=>'gui','嶲'=>'gui','巂'=>'gui','帰'=>'gui','庋'=>'gui','庪'=>'gui','归'=>'gui','恑'=>'gui','摫'=>'gui','撌'=>'gui','攰'=>'gui','攱'=>'gui','昋'=>'gui','晷'=>'gui','柜'=>'gui','桂'=>'gui','椝'=>'gui','椢'=>'gui','槶'=>'gui','槻'=>'gui','槼'=>'gui','櫃'=>'gui','櫷'=>'gui','歸'=>'gui','氿'=>'gui','湀'=>'gui','溎'=>'gui','炅'=>'gui','珪'=>'gui','瑰'=>'gui','璝'=>'gui','瓌'=>'gui','癸'=>'gui','皈'=>'gui','瞆'=>'gui','瞡'=>'gui','瞶'=>'gui','硅'=>'gui','祪'=>'gui','禬'=>'gui','窐'=>'gui','筀'=>'gui','簂'=>'gui','簋'=>'gui','胿'=>'gui','膭'=>'gui','茥'=>'gui','蓕'=>'gui','蛫'=>'gui','蟡'=>'gui','袿'=>'gui','襘'=>'gui','規'=>'gui','规'=>'gui','觤'=>'gui','詭'=>'gui','诡'=>'gui','貴'=>'gui','贵'=>'gui','跪'=>'gui','軌'=>'gui','轨'=>'gui','邽'=>'gui','郌'=>'gui','閨'=>'gui','闺'=>'gui','陒'=>'gui','鞼'=>'gui','騩'=>'gui','鬶'=>'gui','鬹'=>'gui','鬼'=>'gui','鮭'=>'gui','鱖'=>'gui','鱥'=>'gui','鲑'=>'gui','鳜'=>'gui','龜'=>'gui','龟'=>'gui','㔳'=>'gui','㙺'=>'gui','㧪'=>'gui','㨳'=>'gui','㩻'=>'gui','㪈'=>'gui','㲹'=>'gui','㸵'=>'gui','䁛'=>'gui','䇈'=>'gui','䌆'=>'gui','䍯'=>'gui','䍷'=>'gui','䐴'=>'gui','䖯'=>'gui','䙆'=>'gui','䝿'=>'gui','䞈'=>'gui','䞨'=>'gui','䠩'=>'gui','䣀'=>'gui','䤥'=>'gui','䯣'=>'gui','䰎'=>'gui','䳏'=>'gui','亁'=>'gan','仠'=>'gan','倝'=>'gan','凎'=>'gan','凲'=>'gan','坩'=>'gan','尲'=>'gan','尴'=>'gan','尶'=>'gan','尷'=>'gan','干'=>'gan','幹'=>'gan','忓'=>'gan','感'=>'gan','擀'=>'gan','攼'=>'gan','敢'=>'gan','旰'=>'gan','杆'=>'gan','柑'=>'gan','桿'=>'gan','榦'=>'gan','橄'=>'gan','檊'=>'gan','汵'=>'gan','泔'=>'gan','淦'=>'gan','漧'=>'gan','澉'=>'gan','灨'=>'gan','玕'=>'gan','甘'=>'gan','疳'=>'gan','皯'=>'gan','盰'=>'gan','矸'=>'gan','秆'=>'gan','稈'=>'gan','竿'=>'gan','笴'=>'gan','筸'=>'gan','簳'=>'gan','粓'=>'gan','紺'=>'gan','绀'=>'gan','肝'=>'gan','芉'=>'gan','苷'=>'gan','衦'=>'gan','詌'=>'gan','贛'=>'gan','赣'=>'gan','赶'=>'gan','趕'=>'gan','迀'=>'gan','酐'=>'gan','骭'=>'gan','魐'=>'gan','鱤'=>'gan','鳡'=>'gan','鳱'=>'gan','㺂'=>'gan','䃭'=>'gan','䇞'=>'gan','䔈'=>'gan','䤗'=>'gan','䯎'=>'gan','䲺'=>'gan','䵟'=>'gan','亅'=>'jue','倔'=>'jue','傕'=>'jue','决'=>'jue','刔'=>'jue','劂'=>'jue','勪'=>'jue','厥'=>'jue','噘'=>'jue','噱'=>'jue','妜'=>'jue','孒'=>'jue','孓'=>'jue','屩'=>'jue','屫'=>'jue','崛'=>'jue','嶡'=>'jue','嶥'=>'jue','彏'=>'jue','憠'=>'jue','憰'=>'jue','戄'=>'jue','抉'=>'jue','挗'=>'jue','捔'=>'jue','掘'=>'jue','撅'=>'jue','撧'=>'jue','攫'=>'jue','斍'=>'jue','桷'=>'jue','橛'=>'jue','橜'=>'jue','欔'=>'jue','欮'=>'jue','殌'=>'jue','氒'=>'jue','決'=>'jue','泬'=>'jue','潏'=>'jue','灍'=>'jue','焆'=>'jue','熦'=>'jue','爑'=>'jue','爝'=>'jue','爴'=>'jue','爵'=>'jue','獗'=>'jue','玃'=>'jue','玦'=>'jue','玨'=>'jue','珏'=>'jue','瑴'=>'jue','瘚'=>'jue','矍'=>'jue','矡'=>'jue','砄'=>'jue','絕'=>'jue','絶'=>'jue','绝'=>'jue','臄'=>'jue','芵'=>'jue','蕝'=>'jue','蕨'=>'jue','虳'=>'jue','蚗'=>'jue','蟨'=>'jue','蟩'=>'jue','覐'=>'jue','覚'=>'jue','覺'=>'jue','觉'=>'jue','觖'=>'jue','觼'=>'jue','訣'=>'jue','譎'=>'jue','诀'=>'jue','谲'=>'jue','貜'=>'jue','赽'=>'jue','趉'=>'jue','趹'=>'jue','蹶'=>'jue','蹷'=>'jue','躩'=>'jue','逫'=>'jue','鈌'=>'jue','鐍'=>'jue','鐝'=>'jue','钁'=>'jue','镢'=>'jue','镼'=>'jue','駃'=>'jue','鴂'=>'jue','鴃'=>'jue','鶌'=>'jue','鷢'=>'jue','龣'=>'jue','㓸'=>'jue','㔃'=>'jue','㔢'=>'jue','㟲'=>'jue','㤜'=>'jue','㩱'=>'jue','㭈'=>'jue','㭾'=>'jue','㰐'=>'jue','㵐'=>'jue','㷾'=>'jue','㸕'=>'jue','㹟'=>'jue','㻕'=>'jue','䀗'=>'jue','䁷'=>'jue','䆕'=>'jue','䆢'=>'jue','䇶'=>'jue','䋉'=>'jue','䍊'=>'jue','䏐'=>'jue','䏣'=>'jue','䐘'=>'jue','䖼'=>'jue','䘿'=>'jue','䙠'=>'jue','䝌'=>'jue','䞵'=>'jue','䞷'=>'jue','䟾'=>'jue','䠇'=>'jue','䡈'=>'jue','䦆'=>'jue','䦼'=>'jue','了'=>'liao','僚'=>'liao','嘹'=>'liao','嫽'=>'liao','寥'=>'liao','寮'=>'liao','尞'=>'liao','尥'=>'liao','尦'=>'liao','屪'=>'liao','嵺'=>'liao','嶚'=>'liao','嶛'=>'liao','廖'=>'liao','廫'=>'liao','憀'=>'liao','憭'=>'liao','撂'=>'liao','撩'=>'liao','敹'=>'liao','料'=>'liao','暸'=>'liao','漻'=>'liao','潦'=>'liao','炓'=>'liao','燎'=>'liao','爎'=>'liao','爒'=>'liao','獠'=>'liao','璙'=>'liao','疗'=>'liao','療'=>'liao','瞭'=>'liao','窷'=>'liao','竂'=>'liao','簝'=>'liao','繚'=>'liao','缭'=>'liao','聊'=>'liao','膋'=>'liao','膫'=>'liao','蓼'=>'liao','蟟'=>'liao','豂'=>'liao','賿'=>'liao','蹘'=>'liao','蹽'=>'liao','辽'=>'liao','遼'=>'liao','鄝'=>'liao','釕'=>'liao','鐐'=>'liao','钌'=>'liao','镣'=>'liao','镽'=>'liao','飉'=>'liao','髎'=>'liao','鷯'=>'liao','鹩'=>'liao','㙩'=>'liao','㝋'=>'liao','㡻'=>'liao','㵳'=>'liao','㶫'=>'liao','㺒'=>'liao','䄦'=>'liao','䉼'=>'liao','䍡'=>'liao','䎆'=>'liao','䑠'=>'liao','䜍'=>'liao','䜮'=>'liao','䝀'=>'liao','䢧'=>'liao','䨅'=>'liao','䩍'=>'liao','亇'=>'ma','傌'=>'ma','吗'=>'ma','唛'=>'ma','嗎'=>'ma','嘛'=>'ma','嘜'=>'ma','妈'=>'ma','媽'=>'ma','嫲'=>'ma','嬤'=>'ma','嬷'=>'ma','杩'=>'ma','榪'=>'ma','溤'=>'ma','犘'=>'ma','犸'=>'ma','獁'=>'ma','玛'=>'ma','瑪'=>'ma','痲'=>'ma','睰'=>'ma','码'=>'ma','碼'=>'ma','礣'=>'ma','祃'=>'ma','禡'=>'ma','罵'=>'ma','蔴'=>'ma','蚂'=>'ma','螞'=>'ma','蟆'=>'ma','蟇'=>'ma','遤'=>'ma','鎷'=>'ma','閁'=>'ma','馬'=>'ma','駡'=>'ma','马'=>'ma','骂'=>'ma','鬕'=>'ma','鰢'=>'ma','鷌'=>'ma','麻'=>'ma','㐷'=>'ma','㑻'=>'ma','㜫'=>'ma','㦄'=>'ma','㨸'=>'ma','㾺'=>'ma','䗫'=>'ma','䣕'=>'ma','䣖'=>'ma','䯦'=>'ma','䳸'=>'ma','争'=>'zheng','佂'=>'zheng','凧'=>'zheng','埩'=>'zheng','塣'=>'zheng','姃'=>'zheng','媜'=>'zheng','峥'=>'zheng','崝'=>'zheng','崢'=>'zheng','帧'=>'zheng','幀'=>'zheng','征'=>'zheng','徰'=>'zheng','徴'=>'zheng','徵'=>'zheng','怔'=>'zheng','愸'=>'zheng','抍'=>'zheng','拯'=>'zheng','挣'=>'zheng','掙'=>'zheng','掟'=>'zheng','揁'=>'zheng','撜'=>'zheng','政'=>'zheng','整'=>'zheng','晸'=>'zheng','正'=>'zheng','氶'=>'zheng','炡'=>'zheng','烝'=>'zheng','爭'=>'zheng','狰'=>'zheng','猙'=>'zheng','症'=>'zheng','癥'=>'zheng','眐'=>'zheng','睁'=>'zheng','睜'=>'zheng','筝'=>'zheng','箏'=>'zheng','篜'=>'zheng','糽'=>'zheng','聇'=>'zheng','蒸'=>'zheng','証'=>'zheng','諍'=>'zheng','證'=>'zheng','证'=>'zheng','诤'=>'zheng','踭'=>'zheng','郑'=>'zheng','鄭'=>'zheng','鉦'=>'zheng','錚'=>'zheng','钲'=>'zheng','铮'=>'zheng','鬇'=>'zheng','鴊'=>'zheng','㡠'=>'zheng','㡧'=>'zheng','㱏'=>'zheng','㽀'=>'zheng','䂻'=>'zheng','䈣'=>'zheng','䛫'=>'zheng','䡕'=>'zheng','䥌'=>'zheng','䥭'=>'zheng','䦛'=>'zheng','䦶'=>'zheng','亍'=>'chu','俶'=>'chu','傗'=>'chu','储'=>'chu','儊'=>'chu','儲'=>'chu','処'=>'chu','出'=>'chu','刍'=>'chu','初'=>'chu','厨'=>'chu','嘼'=>'chu','埱'=>'chu','处'=>'chu','岀'=>'chu','幮'=>'chu','廚'=>'chu','怵'=>'chu','憷'=>'chu','懨'=>'chu','拀'=>'chu','搋'=>'chu','搐'=>'chu','摴'=>'chu','敊'=>'chu','斶'=>'chu','杵'=>'chu','椘'=>'chu','楚'=>'chu','楮'=>'chu','榋'=>'chu','樗'=>'chu','橱'=>'chu','橻'=>'chu','檚'=>'chu','櫉'=>'chu','櫥'=>'chu','欪'=>'chu','歜'=>'chu','滀'=>'chu','滁'=>'chu','濋'=>'chu','犓'=>'chu','珿'=>'chu','琡'=>'chu','璴'=>'chu','矗'=>'chu','础'=>'chu','礎'=>'chu','禇'=>'chu','竌'=>'chu','竐'=>'chu','篨'=>'chu','絀'=>'chu','绌'=>'chu','耡'=>'chu','臅'=>'chu','芻'=>'chu','蒢'=>'chu','蒭'=>'chu','蕏'=>'chu','處'=>'chu','蜍'=>'chu','蟵'=>'chu','褚'=>'chu','触'=>'chu','觸'=>'chu','諔'=>'chu','豖'=>'chu','豠'=>'chu','貙'=>'chu','趎'=>'chu','踀'=>'chu','蹰'=>'chu','躇'=>'chu','躕'=>'chu','鄐'=>'chu','鉏'=>'chu','鋤'=>'chu','锄'=>'chu','閦'=>'chu','除'=>'chu','雏'=>'chu','雛'=>'chu','鶵'=>'chu','黜'=>'chu','齣'=>'chu','齭'=>'chu','齼'=>'chu','㔘'=>'chu','㕏'=>'chu','㕑'=>'chu','㗰'=>'chu','㙇'=>'chu','㡡'=>'chu','㤕'=>'chu','㤘'=>'chu','㶆'=>'chu','㹼'=>'chu','㼥'=>'chu','䅳'=>'chu','䊰'=>'chu','䎝'=>'chu','䎤'=>'chu','䖏'=>'chu','䙕'=>'chu','䙘'=>'chu','䜴'=>'chu','䟞'=>'chu','䟣'=>'chu','䠂'=>'chu','䠧'=>'chu','䦌'=>'chu','䧁'=>'chu','䮞'=>'chu','亏'=>'kui','傀'=>'kui','刲'=>'kui','匮'=>'kui','匱'=>'kui','卼'=>'kui','喟'=>'kui','喹'=>'kui','嘳'=>'kui','夔'=>'kui','奎'=>'kui','媿'=>'kui','嬇'=>'kui','尯'=>'kui','岿'=>'kui','巋'=>'kui','巙'=>'kui','悝'=>'kui','愦'=>'kui','愧'=>'kui','憒'=>'kui','戣'=>'kui','揆'=>'kui','晆'=>'kui','暌'=>'kui','楏'=>'kui','楑'=>'kui','樻'=>'kui','櫆'=>'kui','欳'=>'kui','殨'=>'kui','溃'=>'kui','潰'=>'kui','煃'=>'kui','盔'=>'kui','睽'=>'kui','磈'=>'kui','窥'=>'kui','窺'=>'kui','篑'=>'kui','簣'=>'kui','籄'=>'kui','聧'=>'kui','聩'=>'kui','聭'=>'kui','聵'=>'kui','葵'=>'kui','蒉'=>'kui','蒊'=>'kui','蕢'=>'kui','藈'=>'kui','蘬'=>'kui','蘷'=>'kui','虁'=>'kui','虧'=>'kui','蝰'=>'kui','謉'=>'kui','跬'=>'kui','蹞'=>'kui','躨'=>'kui','逵'=>'kui','鄈'=>'kui','鍨'=>'kui','鍷'=>'kui','鐀'=>'kui','鑎'=>'kui','闚'=>'kui','頄'=>'kui','頍'=>'kui','頯'=>'kui','顝'=>'kui','餽'=>'kui','饋'=>'kui','馈'=>'kui','馗'=>'kui','騤'=>'kui','骙'=>'kui','魁'=>'kui','㕟'=>'kui','㙓'=>'kui','㚝'=>'kui','㛻'=>'kui','㨒'=>'kui','䈐'=>'kui','䍪'=>'kui','䕚'=>'kui','䕫'=>'kui','䟸'=>'kui','䠑'=>'kui','䤆'=>'kui','䦱'=>'kui','䧶'=>'kui','䫥'=>'kui','䯓'=>'kui','䳫'=>'kui','云'=>'yun','伝'=>'yun','傊'=>'yun','允'=>'yun','勻'=>'yun','匀'=>'yun','呍'=>'yun','喗'=>'yun','囩'=>'yun','夽'=>'yun','奫'=>'yun','妘'=>'yun','孕'=>'yun','恽'=>'yun','惲'=>'yun','愠'=>'yun','愪'=>'yun','慍'=>'yun','抎'=>'yun','抣'=>'yun','昀'=>'yun','晕'=>'yun','暈'=>'yun','枟'=>'yun','橒'=>'yun','殒'=>'yun','殞'=>'yun','氲'=>'yun','氳'=>'yun','沄'=>'yun','涢'=>'yun','溳'=>'yun','澐'=>'yun','煴'=>'yun','熅'=>'yun','熉'=>'yun','熨'=>'yun','狁'=>'yun','玧'=>'yun','畇'=>'yun','眃'=>'yun','磒'=>'yun','秐'=>'yun','筼'=>'yun','篔'=>'yun','紜'=>'yun','緼'=>'yun','縕'=>'yun','縜'=>'yun','繧'=>'yun','纭'=>'yun','缊'=>'yun','耘'=>'yun','耺'=>'yun','腪'=>'yun','芸'=>'yun','荺'=>'yun','蒀'=>'yun','蒕'=>'yun','蒷'=>'yun','蕓'=>'yun','蕰'=>'yun','蕴'=>'yun','薀'=>'yun','藴'=>'yun','蘊'=>'yun','蝹'=>'yun','褞'=>'yun','賱'=>'yun','贇'=>'yun','赟'=>'yun','运'=>'yun','運'=>'yun','郓'=>'yun','郧'=>'yun','鄆'=>'yun','鄖'=>'yun','酝'=>'yun','醖'=>'yun','醞'=>'yun','鈗'=>'yun','鋆'=>'yun','阭'=>'yun','陨'=>'yun','隕'=>'yun','雲'=>'yun','霣'=>'yun','韗'=>'yun','韞'=>'yun','韫'=>'yun','韵'=>'yun','韻'=>'yun','頵'=>'yun','餫'=>'yun','馧'=>'yun','馻'=>'yun','齫'=>'yun','齳'=>'yun','㚃'=>'yun','㚺'=>'yun','㜏'=>'yun','㞌'=>'yun','㟦'=>'yun','䆬'=>'yun','䇖'=>'yun','䉙'=>'yun','䚋'=>'yun','䞫'=>'yun','䡝'=>'yun','䢵'=>'yun','䤞'=>'yun','䦾'=>'yun','䨶'=>'yun','䩵'=>'yun','䪳'=>'yun','䲰'=>'yun','䵴'=>'yun','亗'=>'sui','倠'=>'sui','哸'=>'sui','埣'=>'sui','夊'=>'sui','嬘'=>'sui','岁'=>'sui','嵗'=>'sui','旞'=>'sui','檖'=>'sui','歲'=>'sui','歳'=>'sui','浽'=>'sui','滖'=>'sui','澻'=>'sui','濉'=>'sui','瀡'=>'sui','煫'=>'sui','熣'=>'sui','燧'=>'sui','璲'=>'sui','瓍'=>'sui','眭'=>'sui','睟'=>'sui','睢'=>'sui','砕'=>'sui','碎'=>'sui','祟'=>'sui','禭'=>'sui','穂'=>'sui','穗'=>'sui','穟'=>'sui','粋'=>'sui','綏'=>'sui','繀'=>'sui','繐'=>'sui','繸'=>'sui','绥'=>'sui','脺'=>'sui','膸'=>'sui','芕'=>'sui','荽'=>'sui','荾'=>'sui','葰'=>'sui','虽'=>'sui','襚'=>'sui','誶'=>'sui','譢'=>'sui','谇'=>'sui','賥'=>'sui','遀'=>'sui','遂'=>'sui','邃'=>'sui','鐆'=>'sui','鐩'=>'sui','隋'=>'sui','随'=>'sui','隧'=>'sui','隨'=>'sui','雖'=>'sui','鞖'=>'sui','髄'=>'sui','髓'=>'sui','㒸'=>'sui','㞸'=>'sui','㴚'=>'sui','㵦'=>'sui','㻟'=>'sui','㻪'=>'sui','㻽'=>'sui','䅗'=>'sui','䉌'=>'sui','䍁'=>'sui','䔹'=>'sui','䜔'=>'sui','䠔'=>'sui','䡵'=>'sui','䢫'=>'sui','䥙'=>'sui','䭉'=>'sui','䯝'=>'sui','亘'=>'gen','哏'=>'gen','揯'=>'gen','搄'=>'gen','根'=>'gen','艮'=>'gen','茛'=>'gen','跟'=>'gen','㫔'=>'gen','㮓'=>'gen','䫀'=>'gen','亙'=>'geng','刯'=>'geng','哽'=>'geng','啹'=>'geng','喼'=>'geng','嗰'=>'geng','埂'=>'geng','堩'=>'geng','峺'=>'geng','庚'=>'geng','挭'=>'geng','掶'=>'geng','更'=>'geng','梗'=>'geng','椩'=>'geng','浭'=>'geng','焿'=>'geng','畊'=>'geng','絚'=>'geng','綆'=>'geng','緪'=>'geng','縆'=>'geng','绠'=>'geng','羮'=>'geng','羹'=>'geng','耕'=>'geng','耿'=>'geng','莄'=>'geng','菮'=>'geng','賡'=>'geng','赓'=>'geng','郠'=>'geng','骾'=>'geng','鯁'=>'geng','鲠'=>'geng','鶊'=>'geng','鹒'=>'geng','㾘'=>'geng','䋁'=>'geng','䌄'=>'geng','䱍'=>'geng','䱎'=>'geng','䱭'=>'geng','䱴'=>'geng','些'=>'xie','亵'=>'xie','伳'=>'xie','偕'=>'xie','偰'=>'xie','僁'=>'xie','写'=>'xie','冩'=>'xie','劦'=>'xie','勰'=>'xie','协'=>'xie','協'=>'xie','卨'=>'xie','卸'=>'xie','嗋'=>'xie','噧'=>'xie','垥'=>'xie','塮'=>'xie','夑'=>'xie','奊'=>'xie','娎'=>'xie','媟'=>'xie','寫'=>'xie','屑'=>'xie','屓'=>'xie','屟'=>'xie','屧'=>'xie','屭'=>'xie','峫'=>'xie','嶰'=>'xie','廨'=>'xie','徢'=>'xie','恊'=>'xie','愶'=>'xie','懈'=>'xie','拹'=>'xie','挟'=>'xie','挾'=>'xie','揳'=>'xie','携'=>'xie','撷'=>'xie','擕'=>'xie','擷'=>'xie','攜'=>'xie','斜'=>'xie','旪'=>'xie','暬'=>'xie','械'=>'xie','楔'=>'xie','榍'=>'xie','榭'=>'xie','歇'=>'xie','泄'=>'xie','泻'=>'xie','洩'=>'xie','渫'=>'xie','澥'=>'xie','瀉'=>'xie','瀣'=>'xie','灺'=>'xie','炧'=>'xie','炨'=>'xie','焎'=>'xie','熁'=>'xie','燮'=>'xie','燲'=>'xie','爕'=>'xie','猲'=>'xie','獬'=>'xie','瑎'=>'xie','祄'=>'xie','禼'=>'xie','糏'=>'xie','紲'=>'xie','絏'=>'xie','絜'=>'xie','絬'=>'xie','綊'=>'xie','緤'=>'xie','緳'=>'xie','纈'=>'xie','绁'=>'xie','缬'=>'xie','缷'=>'xie','翓'=>'xie','胁'=>'xie','脅'=>'xie','脇'=>'xie','脋'=>'xie','膎'=>'xie','薢'=>'xie','薤'=>'xie','藛'=>'xie','蝎'=>'xie','蝢'=>'xie','蟹'=>'xie','蠍'=>'xie','蠏'=>'xie','衺'=>'xie','褉'=>'xie','褻'=>'xie','襭'=>'xie','諧'=>'xie','謝'=>'xie','讗'=>'xie','谐'=>'xie','谢'=>'xie','躞'=>'xie','躠'=>'xie','邂'=>'xie','邪'=>'xie','鐷'=>'xie','鞋'=>'xie','鞢'=>'xie','鞵'=>'xie','韰'=>'xie','齂'=>'xie','齘'=>'xie','齥'=>'xie','龤'=>'xie','㒠'=>'xie','㓔'=>'xie','㔎'=>'xie','㕐'=>'xie','㖑'=>'xie','㖿'=>'xie','㙝'=>'xie','㙰'=>'xie','㝍'=>'xie','㞕'=>'xie','㣯'=>'xie','㣰'=>'xie','㥟'=>'xie','㦪'=>'xie','㨙'=>'xie','㨝'=>'xie','㩉'=>'xie','㩦'=>'xie','㩪'=>'xie','㭨'=>'xie','㰔'=>'xie','㰡'=>'xie','㳦'=>'xie','㳿'=>'xie','㴬'=>'xie','㴮'=>'xie','㴽'=>'xie','㸉'=>'xie','㽊'=>'xie','䉏'=>'xie','䉣'=>'xie','䊝'=>'xie','䔑'=>'xie','䕈'=>'xie','䕵'=>'xie','䙊'=>'xie','䙎'=>'xie','䙝'=>'xie','䚳'=>'xie','䚸'=>'xie','䡡'=>'xie','䢡'=>'xie','䥱'=>'xie','䥾'=>'xie','䦏'=>'xie','䦑'=>'xie','䩧'=>'xie','䭎'=>'xie','䲒'=>'xie','䵦'=>'xie','亠'=>'tou','偷'=>'tou','偸'=>'tou','头'=>'tou','妵'=>'tou','婾'=>'tou','媮'=>'tou','投'=>'tou','敨'=>'tou','斢'=>'tou','殕'=>'tou','紏'=>'tou','緰'=>'tou','蘣'=>'tou','透'=>'tou','鍮'=>'tou','頭'=>'tou','骰'=>'tou','黈'=>'tou','㓱'=>'tou','㖣'=>'tou','㡏'=>'tou','㢏'=>'tou','㪗'=>'tou','䞬'=>'tou','䟝'=>'tou','䱏'=>'tou','䵉'=>'tou','亡'=>'wang','亾'=>'wang','仼'=>'wang','兦'=>'wang','妄'=>'wang','尣'=>'wang','尩'=>'wang','尪'=>'wang','尫'=>'wang','彺'=>'wang','往'=>'wang','徃'=>'wang','忘'=>'wang','忹'=>'wang','惘'=>'wang','旺'=>'wang','暀'=>'wang','望'=>'wang','朢'=>'wang','枉'=>'wang','棢'=>'wang','汪'=>'wang','瀇'=>'wang','焹'=>'wang','王'=>'wang','盳'=>'wang','網'=>'wang','网'=>'wang','罔'=>'wang','莣'=>'wang','菵'=>'wang','蚟'=>'wang','蛧'=>'wang','蝄'=>'wang','誷'=>'wang','輞'=>'wang','辋'=>'wang','迋'=>'wang','魍'=>'wang','㑌'=>'wang','㓁'=>'wang','㲿'=>'wang','㳹'=>'wang','㴏'=>'wang','䋄'=>'wang','䋞'=>'wang','䛃'=>'wang','䤑'=>'wang','䰣'=>'wang','亢'=>'kang','伉'=>'kang','匟'=>'kang','囥'=>'kang','嫝'=>'kang','嵻'=>'kang','康'=>'kang','忼'=>'kang','慷'=>'kang','扛'=>'kang','抗'=>'kang','摃'=>'kang','槺'=>'kang','漮'=>'kang','炕'=>'kang','犺'=>'kang','砊'=>'kang','穅'=>'kang','粇'=>'kang','糠'=>'kang','躿'=>'kang','邟'=>'kang','鈧'=>'kang','鏮'=>'kang','钪'=>'kang','閌'=>'kang','闶'=>'kang','鱇'=>'kang','㰠'=>'kang','䡉'=>'kang','亣'=>'da','剳'=>'da','匒'=>'da','呾'=>'da','咑'=>'da','哒'=>'da','嗒'=>'da','噠'=>'da','垯'=>'da','墶'=>'da','大'=>'da','妲'=>'da','怛'=>'da','打'=>'da','搭'=>'da','撘'=>'da','橽'=>'da','沓'=>'da','溚'=>'da','炟'=>'da','燵'=>'da','畣'=>'da','瘩'=>'da','眔'=>'da','笪'=>'da','答'=>'da','繨'=>'da','羍'=>'da','耷'=>'da','荅'=>'da','荙'=>'da','薘'=>'da','蟽'=>'da','褡'=>'da','詚'=>'da','跶'=>'da','躂'=>'da','达'=>'da','迏'=>'da','迖'=>'da','逹'=>'da','達'=>'da','鎉'=>'da','鎝'=>'da','鐽'=>'da','靼'=>'da','鞑'=>'da','韃'=>'da','龖'=>'da','龘'=>'da','㙮'=>'da','㜓'=>'da','㟷'=>'da','㯚'=>'da','㾑'=>'da','㿯'=>'da','䃮'=>'da','䐊'=>'da','䑽'=>'da','䩢'=>'da','䳴'=>'da','䵣'=>'da','交'=>'jiao','佼'=>'jiao','侥'=>'jiao','僥'=>'jiao','僬'=>'jiao','儌'=>'jiao','剿'=>'jiao','劋'=>'jiao','勦'=>'jiao','叫'=>'jiao','呌'=>'jiao','嘂'=>'jiao','嘄'=>'jiao','嘦'=>'jiao','噍'=>'jiao','噭'=>'jiao','嚼'=>'jiao','姣'=>'jiao','娇'=>'jiao','嬌'=>'jiao','嬓'=>'jiao','孂'=>'jiao','峤'=>'jiao','峧'=>'jiao','嶕'=>'jiao','嶠'=>'jiao','嶣'=>'jiao','徼'=>'jiao','憍'=>'jiao','挍'=>'jiao','挢'=>'jiao','捁'=>'jiao','搅'=>'jiao','摷'=>'jiao','撟'=>'jiao','撹'=>'jiao','攪'=>'jiao','敎'=>'jiao','教'=>'jiao','敫'=>'jiao','敽'=>'jiao','敿'=>'jiao','斠'=>'jiao','晈'=>'jiao','暞'=>'jiao','曒'=>'jiao','椒'=>'jiao','櫵'=>'jiao','浇'=>'jiao','湫'=>'jiao','湬'=>'jiao','滘'=>'jiao','漖'=>'jiao','潐'=>'jiao','澆'=>'jiao','灚'=>'jiao','烄'=>'jiao','焦'=>'jiao','焳'=>'jiao','煍'=>'jiao','燋'=>'jiao','狡'=>'jiao','獥'=>'jiao','珓'=>'jiao','璬'=>'jiao','皎'=>'jiao','皦'=>'jiao','皭'=>'jiao','矫'=>'jiao','矯'=>'jiao','礁'=>'jiao','穚'=>'jiao','窌'=>'jiao','窖'=>'jiao','笅'=>'jiao','筊'=>'jiao','簥'=>'jiao','絞'=>'jiao','繳'=>'jiao','纐'=>'jiao','绞'=>'jiao','缴'=>'jiao','胶'=>'jiao','脚'=>'jiao','腳'=>'jiao','膠'=>'jiao','膲'=>'jiao','臫'=>'jiao','艽'=>'jiao','芁'=>'jiao','茭'=>'jiao','茮'=>'jiao','蕉'=>'jiao','藠'=>'jiao','虠'=>'jiao','蛟'=>'jiao','蟜'=>'jiao','蟭'=>'jiao','角'=>'jiao','訆'=>'jiao','譑'=>'jiao','譥'=>'jiao','賋'=>'jiao','趭'=>'jiao','跤'=>'jiao','踋'=>'jiao','較'=>'jiao','轇'=>'jiao','轎'=>'jiao','轿'=>'jiao','较'=>'jiao','郊'=>'jiao','酵'=>'jiao','醮'=>'jiao','釂'=>'jiao','鉸'=>'jiao','鐎'=>'jiao','铰'=>'jiao','餃'=>'jiao','饺'=>'jiao','驕'=>'jiao','骄'=>'jiao','鮫'=>'jiao','鱎'=>'jiao','鲛'=>'jiao','鵁'=>'jiao','鵤'=>'jiao','鷦'=>'jiao','鷮'=>'jiao','鹪'=>'jiao','㠐'=>'jiao','㩰'=>'jiao','㬭'=>'jiao','㭂'=>'jiao','㰾'=>'jiao','㳅'=>'jiao','㽱'=>'jiao','㽲'=>'jiao','䀊'=>'jiao','䁶'=>'jiao','䂃'=>'jiao','䆗'=>'jiao','䘨'=>'jiao','䚩'=>'jiao','䠛'=>'jiao','䣤'=>'jiao','䥞'=>'jiao','䪒'=>'jiao','䴔'=>'jiao','䴛'=>'jiao','亨'=>'heng','哼'=>'heng','啈'=>'heng','囍'=>'heng','堼'=>'heng','姮'=>'heng','恆'=>'heng','恒'=>'heng','悙'=>'heng','桁'=>'heng','横'=>'heng','橫'=>'heng','涥'=>'heng','烆'=>'heng','珩'=>'heng','胻'=>'heng','脝'=>'heng','蘅'=>'heng','衡'=>'heng','鑅'=>'heng','鴴'=>'heng','鵆'=>'heng','鸻'=>'heng','㔰'=>'heng','㶇'=>'heng','䄓'=>'heng','䒛'=>'heng','䬖'=>'heng','䬝'=>'heng','䯒'=>'heng','亲'=>'qin','侵'=>'qin','勤'=>'qin','吢'=>'qin','吣'=>'qin','唚'=>'qin','嗪'=>'qin','噙'=>'qin','坅'=>'qin','埁'=>'qin','媇'=>'qin','嫀'=>'qin','寑'=>'qin','寝'=>'qin','寢'=>'qin','寴'=>'qin','嵚'=>'qin','嶔'=>'qin','庈'=>'qin','懃'=>'qin','懄'=>'qin','抋'=>'qin','捦'=>'qin','揿'=>'qin','搇'=>'qin','撳'=>'qin','擒'=>'qin','斳'=>'qin','昑'=>'qin','梫'=>'qin','檎'=>'qin','欽'=>'qin','沁'=>'qin','溱'=>'qin','澿'=>'qin','瀙'=>'qin','珡'=>'qin','琴'=>'qin','琹'=>'qin','瘽'=>'qin','矝'=>'qin','禽'=>'qin','秦'=>'qin','笉'=>'qin','綅'=>'qin','耹'=>'qin','芩'=>'qin','芹'=>'qin','菣'=>'qin','菦'=>'qin','菳'=>'qin','藽'=>'qin','蚙'=>'qin','螓'=>'qin','螼'=>'qin','蠄'=>'qin','衾'=>'qin','親'=>'qin','誛'=>'qin','赺'=>'qin','赾'=>'qin','鈙'=>'qin','鋟'=>'qin','钦'=>'qin','锓'=>'qin','雂'=>'qin','靲'=>'qin','顉'=>'qin','駸'=>'qin','骎'=>'qin','鮼'=>'qin','鳹'=>'qin','㝲'=>'qin','㞬'=>'qin','㢙'=>'qin','㤈'=>'qin','㩒'=>'qin','㪁'=>'qin','㮗'=>'qin','㾛'=>'qin','䈜'=>'qin','䔷'=>'qin','䖌'=>'qin','䠴'=>'qin','䦦'=>'qin','亳'=>'bo','仢'=>'bo','伯'=>'bo','侼'=>'bo','僠'=>'bo','僰'=>'bo','勃'=>'bo','博'=>'bo','卜'=>'bo','啵'=>'bo','嚗'=>'bo','壆'=>'bo','孛'=>'bo','孹'=>'bo','嶓'=>'bo','帛'=>'bo','愽'=>'bo','懪'=>'bo','拨'=>'bo','挬'=>'bo','捕'=>'bo','搏'=>'bo','撥'=>'bo','播'=>'bo','擘'=>'bo','柭'=>'bo','桲'=>'bo','檗'=>'bo','欂'=>'bo','泊'=>'bo','波'=>'bo','浡'=>'bo','淿'=>'bo','渤'=>'bo','湐'=>'bo','煿'=>'bo','牔'=>'bo','犦'=>'bo','犻'=>'bo','狛'=>'bo','猼'=>'bo','玻'=>'bo','瓝'=>'bo','瓟'=>'bo','癶'=>'bo','癷'=>'bo','盋'=>'bo','砵'=>'bo','碆'=>'bo','磻'=>'bo','礡'=>'bo','礴'=>'bo','秡'=>'bo','箔'=>'bo','箥'=>'bo','簙'=>'bo','簸'=>'bo','糪'=>'bo','紴'=>'bo','缽'=>'bo','胉'=>'bo','脖'=>'bo','膊'=>'bo','舶'=>'bo','艊'=>'bo','苩'=>'bo','菠'=>'bo','葧'=>'bo','蔔'=>'bo','蘗'=>'bo','蚾'=>'bo','袚'=>'bo','袯'=>'bo','袰'=>'bo','襏'=>'bo','襮'=>'bo','譒'=>'bo','豰'=>'bo','跛'=>'bo','踣'=>'bo','蹳'=>'bo','郣'=>'bo','鈸'=>'bo','鉑'=>'bo','鉢'=>'bo','鋍'=>'bo','鎛'=>'bo','鑮'=>'bo','钵'=>'bo','钹'=>'bo','铂'=>'bo','镈'=>'bo','餑'=>'bo','餺'=>'bo','饽'=>'bo','馎'=>'bo','馛'=>'bo','馞'=>'bo','駁'=>'bo','駮'=>'bo','驋'=>'bo','驳'=>'bo','髆'=>'bo','髉'=>'bo','鮊'=>'bo','鱍'=>'bo','鲌'=>'bo','鵓'=>'bo','鹁'=>'bo','㖕'=>'bo','㗘'=>'bo','㝿'=>'bo','㟑'=>'bo','㧳'=>'bo','㩧'=>'bo','㩭'=>'bo','㪍'=>'bo','㬍'=>'bo','㬧'=>'bo','㱟'=>'bo','㴾'=>'bo','㶿'=>'bo','㹀'=>'bo','䂍'=>'bo','䊿'=>'bo','䍨'=>'bo','䍸'=>'bo','䑈'=>'bo','䒄'=>'bo','䗚'=>'bo','䙏'=>'bo','䞳'=>'bo','䟛'=>'bo','䢌'=>'bo','䥬'=>'bo','䪇'=>'bo','䪬'=>'bo','䫊'=>'bo','䬪'=>'bo','䭦'=>'bo','䭯'=>'bo','䮀'=>'bo','䮂'=>'bo','䯋'=>'bo','䰊'=>'bo','䶈'=>'bo','亷'=>'lian','僆'=>'lian','劆'=>'lian','匲'=>'lian','匳'=>'lian','嗹'=>'lian','噒'=>'lian','堜'=>'lian','奁'=>'lian','奩'=>'lian','娈'=>'lian','媡'=>'lian','嫾'=>'lian','嬚'=>'lian','帘'=>'lian','廉'=>'lian','怜'=>'lian','恋'=>'lian','慩'=>'lian','憐'=>'lian','戀'=>'lian','摙'=>'lian','敛'=>'lian','斂'=>'lian','梿'=>'lian','楝'=>'lian','槤'=>'lian','櫣'=>'lian','歛'=>'lian','殓'=>'lian','殮'=>'lian','浰'=>'lian','涟'=>'lian','湅'=>'lian','溓'=>'lian','漣'=>'lian','潋'=>'lian','澰'=>'lian','濂'=>'lian','濓'=>'lian','瀲'=>'lian','炼'=>'lian','煉'=>'lian','熑'=>'lian','燫'=>'lian','琏'=>'lian','瑓'=>'lian','璉'=>'lian','磏'=>'lian','稴'=>'lian','簾'=>'lian','籢'=>'lian','籨'=>'lian','練'=>'lian','縺'=>'lian','纞'=>'lian','练'=>'lian','羷'=>'lian','翴'=>'lian','联'=>'lian','聨'=>'lian','聫'=>'lian','聮'=>'lian','聯'=>'lian','脸'=>'lian','臁'=>'lian','臉'=>'lian','莲'=>'lian','萰'=>'lian','蓮'=>'lian','蔹'=>'lian','薕'=>'lian','蘝'=>'lian','蘞'=>'lian','螊'=>'lian','蠊'=>'lian','裢'=>'lian','裣'=>'lian','褳'=>'lian','襝'=>'lian','覝'=>'lian','謰'=>'lian','譧'=>'lian','蹥'=>'lian','连'=>'lian','連'=>'lian','鄻'=>'lian','錬'=>'lian','鍊'=>'lian','鎌'=>'lian','鏈'=>'lian','鐮'=>'lian','链'=>'lian','镰'=>'lian','鬑'=>'lian','鰊'=>'lian','鰱'=>'lian','鲢'=>'lian','㓎'=>'lian','㜃'=>'lian','㜕'=>'lian','㜻'=>'lian','㝺'=>'lian','㟀'=>'lian','㡘'=>'lian','㢘'=>'lian','㥕'=>'lian','㦁'=>'lian','㦑'=>'lian','㪘'=>'lian','㪝'=>'lian','㯬'=>'lian','㰈'=>'lian','㰸'=>'lian','㱨'=>'lian','㶌'=>'lian','㶑'=>'lian','㺦'=>'lian','㼑'=>'lian','㼓'=>'lian','㾾'=>'lian','䁠'=>'lian','䃛'=>'lian','䆂'=>'lian','䇜'=>'lian','䌞'=>'lian','䏈'=>'lian','䙺'=>'lian','䥥'=>'lian','䨬'=>'lian','䭑'=>'lian','亸'=>'duo','仛'=>'duo','凙'=>'duo','刴'=>'duo','剁'=>'duo','剟'=>'duo','剫'=>'duo','咄'=>'duo','哆'=>'duo','哚'=>'duo','喥'=>'duo','嚉'=>'duo','嚲'=>'duo','垛'=>'duo','垜'=>'duo','埵'=>'duo','堕'=>'duo','墮'=>'duo','墯'=>'duo','多'=>'duo','夛'=>'duo','夺'=>'duo','奪'=>'duo','尮'=>'duo','崜'=>'duo','嶞'=>'duo','惰'=>'duo','憜'=>'duo','挅'=>'duo','挆'=>'duo','掇'=>'duo','敓'=>'duo','敚'=>'duo','敠'=>'duo','敪'=>'duo','朵'=>'duo','朶'=>'duo','柮'=>'duo','桗'=>'duo','椯'=>'duo','毲'=>'duo','沲'=>'duo','痥'=>'duo','綞'=>'duo','缍'=>'duo','舵'=>'duo','茤'=>'duo','裰'=>'duo','趓'=>'duo','跢'=>'duo','跥'=>'duo','跺'=>'duo','踱'=>'duo','躱'=>'duo','躲'=>'duo','軃'=>'duo','鈬'=>'duo','鐸'=>'duo','铎'=>'duo','陊'=>'duo','陏'=>'duo','飿'=>'duo','饳'=>'duo','鬌'=>'duo','鮵'=>'duo','鵽'=>'duo','㔍'=>'duo','㖼'=>'duo','㙐'=>'duo','㛆'=>'duo','㛊'=>'duo','㣞'=>'duo','㥩'=>'duo','㧷'=>'duo','㻔'=>'duo','㻧'=>'duo','䅜'=>'duo','䍴'=>'duo','䐾'=>'duo','䑨'=>'duo','䒳'=>'duo','䙃'=>'duo','䙟'=>'duo','䙤'=>'duo','䠤'=>'duo','䤪'=>'duo','䤻'=>'duo','䩔'=>'duo','䩣'=>'duo','䫂'=>'duo','䯬'=>'duo','人'=>'ren','亻'=>'ren','仁'=>'ren','仞'=>'ren','仭'=>'ren','任'=>'ren','刃'=>'ren','刄'=>'ren','壬'=>'ren','妊'=>'ren','姙'=>'ren','屻'=>'ren','忈'=>'ren','忍'=>'ren','忎'=>'ren','恁'=>'ren','扨'=>'ren','朲'=>'ren','杒'=>'ren','栠'=>'ren','栣'=>'ren','梕'=>'ren','棯'=>'ren','牣'=>'ren','秂'=>'ren','秹'=>'ren','稔'=>'ren','紉'=>'ren','紝'=>'ren','絍'=>'ren','綛'=>'ren','纫'=>'ren','纴'=>'ren','肕'=>'ren','腍'=>'ren','芢'=>'ren','荏'=>'ren','荵'=>'ren','葚'=>'ren','衽'=>'ren','袵'=>'ren','訒'=>'ren','認'=>'ren','认'=>'ren','讱'=>'ren','躵'=>'ren','軔'=>'ren','轫'=>'ren','鈓'=>'ren','銋'=>'ren','靭'=>'ren','靱'=>'ren','韌'=>'ren','韧'=>'ren','飪'=>'ren','餁'=>'ren','饪'=>'ren','魜'=>'ren','鵀'=>'ren','㠴'=>'ren','㣼'=>'ren','㶵'=>'ren','㸾'=>'ren','䀼'=>'ren','䇮'=>'ren','䋕'=>'ren','䌾'=>'ren','䏕'=>'ren','䏰'=>'ren','䭃'=>'ren','䴦'=>'ren','亽'=>'ra','囕'=>'ra','罖'=>'ra','仄'=>'ze','伬'=>'ze','则'=>'ze','則'=>'ze','唶'=>'ze','啧'=>'ze','啫'=>'ze','嘖'=>'ze','夨'=>'ze','嫧'=>'ze','崱'=>'ze','帻'=>'ze','幘'=>'ze','庂'=>'ze','択'=>'ze','择'=>'ze','捑'=>'ze','擇'=>'ze','昃'=>'ze','昗'=>'ze','樍'=>'ze','歵'=>'ze','汄'=>'ze','沢'=>'ze','泎'=>'ze','泽'=>'ze','溭'=>'ze','澤'=>'ze','皟'=>'ze','瞔'=>'ze','矠'=>'ze','礋'=>'ze','稄'=>'ze','笮'=>'ze','箦'=>'ze','簀'=>'ze','耫'=>'ze','舴'=>'ze','蔶'=>'ze','蠌'=>'ze','襗'=>'ze','諎'=>'ze','謮'=>'ze','責'=>'ze','賾'=>'ze','责'=>'ze','赜'=>'ze','迮'=>'ze','鸅'=>'ze','齚'=>'ze','齰'=>'ze','㖽'=>'ze','㣱'=>'ze','㳁'=>'ze','㳻'=>'ze','䃎'=>'ze','䇥'=>'ze','䕉'=>'ze','䕪'=>'ze','䰹'=>'ze','䶦'=>'ze','仅'=>'jin','今'=>'jin','伒'=>'jin','侭'=>'jin','僅'=>'jin','僸'=>'jin','儘'=>'jin','兓'=>'jin','凚'=>'jin','劤'=>'jin','劲'=>'jin','勁'=>'jin','卺'=>'jin','厪'=>'jin','噤'=>'jin','嚍'=>'jin','埐'=>'jin','堇'=>'jin','堻'=>'jin','墐'=>'jin','壗'=>'jin','妗'=>'jin','嫤'=>'jin','嬧'=>'jin','寖'=>'jin','尽'=>'jin','嶜'=>'jin','巹'=>'jin','巾'=>'jin','廑'=>'jin','惍'=>'jin','慬'=>'jin','搢'=>'jin','斤'=>'jin','晉'=>'jin','晋'=>'jin','枃'=>'jin','槿'=>'jin','歏'=>'jin','殣'=>'jin','津'=>'jin','浕'=>'jin','浸'=>'jin','溍'=>'jin','漌'=>'jin','濅'=>'jin','濜'=>'jin','烬'=>'jin','煡'=>'jin','燼'=>'jin','珒'=>'jin','琎'=>'jin','琻'=>'jin','瑨'=>'jin','瑾'=>'jin','璡'=>'jin','璶'=>'jin','盡'=>'jin','矜'=>'jin','砛'=>'jin','祲'=>'jin','禁'=>'jin','筋'=>'jin','紟'=>'jin','紧'=>'jin','緊'=>'jin','縉'=>'jin','缙'=>'jin','荕'=>'jin','荩'=>'jin','菫'=>'jin','蓳'=>'jin','藎'=>'jin','衿'=>'jin','襟'=>'jin','覲'=>'jin','觐'=>'jin','觔'=>'jin','謹'=>'jin','谨'=>'jin','賮'=>'jin','贐'=>'jin','赆'=>'jin','近'=>'jin','进'=>'jin','進'=>'jin','金'=>'jin','釒'=>'jin','錦'=>'jin','钅'=>'jin','锦'=>'jin','靳'=>'jin','饉'=>'jin','馑'=>'jin','鹶'=>'jin','黅'=>'jin','齽'=>'jin','㝻'=>'jin','㨷'=>'jin','㬐'=>'jin','㬜'=>'jin','㯲'=>'jin','㯸'=>'jin','㰹'=>'jin','㱈'=>'jin','㴆'=>'jin','㶦'=>'jin','㶳'=>'jin','㹏'=>'jin','䀆'=>'jin','䆮'=>'jin','䋮'=>'jin','䌝'=>'jin','䐶'=>'jin','䑤'=>'jin','䒺'=>'jin','䖐'=>'jin','䗯'=>'jin','䝲'=>'jin','䤐'=>'jin','䥆'=>'jin','䫴'=>'jin','䭙'=>'jin','䶖'=>'jin','仆'=>'pu','僕'=>'pu','匍'=>'pu','噗'=>'pu','圃'=>'pu','圑'=>'pu','圤'=>'pu','埔'=>'pu','墣'=>'pu','巬'=>'pu','巭'=>'pu','扑'=>'pu','抪'=>'pu','撲'=>'pu','擈'=>'pu','攴'=>'pu','攵'=>'pu','普'=>'pu','暜'=>'pu','曝'=>'pu','朴'=>'pu','柨'=>'pu','樸'=>'pu','檏'=>'pu','氆'=>'pu','浦'=>'pu','溥'=>'pu','潽'=>'pu','濮'=>'pu','瀑'=>'pu','炇'=>'pu','烳'=>'pu','璞'=>'pu','痡'=>'pu','瞨'=>'pu','穙'=>'pu','纀'=>'pu','舖'=>'pu','舗'=>'pu','莆'=>'pu','菐'=>'pu','菩'=>'pu','葡'=>'pu','蒱'=>'pu','蒲'=>'pu','諩'=>'pu','譜'=>'pu','谱'=>'pu','贌'=>'pu','蹼'=>'pu','酺'=>'pu','鋪'=>'pu','鏷'=>'pu','鐠'=>'pu','铺'=>'pu','镤'=>'pu','镨'=>'pu','陠'=>'pu','駇'=>'pu','鯆'=>'pu','㒒'=>'pu','㬥'=>'pu','㯷'=>'pu','㲫'=>'pu','㹒'=>'pu','㺪'=>'pu','䈬'=>'pu','䈻'=>'pu','䑑'=>'pu','䔕'=>'pu','䗱'=>'pu','䧤'=>'pu','䲕'=>'pu','䴆'=>'pu','仈'=>'ba','八'=>'ba','叐'=>'ba','叭'=>'ba','吧'=>'ba','哵'=>'ba','坝'=>'ba','坺'=>'ba','垻'=>'ba','墢'=>'ba','壩'=>'ba','夿'=>'ba','妭'=>'ba','岜'=>'ba','巴'=>'ba','弝'=>'ba','扒'=>'ba','把'=>'ba','抜'=>'ba','拔'=>'ba','捌'=>'ba','朳'=>'ba','欛'=>'ba','灞'=>'ba','炦'=>'ba','爸'=>'ba','犮'=>'ba','玐'=>'ba','疤'=>'ba','癹'=>'ba','矲'=>'ba','笆'=>'ba','粑'=>'ba','紦'=>'ba','罢'=>'ba','罷'=>'ba','羓'=>'ba','耙'=>'ba','胈'=>'ba','芭'=>'ba','茇'=>'ba','菝'=>'ba','蚆'=>'ba','覇'=>'ba','詙'=>'ba','豝'=>'ba','跁'=>'ba','跋'=>'ba','軷'=>'ba','釛'=>'ba','釟'=>'ba','鈀'=>'ba','钯'=>'ba','霸'=>'ba','靶'=>'ba','颰'=>'ba','魃'=>'ba','魞'=>'ba','鮁'=>'ba','鲃'=>'ba','鲅'=>'ba','鼥'=>'ba','㔜'=>'ba','㖠'=>'ba','㞎'=>'ba','㧊'=>'ba','㶚'=>'ba','䃻'=>'ba','䆉'=>'ba','䇑'=>'ba','䎬'=>'ba','䟦'=>'ba','䥯'=>'ba','䩗'=>'ba','䩻'=>'ba','䰾'=>'ba','䱝'=>'ba','䳁'=>'ba','䳊'=>'ba','仍'=>'reng','扔'=>'reng','礽'=>'reng','芿'=>'reng','辸'=>'reng','陾'=>'reng','㭁'=>'reng','㺱'=>'reng','䄧'=>'reng','䚮'=>'reng','仏'=>'fo','佛'=>'fo','坲'=>'fo','梻'=>'fo','仐'=>'tao','匋'=>'tao','咷'=>'tao','啕'=>'tao','夲'=>'tao','套'=>'tao','嫍'=>'tao','幍'=>'tao','弢'=>'tao','慆'=>'tao','掏'=>'tao','搯'=>'tao','桃'=>'tao','梼'=>'tao','槄'=>'tao','檮'=>'tao','洮'=>'tao','涛'=>'tao','淘'=>'tao','滔'=>'tao','濤'=>'tao','瑫'=>'tao','畓'=>'tao','祹'=>'tao','絛'=>'tao','綯'=>'tao','縚'=>'tao','縧'=>'tao','绦'=>'tao','绹'=>'tao','萄'=>'tao','蜪'=>'tao','裪'=>'tao','討'=>'tao','詜'=>'tao','謟'=>'tao','讨'=>'tao','迯'=>'tao','逃'=>'tao','醄'=>'tao','鋾'=>'tao','錭'=>'tao','陶'=>'tao','鞀'=>'tao','鞉'=>'tao','鞱'=>'tao','韜'=>'tao','韬'=>'tao','飸'=>'tao','饀'=>'tao','饕'=>'tao','駣'=>'tao','騊'=>'tao','鼗'=>'tao','㚐'=>'tao','㹗'=>'tao','䚯'=>'tao','䚵'=>'tao','䬞'=>'tao','䵚'=>'tao','仑'=>'lun','伦'=>'lun','侖'=>'lun','倫'=>'lun','囵'=>'lun','圇'=>'lun','埨'=>'lun','婨'=>'lun','崘'=>'lun','崙'=>'lun','惀'=>'lun','抡'=>'lun','掄'=>'lun','棆'=>'lun','沦'=>'lun','淪'=>'lun','溣'=>'lun','碖'=>'lun','磮'=>'lun','稐'=>'lun','綸'=>'lun','纶'=>'lun','耣'=>'lun','腀'=>'lun','菕'=>'lun','蜦'=>'lun','論'=>'lun','论'=>'lun','踚'=>'lun','輪'=>'lun','轮'=>'lun','錀'=>'lun','陯'=>'lun','鯩'=>'lun','㖮'=>'lun','㷍'=>'lun','䈁'=>'lun','䑳'=>'lun','仓'=>'cang','仺'=>'cang','伧'=>'cang','倉'=>'cang','傖'=>'cang','凔'=>'cang','匨'=>'cang','嵢'=>'cang','欌'=>'cang','沧'=>'cang','滄'=>'cang','濸'=>'cang','獊'=>'cang','罉'=>'cang','舱'=>'cang','艙'=>'cang','苍'=>'cang','蒼'=>'cang','蔵'=>'cang','藏'=>'cang','螥'=>'cang','賶'=>'cang','鑶'=>'cang','鶬'=>'cang','鸧'=>'cang','㵴'=>'cang','㶓'=>'cang','䅮'=>'cang','䢢'=>'cang','仔'=>'zi','倳'=>'zi','兹'=>'zi','剚'=>'zi','吇'=>'zi','呰'=>'zi','咨'=>'zi','唨'=>'zi','啙'=>'zi','嗞'=>'zi','姉'=>'zi','姊'=>'zi','姕'=>'zi','姿'=>'zi','子'=>'zi','孖'=>'zi','字'=>'zi','孜'=>'zi','孳'=>'zi','孶'=>'zi','崰'=>'zi','嵫'=>'zi','恣'=>'zi','杍'=>'zi','栥'=>'zi','梓'=>'zi','椔'=>'zi','榟'=>'zi','橴'=>'zi','淄'=>'zi','渍'=>'zi','湽'=>'zi','滋'=>'zi','滓'=>'zi','漬'=>'zi','澬'=>'zi','牸'=>'zi','玆'=>'zi','眥'=>'zi','眦'=>'zi','矷'=>'zi','禌'=>'zi','秄'=>'zi','秭'=>'zi','秶'=>'zi','稵'=>'zi','笫'=>'zi','籽'=>'zi','粢'=>'zi','紎'=>'zi','紫'=>'zi','緇'=>'zi','缁'=>'zi','耔'=>'zi','胏'=>'zi','胔'=>'zi','胾'=>'zi','自'=>'zi','芓'=>'zi','茊'=>'zi','茡'=>'zi','茲'=>'zi','葘'=>'zi','虸'=>'zi','觜'=>'zi','訾'=>'zi','訿'=>'zi','諮'=>'zi','谘'=>'zi','貲'=>'zi','資'=>'zi','赀'=>'zi','资'=>'zi','赼'=>'zi','趑'=>'zi','趦'=>'zi','輜'=>'zi','輺'=>'zi','辎'=>'zi','鄑'=>'zi','釨'=>'zi','鈭'=>'zi','錙'=>'zi','鍿'=>'zi','鎡'=>'zi','锱'=>'zi','镃'=>'zi','頾'=>'zi','頿'=>'zi','髭'=>'zi','鯔'=>'zi','鰦'=>'zi','鲻'=>'zi','鶅'=>'zi','鼒'=>'zi','齍'=>'zi','齜'=>'zi','龇'=>'zi','㜽'=>'zi','㧗'=>'zi','㰣'=>'zi','㰷'=>'zi','㱴'=>'zi','㺭'=>'zi','䅆'=>'zi','䐉'=>'zi','䔂'=>'zi','䘣'=>'zi','他'=>'ta','侤'=>'ta','咜'=>'ta','嚃'=>'ta','嚺'=>'ta','塌'=>'ta','塔'=>'ta','墖'=>'ta','她'=>'ta','它'=>'ta','崉'=>'ta','挞'=>'ta','搨'=>'ta','撻'=>'ta','榙'=>'ta','榻'=>'ta','毾'=>'ta','涾'=>'ta','溻'=>'ta','澾'=>'ta','濌'=>'ta','牠'=>'ta','狧'=>'ta','獭'=>'ta','獺'=>'ta','祂'=>'ta','禢'=>'ta','褟'=>'ta','襨'=>'ta','誻'=>'ta','譶'=>'ta','趿'=>'ta','踏'=>'ta','蹋'=>'ta','蹹'=>'ta','躢'=>'ta','遝'=>'ta','遢'=>'ta','鉈'=>'ta','錔'=>'ta','铊'=>'ta','闒'=>'ta','闥'=>'ta','闼'=>'ta','阘'=>'ta','鞜'=>'ta','鞳'=>'ta','鮙'=>'ta','鰨'=>'ta','鳎'=>'ta','㒓'=>'ta','㗳'=>'ta','㛥'=>'ta','㣛'=>'ta','㣵'=>'ta','㧺'=>'ta','㭼'=>'ta','㯓'=>'ta','㳠'=>'ta','㳫'=>'ta','㹺'=>'ta','㺚'=>'ta','㿹'=>'ta','䂿'=>'ta','䈋'=>'ta','䈳'=>'ta','䌈'=>'ta','䍇'=>'ta','䍝'=>'ta','䎓'=>'ta','䑜'=>'ta','䓠'=>'ta','䜚'=>'ta','䵬'=>'ta','䶀'=>'ta','䶁'=>'ta','仙'=>'xian','仚'=>'xian','伭'=>'xian','佡'=>'xian','僊'=>'xian','僩'=>'xian','僲'=>'xian','僴'=>'xian','先'=>'xian','冼'=>'xian','县'=>'xian','咞'=>'xian','咸'=>'xian','哯'=>'xian','唌'=>'xian','啣'=>'xian','嘕'=>'xian','垷'=>'xian','奾'=>'xian','妶'=>'xian','姭'=>'xian','娊'=>'xian','娨'=>'xian','娴'=>'xian','娹'=>'xian','婱'=>'xian','嫌'=>'xian','嫺'=>'xian','嫻'=>'xian','嬐'=>'xian','孅'=>'xian','宪'=>'xian','尟'=>'xian','尠'=>'xian','屳'=>'xian','岘'=>'xian','峴'=>'xian','崄'=>'xian','嶮'=>'xian','幰'=>'xian','廯'=>'xian','弦'=>'xian','忺'=>'xian','憪'=>'xian','憲'=>'xian','憸'=>'xian','挦'=>'xian','掀'=>'xian','搟'=>'xian','撊'=>'xian','撏'=>'xian','攇'=>'xian','攕'=>'xian','显'=>'xian','晛'=>'xian','暹'=>'xian','杴'=>'xian','枮'=>'xian','橌'=>'xian','櫶'=>'xian','毨'=>'xian','氙'=>'xian','涀'=>'xian','涎'=>'xian','湺'=>'xian','澖'=>'xian','瀗'=>'xian','灦'=>'xian','烍'=>'xian','燹'=>'xian','狝'=>'xian','猃'=>'xian','献'=>'xian','獫'=>'xian','獮'=>'xian','獻'=>'xian','玁'=>'xian','现'=>'xian','珗'=>'xian','現'=>'xian','甉'=>'xian','痫'=>'xian','癇'=>'xian','癎'=>'xian','県'=>'xian','睍'=>'xian','硍'=>'xian','礥'=>'xian','祆'=>'xian','禒'=>'xian','秈'=>'xian','筅'=>'xian','箲'=>'xian','籼'=>'xian','粯'=>'xian','糮'=>'xian','絃'=>'xian','絤'=>'xian','綫'=>'xian','線'=>'xian','縣'=>'xian','繊'=>'xian','纎'=>'xian','纖'=>'xian','纤'=>'xian','线'=>'xian','缐'=>'xian','羡'=>'xian','羨'=>'xian','胘'=>'xian','腺'=>'xian','臔'=>'xian','臽'=>'xian','舷'=>'xian','苋'=>'xian','苮'=>'xian','莧'=>'xian','莶'=>'xian','薟'=>'xian','藓'=>'xian','藔'=>'xian','藖'=>'xian','蘚'=>'xian','蚬'=>'xian','蚿'=>'xian','蛝'=>'xian','蜆'=>'xian','衔'=>'xian','衘'=>'xian','褼'=>'xian','襳'=>'xian','誢'=>'xian','誸'=>'xian','諴'=>'xian','譣'=>'xian','豏'=>'xian','賢'=>'xian','贒'=>'xian','贤'=>'xian','赻'=>'xian','跣'=>'xian','跹'=>'xian','蹮'=>'xian','躚'=>'xian','輱'=>'xian','酰'=>'xian','醎'=>'xian','銛'=>'xian','銜'=>'xian','鋧'=>'xian','錎'=>'xian','鍁'=>'xian','鍂'=>'xian','鍌'=>'xian','鏾'=>'xian','鑦'=>'xian','铦'=>'xian','锨'=>'xian','閑'=>'xian','闲'=>'xian','限'=>'xian','陥'=>'xian','险'=>'xian','陷'=>'xian','険'=>'xian','險'=>'xian','霰'=>'xian','韅'=>'xian','韯'=>'xian','韱'=>'xian','顕'=>'xian','顯'=>'xian','餡'=>'xian','馅'=>'xian','馦'=>'xian','鮮'=>'xian','鱻'=>'xian','鲜'=>'xian','鶱'=>'xian','鷳'=>'xian','鷴'=>'xian','鷼'=>'xian','鹇'=>'xian','鹹'=>'xian','麲'=>'xian','鼸'=>'xian','㔵'=>'xian','㘅'=>'xian','㘋'=>'xian','㛾'=>'xian','㜪'=>'xian','㡉'=>'xian','㡾'=>'xian','㢺'=>'xian','㦓'=>'xian','㧋'=>'xian','㧥'=>'xian','㩈'=>'xian','㪇'=>'xian','㫫'=>'xian','㬎'=>'xian','㬗'=>'xian','㭠'=>'xian','㭹'=>'xian','㮭'=>'xian','㯀'=>'xian','㳄'=>'xian','㳭'=>'xian','㵪'=>'xian','㶍'=>'xian','㺌'=>'xian','㿅'=>'xian','䀏'=>'xian','䁂'=>'xian','䃱'=>'xian','䃸'=>'xian','䉯'=>'xian','䉳'=>'xian','䏹'=>'xian','䒸'=>'xian','䕔'=>'xian','䗾'=>'xian','䘆'=>'xian','䚚'=>'xian','䜢'=>'xian','䝨'=>'xian','䞁'=>'xian','䢾'=>'xian','䤼'=>'xian','䥪'=>'xian','䦥'=>'xian','䧋'=>'xian','䧟'=>'xian','䧮'=>'xian','䨘'=>'xian','䨷'=>'xian','䱤'=>'xian','䲗'=>'xian','䵇'=>'xian','䶟'=>'xian','䶢'=>'xian','仜'=>'hong','叿'=>'hong','吰'=>'hong','哄'=>'hong','嗊'=>'hong','嚝'=>'hong','垬'=>'hong','妅'=>'hong','娂'=>'hong','宏'=>'hong','宖'=>'hong','弘'=>'hong','彋'=>'hong','揈'=>'hong','撔'=>'hong','晎'=>'hong','汯'=>'hong','泓'=>'hong','洪'=>'hong','浤'=>'hong','渱'=>'hong','渹'=>'hong','潂'=>'hong','澋'=>'hong','澒'=>'hong','灴'=>'hong','烘'=>'hong','焢'=>'hong','玒'=>'hong','玜'=>'hong','硔'=>'hong','硡'=>'hong','竑'=>'hong','竤'=>'hong','篊'=>'hong','粠'=>'hong','紅'=>'hong','紘'=>'hong','紭'=>'hong','綋'=>'hong','红'=>'hong','纮'=>'hong','翃'=>'hong','翝'=>'hong','耾'=>'hong','苰'=>'hong','荭'=>'hong','葒'=>'hong','葓'=>'hong','蕻'=>'hong','薨'=>'hong','虹'=>'hong','訇'=>'hong','訌'=>'hong','讧'=>'hong','谹'=>'hong','谼'=>'hong','谾'=>'hong','軣'=>'hong','輷'=>'hong','轟'=>'hong','轰'=>'hong','鈜'=>'hong','鉷'=>'hong','銾'=>'hong','鋐'=>'hong','鍧'=>'hong','閎'=>'hong','閧'=>'hong','闀'=>'hong','闂'=>'hong','闳'=>'hong','霐'=>'hong','霟'=>'hong','鞃'=>'hong','鬨'=>'hong','魟'=>'hong','鴻'=>'hong','鸿'=>'hong','黉'=>'hong','黌'=>'hong','㖓'=>'hong','㢬'=>'hong','㬴'=>'hong','㶹'=>'hong','䀧'=>'hong','䂫'=>'hong','䃔'=>'hong','䆖'=>'hong','䉺'=>'hong','䍔'=>'hong','䜫'=>'hong','䞑'=>'hong','䡌'=>'hong','䡏'=>'hong','䧆'=>'hong','䨎'=>'hong','䩑'=>'hong','䪦'=>'hong','䫹'=>'hong','䫺'=>'hong','䲨'=>'hong','仝'=>'tong','佟'=>'tong','僮'=>'tong','勭'=>'tong','同'=>'tong','哃'=>'tong','嗵'=>'tong','囲'=>'tong','峂'=>'tong','庝'=>'tong','彤'=>'tong','恸'=>'tong','慟'=>'tong','憅'=>'tong','捅'=>'tong','晍'=>'tong','曈'=>'tong','朣'=>'tong','桐'=>'tong','桶'=>'tong','樋'=>'tong','橦'=>'tong','氃'=>'tong','浵'=>'tong','潼'=>'tong','炵'=>'tong','烔'=>'tong','熥'=>'tong','犝'=>'tong','狪'=>'tong','獞'=>'tong','痌'=>'tong','痛'=>'tong','眮'=>'tong','瞳'=>'tong','砼'=>'tong','秱'=>'tong','穜'=>'tong','童'=>'tong','筒'=>'tong','筩'=>'tong','粡'=>'tong','絧'=>'tong','統'=>'tong','綂'=>'tong','统'=>'tong','膧'=>'tong','茼'=>'tong','蓪'=>'tong','蚒'=>'tong','衕'=>'tong','赨'=>'tong','通'=>'tong','酮'=>'tong','鉖'=>'tong','鉵'=>'tong','銅'=>'tong','铜'=>'tong','餇'=>'tong','鮦'=>'tong','鲖'=>'tong','㛚'=>'tong','㠉'=>'tong','㠽'=>'tong','㣚'=>'tong','㣠'=>'tong','㤏'=>'tong','㪌'=>'tong','㮔'=>'tong','㸗'=>'tong','㼧'=>'tong','㼿'=>'tong','䂈'=>'tong','䆚'=>'tong','䆹'=>'tong','䮵'=>'tong','䳋'=>'tong','䴀'=>'tong','䶱'=>'tong','代'=>'dai','侢'=>'dai','傣'=>'dai','叇'=>'dai','呆'=>'dai','呔'=>'dai','垈'=>'dai','埭'=>'dai','岱'=>'dai','帒'=>'dai','带'=>'dai','帯'=>'dai','帶'=>'dai','廗'=>'dai','待'=>'dai','怠'=>'dai','懛'=>'dai','戴'=>'dai','曃'=>'dai','柋'=>'dai','歹'=>'dai','殆'=>'dai','汏'=>'dai','瀻'=>'dai','獃'=>'dai','玳'=>'dai','瑇'=>'dai','甙'=>'dai','簤'=>'dai','紿'=>'dai','緿'=>'dai','绐'=>'dai','艜'=>'dai','蚮'=>'dai','袋'=>'dai','襶'=>'dai','貸'=>'dai','贷'=>'dai','蹛'=>'dai','軑'=>'dai','軚'=>'dai','軩'=>'dai','轪'=>'dai','迨'=>'dai','逮'=>'dai','霴'=>'dai','靆'=>'dai','鮘'=>'dai','鴏'=>'dai','黛'=>'dai','黱'=>'dai','㐲'=>'dai','㞭'=>'dai','㫹'=>'dai','㯂'=>'dai','㶡'=>'dai','㻖'=>'dai','㿃'=>'dai','䈆'=>'dai','䒫'=>'dai','䚞'=>'dai','䚟'=>'dai','令'=>'ling','伶'=>'ling','凌'=>'ling','刢'=>'ling','另'=>'ling','呤'=>'ling','囹'=>'ling','坽'=>'ling','夌'=>'ling','姈'=>'ling','婈'=>'ling','孁'=>'ling','岭'=>'ling','岺'=>'ling','崚'=>'ling','嶺'=>'ling','彾'=>'ling','掕'=>'ling','昤'=>'ling','朎'=>'ling','柃'=>'ling','棂'=>'ling','櫺'=>'ling','欞'=>'ling','泠'=>'ling','淩'=>'ling','澪'=>'ling','瀮'=>'ling','灵'=>'ling','炩'=>'ling','燯'=>'ling','爧'=>'ling','狑'=>'ling','玲'=>'ling','琌'=>'ling','瓴'=>'ling','皊'=>'ling','砱'=>'ling','祾'=>'ling','秢'=>'ling','竛'=>'ling','笭'=>'ling','紷'=>'ling','綾'=>'ling','绫'=>'ling','羚'=>'ling','翎'=>'ling','聆'=>'ling','舲'=>'ling','苓'=>'ling','菱'=>'ling','蓤'=>'ling','蔆'=>'ling','蕶'=>'ling','蘦'=>'ling','蛉'=>'ling','衑'=>'ling','袊'=>'ling','裬'=>'ling','詅'=>'ling','跉'=>'ling','軨'=>'ling','輘'=>'ling','酃'=>'ling','醽'=>'ling','鈴'=>'ling','錂'=>'ling','铃'=>'ling','閝'=>'ling','阾'=>'ling','陵'=>'ling','零'=>'ling','霊'=>'ling','霗'=>'ling','霛'=>'ling','霝'=>'ling','靈'=>'ling','領'=>'ling','领'=>'ling','駖'=>'ling','魿'=>'ling','鯪'=>'ling','鲮'=>'ling','鴒'=>'ling','鸰'=>'ling','鹷'=>'ling','麢'=>'ling','齡'=>'ling','齢'=>'ling','龄'=>'ling','龗'=>'ling','㖫'=>'ling','㡵'=>'ling','㥄'=>'ling','㦭'=>'ling','㪮'=>'ling','㬡'=>'ling','㯪'=>'ling','㱥'=>'ling','㲆'=>'ling','㸳'=>'ling','㻏'=>'ling','㾉'=>'ling','䄥'=>'ling','䈊'=>'ling','䉁'=>'ling','䉖'=>'ling','䉹'=>'ling','䌢'=>'ling','䍅'=>'ling','䔖'=>'ling','䕘'=>'ling','䖅'=>'ling','䙥'=>'ling','䚖'=>'ling','䠲'=>'ling','䡼'=>'ling','䡿'=>'ling','䧙'=>'ling','䨩'=>'ling','䯍'=>'ling','䰱'=>'ling','䴇'=>'ling','䴒'=>'ling','䴫'=>'ling','仦'=>'chao','仯'=>'chao','吵'=>'chao','嘲'=>'chao','巐'=>'chao','巢'=>'chao','巣'=>'chao','弨'=>'chao','怊'=>'chao','抄'=>'chao','晁'=>'chao','朝'=>'chao','樔'=>'chao','欩'=>'chao','漅'=>'chao','潮'=>'chao','炒'=>'chao','焯'=>'chao','煼'=>'chao','牊'=>'chao','眧'=>'chao','窲'=>'chao','繛'=>'chao','罺'=>'chao','耖'=>'chao','觘'=>'chao','訬'=>'chao','謿'=>'chao','超'=>'chao','轈'=>'chao','鄛'=>'chao','鈔'=>'chao','钞'=>'chao','麨'=>'chao','鼂'=>'chao','鼌'=>'chao','㶤'=>'chao','㷅'=>'chao','䄻'=>'chao','䎐'=>'chao','䏚'=>'chao','䬤'=>'chao','䰫'=>'chao','仧'=>'chang','伥'=>'chang','倀'=>'chang','倡'=>'chang','偿'=>'chang','僘'=>'chang','償'=>'chang','兏'=>'chang','厂'=>'chang','厰'=>'chang','唱'=>'chang','嘗'=>'chang','嚐'=>'chang','场'=>'chang','場'=>'chang','塲'=>'chang','娼'=>'chang','嫦'=>'chang','尝'=>'chang','常'=>'chang','廠'=>'chang','徜'=>'chang','怅'=>'chang','悵'=>'chang','惝'=>'chang','敞'=>'chang','昌'=>'chang','昶'=>'chang','晿'=>'chang','暢'=>'chang','椙'=>'chang','氅'=>'chang','淐'=>'chang','猖'=>'chang','玚'=>'chang','琩'=>'chang','瑒'=>'chang','瑺'=>'chang','瓺'=>'chang','甞'=>'chang','畅'=>'chang','畼'=>'chang','肠'=>'chang','腸'=>'chang','膓'=>'chang','苌'=>'chang','菖'=>'chang','萇'=>'chang','蟐'=>'chang','裮'=>'chang','誯'=>'chang','鋹'=>'chang','鋿'=>'chang','錩'=>'chang','鏛'=>'chang','锠'=>'chang','長'=>'chang','镸'=>'chang','长'=>'chang','閶'=>'chang','阊'=>'chang','韔'=>'chang','鬯'=>'chang','鯧'=>'chang','鱨'=>'chang','鲳'=>'chang','鲿'=>'chang','鼚'=>'chang','㙊'=>'chang','㦂'=>'chang','㫤'=>'chang','䕋'=>'chang','䗅'=>'chang','䠀'=>'chang','䠆'=>'chang','䩨'=>'chang','䯴'=>'chang','仨'=>'sa','卅'=>'sa','摋'=>'sa','撒'=>'sa','栍'=>'sa','桬'=>'sa','櫒'=>'sa','洒'=>'sa','潵'=>'sa','灑'=>'sa','脎'=>'sa','萨'=>'sa','薩'=>'sa','訯'=>'sa','鈒'=>'sa','钑'=>'sa','隡'=>'sa','靸'=>'sa','颯'=>'sa','飒'=>'sa','馺'=>'sa','㒎'=>'sa','㪪'=>'sa','㳐'=>'sa','㽂'=>'sa','䊛'=>'sa','䘮'=>'sa','䙣'=>'sa','䬃'=>'sa','们'=>'men','們'=>'men','悶'=>'men','懑'=>'men','懣'=>'men','扪'=>'men','捫'=>'men','暪'=>'men','椚'=>'men','焖'=>'men','燜'=>'men','玣'=>'men','璊'=>'men','穈'=>'men','菛'=>'men','虋'=>'men','鍆'=>'men','钔'=>'men','門'=>'men','閅'=>'men','门'=>'men','闷'=>'men','㡈'=>'men','㥃'=>'men','㦖'=>'men','㨺'=>'men','㱪'=>'men','㵍'=>'men','䊟'=>'men','䝧'=>'men','䫒'=>'men','仮'=>'fan','凡'=>'fan','凢'=>'fan','凣'=>'fan','勫'=>'fan','匥'=>'fan','反'=>'fan','噃'=>'fan','墦'=>'fan','奿'=>'fan','嬎'=>'fan','嬏'=>'fan','嬔'=>'fan','帆'=>'fan','幡'=>'fan','忛'=>'fan','憣'=>'fan','払'=>'fan','旙'=>'fan','旛'=>'fan','杋'=>'fan','柉'=>'fan','梵'=>'fan','棥'=>'fan','樊'=>'fan','橎'=>'fan','氾'=>'fan','汎'=>'fan','泛'=>'fan','滼'=>'fan','瀪'=>'fan','瀿'=>'fan','烦'=>'fan','煩'=>'fan','燔'=>'fan','犯'=>'fan','犿'=>'fan','璠'=>'fan','畈'=>'fan','番'=>'fan','盕'=>'fan','矾'=>'fan','礬'=>'fan','笲'=>'fan','笵'=>'fan','範'=>'fan','籓'=>'fan','籵'=>'fan','緐'=>'fan','繁'=>'fan','繙'=>'fan','羳'=>'fan','翻'=>'fan','膰'=>'fan','舤'=>'fan','舧'=>'fan','范'=>'fan','蕃'=>'fan','薠'=>'fan','藩'=>'fan','蘩'=>'fan','蠜'=>'fan','襎'=>'fan','訉'=>'fan','販'=>'fan','贩'=>'fan','蹯'=>'fan','軓'=>'fan','軬'=>'fan','轓'=>'fan','辺'=>'fan','返'=>'fan','釩'=>'fan','鐇'=>'fan','钒'=>'fan','颿'=>'fan','飜'=>'fan','飯'=>'fan','飰'=>'fan','饭'=>'fan','鱕'=>'fan','鷭'=>'fan','㕨'=>'fan','㝃'=>'fan','㠶'=>'fan','㤆'=>'fan','㴀'=>'fan','㶗'=>'fan','㸋'=>'fan','㺕'=>'fan','㼝'=>'fan','㽹'=>'fan','䀀'=>'fan','䀟'=>'fan','䉊'=>'fan','䉒'=>'fan','䊩'=>'fan','䋣'=>'fan','䋦'=>'fan','䌓'=>'fan','䐪'=>'fan','䒠'=>'fan','䒦'=>'fan','䛀'=>'fan','䡊'=>'fan','䣲'=>'fan','䪛'=>'fan','䪤'=>'fan','䫶'=>'fan','䭵'=>'fan','䮳'=>'fan','仰'=>'yang','佒'=>'yang','佯'=>'yang','傟'=>'yang','养'=>'yang','劷'=>'yang','卬'=>'yang','咉'=>'yang','坱'=>'yang','垟'=>'yang','央'=>'yang','奍'=>'yang','姎'=>'yang','岟'=>'yang','崵'=>'yang','崸'=>'yang','徉'=>'yang','怏'=>'yang','恙'=>'yang','慃'=>'yang','懩'=>'yang','扬'=>'yang','抰'=>'yang','揚'=>'yang','攁'=>'yang','敭'=>'yang','旸'=>'yang','昜'=>'yang','暘'=>'yang','杨'=>'yang','柍'=>'yang','样'=>'yang','楊'=>'yang','楧'=>'yang','様'=>'yang','樣'=>'yang','殃'=>'yang','氜'=>'yang','氧'=>'yang','氱'=>'yang','泱'=>'yang','洋'=>'yang','漾'=>'yang','瀁'=>'yang','炀'=>'yang','炴'=>'yang','烊'=>'yang','煬'=>'yang','珜'=>'yang','疡'=>'yang','痒'=>'yang','瘍'=>'yang','癢'=>'yang','眏'=>'yang','眻'=>'yang','礢'=>'yang','禓'=>'yang','秧'=>'yang','紻'=>'yang','羊'=>'yang','羏'=>'yang','羕'=>'yang','羪'=>'yang','胦'=>'yang','蛘'=>'yang','詇'=>'yang','諹'=>'yang','軮'=>'yang','輰'=>'yang','鉠'=>'yang','鍈'=>'yang','鍚'=>'yang','鐊'=>'yang','钖'=>'yang','阦'=>'yang','阳'=>'yang','陽'=>'yang','雵'=>'yang','霷'=>'yang','鞅'=>'yang','颺'=>'yang','飏'=>'yang','養'=>'yang','駚'=>'yang','鰑'=>'yang','鴦'=>'yang','鴹'=>'yang','鸉'=>'yang','鸯'=>'yang','㔦'=>'yang','㟅'=>'yang','㨾'=>'yang','㬕'=>'yang','㺊'=>'yang','㿮'=>'yang','䁑'=>'yang','䇦'=>'yang','䑆'=>'yang','䒋'=>'yang','䖹'=>'yang','䬗'=>'yang','䬬'=>'yang','䬺'=>'yang','䭐'=>'yang','䵮'=>'yang','仴'=>'wo','倭'=>'wo','偓'=>'wo','卧'=>'wo','唩'=>'wo','喔'=>'wo','婐'=>'wo','婑'=>'wo','媉'=>'wo','幄'=>'wo','我'=>'wo','挝'=>'wo','捰'=>'wo','捾'=>'wo','握'=>'wo','撾'=>'wo','斡'=>'wo','楃'=>'wo','沃'=>'wo','涡'=>'wo','涹'=>'wo','渥'=>'wo','渦'=>'wo','濣'=>'wo','焥'=>'wo','猧'=>'wo','瓁'=>'wo','瞃'=>'wo','硪'=>'wo','窝'=>'wo','窩'=>'wo','肟'=>'wo','腛'=>'wo','臒'=>'wo','臥'=>'wo','莴'=>'wo','萵'=>'wo','蜗'=>'wo','蝸'=>'wo','踒'=>'wo','齷'=>'wo','龌'=>'wo','㠛'=>'wo','㦱'=>'wo','㧴'=>'wo','㱧'=>'wo','䁊'=>'wo','䠎'=>'wo','䰀'=>'wo','件'=>'jian','侟'=>'jian','俭'=>'jian','俴'=>'jian','倹'=>'jian','健'=>'jian','僭'=>'jian','儉'=>'jian','兼'=>'jian','冿'=>'jian','减'=>'jian','剑'=>'jian','剣'=>'jian','剪'=>'jian','剱'=>'jian','劍'=>'jian','劎'=>'jian','劒'=>'jian','劔'=>'jian','囏'=>'jian','囝'=>'jian','坚'=>'jian','堅'=>'jian','墹'=>'jian','奸'=>'jian','姦'=>'jian','姧'=>'jian','寋'=>'jian','尖'=>'jian','帴'=>'jian','幵'=>'jian','建'=>'jian','弿'=>'jian','彅'=>'jian','徤'=>'jian','惤'=>'jian','戋'=>'jian','戔'=>'jian','戩'=>'jian','戬'=>'jian','拣'=>'jian','挸'=>'jian','捡'=>'jian','揀'=>'jian','揃'=>'jian','搛'=>'jian','撿'=>'jian','擶'=>'jian','旔'=>'jian','暕'=>'jian','枧'=>'jian','柬'=>'jian','栫'=>'jian','梘'=>'jian','检'=>'jian','検'=>'jian','椷'=>'jian','椾'=>'jian','楗'=>'jian','榗'=>'jian','槛'=>'jian','樫'=>'jian','橺'=>'jian','檢'=>'jian','檻'=>'jian','櫼'=>'jian','歼'=>'jian','殱'=>'jian','殲'=>'jian','毽'=>'jian','洊'=>'jian','涧'=>'jian','渐'=>'jian','減'=>'jian','湔'=>'jian','湕'=>'jian','溅'=>'jian','漸'=>'jian','澗'=>'jian','濺'=>'jian','瀐'=>'jian','瀳'=>'jian','瀸'=>'jian','瀽'=>'jian','煎'=>'jian','熞'=>'jian','熸'=>'jian','牋'=>'jian','牮'=>'jian','犍'=>'jian','猏'=>'jian','玪'=>'jian','珔'=>'jian','瑊'=>'jian','瑐'=>'jian','监'=>'jian','監'=>'jian','睑'=>'jian','睷'=>'jian','瞯'=>'jian','瞷'=>'jian','瞼'=>'jian','硷'=>'jian','碊'=>'jian','碱'=>'jian','磵'=>'jian','礀'=>'jian','礆'=>'jian','礛'=>'jian','笕'=>'jian','笺'=>'jian','筧'=>'jian','简'=>'jian','箋'=>'jian','箭'=>'jian','篯'=>'jian','簡'=>'jian','籛'=>'jian','糋'=>'jian','絸'=>'jian','緘'=>'jian','縑'=>'jian','繝'=>'jian','繭'=>'jian','缄'=>'jian','缣'=>'jian','翦'=>'jian','聻'=>'jian','肩'=>'jian','腱'=>'jian','臶'=>'jian','舰'=>'jian','艦'=>'jian','艰'=>'jian','艱'=>'jian','茧'=>'jian','荐'=>'jian','菅'=>'jian','菺'=>'jian','葌'=>'jian','葏'=>'jian','葥'=>'jian','蒹'=>'jian','蕑'=>'jian','蕳'=>'jian','薦'=>'jian','藆'=>'jian','虃'=>'jian','螹'=>'jian','蠒'=>'jian','袸'=>'jian','裥'=>'jian','襇'=>'jian','襉'=>'jian','襺'=>'jian','見'=>'jian','覵'=>'jian','覸'=>'jian','见'=>'jian','詃'=>'jian','諓'=>'jian','諫'=>'jian','謇'=>'jian','謭'=>'jian','譼'=>'jian','譾'=>'jian','谏'=>'jian','谫'=>'jian','豜'=>'jian','豣'=>'jian','賎'=>'jian','賤'=>'jian','贱'=>'jian','趝'=>'jian','趼'=>'jian','跈'=>'jian','践'=>'jian','踐'=>'jian','踺'=>'jian','蹇'=>'jian','轞'=>'jian','釼'=>'jian','鉴'=>'jian','鋻'=>'jian','鍳'=>'jian','鍵'=>'jian','鏩'=>'jian','鐗'=>'jian','鐧'=>'jian','鑑'=>'jian','鑒'=>'jian','鑬'=>'jian','鑯'=>'jian','鑳'=>'jian','锏'=>'jian','键'=>'jian','閒'=>'jian','間'=>'jian','间'=>'jian','靬'=>'jian','鞬'=>'jian','鞯'=>'jian','韀'=>'jian','韉'=>'jian','餞'=>'jian','餰'=>'jian','饯'=>'jian','馢'=>'jian','鬋'=>'jian','鰎'=>'jian','鰔'=>'jian','鰜'=>'jian','鰹'=>'jian','鲣'=>'jian','鳒'=>'jian','鳽'=>'jian','鵳'=>'jian','鶼'=>'jian','鹣'=>'jian','鹸'=>'jian','鹻'=>'jian','鹼'=>'jian','麉'=>'jian','㓺'=>'jian','㔋'=>'jian','㔓'=>'jian','㣤'=>'jian','㦗'=>'jian','㨴'=>'jian','㨵'=>'jian','㯺'=>'jian','㰄'=>'jian','㳨'=>'jian','㶕'=>'jian','㺝'=>'jian','䄯'=>'jian','䅐'=>'jian','䇟'=>'jian','䉍'=>'jian','䛳'=>'jian','䟅'=>'jian','䟰'=>'jian','䤔'=>'jian','䥜'=>'jian','䧖'=>'jian','䩆'=>'jian','䬻'=>'jian','䭈'=>'jian','䭕'=>'jian','䭠'=>'jian','䮿'=>'jian','䯛'=>'jian','䯡'=>'jian','䵖'=>'jian','䵛'=>'jian','䵡'=>'jian','䵤'=>'jian','䶠'=>'jian','价'=>'jia','佳'=>'jia','假'=>'jia','傢'=>'jia','價'=>'jia','加'=>'jia','叚'=>'jia','唊'=>'jia','嗧'=>'jia','嘉'=>'jia','圿'=>'jia','埉'=>'jia','夹'=>'jia','夾'=>'jia','婽'=>'jia','嫁'=>'jia','宊'=>'jia','家'=>'jia','岬'=>'jia','幏'=>'jia','徦'=>'jia','恝'=>'jia','戛'=>'jia','戞'=>'jia','扴'=>'jia','抸'=>'jia','拁'=>'jia','斚'=>'jia','斝'=>'jia','架'=>'jia','枷'=>'jia','梜'=>'jia','椵'=>'jia','榎'=>'jia','榢'=>'jia','槚'=>'jia','檟'=>'jia','毠'=>'jia','泇'=>'jia','浃'=>'jia','浹'=>'jia','犌'=>'jia','猳'=>'jia','玾'=>'jia','珈'=>'jia','甲'=>'jia','痂'=>'jia','瘕'=>'jia','稼'=>'jia','笳'=>'jia','糘'=>'jia','耞'=>'jia','胛'=>'jia','脥'=>'jia','腵'=>'jia','荚'=>'jia','莢'=>'jia','葭'=>'jia','蛱'=>'jia','蛺'=>'jia','袈'=>'jia','袷'=>'jia','裌'=>'jia','豭'=>'jia','貑'=>'jia','賈'=>'jia','贾'=>'jia','跏'=>'jia','跲'=>'jia','迦'=>'jia','郏'=>'jia','郟'=>'jia','鉀'=>'jia','鉫'=>'jia','鋏'=>'jia','鎵'=>'jia','钾'=>'jia','铗'=>'jia','镓'=>'jia','頬'=>'jia','頰'=>'jia','颊'=>'jia','餄'=>'jia','駕'=>'jia','驾'=>'jia','鴶'=>'jia','鵊'=>'jia','麚'=>'jia','㕅'=>'jia','㪴'=>'jia','㮖'=>'jia','㼪'=>'jia','㿓'=>'jia','䀫'=>'jia','䁍'=>'jia','䑝'=>'jia','䕛'=>'jia','䛟'=>'jia','䩡'=>'jia','仸'=>'yao','倄'=>'yao','偠'=>'yao','傜'=>'yao','吆'=>'yao','咬'=>'yao','喓'=>'yao','嗂'=>'yao','垚'=>'yao','堯'=>'yao','夭'=>'yao','妖'=>'yao','姚'=>'yao','婹'=>'yao','媱'=>'yao','宎'=>'yao','尧'=>'yao','尭'=>'yao','岆'=>'yao','峣'=>'yao','崾'=>'yao','嶢'=>'yao','嶤'=>'yao','幺'=>'yao','徭'=>'yao','徺'=>'yao','愮'=>'yao','抭'=>'yao','揺'=>'yao','搖'=>'yao','摇'=>'yao','摿'=>'yao','暚'=>'yao','曜'=>'yao','曣'=>'yao','杳'=>'yao','枖'=>'yao','柼'=>'yao','楆'=>'yao','榚'=>'yao','榣'=>'yao','殀'=>'yao','殽'=>'yao','溔'=>'yao','烑'=>'yao','熎'=>'yao','燿'=>'yao','爻'=>'yao','狕'=>'yao','猺'=>'yao','獟'=>'yao','珧'=>'yao','瑤'=>'yao','瑶'=>'yao','眑'=>'yao','矅'=>'yao','磘'=>'yao','祅'=>'yao','穾'=>'yao','窅'=>'yao','窈'=>'yao','窑'=>'yao','窔'=>'yao','窯'=>'yao','窰'=>'yao','筄'=>'yao','繇'=>'yao','纅'=>'yao','耀'=>'yao','肴'=>'yao','腰'=>'yao','舀'=>'yao','艞'=>'yao','苭'=>'yao','药'=>'yao','葯'=>'yao','葽'=>'yao','蓔'=>'yao','薬'=>'yao','藥'=>'yao','蘨'=>'yao','袎'=>'yao','要'=>'yao','覞'=>'yao','訞'=>'yao','詏'=>'yao','謠'=>'yao','謡'=>'yao','讑'=>'yao','谣'=>'yao','軺'=>'yao','轺'=>'yao','遙'=>'yao','遥'=>'yao','邀'=>'yao','銚'=>'yao','鎐'=>'yao','鑰'=>'yao','闄'=>'yao','靿'=>'yao','顤'=>'yao','颻'=>'yao','飖'=>'yao','餆'=>'yao','餚'=>'yao','騕'=>'yao','鰩'=>'yao','鳐'=>'yao','鴁'=>'yao','鴢'=>'yao','鷂'=>'yao','鷕'=>'yao','鹞'=>'yao','鼼'=>'yao','齩'=>'yao','㔽'=>'yao','㝔'=>'yao','㞁'=>'yao','㟱'=>'yao','㢓'=>'yao','㨱'=>'yao','㫏'=>'yao','㫐'=>'yao','㮁'=>'yao','㴭'=>'yao','㵸'=>'yao','㿑'=>'yao','㿢'=>'yao','䁏'=>'yao','䁘'=>'yao','䂚'=>'yao','䆙'=>'yao','䆞'=>'yao','䉰'=>'yao','䋂'=>'yao','䋤'=>'yao','䌊'=>'yao','䌛'=>'yao','䍃'=>'yao','䑬'=>'yao','䔄'=>'yao','䖴'=>'yao','䙅'=>'yao','䚺'=>'yao','䚻'=>'yao','䢣'=>'yao','䬙'=>'yao','䴠'=>'yao','䶧'=>'yao','份'=>'fen','偾'=>'fen','僨'=>'fen','分'=>'fen','吩'=>'fen','坆'=>'fen','坋'=>'fen','坟'=>'fen','墳'=>'fen','奋'=>'fen','奮'=>'fen','妢'=>'fen','岎'=>'fen','帉'=>'fen','幩'=>'fen','弅'=>'fen','忿'=>'fen','愤'=>'fen','憤'=>'fen','昐'=>'fen','朆'=>'fen','枌'=>'fen','梤'=>'fen','棻'=>'fen','棼'=>'fen','橨'=>'fen','氛'=>'fen','汾'=>'fen','瀵'=>'fen','炃'=>'fen','焚'=>'fen','燌'=>'fen','燓'=>'fen','玢'=>'fen','瞓'=>'fen','秎'=>'fen','竕'=>'fen','粉'=>'fen','粪'=>'fen','糞'=>'fen','紛'=>'fen','纷'=>'fen','羒'=>'fen','羵'=>'fen','翂'=>'fen','肦'=>'fen','膹'=>'fen','芬'=>'fen','蒶'=>'fen','蕡'=>'fen','蚠'=>'fen','蚡'=>'fen','衯'=>'fen','訜'=>'fen','豮'=>'fen','豶'=>'fen','躮'=>'fen','轒'=>'fen','酚'=>'fen','鈖'=>'fen','鐼'=>'fen','隫'=>'fen','雰'=>'fen','餴'=>'fen','饙'=>'fen','馚'=>'fen','馩'=>'fen','魵'=>'fen','鱝'=>'fen','鲼'=>'fen','鳻'=>'fen','黂'=>'fen','黺'=>'fen','鼖'=>'fen','鼢'=>'fen','㖹'=>'fen','㥹'=>'fen','㮥'=>'fen','㷊'=>'fen','㸮'=>'fen','㿎'=>'fen','䩿'=>'fen','䯨'=>'fen','䴅'=>'fen','仾'=>'di','低'=>'di','俤'=>'di','偙'=>'di','僀'=>'di','厎'=>'di','呧'=>'di','唙'=>'di','啇'=>'di','啲'=>'di','嘀'=>'di','嚁'=>'di','地'=>'di','坔'=>'di','坻'=>'di','埊'=>'di','埞'=>'di','堤'=>'di','墑'=>'di','墬'=>'di','奃'=>'di','娣'=>'di','媂'=>'di','嫡'=>'di','嶳'=>'di','帝'=>'di','底'=>'di','廸'=>'di','弚'=>'di','弟'=>'di','弤'=>'di','彽'=>'di','怟'=>'di','慸'=>'di','抵'=>'di','拞'=>'di','掋'=>'di','摕'=>'di','敌'=>'di','敵'=>'di','旳'=>'di','杕'=>'di','枤'=>'di','柢'=>'di','梊'=>'di','梑'=>'di','棣'=>'di','氐'=>'di','涤'=>'di','滌'=>'di','滴'=>'di','焍'=>'di','牴'=>'di','狄'=>'di','玓'=>'di','甋'=>'di','眱'=>'di','睇'=>'di','砥'=>'di','碲'=>'di','磾'=>'di','祶'=>'di','禘'=>'di','笛'=>'di','第'=>'di','篴'=>'di','籴'=>'di','糴'=>'di','締'=>'di','缔'=>'di','羝'=>'di','翟'=>'di','聜'=>'di','肑'=>'di','腣'=>'di','苐'=>'di','苖'=>'di','荻'=>'di','菂'=>'di','菧'=>'di','蒂'=>'di','蔋'=>'di','蔐'=>'di','蔕'=>'di','藡'=>'di','蝃'=>'di','螮'=>'di','袛'=>'di','覿'=>'di','觌'=>'di','觝'=>'di','詆'=>'di','諦'=>'di','诋'=>'di','谛'=>'di','豴'=>'di','趆'=>'di','踶'=>'di','軧'=>'di','迪'=>'di','递'=>'di','逓'=>'di','遞'=>'di','遰'=>'di','邸'=>'di','釱'=>'di','鉪'=>'di','鍉'=>'di','鏑'=>'di','镝'=>'di','阺'=>'di','隄'=>'di','靮'=>'di','鞮'=>'di','頔'=>'di','馰'=>'di','骶'=>'di','髢'=>'di','魡'=>'di','鯳'=>'di','鸐'=>'di','㡳'=>'di','㢩'=>'di','㣙'=>'di','㦅'=>'di','㪆'=>'di','㭽'=>'di','㰅'=>'di','㹍'=>'di','㼵'=>'di','䀸'=>'di','䀿'=>'di','䂡'=>'di','䊮'=>'di','䍕'=>'di','䏑'=>'di','䑭'=>'di','䑯'=>'di','䞶'=>'di','䟡'=>'di','䢑'=>'di','䣌'=>'di','䧝'=>'di','䨀'=>'di','䨤'=>'di','䩘'=>'di','䩚'=>'di','䮤'=>'di','䯼'=>'di','䱃'=>'di','䱱'=>'di','䴞'=>'di','䵠'=>'di','䶍'=>'di','仿'=>'fang','倣'=>'fang','匚'=>'fang','坊'=>'fang','埅'=>'fang','堏'=>'fang','妨'=>'fang','彷'=>'fang','房'=>'fang','放'=>'fang','方'=>'fang','旊'=>'fang','昉'=>'fang','昘'=>'fang','枋'=>'fang','淓'=>'fang','牥'=>'fang','瓬'=>'fang','眆'=>'fang','紡'=>'fang','纺'=>'fang','肪'=>'fang','舫'=>'fang','芳'=>'fang','蚄'=>'fang','訪'=>'fang','访'=>'fang','趽'=>'fang','邡'=>'fang','鈁'=>'fang','錺'=>'fang','钫'=>'fang','防'=>'fang','髣'=>'fang','魴'=>'fang','鲂'=>'fang','鴋'=>'fang','鶭'=>'fang','㑂'=>'fang','㕫'=>'fang','㤃'=>'fang','㧍'=>'fang','㯐'=>'fang','䢍'=>'fang','䦈'=>'fang','䲱'=>'fang','伂'=>'pei','佩'=>'pei','俖'=>'pei','呸'=>'pei','培'=>'pei','姵'=>'pei','嶏'=>'pei','帔'=>'pei','怌'=>'pei','斾'=>'pei','旆'=>'pei','柸'=>'pei','毰'=>'pei','沛'=>'pei','浿'=>'pei','珮'=>'pei','笩'=>'pei','肧'=>'pei','胚'=>'pei','蓜'=>'pei','衃'=>'pei','裴'=>'pei','裵'=>'pei','賠'=>'pei','赔'=>'pei','轡'=>'pei','辔'=>'pei','配'=>'pei','醅'=>'pei','錇'=>'pei','锫'=>'pei','阫'=>'pei','陪'=>'pei','陫'=>'pei','霈'=>'pei','馷'=>'pei','㟝'=>'pei','㤄'=>'pei','㧩'=>'pei','㫲'=>'pei','㳈'=>'pei','䊃'=>'pei','䣙'=>'pei','䪹'=>'pei','䫠'=>'pei','䲹'=>'pei','伄'=>'diao','凋'=>'diao','刁'=>'diao','刟'=>'diao','叼'=>'diao','吊'=>'diao','奝'=>'diao','屌'=>'diao','弔'=>'diao','弴'=>'diao','彫'=>'diao','扚'=>'diao','掉'=>'diao','殦'=>'diao','汈'=>'diao','琱'=>'diao','瘹'=>'diao','瞗'=>'diao','碉'=>'diao','窎'=>'diao','窵'=>'diao','竨'=>'diao','簓'=>'diao','蓧'=>'diao','藋'=>'diao','虭'=>'diao','蛁'=>'diao','訋'=>'diao','調'=>'diao','调'=>'diao','貂'=>'diao','釣'=>'diao','鈟'=>'diao','銱'=>'diao','鋽'=>'diao','鑃'=>'diao','钓'=>'diao','铞'=>'diao','雕'=>'diao','雿'=>'diao','鮉'=>'diao','鯛'=>'diao','鲷'=>'diao','鳭'=>'diao','鵰'=>'diao','鼦'=>'diao','㒛'=>'diao','㪕'=>'diao','㹿'=>'diao','䂪'=>'diao','䂽'=>'diao','䉆'=>'diao','䔙'=>'diao','䠼'=>'diao','䵲'=>'diao','伅'=>'dun','吨'=>'dun','噸'=>'dun','囤'=>'dun','墩'=>'dun','墪'=>'dun','壿'=>'dun','庉'=>'dun','惇'=>'dun','憞'=>'dun','撉'=>'dun','撴'=>'dun','敦'=>'dun','橔'=>'dun','沌'=>'dun','潡'=>'dun','炖'=>'dun','燉'=>'dun','犜'=>'dun','獤'=>'dun','盹'=>'dun','盾'=>'dun','砘'=>'dun','碷'=>'dun','礅'=>'dun','腞'=>'dun','蜳'=>'dun','趸'=>'dun','踲'=>'dun','蹲'=>'dun','蹾'=>'dun','躉'=>'dun','逇'=>'dun','遁'=>'dun','遯'=>'dun','鈍'=>'dun','钝'=>'dun','頓'=>'dun','顿'=>'dun','驐'=>'dun','㬿'=>'dun','䤜'=>'dun','伈'=>'xin','伩'=>'xin','信'=>'xin','俽'=>'xin','噷'=>'xin','噺'=>'xin','囟'=>'xin','妡'=>'xin','嬜'=>'xin','孞'=>'xin','廞'=>'xin','心'=>'xin','忄'=>'xin','忻'=>'xin','惞'=>'xin','新'=>'xin','昕'=>'xin','杺'=>'xin','枔'=>'xin','欣'=>'xin','歆'=>'xin','潃'=>'xin','炘'=>'xin','焮'=>'xin','盺'=>'xin','脪'=>'xin','舋'=>'xin','芯'=>'xin','莘'=>'xin','薪'=>'xin','衅'=>'xin','訢'=>'xin','訫'=>'xin','軐'=>'xin','辛'=>'xin','邤'=>'xin','釁'=>'xin','鈊'=>'xin','鋅'=>'xin','鐔'=>'xin','鑫'=>'xin','锌'=>'xin','阠'=>'xin','顖'=>'xin','馨'=>'xin','馫'=>'xin','馸'=>'xin','鬵'=>'xin','㐰'=>'xin','㚯'=>'xin','㛛'=>'xin','㭄'=>'xin','䒖'=>'xin','䚱'=>'xin','䛨'=>'xin','䜗'=>'xin','䜣'=>'xin','䰼'=>'xin','伌'=>'ai','僾'=>'ai','凒'=>'ai','叆'=>'ai','哀'=>'ai','哎'=>'ai','唉'=>'ai','啀'=>'ai','嗌'=>'ai','嗳'=>'ai','嘊'=>'ai','噯'=>'ai','埃'=>'ai','塧'=>'ai','壒'=>'ai','娾'=>'ai','嫒'=>'ai','嬡'=>'ai','嵦'=>'ai','愛'=>'ai','懓'=>'ai','懝'=>'ai','挨'=>'ai','捱'=>'ai','敱'=>'ai','敳'=>'ai','昹'=>'ai','暧'=>'ai','曖'=>'ai','欸'=>'ai','毐'=>'ai','溰'=>'ai','溾'=>'ai','濭'=>'ai','爱'=>'ai','瑷'=>'ai','璦'=>'ai','癌'=>'ai','皑'=>'ai','皚'=>'ai','皧'=>'ai','瞹'=>'ai','矮'=>'ai','砹'=>'ai','硋'=>'ai','碍'=>'ai','礙'=>'ai','艾'=>'ai','蔼'=>'ai','薆'=>'ai','藹'=>'ai','譪'=>'ai','譺'=>'ai','賹'=>'ai','躷'=>'ai','鎄'=>'ai','鑀'=>'ai','锿'=>'ai','隘'=>'ai','霭'=>'ai','靄'=>'ai','靉'=>'ai','餲'=>'ai','馤'=>'ai','鱫'=>'ai','鴱'=>'ai','㑸'=>'ai','㕌'=>'ai','㗒'=>'ai','㗨'=>'ai','㘷'=>'ai','㝶'=>'ai','㢊'=>'ai','㤅'=>'ai','㱯'=>'ai','㿄'=>'ai','䀳'=>'ai','䅬'=>'ai','䑂'=>'ai','䔽'=>'ai','䝽'=>'ai','䠹'=>'ai','䨠'=>'ai','䬵'=>'ai','䶣'=>'ai','休'=>'xiu','俢'=>'xiu','修'=>'xiu','咻'=>'xiu','嗅'=>'xiu','岫'=>'xiu','庥'=>'xiu','朽'=>'xiu','樇'=>'xiu','溴'=>'xiu','滫'=>'xiu','烋'=>'xiu','烌'=>'xiu','珛'=>'xiu','琇'=>'xiu','璓'=>'xiu','秀'=>'xiu','糔'=>'xiu','綇'=>'xiu','綉'=>'xiu','繍'=>'xiu','繡'=>'xiu','绣'=>'xiu','羞'=>'xiu','脙'=>'xiu','脩'=>'xiu','臹'=>'xiu','苬'=>'xiu','螑'=>'xiu','袖'=>'xiu','裦'=>'xiu','褎'=>'xiu','褏'=>'xiu','貅'=>'xiu','銝'=>'xiu','銹'=>'xiu','鎀'=>'xiu','鏅'=>'xiu','鏥'=>'xiu','鏽'=>'xiu','锈'=>'xiu','飍'=>'xiu','饈'=>'xiu','馐'=>'xiu','髤'=>'xiu','髹'=>'xiu','鮴'=>'xiu','鵂'=>'xiu','鸺'=>'xiu','齅'=>'xiu','㗜'=>'xiu','㱙'=>'xiu','㾋'=>'xiu','伖'=>'nu','伮'=>'nu','傉'=>'nu','努'=>'nu','奴'=>'nu','孥'=>'nu','弩'=>'nu','怒'=>'nu','搙'=>'nu','砮'=>'nu','笯'=>'nu','胬'=>'nu','駑'=>'nu','驽'=>'nu','㚢'=>'nu','䢞'=>'nu','伙'=>'huo','佸'=>'huo','俰'=>'huo','剨'=>'huo','劐'=>'huo','吙'=>'huo','咟'=>'huo','嗀'=>'huo','嚄'=>'huo','嚯'=>'huo','嚿'=>'huo','夥'=>'huo','夻'=>'huo','奯'=>'huo','惑'=>'huo','或'=>'huo','捇'=>'huo','掝'=>'huo','擭'=>'huo','攉'=>'huo','旤'=>'huo','曤'=>'huo','檴'=>'huo','沎'=>'huo','活'=>'huo','湱'=>'huo','漷'=>'huo','濩'=>'huo','瀖'=>'huo','火'=>'huo','獲'=>'huo','癨'=>'huo','眓'=>'huo','矆'=>'huo','矐'=>'huo','祸'=>'huo','禍'=>'huo','秮'=>'huo','秳'=>'huo','穫'=>'huo','耠'=>'huo','耯'=>'huo','臛'=>'huo','艧'=>'huo','获'=>'huo','蒦'=>'huo','藿'=>'huo','蠖'=>'huo','謋'=>'huo','豁'=>'huo','貨'=>'huo','货'=>'huo','邩'=>'huo','鈥'=>'huo','鍃'=>'huo','鑊'=>'huo','钬'=>'huo','锪'=>'huo','镬'=>'huo','閄'=>'huo','雘'=>'huo','霍'=>'huo','靃'=>'huo','騞'=>'huo','㗲'=>'huo','㘞'=>'huo','㦜'=>'huo','㦯'=>'huo','㨯'=>'huo','㯉'=>'huo','㸌'=>'huo','䁨'=>'huo','䂄'=>'huo','䄀'=>'huo','䄆'=>'huo','䄑'=>'huo','䉟'=>'huo','䋭'=>'huo','䣶'=>'huo','䦚'=>'huo','䯏'=>'huo','䰥'=>'huo','会'=>'hui','佪'=>'hui','僡'=>'hui','儶'=>'hui','匯'=>'hui','卉'=>'hui','咴'=>'hui','哕'=>'hui','喙'=>'hui','嘒'=>'hui','噅'=>'hui','噕'=>'hui','噦'=>'hui','嚖'=>'hui','囘'=>'hui','回'=>'hui','囬'=>'hui','圚'=>'hui','婎'=>'hui','媈'=>'hui','孈'=>'hui','寭'=>'hui','屷'=>'hui','幑'=>'hui','廻'=>'hui','廽'=>'hui','彗'=>'hui','彙'=>'hui','彚'=>'hui','徻'=>'hui','徽'=>'hui','恚'=>'hui','恛'=>'hui','恢'=>'hui','恵'=>'hui','悔'=>'hui','惠'=>'hui','慧'=>'hui','憓'=>'hui','懳'=>'hui','拻'=>'hui','挥'=>'hui','揮'=>'hui','撝'=>'hui','晖'=>'hui','晦'=>'hui','暉'=>'hui','暳'=>'hui','會'=>'hui','桧'=>'hui','楎'=>'hui','槥'=>'hui','橞'=>'hui','檅'=>'hui','檓'=>'hui','檜'=>'hui','櫘'=>'hui','毀'=>'hui','毁'=>'hui','毇'=>'hui','汇'=>'hui','泋'=>'hui','洃'=>'hui','洄'=>'hui','浍'=>'hui','湏'=>'hui','滙'=>'hui','潓'=>'hui','澮'=>'hui','瀈'=>'hui','灰'=>'hui','灳'=>'hui','烠'=>'hui','烣'=>'hui','烩'=>'hui','烪'=>'hui','煇'=>'hui','燬'=>'hui','燴'=>'hui','獩'=>'hui','珲'=>'hui','琿'=>'hui','璤'=>'hui','璯'=>'hui','痐'=>'hui','瘣'=>'hui','睳'=>'hui','瞺'=>'hui','禈'=>'hui','秽'=>'hui','穢'=>'hui','篲'=>'hui','絵'=>'hui','繢'=>'hui','繪'=>'hui','绘'=>'hui','缋'=>'hui','翙'=>'hui','翚'=>'hui','翬'=>'hui','翽'=>'hui','芔'=>'hui','茴'=>'hui','荟'=>'hui','蔧'=>'hui','蕙'=>'hui','薈'=>'hui','薉'=>'hui','藱'=>'hui','虺'=>'hui','蚘'=>'hui','蛔'=>'hui','蛕'=>'hui','蜖'=>'hui','螝'=>'hui','蟪'=>'hui','袆'=>'hui','褘'=>'hui','詯'=>'hui','詼'=>'hui','誨'=>'hui','諱'=>'hui','譓'=>'hui','譭'=>'hui','譮'=>'hui','譿'=>'hui','讳'=>'hui','诙'=>'hui','诲'=>'hui','豗'=>'hui','賄'=>'hui','贿'=>'hui','輝'=>'hui','辉'=>'hui','迴'=>'hui','逥'=>'hui','鏸'=>'hui','鐬'=>'hui','闠'=>'hui','阓'=>'hui','隓'=>'hui','隳'=>'hui','靧'=>'hui','韢'=>'hui','頮'=>'hui','顪'=>'hui','餯'=>'hui','鮰'=>'hui','鰴'=>'hui','麾'=>'hui','㑰'=>'hui','㑹'=>'hui','㒑'=>'hui','㜇'=>'hui','㞧'=>'hui','㤬'=>'hui','㥣'=>'hui','㨤'=>'hui','㨹'=>'hui','㩓'=>'hui','㩨'=>'hui','㬩'=>'hui','㰥'=>'hui','㱱'=>'hui','㷄'=>'hui','㷐'=>'hui','㻅'=>'hui','䂕'=>'hui','䃣'=>'hui','䅏'=>'hui','䇻'=>'hui','䌇'=>'hui','䏨'=>'hui','䕇'=>'hui','䙌'=>'hui','䙡'=>'hui','䛛'=>'hui','䛼'=>'hui','䜋'=>'hui','䤧'=>'hui','䧥'=>'hui','䩈'=>'hui','䫭'=>'hui','伡'=>'che','俥'=>'che','偖'=>'che','勶'=>'che','唓'=>'che','坼'=>'che','奲'=>'che','屮'=>'che','彻'=>'che','徹'=>'che','扯'=>'che','掣'=>'che','撤'=>'che','撦'=>'che','澈'=>'che','烢'=>'che','烲'=>'che','爡'=>'che','瞮'=>'che','砗'=>'che','硨'=>'che','硩'=>'che','聅'=>'che','莗'=>'che','蛼'=>'che','車'=>'che','车'=>'che','迠'=>'che','頙'=>'che','㔭'=>'che','㥉'=>'che','㨋'=>'che','㬚'=>'che','㯙'=>'che','㱌'=>'che','㵃'=>'che','㵔'=>'che','㾝'=>'che','㿭'=>'che','䁤'=>'che','䋲'=>'che','䑲'=>'che','䒆'=>'che','䚢'=>'che','䛸'=>'che','䜠'=>'che','䞣'=>'che','䧪'=>'che','䨁'=>'che','䰩'=>'che','伨'=>'xun','侚'=>'xun','偱'=>'xun','勋'=>'xun','勛'=>'xun','勲'=>'xun','勳'=>'xun','卂'=>'xun','噀'=>'xun','噚'=>'xun','嚑'=>'xun','坃'=>'xun','埙'=>'xun','塤'=>'xun','壎'=>'xun','壦'=>'xun','奞'=>'xun','寻'=>'xun','尋'=>'xun','峋'=>'xun','巡'=>'xun','巽'=>'xun','廵'=>'xun','徇'=>'xun','循'=>'xun','恂'=>'xun','愻'=>'xun','揗'=>'xun','攳'=>'xun','旬'=>'xun','曛'=>'xun','杊'=>'xun','栒'=>'xun','桪'=>'xun','樳'=>'xun','殉'=>'xun','殾'=>'xun','毥'=>'xun','汛'=>'xun','洵'=>'xun','浔'=>'xun','潯'=>'xun','灥'=>'xun','焄'=>'xun','熏'=>'xun','燂'=>'xun','燅'=>'xun','燖'=>'xun','燻'=>'xun','爋'=>'xun','狥'=>'xun','獯'=>'xun','珣'=>'xun','璕'=>'xun','矄'=>'xun','窨'=>'xun','紃'=>'xun','纁'=>'xun','臐'=>'xun','荀'=>'xun','蔒'=>'xun','蕈'=>'xun','薫'=>'xun','薰'=>'xun','蘍'=>'xun','蟳'=>'xun','襑'=>'xun','訊'=>'xun','訓'=>'xun','訙'=>'xun','詢'=>'xun','训'=>'xun','讯'=>'xun','询'=>'xun','賐'=>'xun','迅'=>'xun','迿'=>'xun','逊'=>'xun','遜'=>'xun','鄩'=>'xun','醺'=>'xun','鑂'=>'xun','顨'=>'xun','馴'=>'xun','駨'=>'xun','驯'=>'xun','鱏'=>'xun','鱘'=>'xun','鲟'=>'xun','㜄'=>'xun','㝁'=>'xun','㢲'=>'xun','㨚'=>'xun','㰊'=>'xun','㰬'=>'xun','㽦'=>'xun','䋸'=>'xun','䑕'=>'xun','䖲'=>'xun','䙉'=>'xun','䛜'=>'xun','䞊'=>'xun','䭀'=>'xun','估'=>'gu','傦'=>'gu','僱'=>'gu','凅'=>'gu','古'=>'gu','咕'=>'gu','唂'=>'gu','唃'=>'gu','啒'=>'gu','嘏'=>'gu','固'=>'gu','堌'=>'gu','夃'=>'gu','姑'=>'gu','嫴'=>'gu','孤'=>'gu','尳'=>'gu','峠'=>'gu','崓'=>'gu','崮'=>'gu','怘'=>'gu','愲'=>'gu','扢'=>'gu','故'=>'gu','柧'=>'gu','梏'=>'gu','棝'=>'gu','榖'=>'gu','榾'=>'gu','橭'=>'gu','毂'=>'gu','汩'=>'gu','沽'=>'gu','泒'=>'gu','淈'=>'gu','濲'=>'gu','瀔'=>'gu','焸'=>'gu','牯'=>'gu','牿'=>'gu','痼'=>'gu','皷'=>'gu','盬'=>'gu','瞽'=>'gu','硲'=>'gu','祻'=>'gu','稒'=>'gu','穀'=>'gu','笟'=>'gu','箍'=>'gu','箛'=>'gu','篐'=>'gu','糓'=>'gu','縎'=>'gu','罛'=>'gu','罟'=>'gu','羖'=>'gu','股'=>'gu','脵'=>'gu','臌'=>'gu','菇'=>'gu','菰'=>'gu','蓇'=>'gu','薣'=>'gu','蛄'=>'gu','蛊'=>'gu','蛌'=>'gu','蠱'=>'gu','觚'=>'gu','詁'=>'gu','诂'=>'gu','谷'=>'gu','軱'=>'gu','軲'=>'gu','轂'=>'gu','轱'=>'gu','辜'=>'gu','逧'=>'gu','酤'=>'gu','鈲'=>'gu','鈷'=>'gu','錮'=>'gu','钴'=>'gu','锢'=>'gu','雇'=>'gu','頋'=>'gu','顧'=>'gu','顾'=>'gu','餶'=>'gu','馉'=>'gu','骨'=>'gu','鮕'=>'gu','鯝'=>'gu','鲴'=>'gu','鴣'=>'gu','鵠'=>'gu','鶻'=>'gu','鸪'=>'gu','鹄'=>'gu','鹘'=>'gu','鼓'=>'gu','鼔'=>'gu','㒴'=>'gu','㚉'=>'gu','㧽'=>'gu','㯏'=>'gu','㼋'=>'gu','㽽'=>'gu','㾶'=>'gu','䀇'=>'gu','䀜'=>'gu','䀦'=>'gu','䀰'=>'gu','䅽'=>'gu','䊺'=>'gu','䍍'=>'gu','䍛'=>'gu','䐨'=>'gu','䓢'=>'gu','䜼'=>'gu','䡩'=>'gu','䮩'=>'gu','䵻'=>'gu','䶜'=>'gu','伱'=>'ni','伲'=>'ni','你'=>'ni','倪'=>'ni','儗'=>'ni','儞'=>'ni','匿'=>'ni','坭'=>'ni','埿'=>'ni','堄'=>'ni','妮'=>'ni','婗'=>'ni','嫟'=>'ni','嬺'=>'ni','孴'=>'ni','尼'=>'ni','屔'=>'ni','屰'=>'ni','怩'=>'ni','惄'=>'ni','愵'=>'ni','抳'=>'ni','拟'=>'ni','掜'=>'ni','擬'=>'ni','旎'=>'ni','昵'=>'ni','晲'=>'ni','暱'=>'ni','柅'=>'ni','棿'=>'ni','檷'=>'ni','氼'=>'ni','泥'=>'ni','淣'=>'ni','溺'=>'ni','狔'=>'ni','猊'=>'ni','痆'=>'ni','眤'=>'ni','睨'=>'ni','秜'=>'ni','籾'=>'ni','縌'=>'ni','胒'=>'ni','腻'=>'ni','膩'=>'ni','臡'=>'ni','苨'=>'ni','薿'=>'ni','蚭'=>'ni','蜺'=>'ni','觬'=>'ni','貎'=>'ni','跜'=>'ni','輗'=>'ni','迡'=>'ni','逆'=>'ni','郳'=>'ni','鈮'=>'ni','鉨'=>'ni','鑈'=>'ni','铌'=>'ni','隬'=>'ni','霓'=>'ni','馜'=>'ni','鯢'=>'ni','鲵'=>'ni','麑'=>'ni','齯'=>'ni','㞾'=>'ni','㠜'=>'ni','㣇'=>'ni','㥾'=>'ni','㦐'=>'ni','㪒'=>'ni','㲻'=>'ni','㵫'=>'ni','㹸'=>'ni','䁥'=>'ni','䕥'=>'ni','䘌'=>'ni','䘦'=>'ni','䘽'=>'ni','䛏'=>'ni','䝚'=>'ni','䦵'=>'ni','䧇'=>'ni','䭲'=>'ni','䰯'=>'ni','䵑'=>'ni','䵒'=>'ni','伴'=>'ban','办'=>'ban','半'=>'ban','坂'=>'ban','姅'=>'ban','岅'=>'ban','怑'=>'ban','扮'=>'ban','扳'=>'ban','拌'=>'ban','搬'=>'ban','攽'=>'ban','斑'=>'ban','斒'=>'ban','昄'=>'ban','朌'=>'ban','板'=>'ban','湴'=>'ban','版'=>'ban','班'=>'ban','瓣'=>'ban','瓪'=>'ban','瘢'=>'ban','癍'=>'ban','秚'=>'ban','粄'=>'ban','絆'=>'ban','绊'=>'ban','舨'=>'ban','般'=>'ban','蝂'=>'ban','螁'=>'ban','螌'=>'ban','褩'=>'ban','辦'=>'ban','辬'=>'ban','鈑'=>'ban','鉡'=>'ban','钣'=>'ban','闆'=>'ban','阪'=>'ban','靽'=>'ban','頒'=>'ban','颁'=>'ban','魬'=>'ban','㚘'=>'ban','㩯'=>'ban','㪵'=>'ban','㸞'=>'ban','㺜'=>'ban','䉽'=>'ban','䕰'=>'ban','䬳'=>'ban','伵'=>'xu','侐'=>'xu','俆'=>'xu','偦'=>'xu','冔'=>'xu','勖'=>'xu','勗'=>'xu','卹'=>'xu','叙'=>'xu','呴'=>'xu','喣'=>'xu','嘘'=>'xu','噓'=>'xu','垿'=>'xu','墟'=>'xu','壻'=>'xu','姁'=>'xu','婿'=>'xu','媭'=>'xu','嬃'=>'xu','幁'=>'xu','序'=>'xu','徐'=>'xu','恤'=>'xu','慉'=>'xu','戌'=>'xu','揟'=>'xu','敍'=>'xu','敘'=>'xu','旭'=>'xu','旴'=>'xu','昫'=>'xu','暊'=>'xu','朂'=>'xu','栩'=>'xu','楈'=>'xu','槒'=>'xu','欨'=>'xu','欰'=>'xu','欻'=>'xu','歔'=>'xu','歘'=>'xu','殈'=>'xu','汿'=>'xu','沀'=>'xu','洫'=>'xu','湑'=>'xu','溆'=>'xu','漵'=>'xu','潊'=>'xu','烅'=>'xu','烼'=>'xu','煦'=>'xu','獝'=>'xu','珝'=>'xu','珬'=>'xu','畜'=>'xu','疞'=>'xu','盢'=>'xu','盨'=>'xu','盱'=>'xu','瞁'=>'xu','瞲'=>'xu','砉'=>'xu','稰'=>'xu','稸'=>'xu','窢'=>'xu','糈'=>'xu','絮'=>'xu','続'=>'xu','緒'=>'xu','緖'=>'xu','縃'=>'xu','續'=>'xu','绪'=>'xu','续'=>'xu','聟'=>'xu','胥'=>'xu','蒣'=>'xu','蓄'=>'xu','蓿'=>'xu','蕦'=>'xu','藇'=>'xu','藚'=>'xu','虗'=>'xu','虚'=>'xu','虛'=>'xu','蝑'=>'xu','訏'=>'xu','許'=>'xu','訹'=>'xu','詡'=>'xu','諝'=>'xu','譃'=>'xu','许'=>'xu','诩'=>'xu','谞'=>'xu','賉'=>'xu','鄦'=>'xu','酗'=>'xu','醑'=>'xu','銊'=>'xu','鑐'=>'xu','需'=>'xu','須'=>'xu','頊'=>'xu','须'=>'xu','顼'=>'xu','驉'=>'xu','鬚'=>'xu','魆'=>'xu','魖'=>'xu','鱮'=>'xu','㐨'=>'xu','㑔'=>'xu','㑯'=>'xu','㕛'=>'xu','㖅'=>'xu','㗵'=>'xu','㘧'=>'xu','㚜'=>'xu','㜅'=>'xu','㜿'=>'xu','㞊'=>'xu','㞰'=>'xu','㤢'=>'xu','㥠'=>'xu','㦽'=>'xu','㰲'=>'xu','㵰'=>'xu','㷦'=>'xu','㺷'=>'xu','㾥'=>'xu','䂆'=>'xu','䅡'=>'xu','䋶'=>'xu','䍱'=>'xu','䔓'=>'xu','䘏'=>'xu','䙒'=>'xu','䛙'=>'xu','䜡'=>'xu','䢕'=>'xu','䣱'=>'xu','䣴'=>'xu','䦗'=>'xu','䦽'=>'xu','䬔'=>'xu','䱛'=>'xu','䳳'=>'xu','伷'=>'zhou','侜'=>'zhou','僽'=>'zhou','冑'=>'zhou','周'=>'zhou','呪'=>'zhou','咒'=>'zhou','咮'=>'zhou','喌'=>'zhou','噣'=>'zhou','嚋'=>'zhou','妯'=>'zhou','婤'=>'zhou','宙'=>'zhou','州'=>'zhou','帚'=>'zhou','徟'=>'zhou','昼'=>'zhou','晝'=>'zhou','晭'=>'zhou','洀'=>'zhou','洲'=>'zhou','淍'=>'zhou','炿'=>'zhou','烐'=>'zhou','珘'=>'zhou','甃'=>'zhou','疛'=>'zhou','皱'=>'zhou','皺'=>'zhou','盩'=>'zhou','睭'=>'zhou','矪'=>'zhou','碡'=>'zhou','箒'=>'zhou','籀'=>'zhou','籒'=>'zhou','籕'=>'zhou','粙'=>'zhou','粥'=>'zhou','紂'=>'zhou','縐'=>'zhou','纣'=>'zhou','绉'=>'zhou','肘'=>'zhou','胄'=>'zhou','舟'=>'zhou','荮'=>'zhou','菷'=>'zhou','葤'=>'zhou','詋'=>'zhou','謅'=>'zhou','譸'=>'zhou','诌'=>'zhou','诪'=>'zhou','賙'=>'zhou','赒'=>'zhou','軸'=>'zhou','輈'=>'zhou','輖'=>'zhou','轴'=>'zhou','辀'=>'zhou','週'=>'zhou','郮'=>'zhou','酎'=>'zhou','銂'=>'zhou','霌'=>'zhou','駎'=>'zhou','駲'=>'zhou','騆'=>'zhou','驟'=>'zhou','骤'=>'zhou','鯞'=>'zhou','鵃'=>'zhou','鸼'=>'zhou','㑇'=>'zhou','㑳'=>'zhou','㔌'=>'zhou','㛩'=>'zhou','㥮'=>'zhou','㼙'=>'zhou','㾭'=>'zhou','䇠'=>'zhou','䈙'=>'zhou','䋓'=>'zhou','䎻'=>'zhou','䏲'=>'zhou','䐍'=>'zhou','䖞'=>'zhou','䛆'=>'zhou','䩜'=>'zhou','䶇'=>'zhou','伸'=>'shen','侁'=>'shen','侺'=>'shen','兟'=>'shen','呻'=>'shen','哂'=>'shen','堔'=>'shen','妽'=>'shen','姺'=>'shen','娠'=>'shen','婶'=>'shen','嬸'=>'shen','审'=>'shen','宷'=>'shen','審'=>'shen','屾'=>'shen','峷'=>'shen','弞'=>'shen','愼'=>'shen','慎'=>'shen','扟'=>'shen','抌'=>'shen','昚'=>'shen','曋'=>'shen','柛'=>'shen','椮'=>'shen','椹'=>'shen','榊'=>'shen','氠'=>'shen','沈'=>'shen','涁'=>'shen','深'=>'shen','渖'=>'shen','渗'=>'shen','滲'=>'shen','瀋'=>'shen','燊'=>'shen','珅'=>'shen','甚'=>'shen','甡'=>'shen','甧'=>'shen','申'=>'shen','瘆'=>'shen','瘮'=>'shen','眒'=>'shen','眘'=>'shen','瞫'=>'shen','矤'=>'shen','矧'=>'shen','砷'=>'shen','神'=>'shen','祳'=>'shen','穼'=>'shen','籶'=>'shen','籸'=>'shen','紳'=>'shen','绅'=>'shen','罙'=>'shen','罧'=>'shen','肾'=>'shen','胂'=>'shen','脤'=>'shen','腎'=>'shen','葠'=>'shen','蓡'=>'shen','蔘'=>'shen','薓'=>'shen','蜃'=>'shen','裑'=>'shen','覾'=>'shen','訠'=>'shen','訷'=>'shen','詵'=>'shen','諗'=>'shen','讅'=>'shen','诜'=>'shen','谂'=>'shen','谉'=>'shen','身'=>'shen','邥'=>'shen','鉮'=>'shen','鋠'=>'shen','頣'=>'shen','駪'=>'shen','魫'=>'shen','鯓'=>'shen','鯵'=>'shen','鰰'=>'shen','鰺'=>'shen','鲹'=>'shen','鵢'=>'shen','㔤'=>'shen','㜤'=>'shen','㥲'=>'shen','㰂'=>'shen','㰮'=>'shen','㵊'=>'shen','㵕'=>'shen','㾕'=>'shen','䆦'=>'shen','䰠'=>'shen','伹'=>'qu','佉'=>'qu','佢'=>'qu','刞'=>'qu','劬'=>'qu','匤'=>'qu','匷'=>'qu','区'=>'qu','區'=>'qu','厺'=>'qu','去'=>'qu','取'=>'qu','呿'=>'qu','坥'=>'qu','娶'=>'qu','屈'=>'qu','岖'=>'qu','岨'=>'qu','岴'=>'qu','嶇'=>'qu','忂'=>'qu','憈'=>'qu','戵'=>'qu','抾'=>'qu','敺'=>'qu','斪'=>'qu','曲'=>'qu','朐'=>'qu','朑'=>'qu','欋'=>'qu','氍'=>'qu','浀'=>'qu','淭'=>'qu','渠'=>'qu','灈'=>'qu','璖'=>'qu','璩'=>'qu','癯'=>'qu','磲'=>'qu','祛'=>'qu','竘'=>'qu','竬'=>'qu','筁'=>'qu','籧'=>'qu','粬'=>'qu','紶'=>'qu','絇'=>'qu','翑'=>'qu','翵'=>'qu','耝'=>'qu','胊'=>'qu','胠'=>'qu','臞'=>'qu','菃'=>'qu','葋'=>'qu','蕖'=>'qu','蘧'=>'qu','蛆'=>'qu','蛐'=>'qu','蝺'=>'qu','螶'=>'qu','蟝'=>'qu','蠷'=>'qu','蠼'=>'qu','衐'=>'qu','衢'=>'qu','袪'=>'qu','覰'=>'qu','覷'=>'qu','覻'=>'qu','觑'=>'qu','詓'=>'qu','詘'=>'qu','誳'=>'qu','诎'=>'qu','趋'=>'qu','趣'=>'qu','趨'=>'qu','躣'=>'qu','躯'=>'qu','軀'=>'qu','軥'=>'qu','迲'=>'qu','郥'=>'qu','鑺'=>'qu','閴'=>'qu','闃'=>'qu','阒'=>'qu','阹'=>'qu','駆'=>'qu','駈'=>'qu','驅'=>'qu','驱'=>'qu','髷'=>'qu','魼'=>'qu','鰸'=>'qu','鱋'=>'qu','鴝'=>'qu','鸜'=>'qu','鸲'=>'qu','麮'=>'qu','麯'=>'qu','麴'=>'qu','麹'=>'qu','黢'=>'qu','鼁'=>'qu','鼩'=>'qu','齲'=>'qu','龋'=>'qu','㖆'=>'qu','㜹'=>'qu','㠊'=>'qu','㣄'=>'qu','㧁'=>'qu','㫢'=>'qu','㯫'=>'qu','㰦'=>'qu','㲘'=>'qu','䀠'=>'qu','䁦'=>'qu','䂂'=>'qu','䋧'=>'qu','䒧'=>'qu','䝣'=>'qu','䞤'=>'qu','䟊'=>'qu','䠐'=>'qu','䵶'=>'qu','䶚'=>'qu','伻'=>'beng','嘣'=>'beng','埄'=>'beng','埲'=>'beng','塴'=>'beng','奟'=>'beng','崩'=>'beng','嵭'=>'beng','泵'=>'beng','琣'=>'beng','琫'=>'beng','甏'=>'beng','甭'=>'beng','痭'=>'beng','祊'=>'beng','絣'=>'beng','綳'=>'beng','繃'=>'beng','绷'=>'beng','菶'=>'beng','跰'=>'beng','蹦'=>'beng','迸'=>'beng','逬'=>'beng','鏰'=>'beng','镚'=>'beng','閍'=>'beng','鞛'=>'beng','㑟'=>'beng','㱶'=>'beng','㷯'=>'beng','䋽'=>'beng','䙀'=>'beng','䨻'=>'beng','䩬'=>'beng','䭰'=>'beng','䳞'=>'beng','伽'=>'ga','嘎'=>'ga','嘠'=>'ga','噶'=>'ga','尕'=>'ga','尜'=>'ga','尬'=>'ga','旮'=>'ga','玍'=>'ga','釓'=>'ga','錷'=>'ga','钆'=>'ga','魀'=>'ga','佃'=>'dian','傎'=>'dian','典'=>'dian','厧'=>'dian','唸'=>'dian','坫'=>'dian','垫'=>'dian','墊'=>'dian','壂'=>'dian','奌'=>'dian','奠'=>'dian','婝'=>'dian','婰'=>'dian','嵮'=>'dian','巅'=>'dian','巓'=>'dian','巔'=>'dian','店'=>'dian','惦'=>'dian','扂'=>'dian','掂'=>'dian','攧'=>'dian','敁'=>'dian','敟'=>'dian','椣'=>'dian','槙'=>'dian','橂'=>'dian','殿'=>'dian','淀'=>'dian','滇'=>'dian','澱'=>'dian','点'=>'dian','玷'=>'dian','琔'=>'dian','电'=>'dian','甸'=>'dian','瘨'=>'dian','癜'=>'dian','癫'=>'dian','癲'=>'dian','碘'=>'dian','磹'=>'dian','簟'=>'dian','蒧'=>'dian','蕇'=>'dian','蜔'=>'dian','踮'=>'dian','蹎'=>'dian','鈿'=>'dian','钿'=>'dian','阽'=>'dian','電'=>'dian','靛'=>'dian','顚'=>'dian','顛'=>'dian','颠'=>'dian','驔'=>'dian','點'=>'dian','齻'=>'dian','㓠'=>'dian','㚲'=>'dian','㝪'=>'dian','㞟'=>'dian','㥆'=>'dian','㵤'=>'dian','㶘'=>'dian','㸃'=>'dian','㼭'=>'dian','䍄'=>'dian','䓦'=>'dian','䟍'=>'dian','䧃'=>'dian','佄'=>'han','傼'=>'han','兯'=>'han','函'=>'han','凾'=>'han','厈'=>'han','含'=>'han','咁'=>'han','哻'=>'han','唅'=>'han','喊'=>'han','圅'=>'han','垾'=>'han','娢'=>'han','嫨'=>'han','寒'=>'han','屽'=>'han','崡'=>'han','嵅'=>'han','悍'=>'han','憨'=>'han','憾'=>'han','扞'=>'han','捍'=>'han','撖'=>'han','撼'=>'han','旱'=>'han','晗'=>'han','晘'=>'han','晥'=>'han','暵'=>'han','梒'=>'han','汉'=>'han','汗'=>'han','浛'=>'han','浫'=>'han','涆'=>'han','涵'=>'han','淊'=>'han','漢'=>'han','澏'=>'han','瀚'=>'han','焊'=>'han','焓'=>'han','熯'=>'han','爳'=>'han','猂'=>'han','琀'=>'han','甝'=>'han','皔'=>'han','睅'=>'han','筨'=>'han','罕'=>'han','翰'=>'han','肣'=>'han','莟'=>'han','菡'=>'han','蔊'=>'han','蘫'=>'han','虷'=>'han','蚶'=>'han','蛿'=>'han','蜬'=>'han','蜭'=>'han','螒'=>'han','譀'=>'han','谽'=>'han','豃'=>'han','邗'=>'han','邯'=>'han','酣'=>'han','釬'=>'han','銲'=>'han','鋎'=>'han','鋡'=>'han','閈'=>'han','闬'=>'han','雗'=>'han','韓'=>'han','韩'=>'han','頇'=>'han','頷'=>'han','顄'=>'han','顸'=>'han','颔'=>'han','馠'=>'han','馯'=>'han','駻'=>'han','鬫'=>'han','魽'=>'han','鶾'=>'han','鼾'=>'han','㑵'=>'han','㒈'=>'han','㖤'=>'han','㘎'=>'han','㘕'=>'han','㘚'=>'han','㙈'=>'han','㙔'=>'han','㙳'=>'han','㜦'=>'han','㟏'=>'han','㟔'=>'han','㢨'=>'han','㨔'=>'han','㪋'=>'han','㮀'=>'han','㲦'=>'han','㵄'=>'han','㵎'=>'han','㶰'=>'han','㸁'=>'han','㺖'=>'han','㼨'=>'han','㽉'=>'han','㽳'=>'han','䁔'=>'han','䈄'=>'han','䌍'=>'han','䍐'=>'han','䍑'=>'han','䎯'=>'han','䏷'=>'han','䐄'=>'han','䓍'=>'han','䓿'=>'han','䕿'=>'han','䖔'=>'han','䗙'=>'han','䘶'=>'han','䛞'=>'han','䤴'=>'han','䥁'=>'han','䧲'=>'han','䨡'=>'han','䫲'=>'han','䮧'=>'han','䶃'=>'han','佊'=>'bi','佖'=>'bi','俾'=>'bi','偪'=>'bi','匂'=>'bi','匕'=>'bi','吡'=>'bi','哔'=>'bi','啚'=>'bi','嗶'=>'bi','坒'=>'bi','堛'=>'bi','壁'=>'bi','夶'=>'bi','奰'=>'bi','妣'=>'bi','妼'=>'bi','婢'=>'bi','嬖'=>'bi','嬶'=>'bi','屄'=>'bi','币'=>'bi','幣'=>'bi','幤'=>'bi','庇'=>'bi','庳'=>'bi','廦'=>'bi','弊'=>'bi','弻'=>'bi','弼'=>'bi','彃'=>'bi','彼'=>'bi','必'=>'bi','怭'=>'bi','愊'=>'bi','愎'=>'bi','敝'=>'bi','斃'=>'bi','朼'=>'bi','枈'=>'bi','柀'=>'bi','柲'=>'bi','梐'=>'bi','楅'=>'bi','比'=>'bi','毕'=>'bi','毖'=>'bi','毙'=>'bi','毴'=>'bi','沘'=>'bi','湢'=>'bi','滗'=>'bi','滭'=>'bi','潷'=>'bi','濞'=>'bi','煏'=>'bi','熚'=>'bi','狴'=>'bi','獘'=>'bi','獙'=>'bi','珌'=>'bi','璧'=>'bi','畀'=>'bi','畁'=>'bi','畢'=>'bi','疕'=>'bi','疪'=>'bi','痹'=>'bi','痺'=>'bi','皀'=>'bi','皕'=>'bi','碧'=>'bi','禆'=>'bi','秕'=>'bi','稫'=>'bi','笔'=>'bi','筆'=>'bi','筚'=>'bi','箅'=>'bi','箆'=>'bi','篦'=>'bi','篳'=>'bi','粃'=>'bi','粊'=>'bi','綼'=>'bi','縪'=>'bi','繴'=>'bi','罼'=>'bi','聛'=>'bi','胇'=>'bi','腷'=>'bi','臂'=>'bi','舭'=>'bi','苾'=>'bi','荜'=>'bi','荸'=>'bi','萆'=>'bi','萞'=>'bi','蓖'=>'bi','蓽'=>'bi','蔽'=>'bi','薜'=>'bi','蜌'=>'bi','螕'=>'bi','袐'=>'bi','裨'=>'bi','襅'=>'bi','襞'=>'bi','襣'=>'bi','觱'=>'bi','詖'=>'bi','诐'=>'bi','豍'=>'bi','貏'=>'bi','貱'=>'bi','贔'=>'bi','赑'=>'bi','跸'=>'bi','蹕'=>'bi','躃'=>'bi','躄'=>'bi','辟'=>'bi','逼'=>'bi','避'=>'bi','邲'=>'bi','鄙'=>'bi','鄨'=>'bi','鄪'=>'bi','鉍'=>'bi','鎞'=>'bi','鏎'=>'bi','鐴'=>'bi','铋'=>'bi','閇'=>'bi','閉'=>'bi','閟'=>'bi','闭'=>'bi','陛'=>'bi','鞞'=>'bi','鞸'=>'bi','韠'=>'bi','飶'=>'bi','饆'=>'bi','馝'=>'bi','駜'=>'bi','驆'=>'bi','髀'=>'bi','髲'=>'bi','魓'=>'bi','鮅'=>'bi','鰏'=>'bi','鲾'=>'bi','鵖'=>'bi','鷝'=>'bi','鷩'=>'bi','鼊'=>'bi','鼻'=>'bi','㓖'=>'bi','㗉'=>'bi','㘠'=>'bi','㘩'=>'bi','㙄'=>'bi','㚰'=>'bi','㠲'=>'bi','㡀'=>'bi','㡙'=>'bi','㢰'=>'bi','㢶'=>'bi','㢸'=>'bi','㧙'=>'bi','㪏'=>'bi','㪤'=>'bi','㮰'=>'bi','㮿'=>'bi','㯇'=>'bi','㱸'=>'bi','㳼'=>'bi','㵥'=>'bi','㵨'=>'bi','㹃'=>'bi','㻫'=>'bi','㻶'=>'bi','㿫'=>'bi','䀣'=>'bi','䁹'=>'bi','䃾'=>'bi','䄶'=>'bi','䇷'=>'bi','䊧'=>'bi','䋔'=>'bi','䌟'=>'bi','䎵'=>'bi','䏢'=>'bi','䏶'=>'bi','䕗'=>'bi','䖩'=>'bi','䘡'=>'bi','䟆'=>'bi','䟤'=>'bi','䠋'=>'bi','䣥'=>'bi','䦘'=>'bi','䧗'=>'bi','䨆'=>'bi','䩛'=>'bi','䪐'=>'bi','䫁'=>'bi','䫾'=>'bi','䭮'=>'bi','䮡'=>'bi','䯗'=>'bi','䵄'=>'bi','佋'=>'zhao','兆'=>'zhao','召'=>'zhao','啁'=>'zhao','垗'=>'zhao','妱'=>'zhao','巶'=>'zhao','找'=>'zhao','招'=>'zhao','旐'=>'zhao','昭'=>'zhao','曌'=>'zhao','枛'=>'zhao','棹'=>'zhao','櫂'=>'zhao','沼'=>'zhao','炤'=>'zhao','照'=>'zhao','燳'=>'zhao','爫'=>'zhao','狣'=>'zhao','瑵'=>'zhao','盄'=>'zhao','瞾'=>'zhao','窼'=>'zhao','笊'=>'zhao','箌'=>'zhao','罀'=>'zhao','罩'=>'zhao','羄'=>'zhao','肁'=>'zhao','肇'=>'zhao','肈'=>'zhao','詔'=>'zhao','诏'=>'zhao','赵'=>'zhao','趙'=>'zhao','釗'=>'zhao','鉊'=>'zhao','鍣'=>'zhao','钊'=>'zhao','駋'=>'zhao','鮡'=>'zhao','㕚'=>'zhao','㡽'=>'zhao','㨄'=>'zhao','㷖'=>'zhao','㺐'=>'zhao','䃍'=>'zhao','䈃'=>'zhao','䈇'=>'zhao','䍜'=>'zhao','䍮'=>'zhao','䝖'=>'zhao','䮓'=>'zhao','佌'=>'ci','佽'=>'ci','偨'=>'ci','刺'=>'ci','刾'=>'ci','呲'=>'ci','嗭'=>'ci','垐'=>'ci','堲'=>'ci','嬨'=>'ci','庛'=>'ci','慈'=>'ci','朿'=>'ci','柌'=>'ci','栨'=>'ci','次'=>'ci','此'=>'ci','泚'=>'ci','濨'=>'ci','玼'=>'ci','珁'=>'ci','瓷'=>'ci','甆'=>'ci','疵'=>'ci','皉'=>'ci','磁'=>'ci','礠'=>'ci','祠'=>'ci','糍'=>'ci','絘'=>'ci','縒'=>'ci','茈'=>'ci','茦'=>'ci','茨'=>'ci','莿'=>'ci','薋'=>'ci','蛓'=>'ci','螆'=>'ci','蠀'=>'ci','詞'=>'ci','词'=>'ci','賜'=>'ci','赐'=>'ci','趀'=>'ci','跐'=>'ci','辝'=>'ci','辞'=>'ci','辤'=>'ci','辭'=>'ci','鈶'=>'ci','雌'=>'ci','飺'=>'ci','餈'=>'ci','骴'=>'ci','鴜'=>'ci','鶿'=>'ci','鷀'=>'ci','鹚'=>'ci','㓨'=>'ci','㘂'=>'ci','㘹'=>'ci','㞖'=>'ci','㠿'=>'ci','㡹'=>'ci','㢀'=>'ci','㤵'=>'ci','㩞'=>'ci','㹂'=>'ci','䂣'=>'ci','䆅'=>'ci','䈘'=>'ci','䓧'=>'ci','䖪'=>'ci','䗹'=>'ci','䛐'=>'ci','䦻'=>'ci','䧳'=>'ci','䨏'=>'ci','䭣'=>'ci','䯸'=>'ci','䰍'=>'ci','䲿'=>'ci','䳄'=>'ci','䳐'=>'ci','佐'=>'zuo','作'=>'zuo','侳'=>'zuo','做'=>'zuo','咗'=>'zuo','唑'=>'zuo','坐'=>'zuo','岝'=>'zuo','岞'=>'zuo','左'=>'zuo','座'=>'zuo','怍'=>'zuo','捽'=>'zuo','昨'=>'zuo','柞'=>'zuo','椊'=>'zuo','祚'=>'zuo','秨'=>'zuo','稓'=>'zuo','筰'=>'zuo','糳'=>'zuo','繓'=>'zuo','胙'=>'zuo','莋'=>'zuo','葃'=>'zuo','葄'=>'zuo','蓙'=>'zuo','袏'=>'zuo','鈼'=>'zuo','阼'=>'zuo','飵'=>'zuo','㑅'=>'zuo','㘀'=>'zuo','㘴'=>'zuo','㛗'=>'zuo','㝾'=>'zuo','㭮'=>'zuo','㸲'=>'zuo','䋏'=>'zuo','䎰'=>'zuo','䔘'=>'zuo','䝫'=>'zuo','䞰'=>'zuo','体'=>'ti','倜'=>'ti','偍'=>'ti','剃'=>'ti','剔'=>'ti','厗'=>'ti','啼'=>'ti','嗁'=>'ti','嚏'=>'ti','嚔'=>'ti','媞'=>'ti','屉'=>'ti','屜'=>'ti','崹'=>'ti','徲'=>'ti','悌'=>'ti','悐'=>'ti','惕'=>'ti','惖'=>'ti','惿'=>'ti','戻'=>'ti','挮'=>'ti','掦'=>'ti','提'=>'ti','揥'=>'ti','替'=>'ti','梯'=>'ti','楴'=>'ti','歒'=>'ti','殢'=>'ti','洟'=>'ti','涕'=>'ti','渧'=>'ti','漽'=>'ti','珶'=>'ti','瑅'=>'ti','瓋'=>'ti','碮'=>'ti','稊'=>'ti','籊'=>'ti','綈'=>'ti','緹'=>'ti','绨'=>'ti','缇'=>'ti','罤'=>'ti','蕛'=>'ti','薙'=>'ti','蝭'=>'ti','裼'=>'ti','褅'=>'ti','謕'=>'ti','趧'=>'ti','趯'=>'ti','踢'=>'ti','蹄'=>'ti','蹏'=>'ti','躰'=>'ti','軆'=>'ti','逖'=>'ti','逷'=>'ti','遆'=>'ti','醍'=>'ti','銻'=>'ti','鍗'=>'ti','鐟'=>'ti','锑'=>'ti','題'=>'ti','题'=>'ti','騠'=>'ti','骵'=>'ti','體'=>'ti','髰'=>'ti','鬀'=>'ti','鬄'=>'ti','鮷'=>'ti','鯷'=>'ti','鳀'=>'ti','鴺'=>'ti','鵜'=>'ti','鶗'=>'ti','鶙'=>'ti','鷈'=>'ti','鷉'=>'ti','鹈'=>'ti','㖒'=>'ti','㗣'=>'ti','㡗'=>'ti','㣢'=>'ti','㬱'=>'ti','㯩'=>'ti','䅠'=>'ti','䌡'=>'ti','䎮'=>'ti','䔶'=>'ti','䙗'=>'ti','䚣'=>'ti','䛱'=>'ti','䝰'=>'ti','䣡'=>'ti','䣽'=>'ti','䧅'=>'ti','䨑'=>'ti','䪆'=>'ti','䬾'=>'ti','䯜'=>'ti','䴘'=>'ti','䶏'=>'ti','䶑'=>'ti','佔'=>'zhan','偡'=>'zhan','占'=>'zhan','噡'=>'zhan','嫸'=>'zhan','展'=>'zhan','崭'=>'zhan','嶃'=>'zhan','嶄'=>'zhan','嶘'=>'zhan','嶦'=>'zhan','惉'=>'zhan','战'=>'zhan','戦'=>'zhan','戰'=>'zhan','拃'=>'zhan','搌'=>'zhan','斩'=>'zhan','斬'=>'zhan','旃'=>'zhan','旜'=>'zhan','栈'=>'zhan','栴'=>'zhan','桟'=>'zhan','棧'=>'zhan','榐'=>'zhan','橏'=>'zhan','毡'=>'zhan','氈'=>'zhan','氊'=>'zhan','沾'=>'zhan','湛'=>'zhan','澶'=>'zhan','琖'=>'zhan','皽'=>'zhan','盏'=>'zhan','盞'=>'zhan','瞻'=>'zhan','站'=>'zhan','粘'=>'zhan','綻'=>'zhan','绽'=>'zhan','菚'=>'zhan','薝'=>'zhan','蘸'=>'zhan','虥'=>'zhan','虦'=>'zhan','蛅'=>'zhan','覱'=>'zhan','詀'=>'zhan','詹'=>'zhan','譫'=>'zhan','讝'=>'zhan','谵'=>'zhan','趈'=>'zhan','蹍'=>'zhan','輚'=>'zhan','輾'=>'zhan','轏'=>'zhan','辗'=>'zhan','邅'=>'zhan','醆'=>'zhan','閚'=>'zhan','霑'=>'zhan','颭'=>'zhan','飐'=>'zhan','飦'=>'zhan','饘'=>'zhan','驏'=>'zhan','驙'=>'zhan','骣'=>'zhan','魙'=>'zhan','鱣'=>'zhan','鳣'=>'zhan','鸇'=>'zhan','鹯'=>'zhan','黵'=>'zhan','㞡'=>'zhan','㟞'=>'zhan','㠭'=>'zhan','㣶'=>'zhan','㺘'=>'zhan','㻵'=>'zhan','䁴'=>'zhan','䋎'=>'zhan','䎒'=>'zhan','䗃'=>'zhan','䘺'=>'zhan','䟋'=>'zhan','䡀'=>'zhan','䩅'=>'zhan','䪌'=>'zhan','䱠'=>'zhan','䱼'=>'zhan','何'=>'he','佫'=>'he','劾'=>'he','合'=>'he','呵'=>'he','咊'=>'he','和'=>'he','哬'=>'he','啝'=>'he','喝'=>'he','嗃'=>'he','嗬'=>'he','垎'=>'he','壑'=>'he','姀'=>'he','寉'=>'he','峆'=>'he','惒'=>'he','抲'=>'he','敆'=>'he','曷'=>'he','柇'=>'he','核'=>'he','楁'=>'he','欱'=>'he','毼'=>'he','河'=>'he','涸'=>'he','渮'=>'he','湼'=>'he','澕'=>'he','焃'=>'he','煂'=>'he','熆'=>'he','熇'=>'he','燺'=>'he','爀'=>'he','狢'=>'he','癋'=>'he','皬'=>'he','盇'=>'he','盉'=>'he','盍'=>'he','盒'=>'he','碋'=>'he','礉'=>'he','禾'=>'he','秴'=>'he','篕'=>'he','籺'=>'he','粭'=>'he','翮'=>'he','翯'=>'he','荷'=>'he','菏'=>'he','萂'=>'he','蚵'=>'he','螛'=>'he','蠚'=>'he','袔'=>'he','褐'=>'he','覈'=>'he','訶'=>'he','訸'=>'he','詥'=>'he','诃'=>'he','貈'=>'he','貉'=>'he','賀'=>'he','贺'=>'he','赫'=>'he','郃'=>'he','鉌'=>'he','鑉'=>'he','閡'=>'he','闔'=>'he','阂'=>'he','阖'=>'he','隺'=>'he','靍'=>'he','靎'=>'he','靏'=>'he','鞨'=>'he','頜'=>'he','颌'=>'he','饸'=>'he','魺'=>'he','鲄'=>'he','鶡'=>'he','鶴'=>'he','鸖'=>'he','鹖'=>'he','鹤'=>'he','麧'=>'he','齃'=>'he','齕'=>'he','龁'=>'he','龢'=>'he','㓭'=>'he','㔠'=>'he','㕡'=>'he','㕰'=>'he','㥺'=>'he','㦦'=>'he','㪉'=>'he','㬞'=>'he','㭘'=>'he','㭱'=>'he','㮝'=>'he','㮫'=>'he','㵑'=>'he','㷎'=>'he','㷤'=>'he','㹇'=>'he','㿣'=>'he','䃒'=>'he','䅂'=>'he','䎋'=>'he','䒩'=>'he','䓼'=>'he','䕣'=>'he','䚂'=>'he','䞦'=>'he','䢗'=>'he','䪚'=>'he','䫘'=>'he','䳚'=>'he','䳽'=>'he','䴳'=>'he','䵱'=>'he','䶅'=>'he','佘'=>'she','厍'=>'she','厙'=>'she','奢'=>'she','射'=>'she','弽'=>'she','慑'=>'she','慴'=>'she','懾'=>'she','捨'=>'she','摂'=>'she','摄'=>'she','摵'=>'she','攝'=>'she','檨'=>'she','欇'=>'she','涉'=>'she','涻'=>'she','渉'=>'she','滠'=>'she','灄'=>'she','猞'=>'she','畲'=>'she','社'=>'she','舌'=>'she','舍'=>'she','舎'=>'she','蔎'=>'she','虵'=>'she','蛇'=>'she','蛥'=>'she','蠂'=>'she','設'=>'she','设'=>'she','賒'=>'she','賖'=>'she','赊'=>'she','赦'=>'she','輋'=>'she','韘'=>'she','騇'=>'she','麝'=>'she','㒤'=>'she','㢵'=>'she','㭙'=>'she','㰒'=>'she','㴇'=>'she','䀅'=>'she','䁋'=>'she','䁯'=>'she','䂠'=>'she','䄕'=>'she','䌰'=>'she','䞌'=>'she','䠶'=>'she','䤮'=>'she','䬷'=>'she','䵥'=>'she','佝'=>'gou','冓'=>'gou','勾'=>'gou','坸'=>'gou','垢'=>'gou','够'=>'gou','夠'=>'gou','姤'=>'gou','媾'=>'gou','岣'=>'gou','彀'=>'gou','搆'=>'gou','撀'=>'gou','构'=>'gou','枸'=>'gou','構'=>'gou','沟'=>'gou','溝'=>'gou','煹'=>'gou','狗'=>'gou','玽'=>'gou','笱'=>'gou','篝'=>'gou','簼'=>'gou','緱'=>'gou','缑'=>'gou','耇'=>'gou','耈'=>'gou','耉'=>'gou','苟'=>'gou','茩'=>'gou','蚼'=>'gou','袧'=>'gou','褠'=>'gou','覯'=>'gou','觏'=>'gou','訽'=>'gou','詬'=>'gou','诟'=>'gou','豿'=>'gou','購'=>'gou','购'=>'gou','遘'=>'gou','鈎'=>'gou','鉤'=>'gou','钩'=>'gou','雊'=>'gou','鞲'=>'gou','韝'=>'gou','㗕'=>'gou','㜌'=>'gou','㝅'=>'gou','㝤'=>'gou','㨌'=>'gou','㳶'=>'gou','㺃'=>'gou','䃓'=>'gou','䝭'=>'gou','䞀'=>'gou','佞'=>'ning','侫'=>'ning','儜'=>'ning','凝'=>'ning','咛'=>'ning','嚀'=>'ning','嬣'=>'ning','宁'=>'ning','寍'=>'ning','寕'=>'ning','寗'=>'ning','寜'=>'ning','寧'=>'ning','拧'=>'ning','擰'=>'ning','柠'=>'ning','橣'=>'ning','檸'=>'ning','泞'=>'ning','澝'=>'ning','濘'=>'ning','狞'=>'ning','獰'=>'ning','甯'=>'ning','矃'=>'ning','聍'=>'ning','聹'=>'ning','薴'=>'ning','鑏'=>'ning','鬡'=>'ning','鸋'=>'ning','㝕'=>'ning','㣷'=>'ning','㲰'=>'ning','㿦'=>'ning','䔭'=>'ning','䗿'=>'ning','䭢'=>'ning','佣'=>'yong','俑'=>'yong','傛'=>'yong','傭'=>'yong','勇'=>'yong','勈'=>'yong','咏'=>'yong','喁'=>'yong','嗈'=>'yong','噰'=>'yong','埇'=>'yong','塎'=>'yong','墉'=>'yong','壅'=>'yong','嫞'=>'yong','嵱'=>'yong','庸'=>'yong','廱'=>'yong','彮'=>'yong','怺'=>'yong','恿'=>'yong','悀'=>'yong','惥'=>'yong','愑'=>'yong','愹'=>'yong','慂'=>'yong','慵'=>'yong','拥'=>'yong','擁'=>'yong','柡'=>'yong','栐'=>'yong','槦'=>'yong','永'=>'yong','泳'=>'yong','涌'=>'yong','湧'=>'yong','滽'=>'yong','澭'=>'yong','灉'=>'yong','牅'=>'yong','用'=>'yong','甬'=>'yong','痈'=>'yong','癕'=>'yong','癰'=>'yong','砽'=>'yong','硧'=>'yong','禜'=>'yong','臃'=>'yong','苚'=>'yong','蛹'=>'yong','詠'=>'yong','踊'=>'yong','踴'=>'yong','邕'=>'yong','郺'=>'yong','鄘'=>'yong','醟'=>'yong','銿'=>'yong','鏞'=>'yong','镛'=>'yong','雍'=>'yong','雝'=>'yong','顒'=>'yong','颙'=>'yong','饔'=>'yong','鯒'=>'yong','鰫'=>'yong','鱅'=>'yong','鲬'=>'yong','鳙'=>'yong','鷛'=>'yong','㐯'=>'yong','㙲'=>'yong','㝘'=>'yong','㞲'=>'yong','㦷'=>'yong','㶲'=>'yong','㷏'=>'yong','㽫'=>'yong','䗤'=>'yong','䞻'=>'yong','佤'=>'wa','劸'=>'wa','咓'=>'wa','哇'=>'wa','啘'=>'wa','嗗'=>'wa','嗢'=>'wa','娃'=>'wa','娲'=>'wa','媧'=>'wa','屲'=>'wa','徍'=>'wa','挖'=>'wa','搲'=>'wa','攨'=>'wa','洼'=>'wa','溛'=>'wa','漥'=>'wa','瓦'=>'wa','瓲'=>'wa','畖'=>'wa','砙'=>'wa','窊'=>'wa','窪'=>'wa','聉'=>'wa','腽'=>'wa','膃'=>'wa','蛙'=>'wa','袜'=>'wa','襪'=>'wa','邷'=>'wa','韈'=>'wa','韤'=>'wa','鼃'=>'wa','㧚'=>'wa','㰪'=>'wa','㼘'=>'wa','䎳'=>'wa','䚴'=>'wa','䠚'=>'wa','佧'=>'ka','卡'=>'ka','咔'=>'ka','咖'=>'ka','咯'=>'ka','喀'=>'ka','垰'=>'ka','胩'=>'ka','裃'=>'ka','鉲'=>'ka','佨'=>'bao','保'=>'bao','儤'=>'bao','剝'=>'bao','剥'=>'bao','勹'=>'bao','勽'=>'bao','包'=>'bao','堡'=>'bao','堢'=>'bao','報'=>'bao','媬'=>'bao','嫑'=>'bao','孢'=>'bao','宝'=>'bao','寚'=>'bao','寳'=>'bao','寶'=>'bao','忁'=>'bao','怉'=>'bao','报'=>'bao','抱'=>'bao','暴'=>'bao','曓'=>'bao','煲'=>'bao','爆'=>'bao','珤'=>'bao','窇'=>'bao','笣'=>'bao','緥'=>'bao','胞'=>'bao','苞'=>'bao','菢'=>'bao','萡'=>'bao','葆'=>'bao','蕔'=>'bao','薄'=>'bao','藵'=>'bao','虣'=>'bao','袌'=>'bao','褒'=>'bao','褓'=>'bao','襃'=>'bao','豹'=>'bao','賲'=>'bao','趵'=>'bao','鉋'=>'bao','鑤'=>'bao','铇'=>'bao','闁'=>'bao','雹'=>'bao','靌'=>'bao','靤'=>'bao','飹'=>'bao','飽'=>'bao','饱'=>'bao','駂'=>'bao','骲'=>'bao','髱'=>'bao','鮑'=>'bao','鲍'=>'bao','鳵'=>'bao','鴇'=>'bao','鸨'=>'bao','齙'=>'bao','龅'=>'bao','㙅'=>'bao','㙸'=>'bao','㫧'=>'bao','㲏'=>'bao','㲒'=>'bao','㵡'=>'bao','㻄'=>'bao','㿺'=>'bao','䈏'=>'bao','䎂'=>'bao','䤖'=>'bao','䥤'=>'bao','䨌'=>'bao','䨔'=>'bao','䪨'=>'bao','䭋'=>'bao','䳈'=>'bao','䳰'=>'bao','䴐'=>'bao','佬'=>'lao','僗'=>'lao','劳'=>'lao','労'=>'lao','勞'=>'lao','咾'=>'lao','哰'=>'lao','唠'=>'lao','嗠'=>'lao','嘮'=>'lao','姥'=>'lao','嫪'=>'lao','崂'=>'lao','嶗'=>'lao','恅'=>'lao','憥'=>'lao','憦'=>'lao','捞'=>'lao','撈'=>'lao','朥'=>'lao','栳'=>'lao','橑'=>'lao','橯'=>'lao','浶'=>'lao','涝'=>'lao','澇'=>'lao','烙'=>'lao','牢'=>'lao','狫'=>'lao','珯'=>'lao','痨'=>'lao','癆'=>'lao','硓'=>'lao','磱'=>'lao','窂'=>'lao','簩'=>'lao','粩'=>'lao','老'=>'lao','耂'=>'lao','耢'=>'lao','耮'=>'lao','荖'=>'lao','蛯'=>'lao','蟧'=>'lao','軂'=>'lao','轑'=>'lao','酪'=>'lao','醪'=>'lao','銠'=>'lao','鐒'=>'lao','铑'=>'lao','铹'=>'lao','顟'=>'lao','髝'=>'lao','鮱'=>'lao','㗦'=>'lao','㞠'=>'lao','㟉'=>'lao','㟙'=>'lao','㟹'=>'lao','㧯'=>'lao','㨓'=>'lao','䃕'=>'lao','䇭'=>'lao','䕩'=>'lao','䜎'=>'lao','䝁'=>'lao','䝤'=>'lao','䲏'=>'lao','䳓'=>'lao','䵏'=>'lao','佰'=>'bai','兡'=>'bai','呗'=>'bai','唄'=>'bai','庍'=>'bai','拜'=>'bai','拝'=>'bai','挀'=>'bai','捭'=>'bai','掰'=>'bai','摆'=>'bai','擺'=>'bai','敗'=>'bai','柏'=>'bai','栢'=>'bai','猈'=>'bai','瓸'=>'bai','白'=>'bai','百'=>'bai','稗'=>'bai','竡'=>'bai','粨'=>'bai','粺'=>'bai','絔'=>'bai','薭'=>'bai','襬'=>'bai','贁'=>'bai','败'=>'bai','鞁'=>'bai','韛'=>'bai','㗑'=>'bai','㗗'=>'bai','㠔'=>'bai','㼟'=>'bai','㼣'=>'bai','㿟'=>'bai','䒔'=>'bai','䙓'=>'bai','䢙'=>'bai','䳆'=>'bai','䴽'=>'bai','佲'=>'ming','冥'=>'ming','凕'=>'ming','名'=>'ming','命'=>'ming','姳'=>'ming','嫇'=>'ming','慏'=>'ming','掵'=>'ming','明'=>'ming','暝'=>'ming','朙'=>'ming','榠'=>'ming','洺'=>'ming','溟'=>'ming','猽'=>'ming','眀'=>'ming','眳'=>'ming','瞑'=>'ming','茗'=>'ming','蓂'=>'ming','螟'=>'ming','覭'=>'ming','詺'=>'ming','鄍'=>'ming','酩'=>'ming','銘'=>'ming','铭'=>'ming','鳴'=>'ming','鸣'=>'ming','㝠'=>'ming','㟰'=>'ming','㫥'=>'ming','䄙'=>'ming','䆨'=>'ming','䆩'=>'ming','䊅'=>'ming','䒌'=>'ming','䫤'=>'ming','佷'=>'hen','很'=>'hen','恨'=>'hen','拫'=>'hen','狠'=>'hen','痕'=>'hen','詪'=>'hen','鞎'=>'hen','㯊'=>'hen','䓳'=>'hen','佺'=>'quan','全'=>'quan','券'=>'quan','劝'=>'quan','勧'=>'quan','勸'=>'quan','啳'=>'quan','圈'=>'quan','圏'=>'quan','埢'=>'quan','姾'=>'quan','婘'=>'quan','孉'=>'quan','峑'=>'quan','巏'=>'quan','巻'=>'quan','恮'=>'quan','悛'=>'quan','惓'=>'quan','拳'=>'quan','搼'=>'quan','权'=>'quan','棬'=>'quan','椦'=>'quan','楾'=>'quan','権'=>'quan','權'=>'quan','汱'=>'quan','泉'=>'quan','洤'=>'quan','湶'=>'quan','烇'=>'quan','牶'=>'quan','牷'=>'quan','犈'=>'quan','犬'=>'quan','犭'=>'quan','瑔'=>'quan','甽'=>'quan','畎'=>'quan','痊'=>'quan','硂'=>'quan','筌'=>'quan','絟'=>'quan','綣'=>'quan','縓'=>'quan','绻'=>'quan','腃'=>'quan','荃'=>'quan','葲'=>'quan','虇'=>'quan','蜷'=>'quan','蠸'=>'quan','觠'=>'quan','詮'=>'quan','诠'=>'quan','跧'=>'quan','踡'=>'quan','輇'=>'quan','辁'=>'quan','醛'=>'quan','銓'=>'quan','鐉'=>'quan','铨'=>'quan','闎'=>'quan','韏'=>'quan','顴'=>'quan','颧'=>'quan','駩'=>'quan','騡'=>'quan','鬈'=>'quan','鰁'=>'quan','鳈'=>'quan','齤'=>'quan','㒰'=>'quan','㟨'=>'quan','㟫'=>'quan','䀬'=>'quan','䄐'=>'quan','䊎'=>'quan','䑏'=>'quan','䟒'=>'quan','䠰'=>'quan','佻'=>'tiao','嬥'=>'tiao','宨'=>'tiao','岧'=>'tiao','岹'=>'tiao','庣'=>'tiao','恌'=>'tiao','挑'=>'tiao','旫'=>'tiao','晀'=>'tiao','朓'=>'tiao','条'=>'tiao','條'=>'tiao','樤'=>'tiao','眺'=>'tiao','祒'=>'tiao','祧'=>'tiao','窕'=>'tiao','窱'=>'tiao','笤'=>'tiao','粜'=>'tiao','糶'=>'tiao','絩'=>'tiao','聎'=>'tiao','脁'=>'tiao','芀'=>'tiao','蓚'=>'tiao','蓨'=>'tiao','蜩'=>'tiao','螩'=>'tiao','覜'=>'tiao','誂'=>'tiao','趒'=>'tiao','跳'=>'tiao','迢'=>'tiao','鋚'=>'tiao','鎥'=>'tiao','铫'=>'tiao','鞗'=>'tiao','頫'=>'tiao','髫'=>'tiao','鯈'=>'tiao','鰷'=>'tiao','鲦'=>'tiao','齠'=>'tiao','龆'=>'tiao','㑿'=>'tiao','㟘'=>'tiao','㸠'=>'tiao','䎄'=>'tiao','䒒'=>'tiao','䖺'=>'tiao','䟭'=>'tiao','䠷'=>'tiao','䩦'=>'tiao','䯾'=>'tiao','䱔'=>'tiao','䳂'=>'tiao','侀'=>'xing','倖'=>'xing','兴'=>'xing','刑'=>'xing','哘'=>'xing','型'=>'xing','垶'=>'xing','塂'=>'xing','姓'=>'xing','娙'=>'xing','婞'=>'xing','嬹'=>'xing','幸'=>'xing','形'=>'xing','性'=>'xing','悻'=>'xing','惺'=>'xing','擤'=>'xing','星'=>'xing','曐'=>'xing','杏'=>'xing','洐'=>'xing','涬'=>'xing','煋'=>'xing','狌'=>'xing','猩'=>'xing','瑆'=>'xing','皨'=>'xing','睲'=>'xing','硎'=>'xing','箵'=>'xing','篂'=>'xing','緈'=>'xing','腥'=>'xing','臖'=>'xing','興'=>'xing','荇'=>'xing','莕'=>'xing','蛵'=>'xing','行'=>'xing','裄'=>'xing','觪'=>'xing','觲'=>'xing','謃'=>'xing','邢'=>'xing','郉'=>'xing','醒'=>'xing','鈃'=>'xing','鉶'=>'xing','銒'=>'xing','鋞'=>'xing','钘'=>'xing','铏'=>'xing','陉'=>'xing','陘'=>'xing','騂'=>'xing','骍'=>'xing','鮏'=>'xing','鯹'=>'xing','㐩'=>'xing','㓑'=>'xing','㓝'=>'xing','㝭'=>'xing','㣜'=>'xing','㨘'=>'xing','㮐'=>'xing','㼛'=>'xing','㼬'=>'xing','䁄'=>'xing','䂔'=>'xing','䓷'=>'xing','䛭'=>'xing','䣆'=>'xing','䤯'=>'xing','䰢'=>'xing','䳙'=>'xing','侃'=>'kan','偘'=>'kan','冚'=>'kan','刊'=>'kan','勘'=>'kan','坎'=>'kan','埳'=>'kan','堪'=>'kan','堿'=>'kan','塪'=>'kan','墈'=>'kan','崁'=>'kan','嵁'=>'kan','惂'=>'kan','戡'=>'kan','栞'=>'kan','欿'=>'kan','歁'=>'kan','看'=>'kan','瞰'=>'kan','矙'=>'kan','砍'=>'kan','磡'=>'kan','竷'=>'kan','莰'=>'kan','衎'=>'kan','輡'=>'kan','轁'=>'kan','轗'=>'kan','闞'=>'kan','阚'=>'kan','顑'=>'kan','龕'=>'kan','龛'=>'kan','㸝'=>'kan','䀍'=>'kan','䘓'=>'kan','䶫'=>'kan','來'=>'lai','俫'=>'lai','倈'=>'lai','唻'=>'lai','婡'=>'lai','崃'=>'lai','崍'=>'lai','庲'=>'lai','徕'=>'lai','徠'=>'lai','来'=>'lai','梾'=>'lai','棶'=>'lai','涞'=>'lai','淶'=>'lai','濑'=>'lai','瀨'=>'lai','瀬'=>'lai','猍'=>'lai','琜'=>'lai','癞'=>'lai','癩'=>'lai','睐'=>'lai','睞'=>'lai','筙'=>'lai','箂'=>'lai','籁'=>'lai','籟'=>'lai','莱'=>'lai','萊'=>'lai','藾'=>'lai','襰'=>'lai','賚'=>'lai','賴'=>'lai','赉'=>'lai','赖'=>'lai','逨'=>'lai','郲'=>'lai','錸'=>'lai','铼'=>'lai','頼'=>'lai','顂'=>'lai','騋'=>'lai','鯠'=>'lai','鵣'=>'lai','鶆'=>'lai','麳'=>'lai','㚓'=>'lai','㠣'=>'lai','㥎'=>'lai','㾢'=>'lai','䂾'=>'lai','䄤'=>'lai','䅘'=>'lai','䋱'=>'lai','䓶'=>'lai','䚅'=>'lai','䠭'=>'lai','䧒'=>'lai','䲚'=>'lai','侈'=>'chi','侙'=>'chi','俿'=>'chi','傺'=>'chi','勅'=>'chi','匙'=>'chi','卶'=>'chi','叱'=>'chi','叺'=>'chi','吃'=>'chi','呎'=>'chi','哧'=>'chi','啻'=>'chi','喫'=>'chi','嗤'=>'chi','噄'=>'chi','坘'=>'chi','垑'=>'chi','墀'=>'chi','妛'=>'chi','媸'=>'chi','尺'=>'chi','岻'=>'chi','弛'=>'chi','彨'=>'chi','彲'=>'chi','彳'=>'chi','恜'=>'chi','恥'=>'chi','慗'=>'chi','憏'=>'chi','懘'=>'chi','抶'=>'chi','拸'=>'chi','持'=>'chi','摛'=>'chi','攡'=>'chi','敕'=>'chi','斥'=>'chi','杘'=>'chi','欼'=>'chi','歭'=>'chi','歯'=>'chi','池'=>'chi','泜'=>'chi','淔'=>'chi','湁'=>'chi','漦'=>'chi','灻'=>'chi','炽'=>'chi','烾'=>'chi','熾'=>'chi','瓻'=>'chi','痓'=>'chi','痴'=>'chi','痸'=>'chi','瘛'=>'chi','癡'=>'chi','眵'=>'chi','瞝'=>'chi','竾'=>'chi','笞'=>'chi','筂'=>'chi','篪'=>'chi','粚'=>'chi','糦'=>'chi','絺'=>'chi','翄'=>'chi','翅'=>'chi','翤'=>'chi','翨'=>'chi','耛'=>'chi','耻'=>'chi','肔'=>'chi','胣'=>'chi','胵'=>'chi','腟'=>'chi','茌'=>'chi','荎'=>'chi','蚇'=>'chi','蚩'=>'chi','蚳'=>'chi','螭'=>'chi','袲'=>'chi','袳'=>'chi','裭'=>'chi','褫'=>'chi','訵'=>'chi','誺'=>'chi','謘'=>'chi','豉'=>'chi','貾'=>'chi','赤'=>'chi','赿'=>'chi','趍'=>'chi','趩'=>'chi','跮'=>'chi','踟'=>'chi','迟'=>'chi','迣'=>'chi','遅'=>'chi','遟'=>'chi','遫'=>'chi','遲'=>'chi','鉓'=>'chi','鉹'=>'chi','銐'=>'chi','雴'=>'chi','飭'=>'chi','饎'=>'chi','饬'=>'chi','馳'=>'chi','驰'=>'chi','魑'=>'chi','鴟'=>'chi','鵄'=>'chi','鶒'=>'chi','鷘'=>'chi','鸱'=>'chi','麶'=>'chi','黐'=>'chi','齒'=>'chi','齝'=>'chi','齿'=>'chi','㒆'=>'chi','㓼'=>'chi','㓾'=>'chi','㔑'=>'chi','㘜'=>'chi','㙜'=>'chi','㞴'=>'chi','㞿'=>'chi','㟂'=>'chi','㡿'=>'chi','㢁'=>'chi','㢋'=>'chi','㢮'=>'chi','㮛'=>'chi','㱀'=>'chi','㳏'=>'chi','㶴'=>'chi','㽚'=>'chi','䆍'=>'chi','䇼'=>'chi','䈕'=>'chi','䊼'=>'chi','䐤'=>'chi','䑛'=>'chi','䔟'=>'chi','䗖'=>'chi','䙙'=>'chi','䛂'=>'chi','䜄'=>'chi','䜵'=>'chi','䜻'=>'chi','䞾'=>'chi','䟷'=>'chi','䠠'=>'chi','䤲'=>'chi','䪧'=>'chi','䮈'=>'chi','䮻'=>'chi','䰡'=>'chi','䳵'=>'chi','䶔'=>'chi','䶵'=>'chi','侉'=>'kua','咵'=>'kua','垮'=>'kua','夸'=>'kua','姱'=>'kua','挎'=>'kua','晇'=>'kua','胯'=>'kua','舿'=>'kua','誇'=>'kua','跨'=>'kua','銙'=>'kua','骻'=>'kua','㐄'=>'kua','䋀'=>'kua','侊'=>'guang','俇'=>'guang','僙'=>'guang','光'=>'guang','咣'=>'guang','垙'=>'guang','姯'=>'guang','广'=>'guang','広'=>'guang','廣'=>'guang','撗'=>'guang','桄'=>'guang','欟'=>'guang','洸'=>'guang','灮'=>'guang','炗'=>'guang','炚'=>'guang','炛'=>'guang','烡'=>'guang','犷'=>'guang','獷'=>'guang','珖'=>'guang','硄'=>'guang','胱'=>'guang','臦'=>'guang','臩'=>'guang','茪'=>'guang','輄'=>'guang','逛'=>'guang','銧'=>'guang','黆'=>'guang','㫛'=>'guang','侎'=>'mi','冖'=>'mi','冞'=>'mi','冪'=>'mi','咪'=>'mi','嘧'=>'mi','塓'=>'mi','孊'=>'mi','宓'=>'mi','宻'=>'mi','密'=>'mi','峚'=>'mi','幂'=>'mi','幎'=>'mi','幦'=>'mi','弥'=>'mi','弭'=>'mi','彌'=>'mi','戂'=>'mi','擟'=>'mi','攠'=>'mi','敉'=>'mi','榓'=>'mi','樒'=>'mi','櫁'=>'mi','汨'=>'mi','沕'=>'mi','沵'=>'mi','泌'=>'mi','洣'=>'mi','淧'=>'mi','渳'=>'mi','滵'=>'mi','漞'=>'mi','濔'=>'mi','濗'=>'mi','瀰'=>'mi','灖'=>'mi','熐'=>'mi','爢'=>'mi','猕'=>'mi','獼'=>'mi','瓕'=>'mi','眫'=>'mi','眯'=>'mi','瞇'=>'mi','祕'=>'mi','祢'=>'mi','禰'=>'mi','秘'=>'mi','簚'=>'mi','米'=>'mi','粎'=>'mi','糜'=>'mi','糸'=>'mi','縻'=>'mi','羃'=>'mi','羋'=>'mi','脒'=>'mi','芈'=>'mi','葞'=>'mi','蒾'=>'mi','蔝'=>'mi','蔤'=>'mi','藌'=>'mi','蘼'=>'mi','蜜'=>'mi','蝆'=>'mi','袮'=>'mi','覓'=>'mi','覔'=>'mi','覛'=>'mi','觅'=>'mi','詸'=>'mi','謎'=>'mi','謐'=>'mi','谜'=>'mi','谧'=>'mi','踎'=>'mi','迷'=>'mi','醚'=>'mi','醾'=>'mi','醿'=>'mi','釄'=>'mi','銤'=>'mi','镾'=>'mi','靡'=>'mi','鸍'=>'mi','麊'=>'mi','麋'=>'mi','麛'=>'mi','鼏'=>'mi','㜆'=>'mi','㜷'=>'mi','㝥'=>'mi','㟜'=>'mi','㠧'=>'mi','㣆'=>'mi','㥝'=>'mi','㨠'=>'mi','㩢'=>'mi','㫘'=>'mi','㰽'=>'mi','㳴'=>'mi','㳽'=>'mi','㴵'=>'mi','㵋'=>'mi','㸏'=>'mi','㸓'=>'mi','䁇'=>'mi','䉾'=>'mi','䊳'=>'mi','䋛'=>'mi','䌏'=>'mi','䌐'=>'mi','䌕'=>'mi','䌘'=>'mi','䌩'=>'mi','䍘'=>'mi','䕳'=>'mi','䕷'=>'mi','䖑'=>'mi','䛉'=>'mi','䛑'=>'mi','䛧'=>'mi','䣾'=>'mi','䤉'=>'mi','䤍'=>'mi','䥸'=>'mi','䪾'=>'mi','䭧'=>'mi','䭩'=>'mi','䱊'=>'mi','䴢'=>'mi','侒'=>'an','俺'=>'an','儑'=>'an','唵'=>'an','啽'=>'an','垵'=>'an','埯'=>'an','堓'=>'an','婩'=>'an','媕'=>'an','安'=>'an','岸'=>'an','峖'=>'an','庵'=>'an','按'=>'an','揞'=>'an','晻'=>'an','暗'=>'an','案'=>'an','桉'=>'an','氨'=>'an','洝'=>'an','犴'=>'an','玵'=>'an','痷'=>'an','盦'=>'an','盫'=>'an','罯'=>'an','胺'=>'an','腤'=>'an','荌'=>'an','菴'=>'an','萻'=>'an','葊'=>'an','蓭'=>'an','誝'=>'an','諳'=>'an','谙'=>'an','豻'=>'an','貋'=>'an','銨'=>'an','錌'=>'an','铵'=>'an','闇'=>'an','隌'=>'an','雸'=>'an','鞌'=>'an','鞍'=>'an','韽'=>'an','馣'=>'an','鮟'=>'an','鵪'=>'an','鶕'=>'an','鹌'=>'an','黯'=>'an','㜝'=>'an','㟁'=>'an','㱘'=>'an','㸩'=>'an','㽢'=>'an','䁆'=>'an','䅁'=>'an','䅖'=>'an','䎏'=>'an','䎨'=>'an','䜙'=>'an','䬓'=>'an','䮗'=>'an','䯥'=>'an','侓'=>'lu','僇'=>'lu','剹'=>'lu','勎'=>'lu','勠'=>'lu','卢'=>'lu','卤'=>'lu','噜'=>'lu','嚕'=>'lu','嚧'=>'lu','圥'=>'lu','坴'=>'lu','垆'=>'lu','塶'=>'lu','塷'=>'lu','壚'=>'lu','娽'=>'lu','峍'=>'lu','庐'=>'lu','廘'=>'lu','廬'=>'lu','彔'=>'lu','录'=>'lu','戮'=>'lu','挔'=>'lu','捛'=>'lu','掳'=>'lu','摝'=>'lu','撸'=>'lu','擄'=>'lu','擼'=>'lu','攎'=>'lu','枦'=>'lu','栌'=>'lu','椂'=>'lu','樐'=>'lu','樚'=>'lu','橹'=>'lu','櫓'=>'lu','櫨'=>'lu','氇'=>'lu','氌'=>'lu','泸'=>'lu','淕'=>'lu','淥'=>'lu','渌'=>'lu','滷'=>'lu','漉'=>'lu','潞'=>'lu','澛'=>'lu','濾'=>'lu','瀂'=>'lu','瀘'=>'lu','炉'=>'lu','熝'=>'lu','爐'=>'lu','獹'=>'lu','玈'=>'lu','琭'=>'lu','璐'=>'lu','璷'=>'lu','瓐'=>'lu','甪'=>'lu','盝'=>'lu','盧'=>'lu','睩'=>'lu','矑'=>'lu','硉'=>'lu','硵'=>'lu','碌'=>'lu','磠'=>'lu','祿'=>'lu','禄'=>'lu','稑'=>'lu','穋'=>'lu','箓'=>'lu','簏'=>'lu','簬'=>'lu','簵'=>'lu','簶'=>'lu','籙'=>'lu','籚'=>'lu','粶'=>'lu','纑'=>'lu','罏'=>'lu','胪'=>'lu','膔'=>'lu','膟'=>'lu','臚'=>'lu','舮'=>'lu','舻'=>'lu','艣'=>'lu','艪'=>'lu','艫'=>'lu','芦'=>'lu','菉'=>'lu','蓾'=>'lu','蔍'=>'lu','蕗'=>'lu','蘆'=>'lu','虂'=>'lu','虏'=>'lu','虜'=>'lu','螰'=>'lu','蠦'=>'lu','觮'=>'lu','觻'=>'lu','賂'=>'lu','赂'=>'lu','趢'=>'lu','路'=>'lu','踛'=>'lu','蹗'=>'lu','輅'=>'lu','轆'=>'lu','轤'=>'lu','轳'=>'lu','辂'=>'lu','辘'=>'lu','逯'=>'lu','醁'=>'lu','鈩'=>'lu','錄'=>'lu','録'=>'lu','錴'=>'lu','鏀'=>'lu','鏕'=>'lu','鏴'=>'lu','鐪'=>'lu','鑥'=>'lu','鑪'=>'lu','镥'=>'lu','陆'=>'lu','陸'=>'lu','露'=>'lu','顱'=>'lu','颅'=>'lu','騄'=>'lu','騼'=>'lu','髗'=>'lu','魯'=>'lu','魲'=>'lu','鯥'=>'lu','鱸'=>'lu','鲁'=>'lu','鲈'=>'lu','鴼'=>'lu','鵦'=>'lu','鵱'=>'lu','鷺'=>'lu','鸕'=>'lu','鸬'=>'lu','鹭'=>'lu','鹵'=>'lu','鹿'=>'lu','麓'=>'lu','黸'=>'lu','㓐'=>'lu','㔪'=>'lu','㖨'=>'lu','㛬'=>'lu','㜙'=>'lu','㟤'=>'lu','㠠'=>'lu','㢚'=>'lu','㢳'=>'lu','㦇'=>'lu','㪐'=>'lu','㪖'=>'lu','㪭'=>'lu','㫽'=>'lu','㭔'=>'lu','㯝'=>'lu','㯟'=>'lu','㯭'=>'lu','㱺'=>'lu','㼾'=>'lu','㿖'=>'lu','䃙'=>'lu','䌒'=>'lu','䎑'=>'lu','䎼'=>'lu','䐂'=>'lu','䕡'=>'lu','䘵'=>'lu','䚄'=>'lu','䟿'=>'lu','䡎'=>'lu','䡜'=>'lu','䩮'=>'lu','䬛'=>'lu','䮉'=>'lu','䰕'=>'lu','䱚'=>'lu','䲐'=>'lu','䴪'=>'lu','侔'=>'mou','劺'=>'mou','哞'=>'mou','恈'=>'mou','某'=>'mou','桙'=>'mou','洠'=>'mou','牟'=>'mou','眸'=>'mou','瞴'=>'mou','蟱'=>'mou','謀'=>'mou','谋'=>'mou','鉾'=>'mou','鍪'=>'mou','鴾'=>'mou','麰'=>'mou','㭌'=>'mou','䍒'=>'mou','䏬'=>'mou','䗋'=>'mou','䥐'=>'mou','䱕'=>'mou','侘'=>'cha','偛'=>'cha','剎'=>'cha','叉'=>'cha','嗏'=>'cha','垞'=>'cha','奼'=>'cha','姹'=>'cha','察'=>'cha','岔'=>'cha','嵖'=>'cha','差'=>'cha','扠'=>'cha','扱'=>'cha','挿'=>'cha','插'=>'cha','揷'=>'cha','搽'=>'cha','杈'=>'cha','查'=>'cha','査'=>'cha','槎'=>'cha','檫'=>'cha','汊'=>'cha','猹'=>'cha','疀'=>'cha','碴'=>'cha','秅'=>'cha','紁'=>'cha','肞'=>'cha','臿'=>'cha','艖'=>'cha','芆'=>'cha','茬'=>'cha','茶'=>'cha','衩'=>'cha','褨'=>'cha','訍'=>'cha','詧'=>'cha','詫'=>'cha','诧'=>'cha','蹅'=>'cha','釵'=>'cha','銟'=>'cha','鍤'=>'cha','鎈'=>'cha','鑔'=>'cha','钗'=>'cha','锸'=>'cha','镲'=>'cha','靫'=>'cha','餷'=>'cha','馇'=>'cha','㛳'=>'cha','㢉'=>'cha','㢎'=>'cha','㢒'=>'cha','㣾'=>'cha','㤞'=>'cha','㪯'=>'cha','㫅'=>'cha','䁟'=>'cha','䆛'=>'cha','䊬'=>'cha','䑘'=>'cha','䒲'=>'cha','䓭'=>'cha','䕓'=>'cha','䟕'=>'cha','䡨'=>'cha','䤩'=>'cha','䰈'=>'cha','䲦'=>'cha','䶪'=>'cha','供'=>'gong','兝'=>'gong','兣'=>'gong','公'=>'gong','共'=>'gong','功'=>'gong','匑'=>'gong','匔'=>'gong','厷'=>'gong','唝'=>'gong','塨'=>'gong','宫'=>'gong','宮'=>'gong','工'=>'gong','巩'=>'gong','幊'=>'gong','廾'=>'gong','弓'=>'gong','恭'=>'gong','愩'=>'gong','慐'=>'gong','拱'=>'gong','拲'=>'gong','攻'=>'gong','杛'=>'gong','栱'=>'gong','汞'=>'gong','熕'=>'gong','珙'=>'gong','碽'=>'gong','篢'=>'gong','糼'=>'gong','羾'=>'gong','肱'=>'gong','蚣'=>'gong','觥'=>'gong','觵'=>'gong','貢'=>'gong','贑'=>'gong','贡'=>'gong','躬'=>'gong','躳'=>'gong','輁'=>'gong','鞏'=>'gong','髸'=>'gong','龏'=>'gong','龔'=>'gong','龚'=>'gong','㓋'=>'gong','㔶'=>'gong','㤨'=>'gong','㧬'=>'gong','㫒'=>'gong','㭟'=>'gong','㯯'=>'gong','㺬'=>'gong','㼦'=>'gong','䂬'=>'gong','䇨'=>'gong','䡗'=>'gong','䢚'=>'gong','侣'=>'lv','侶'=>'lv','儢'=>'lv','勴'=>'lv','吕'=>'lv','呂'=>'lv','哷'=>'lv','垏'=>'lv','寽'=>'lv','屡'=>'lv','屢'=>'lv','履'=>'lv','嵂'=>'lv','律'=>'lv','慮'=>'lv','旅'=>'lv','曥'=>'lv','梠'=>'lv','榈'=>'lv','櫖'=>'lv','櫚'=>'lv','氀'=>'lv','氯'=>'lv','滤'=>'lv','焒'=>'lv','爈'=>'lv','率'=>'lv','祣'=>'lv','稆'=>'lv','穞'=>'lv','穭'=>'lv','箻'=>'lv','絽'=>'lv','綠'=>'lv','緑'=>'lv','縷'=>'lv','繂'=>'lv','绿'=>'lv','缕'=>'lv','膂'=>'lv','膐'=>'lv','膢'=>'lv','葎'=>'lv','藘'=>'lv','虑'=>'lv','褛'=>'lv','褸'=>'lv','郘'=>'lv','鋁'=>'lv','鑢'=>'lv','铝'=>'lv','閭'=>'lv','闾'=>'lv','馿'=>'lv','驢'=>'lv','驴'=>'lv','鷜'=>'lv','㔧'=>'lv','㠥'=>'lv','㭚'=>'lv','㲶'=>'lv','㻲'=>'lv','㾔'=>'lv','䔞'=>'lv','䢖'=>'lv','䥨'=>'lv','侦'=>'zhen','侲'=>'zhen','偵'=>'zhen','圳'=>'zhen','塦'=>'zhen','姫'=>'zhen','嫃'=>'zhen','寊'=>'zhen','屒'=>'zhen','帪'=>'zhen','弫'=>'zhen','抮'=>'zhen','挋'=>'zhen','振'=>'zhen','揕'=>'zhen','搸'=>'zhen','敒'=>'zhen','敶'=>'zhen','斟'=>'zhen','昣'=>'zhen','朕'=>'zhen','枕'=>'zhen','栕'=>'zhen','栚'=>'zhen','桢'=>'zhen','桭'=>'zhen','楨'=>'zhen','榛'=>'zhen','槇'=>'zhen','樼'=>'zhen','殝'=>'zhen','浈'=>'zhen','湞'=>'zhen','潧'=>'zhen','澵'=>'zhen','獉'=>'zhen','珍'=>'zhen','珎'=>'zhen','瑧'=>'zhen','甄'=>'zhen','畛'=>'zhen','疹'=>'zhen','眕'=>'zhen','眞'=>'zhen','真'=>'zhen','眹'=>'zhen','砧'=>'zhen','碪'=>'zhen','祯'=>'zhen','禎'=>'zhen','禛'=>'zhen','稹'=>'zhen','箴'=>'zhen','籈'=>'zhen','紖'=>'zhen','紾'=>'zhen','絼'=>'zhen','縝'=>'zhen','縥'=>'zhen','纼'=>'zhen','缜'=>'zhen','聄'=>'zhen','胗'=>'zhen','臻'=>'zhen','萙'=>'zhen','葴'=>'zhen','蒖'=>'zhen','蓁'=>'zhen','薽'=>'zhen','蜄'=>'zhen','袗'=>'zhen','裖'=>'zhen','覙'=>'zhen','診'=>'zhen','誫'=>'zhen','诊'=>'zhen','貞'=>'zhen','賑'=>'zhen','贞'=>'zhen','赈'=>'zhen','軫'=>'zhen','轃'=>'zhen','轸'=>'zhen','辴'=>'zhen','遉'=>'zhen','酙'=>'zhen','針'=>'zhen','鉁'=>'zhen','鋴'=>'zhen','錱'=>'zhen','鍖'=>'zhen','鍼'=>'zhen','鎭'=>'zhen','鎮'=>'zhen','针'=>'zhen','镇'=>'zhen','阵'=>'zhen','陣'=>'zhen','震'=>'zhen','靕'=>'zhen','駗'=>'zhen','鬒'=>'zhen','鱵'=>'zhen','鴆'=>'zhen','鸩'=>'zhen','黮'=>'zhen','黰'=>'zhen','㐱'=>'zhen','㓄'=>'zhen','㣀'=>'zhen','㪛'=>'zhen','㮳'=>'zhen','㯢'=>'zhen','㴨'=>'zhen','䂦'=>'zhen','䂧'=>'zhen','䊶'=>'zhen','䏖'=>'zhen','䑐'=>'zhen','䝩'=>'zhen','䟴'=>'zhen','䨯'=>'zhen','䪴'=>'zhen','䫬'=>'zhen','䲴'=>'zhen','䳲'=>'zhen','侧'=>'ce','側'=>'ce','冊'=>'ce','册'=>'ce','厕'=>'ce','厠'=>'ce','墄'=>'ce','廁'=>'ce','恻'=>'ce','惻'=>'ce','憡'=>'ce','拺'=>'ce','敇'=>'ce','测'=>'ce','測'=>'ce','畟'=>'ce','笧'=>'ce','策'=>'ce','筞'=>'ce','筴'=>'ce','箣'=>'ce','簎'=>'ce','粣'=>'ce','荝'=>'ce','萗'=>'ce','萴'=>'ce','蓛'=>'ce','㥽'=>'ce','㨲'=>'ce','㩍'=>'ce','䇲'=>'ce','䈟'=>'ce','䊂'=>'ce','䔴'=>'ce','䜺'=>'ce','侩'=>'kuai','儈'=>'kuai','凷'=>'kuai','哙'=>'kuai','噲'=>'kuai','圦'=>'kuai','块'=>'kuai','塊'=>'kuai','墤'=>'kuai','华科智软'=>'kuai','廥'=>'kuai','快'=>'kuai','擓'=>'kuai','旝'=>'kuai','狯'=>'kuai','獪'=>'kuai','筷'=>'kuai','糩'=>'kuai','脍'=>'kuai','膾'=>'kuai','蒯'=>'kuai','郐'=>'kuai','鄶'=>'kuai','鱠'=>'kuai','鲙'=>'kuai','㔞'=>'kuai','㙕'=>'kuai','㙗'=>'kuai','㟴'=>'kuai','㧟'=>'kuai','㬮'=>'kuai','㱮'=>'kuai','䈛'=>'kuai','䓒'=>'kuai','䭝'=>'kuai','䯤'=>'kuai','䶐'=>'kuai','侪'=>'chai','儕'=>'chai','勑'=>'chai','喍'=>'chai','囆'=>'chai','拆'=>'chai','柴'=>'chai','犲'=>'chai','瘥'=>'chai','祡'=>'chai','茝'=>'chai','虿'=>'chai','蠆'=>'chai','袃'=>'chai','豺'=>'chai','㑪'=>'chai','㳗'=>'chai','㾹'=>'chai','䓱'=>'chai','䘍'=>'chai','侬'=>'nong','儂'=>'nong','农'=>'nong','哝'=>'nong','噥'=>'nong','弄'=>'nong','憹'=>'nong','挊'=>'nong','挵'=>'nong','欁'=>'nong','浓'=>'nong','濃'=>'nong','癑'=>'nong','禯'=>'nong','秾'=>'nong','穠'=>'nong','繷'=>'nong','脓'=>'nong','膿'=>'nong','蕽'=>'nong','襛'=>'nong','農'=>'nong','辳'=>'nong','醲'=>'nong','齈'=>'nong','㶶'=>'nong','䁸'=>'nong','䢉'=>'nong','䵜'=>'nong','侯'=>'hou','候'=>'hou','厚'=>'hou','后'=>'hou','吼'=>'hou','吽'=>'hou','喉'=>'hou','垕'=>'hou','堠'=>'hou','帿'=>'hou','後'=>'hou','洉'=>'hou','犼'=>'hou','猴'=>'hou','瘊'=>'hou','睺'=>'hou','矦'=>'hou','篌'=>'hou','糇'=>'hou','翭'=>'hou','葔'=>'hou','豞'=>'hou','逅'=>'hou','郈'=>'hou','鄇'=>'hou','銗'=>'hou','鍭'=>'hou','餱'=>'hou','骺'=>'hou','鮜'=>'hou','鯸'=>'hou','鱟'=>'hou','鲎'=>'hou','鲘'=>'hou','齁'=>'hou','㕈'=>'hou','㖃'=>'hou','㗋'=>'hou','㤧'=>'hou','㫗'=>'hou','㬋'=>'hou','㮢'=>'hou','㸸'=>'hou','㺅'=>'hou','䂉'=>'hou','䗔'=>'hou','䙈'=>'hou','䞧'=>'hou','䪷'=>'hou','䫛'=>'hou','䳧'=>'hou','侰'=>'jiong','僒'=>'jiong','冂'=>'jiong','冋'=>'jiong','冏'=>'jiong','囧'=>'jiong','坰'=>'jiong','埛'=>'jiong','扃'=>'jiong','泂'=>'jiong','浻'=>'jiong','澃'=>'jiong','炯'=>'jiong','烱'=>'jiong','煚'=>'jiong','煛'=>'jiong','熲'=>'jiong','燑'=>'jiong','燛'=>'jiong','窘'=>'jiong','絅'=>'jiong','綗'=>'jiong','蘏'=>'jiong','蘔'=>'jiong','褧'=>'jiong','迥'=>'jiong','逈'=>'jiong','顈'=>'jiong','颎'=>'jiong','駉'=>'jiong','駫'=>'jiong','㑋'=>'jiong','㓏'=>'jiong','㖥'=>'jiong','㢠'=>'jiong','㤯'=>'jiong','㷗'=>'jiong','㷡'=>'jiong','䌹'=>'jiong','䐃'=>'jiong','䢛'=>'jiong','侽'=>'nan','南'=>'nan','喃'=>'nan','囡'=>'nan','娚'=>'nan','婻'=>'nan','戁'=>'nan','抩'=>'nan','揇'=>'nan','暔'=>'nan','枏'=>'nan','枬'=>'nan','柟'=>'nan','楠'=>'nan','湳'=>'nan','煵'=>'nan','男'=>'nan','畘'=>'nan','腩'=>'nan','莮'=>'nan','萳'=>'nan','蝻'=>'nan','諵'=>'nan','赧'=>'nan','遖'=>'nan','难'=>'nan','難'=>'nan','㓓'=>'nan','㫱'=>'nan','㽖'=>'nan','䁪'=>'nan','䈒'=>'nan','䔜'=>'nan','䔳'=>'nan','䕼'=>'nan','䛁'=>'nan','䶲'=>'nan','侾'=>'xiao','俲'=>'xiao','傚'=>'xiao','削'=>'xiao','効'=>'xiao','呺'=>'xiao','咲'=>'xiao','哓'=>'xiao','哮'=>'xiao','啋'=>'xiao','啸'=>'xiao','嘋'=>'xiao','嘐'=>'xiao','嘨'=>'xiao','嘯'=>'xiao','嘵'=>'xiao','嚣'=>'xiao','嚻'=>'xiao','囂'=>'xiao','婋'=>'xiao','孝'=>'xiao','宯'=>'xiao','宵'=>'xiao','小'=>'xiao','崤'=>'xiao','庨'=>'xiao','彇'=>'xiao','恔'=>'xiao','恷'=>'xiao','憢'=>'xiao','揱'=>'xiao','撨'=>'xiao','效'=>'xiao','敩'=>'xiao','斅'=>'xiao','斆'=>'xiao','晓'=>'xiao','暁'=>'xiao','曉'=>'xiao','枭'=>'xiao','枵'=>'xiao','校'=>'xiao','梟'=>'xiao','櫹'=>'xiao','歊'=>'xiao','歗'=>'xiao','毊'=>'xiao','洨'=>'xiao','消'=>'xiao','涍'=>'xiao','淆'=>'xiao','滧'=>'xiao','潇'=>'xiao','瀟'=>'xiao','灱'=>'xiao','灲'=>'xiao','焇'=>'xiao','熽'=>'xiao','猇'=>'xiao','獢'=>'xiao','痚'=>'xiao','痟'=>'xiao','皛'=>'xiao','皢'=>'xiao','硝'=>'xiao','硣'=>'xiao','穘'=>'xiao','窙'=>'xiao','笑'=>'xiao','筱'=>'xiao','筿'=>'xiao','箫'=>'xiao','篠'=>'xiao','簘'=>'xiao','簫'=>'xiao','綃'=>'xiao','绡'=>'xiao','翛'=>'xiao','肖'=>'xiao','膮'=>'xiao','萧'=>'xiao','萷'=>'xiao','蕭'=>'xiao','藃'=>'xiao','虈'=>'xiao','虓'=>'xiao','蟂'=>'xiao','蟏'=>'xiao','蟰'=>'xiao','蠨'=>'xiao','訤'=>'xiao','詨'=>'xiao','誟'=>'xiao','誵'=>'xiao','謏'=>'xiao','謞'=>'xiao','踃'=>'xiao','逍'=>'xiao','郩'=>'xiao','銷'=>'xiao','销'=>'xiao','霄'=>'xiao','驍'=>'xiao','骁'=>'xiao','髇'=>'xiao','髐'=>'xiao','魈'=>'xiao','鴞'=>'xiao','鴵'=>'xiao','鷍'=>'xiao','鸮'=>'xiao','㑾'=>'xiao','㔅'=>'xiao','㗛'=>'xiao','㚣'=>'xiao','㤊'=>'xiao','㬵'=>'xiao','㹲'=>'xiao','䊥'=>'xiao','䒕'=>'xiao','䒝'=>'xiao','䕧'=>'xiao','䥵'=>'xiao','便'=>'bian','匾'=>'bian','卞'=>'bian','变'=>'bian','変'=>'bian','峅'=>'bian','弁'=>'bian','徧'=>'bian','忭'=>'bian','惼'=>'bian','扁'=>'bian','抃'=>'bian','拚'=>'bian','揙'=>'bian','昪'=>'bian','汳'=>'bian','汴'=>'bian','炞'=>'bian','煸'=>'bian','牑'=>'bian','猵'=>'bian','獱'=>'bian','甂'=>'bian','砭'=>'bian','碥'=>'bian','稨'=>'bian','窆'=>'bian','笾'=>'bian','箯'=>'bian','籩'=>'bian','糄'=>'bian','編'=>'bian','緶'=>'bian','缏'=>'bian','编'=>'bian','艑'=>'bian','苄'=>'bian','萹'=>'bian','藊'=>'bian','蝙'=>'bian','褊'=>'bian','覍'=>'bian','變'=>'bian','貶'=>'bian','贬'=>'bian','辡'=>'bian','辧'=>'bian','辨'=>'bian','辩'=>'bian','辪'=>'bian','辫'=>'bian','辮'=>'bian','辯'=>'bian','边'=>'bian','遍'=>'bian','邉'=>'bian','邊'=>'bian','釆'=>'bian','鍽'=>'bian','閞'=>'bian','鞭'=>'bian','頨'=>'bian','鯾'=>'bian','鯿'=>'bian','鳊'=>'bian','鴘'=>'bian','㝸'=>'bian','㣐'=>'bian','㦚'=>'bian','㭓'=>'bian','㲢'=>'bian','㳎'=>'bian','㳒'=>'bian','㴜'=>'bian','㵷'=>'bian','㺹'=>'bian','㻞'=>'bian','䁵'=>'bian','䉸'=>'bian','䒪'=>'bian','䛒'=>'bian','䡢'=>'bian','䪻'=>'bian','俀'=>'tui','僓'=>'tui','娧'=>'tui','尵'=>'tui','推'=>'tui','煺'=>'tui','穨'=>'tui','脮'=>'tui','腿'=>'tui','蓷'=>'tui','藬'=>'tui','蘈'=>'tui','蛻'=>'tui','蜕'=>'tui','褪'=>'tui','蹆'=>'tui','蹪'=>'tui','退'=>'tui','隤'=>'tui','頹'=>'tui','頺'=>'tui','頽'=>'tui','颓'=>'tui','駾'=>'tui','骽'=>'tui','魋'=>'tui','㞂'=>'tui','㢈'=>'tui','㢑'=>'tui','㦌'=>'tui','㱣'=>'tui','㷟'=>'tui','㾯'=>'tui','㾼'=>'tui','㾽'=>'tui','㿉'=>'tui','㿗'=>'tui','䀃'=>'tui','䅪'=>'tui','䍾'=>'tui','䫋'=>'tui','促'=>'cu','噈'=>'cu','媨'=>'cu','徂'=>'cu','憱'=>'cu','殂'=>'cu','猝'=>'cu','瘄'=>'cu','瘯'=>'cu','簇'=>'cu','粗'=>'cu','縬'=>'cu','蔟'=>'cu','觕'=>'cu','誎'=>'cu','趗'=>'cu','踧'=>'cu','蹙'=>'cu','蹴'=>'cu','蹵'=>'cu','酢'=>'cu','醋'=>'cu','顣'=>'cu','麁'=>'cu','麄'=>'cu','麤'=>'cu','鼀'=>'cu','㗤'=>'cu','㰗'=>'cu','䃚'=>'cu','䎌'=>'cu','䓚'=>'cu','䙯'=>'cu','䛤'=>'cu','䟟'=>'cu','䠓'=>'cu','䠞'=>'cu','䢐'=>'cu','䥄'=>'cu','䥘'=>'cu','䬨'=>'cu','俄'=>'e','偔'=>'e','僫'=>'e','匎'=>'e','卾'=>'e','厄'=>'e','吪'=>'e','呃'=>'e','呝'=>'e','咢'=>'e','咹'=>'e','噁'=>'e','噩'=>'e','囮'=>'e','垩'=>'e','堊'=>'e','堮'=>'e','妸'=>'e','妿'=>'e','姶'=>'e','娥'=>'e','娿'=>'e','婀'=>'e','屙'=>'e','屵'=>'e','岋'=>'e','峉'=>'e','峨'=>'e','峩'=>'e','崿'=>'e','廅'=>'e','恶'=>'e','悪'=>'e','惡'=>'e','愕'=>'e','戹'=>'e','扼'=>'e','搤'=>'e','搹'=>'e','擜'=>'e','枙'=>'e','櫮'=>'e','歞'=>'e','歺'=>'e','涐'=>'e','湂'=>'e','珴'=>'e','琧'=>'e','皒'=>'e','睋'=>'e','砈'=>'e','砐'=>'e','砨'=>'e','硆'=>'e','磀'=>'e','腭'=>'e','苊'=>'e','莪'=>'e','萼'=>'e','蕚'=>'e','蚅'=>'e','蛾'=>'e','蝁'=>'e','覨'=>'e','訛'=>'e','詻'=>'e','誐'=>'e','諤'=>'e','譌'=>'e','讍'=>'e','讹'=>'e','谔'=>'e','豟'=>'e','軛'=>'e','軶'=>'e','轭'=>'e','迗'=>'e','遌'=>'e','遏'=>'e','遻'=>'e','鄂'=>'e','鈋'=>'e','鋨'=>'e','鍔'=>'e','鑩'=>'e','锇'=>'e','锷'=>'e','閼'=>'e','阏'=>'e','阨'=>'e','阸'=>'e','頞'=>'e','頟'=>'e','額'=>'e','顎'=>'e','颚'=>'e','额'=>'e','餓'=>'e','餩'=>'e','饿'=>'e','騀'=>'e','魤'=>'e','鰐'=>'e','鱷'=>'e','鳄'=>'e','鵈'=>'e','鵝'=>'e','鵞'=>'e','鶚'=>'e','鹅'=>'e','鹗'=>'e','齶'=>'e','㓵'=>'e','㔩'=>'e','㕎'=>'e','㖾'=>'e','㗁'=>'e','㟧'=>'e','㠋'=>'e','㡋'=>'e','㦍'=>'e','㧖'=>'e','㩵'=>'e','㮙'=>'e','㱦'=>'e','㷈'=>'e','㼂'=>'e','㼢'=>'e','㼰'=>'e','䄉'=>'e','䆓'=>'e','䑥'=>'e','䑪'=>'e','䓊'=>'e','䔾'=>'e','䕏'=>'e','䖸'=>'e','䙳'=>'e','䛖'=>'e','䝈'=>'e','䞩'=>'e','䣞'=>'e','䩹'=>'e','䫷'=>'e','䱮'=>'e','䳗'=>'e','䳘'=>'e','䳬'=>'e','俈'=>'ku','刳'=>'ku','哭'=>'ku','喾'=>'ku','嚳'=>'ku','圐'=>'ku','堀'=>'ku','崫'=>'ku','库'=>'ku','庫'=>'ku','扝'=>'ku','枯'=>'ku','桍'=>'ku','楛'=>'ku','焅'=>'ku','狜'=>'ku','瘔'=>'ku','矻'=>'ku','秙'=>'ku','窟'=>'ku','絝'=>'ku','绔'=>'ku','苦'=>'ku','袴'=>'ku','裤'=>'ku','褲'=>'ku','跍'=>'ku','郀'=>'ku','酷'=>'ku','骷'=>'ku','鮬'=>'ku','㒂'=>'ku','㠸'=>'ku','䇢'=>'ku','俊'=>'jun','儁'=>'jun','军'=>'jun','君'=>'jun','呁'=>'jun','均'=>'jun','埈'=>'jun','姰'=>'jun','寯'=>'jun','峻'=>'jun','懏'=>'jun','捃'=>'jun','攈'=>'jun','晙'=>'jun','桾'=>'jun','汮'=>'jun','浚'=>'jun','濬'=>'jun','焌'=>'jun','燇'=>'jun','珺'=>'jun','畯'=>'jun','皲'=>'jun','皸'=>'jun','皹'=>'jun','碅'=>'jun','竣'=>'jun','筠'=>'jun','箘'=>'jun','箟'=>'jun','莙'=>'jun','菌'=>'jun','蚐'=>'jun','蜠'=>'jun','袀'=>'jun','覠'=>'jun','軍'=>'jun','郡'=>'jun','鈞'=>'jun','銁'=>'jun','銞'=>'jun','鍕'=>'jun','钧'=>'jun','陖'=>'jun','餕'=>'jun','馂'=>'jun','駿'=>'jun','骏'=>'jun','鮶'=>'jun','鲪'=>'jun','鵔'=>'jun','鵕'=>'jun','鵘'=>'jun','麇'=>'jun','麏'=>'jun','麕'=>'jun','㑺'=>'jun','㒞'=>'jun','㓴'=>'jun','㕙'=>'jun','㝦'=>'jun','㴫'=>'jun','㻒'=>'jun','㽙'=>'jun','䇹'=>'jun','䕑'=>'jun','䜭'=>'jun','䝍'=>'jun','俎'=>'zu','傶'=>'zu','卆'=>'zu','卒'=>'zu','哫'=>'zu','崒'=>'zu','崪'=>'zu','族'=>'zu','爼'=>'zu','珇'=>'zu','祖'=>'zu','租'=>'zu','稡'=>'zu','箤'=>'zu','組'=>'zu','组'=>'zu','菹'=>'zu','葅'=>'zu','蒩'=>'zu','詛'=>'zu','謯'=>'zu','诅'=>'zu','足'=>'zu','踤'=>'zu','踿'=>'zu','鎺'=>'zu','鏃'=>'zu','镞'=>'zu','阻'=>'zu','靻'=>'zu','㞺'=>'zu','㰵'=>'zu','㲞'=>'zu','䅸'=>'zu','䔃'=>'zu','䖕'=>'zu','䚝'=>'zu','䯿'=>'zu','䱣'=>'zu','俒'=>'hun','倱'=>'hun','圂'=>'hun','婚'=>'hun','忶'=>'hun','惛'=>'hun','惽'=>'hun','慁'=>'hun','掍'=>'hun','昏'=>'hun','昬'=>'hun','棔'=>'hun','殙'=>'hun','浑'=>'hun','涽'=>'hun','混'=>'hun','渾'=>'hun','溷'=>'hun','焝'=>'hun','睧'=>'hun','睯'=>'hun','繉'=>'hun','荤'=>'hun','葷'=>'hun','觨'=>'hun','諢'=>'hun','诨'=>'hun','轋'=>'hun','閽'=>'hun','阍'=>'hun','餛'=>'hun','馄'=>'hun','魂'=>'hun','鼲'=>'hun','㑮'=>'hun','㥵'=>'hun','㨡'=>'hun','䅙'=>'hun','䅱'=>'hun','䚠'=>'hun','䛰'=>'hun','䧰'=>'hun','䫟'=>'hun','䰟'=>'hun','䴷'=>'hun','俗'=>'su','傃'=>'su','僳'=>'su','嗉'=>'su','嗽'=>'su','囌'=>'su','塐'=>'su','塑'=>'su','夙'=>'su','嫊'=>'su','宿'=>'su','愫'=>'su','愬'=>'su','憟'=>'su','梀'=>'su','榡'=>'su','樎'=>'su','樕'=>'su','橚'=>'su','櫯'=>'su','殐'=>'su','泝'=>'su','洬'=>'su','涑'=>'su','溯'=>'su','溸'=>'su','潚'=>'su','潥'=>'su','玊'=>'su','珟'=>'su','璛'=>'su','甦'=>'su','碿'=>'su','稣'=>'su','穌'=>'su','窣'=>'su','簌'=>'su','粛'=>'su','粟'=>'su','素'=>'su','縤'=>'su','肃'=>'su','肅'=>'su','膆'=>'su','苏'=>'su','蔌'=>'su','藗'=>'su','蘇'=>'su','蘓'=>'su','觫'=>'su','訴'=>'su','謖'=>'su','诉'=>'su','谡'=>'su','趚'=>'su','蹜'=>'su','速'=>'su','遡'=>'su','遬'=>'su','酥'=>'su','鋉'=>'su','餗'=>'su','驌'=>'su','骕'=>'su','鯂'=>'su','鱐'=>'su','鷫'=>'su','鹔'=>'su','㑉'=>'su','㑛'=>'su','㓘'=>'su','㔄'=>'su','㕖'=>'su','㜚'=>'su','㝛'=>'su','㨞'=>'su','㩋'=>'su','㪩'=>'su','㬘'=>'su','㯈'=>'su','㴋'=>'su','㴑'=>'su','㴼'=>'su','䃤'=>'su','䅇'=>'su','䌚'=>'su','䎘'=>'su','䏋'=>'su','䑿'=>'su','䔎'=>'su','䘻'=>'su','䛾'=>'su','䥔'=>'su','俩'=>'lia','倆'=>'lia','俳'=>'pai','哌'=>'pai','徘'=>'pai','拍'=>'pai','排'=>'pai','棑'=>'pai','派'=>'pai','湃'=>'pai','牌'=>'pai','犤'=>'pai','猅'=>'pai','磗'=>'pai','箄'=>'pai','簰'=>'pai','蒎'=>'pai','輫'=>'pai','鎃'=>'pai','㭛'=>'pai','㵺'=>'pai','䖰'=>'pai','俵'=>'biao','儦'=>'biao','墂'=>'biao','婊'=>'biao','幖'=>'biao','彪'=>'biao','摽'=>'biao','杓'=>'biao','标'=>'biao','標'=>'biao','檦'=>'biao','淲'=>'biao','滮'=>'biao','瀌'=>'biao','灬'=>'biao','熛'=>'biao','爂'=>'biao','猋'=>'biao','瘭'=>'biao','穮'=>'biao','脿'=>'biao','膘'=>'biao','臕'=>'biao','蔈'=>'biao','藨'=>'biao','表'=>'biao','裱'=>'biao','褾'=>'biao','諘'=>'biao','謤'=>'biao','贆'=>'biao','錶'=>'biao','鏢'=>'biao','鑣'=>'biao','镖'=>'biao','镳'=>'biao','颮'=>'biao','颷'=>'biao','飆'=>'biao','飇'=>'biao','飈'=>'biao','飊'=>'biao','飑'=>'biao','飙'=>'biao','飚'=>'biao','驃'=>'biao','驫'=>'biao','骉'=>'biao','骠'=>'biao','髟'=>'biao','鰾'=>'biao','鳔'=>'biao','麃'=>'biao','㟽'=>'biao','㠒'=>'biao','㧼'=>'biao','㯱'=>'biao','㯹'=>'biao','䔸'=>'biao','䞄'=>'biao','俷'=>'fei','剕'=>'fei','匪'=>'fei','厞'=>'fei','吠'=>'fei','啡'=>'fei','奜'=>'fei','妃'=>'fei','婓'=>'fei','婔'=>'fei','屝'=>'fei','废'=>'fei','廃'=>'fei','廢'=>'fei','悱'=>'fei','扉'=>'fei','斐'=>'fei','昲'=>'fei','暃'=>'fei','曊'=>'fei','朏'=>'fei','杮'=>'fei','棐'=>'fei','榧'=>'fei','櫠'=>'fei','沸'=>'fei','淝'=>'fei','渄'=>'fei','濷'=>'fei','狒'=>'fei','猆'=>'fei','疿'=>'fei','痱'=>'fei','癈'=>'fei','篚'=>'fei','緋'=>'fei','绯'=>'fei','翡'=>'fei','肥'=>'fei','肺'=>'fei','胐'=>'fei','腓'=>'fei','菲'=>'fei','萉'=>'fei','蕜'=>'fei','蕟'=>'fei','蜚'=>'fei','蜰'=>'fei','蟦'=>'fei','裶'=>'fei','誹'=>'fei','诽'=>'fei','費'=>'fei','费'=>'fei','鐨'=>'fei','镄'=>'fei','霏'=>'fei','靅'=>'fei','非'=>'fei','靟'=>'fei','飛'=>'fei','飝'=>'fei','飞'=>'fei','餥'=>'fei','馡'=>'fei','騑'=>'fei','騛'=>'fei','鯡'=>'fei','鲱'=>'fei','鼣'=>'fei','㔗'=>'fei','㥱'=>'fei','㩌'=>'fei','㭭'=>'fei','㵒'=>'fei','䆏'=>'fei','䈈'=>'fei','䉬'=>'fei','䑔'=>'fei','䕁'=>'fei','䕠'=>'fei','䚨'=>'fei','䛍'=>'fei','䠊'=>'fei','䤵'=>'fei','䨽'=>'fei','䨾'=>'fei','䰁'=>'fei','俻'=>'bei','倍'=>'bei','偝'=>'bei','偹'=>'bei','備'=>'bei','僃'=>'bei','北'=>'bei','卑'=>'bei','喺'=>'bei','备'=>'bei','悖'=>'bei','悲'=>'bei','惫'=>'bei','愂'=>'bei','憊'=>'bei','揹'=>'bei','昁'=>'bei','杯'=>'bei','桮'=>'bei','梖'=>'bei','焙'=>'bei','牬'=>'bei','犕'=>'bei','狈'=>'bei','狽'=>'bei','珼'=>'bei','琲'=>'bei','盃'=>'bei','碑'=>'bei','碚'=>'bei','禙'=>'bei','糒'=>'bei','背'=>'bei','苝'=>'bei','蓓'=>'bei','藣'=>'bei','蛽'=>'bei','被'=>'bei','褙'=>'bei','誖'=>'bei','貝'=>'bei','贝'=>'bei','軰'=>'bei','輩'=>'bei','辈'=>'bei','邶'=>'bei','鄁'=>'bei','鉳'=>'bei','鋇'=>'bei','鐾'=>'bei','钡'=>'bei','陂'=>'bei','鞴'=>'bei','骳'=>'bei','鵯'=>'bei','鹎'=>'bei','㔨'=>'bei','㛝'=>'bei','㣁'=>'bei','㤳'=>'bei','㰆'=>'bei','㶔'=>'bei','㷶'=>'bei','㸢'=>'bei','㸬'=>'bei','㸽'=>'bei','㻗'=>'bei','㼎'=>'bei','㾱'=>'bei','䁅'=>'bei','䋳'=>'bei','䔒'=>'bei','䠙'=>'bei','䡶'=>'bei','䩀'=>'bei','䰽'=>'bei','倊'=>'zong','倧'=>'zong','偬'=>'zong','傯'=>'zong','堫'=>'zong','宗'=>'zong','嵏'=>'zong','嵕'=>'zong','嵸'=>'zong','总'=>'zong','惣'=>'zong','惾'=>'zong','愡'=>'zong','捴'=>'zong','揔'=>'zong','搃'=>'zong','摠'=>'zong','昮'=>'zong','朡'=>'zong','棕'=>'zong','椶'=>'zong','熧'=>'zong','燪'=>'zong','猔'=>'zong','猣'=>'zong','疭'=>'zong','瘲'=>'zong','碂'=>'zong','磫'=>'zong','稯'=>'zong','粽'=>'zong','糉'=>'zong','綜'=>'zong','緃'=>'zong','総'=>'zong','緵'=>'zong','縂'=>'zong','縦'=>'zong','縱'=>'zong','總'=>'zong','纵'=>'zong','综'=>'zong','翪'=>'zong','腙'=>'zong','艐'=>'zong','葼'=>'zong','蓗'=>'zong','蝬'=>'zong','豵'=>'zong','踨'=>'zong','踪'=>'zong','蹤'=>'zong','錝'=>'zong','鍯'=>'zong','鏓'=>'zong','鑁'=>'zong','騌'=>'zong','騣'=>'zong','骔'=>'zong','鬃'=>'zong','鬉'=>'zong','鬷'=>'zong','鯮'=>'zong','鯼'=>'zong','㢔'=>'zong','㯶'=>'zong','㷓'=>'zong','㹅'=>'zong','䍟'=>'zong','䝋'=>'zong','䰌'=>'zong','倎'=>'tian','兲'=>'tian','唺'=>'tian','塡'=>'tian','填'=>'tian','天'=>'tian','婖'=>'tian','屇'=>'tian','忝'=>'tian','恬'=>'tian','悿'=>'tian','捵'=>'tian','掭'=>'tian','搷'=>'tian','晪'=>'tian','殄'=>'tian','沺'=>'tian','淟'=>'tian','添'=>'tian','湉'=>'tian','琠'=>'tian','瑱'=>'tian','璳'=>'tian','甛'=>'tian','甜'=>'tian','田'=>'tian','畋'=>'tian','畑'=>'tian','畠'=>'tian','痶'=>'tian','盷'=>'tian','睓'=>'tian','睼'=>'tian','碵'=>'tian','磌'=>'tian','窴'=>'tian','緂'=>'tian','胋'=>'tian','腆'=>'tian','舔'=>'tian','舚'=>'tian','菾'=>'tian','覥'=>'tian','觍'=>'tian','賟'=>'tian','酟'=>'tian','錪'=>'tian','闐'=>'tian','阗'=>'tian','靔'=>'tian','靝'=>'tian','靦'=>'tian','餂'=>'tian','鴫'=>'tian','鷆'=>'tian','鷏'=>'tian','黇'=>'tian','㐁'=>'tian','㖭'=>'tian','㙉'=>'tian','㥏'=>'tian','㧂'=>'tian','㮇'=>'tian','㶺'=>'tian','䄼'=>'tian','䄽'=>'tian','䐌'=>'tian','䑚'=>'tian','䟧'=>'tian','䠄'=>'tian','䡒'=>'tian','䡘'=>'tian','䣯'=>'tian','䥖'=>'tian','䩄'=>'tian','倒'=>'dao','刀'=>'dao','刂'=>'dao','到'=>'dao','叨'=>'dao','噵'=>'dao','壔'=>'dao','宲'=>'dao','导'=>'dao','導'=>'dao','屶'=>'dao','岛'=>'dao','島'=>'dao','嶋'=>'dao','嶌'=>'dao','嶹'=>'dao','忉'=>'dao','悼'=>'dao','捣'=>'dao','捯'=>'dao','搗'=>'dao','擣'=>'dao','朷'=>'dao','椡'=>'dao','槝'=>'dao','檤'=>'dao','氘'=>'dao','焘'=>'dao','燾'=>'dao','瓙'=>'dao','盗'=>'dao','盜'=>'dao','祷'=>'dao','禂'=>'dao','禱'=>'dao','稲'=>'dao','稻'=>'dao','纛'=>'dao','翢'=>'dao','翿'=>'dao','舠'=>'dao','菿'=>'dao','衜'=>'dao','衟'=>'dao','蹈'=>'dao','軇'=>'dao','道'=>'dao','釖'=>'dao','陦'=>'dao','隝'=>'dao','隯'=>'dao','魛'=>'dao','鱽'=>'dao','㠀'=>'dao','㿒'=>'dao','䆃'=>'dao','䌦'=>'dao','䧂'=>'dao','䲽'=>'dao','倓'=>'tan','傝'=>'tan','僋'=>'tan','叹'=>'tan','啴'=>'tan','嗿'=>'tan','嘆'=>'tan','嘽'=>'tan','坍'=>'tan','坛'=>'tan','坦'=>'tan','埮'=>'tan','墰'=>'tan','墵'=>'tan','壇'=>'tan','壜'=>'tan','婒'=>'tan','弾'=>'tan','忐'=>'tan','怹'=>'tan','惔'=>'tan','憛'=>'tan','憳'=>'tan','憻'=>'tan','探'=>'tan','摊'=>'tan','撢'=>'tan','擹'=>'tan','攤'=>'tan','昙'=>'tan','暺'=>'tan','曇'=>'tan','榃'=>'tan','橝'=>'tan','檀'=>'tan','歎'=>'tan','毯'=>'tan','湠'=>'tan','滩'=>'tan','潬'=>'tan','潭'=>'tan','灘'=>'tan','炭'=>'tan','璮'=>'tan','痑'=>'tan','痰'=>'tan','瘫'=>'tan','癱'=>'tan','碳'=>'tan','罈'=>'tan','罎'=>'tan','舑'=>'tan','舕'=>'tan','菼'=>'tan','藫'=>'tan','袒'=>'tan','襢'=>'tan','覃'=>'tan','談'=>'tan','譚'=>'tan','譠'=>'tan','谈'=>'tan','谭'=>'tan','貚'=>'tan','貪'=>'tan','賧'=>'tan','贪'=>'tan','赕'=>'tan','郯'=>'tan','醈'=>'tan','醓'=>'tan','醰'=>'tan','鉭'=>'tan','錟'=>'tan','钽'=>'tan','锬'=>'tan','顃'=>'tan','鷤'=>'tan','㲜'=>'tan','㲭'=>'tan','㷋'=>'tan','㽑'=>'tan','䃪'=>'tan','䆱'=>'tan','䉡'=>'tan','䊤'=>'tan','䏙'=>'tan','䐺'=>'tan','䕊'=>'tan','䜖'=>'tan','䞡'=>'tan','䦔'=>'tan','倕'=>'chui','吹'=>'chui','垂'=>'chui','埀'=>'chui','捶'=>'chui','搥'=>'chui','桘'=>'chui','棰'=>'chui','槌'=>'chui','炊'=>'chui','箠'=>'chui','腄'=>'chui','菙'=>'chui','錘'=>'chui','鎚'=>'chui','锤'=>'chui','陲'=>'chui','顀'=>'chui','龡'=>'chui','㓃'=>'chui','㝽'=>'chui','㥨'=>'chui','㩾'=>'chui','䄲'=>'chui','䍋'=>'chui','䞼'=>'chui','䳠'=>'chui','倘'=>'tang','偒'=>'tang','傏'=>'tang','傥'=>'tang','儻'=>'tang','劏'=>'tang','唐'=>'tang','啺'=>'tang','嘡'=>'tang','坣'=>'tang','堂'=>'tang','塘'=>'tang','嵣'=>'tang','帑'=>'tang','戃'=>'tang','搪'=>'tang','摥'=>'tang','曭'=>'tang','棠'=>'tang','榶'=>'tang','樘'=>'tang','橖'=>'tang','汤'=>'tang','淌'=>'tang','湯'=>'tang','溏'=>'tang','漟'=>'tang','烫'=>'tang','煻'=>'tang','燙'=>'tang','爣'=>'tang','瑭'=>'tang','矘'=>'tang','磄'=>'tang','禟'=>'tang','篖'=>'tang','糃'=>'tang','糖'=>'tang','糛'=>'tang','羰'=>'tang','耥'=>'tang','膅'=>'tang','膛'=>'tang','蓎'=>'tang','薚'=>'tang','蝪'=>'tang','螗'=>'tang','螳'=>'tang','赯'=>'tang','趟'=>'tang','踼'=>'tang','蹚'=>'tang','躺'=>'tang','鄌'=>'tang','醣'=>'tang','鎕'=>'tang','鎲'=>'tang','鏜'=>'tang','鐋'=>'tang','钂'=>'tang','铴'=>'tang','镋'=>'tang','镗'=>'tang','闛'=>'tang','隚'=>'tang','鞺'=>'tang','餳'=>'tang','餹'=>'tang','饄'=>'tang','饧'=>'tang','鶶'=>'tang','鼞'=>'tang','㑽'=>'tang','㒉'=>'tang','㙶'=>'tang','㜍'=>'tang','㭻'=>'tang','㲥'=>'tang','㼺'=>'tang','㿩'=>'tang','䅯'=>'tang','䉎'=>'tang','䌅'=>'tang','䟖'=>'tang','䣘'=>'tang','䧜'=>'tang','倥'=>'kong','埪'=>'kong','孔'=>'kong','崆'=>'kong','恐'=>'kong','悾'=>'kong','控'=>'kong','涳'=>'kong','硿'=>'kong','空'=>'kong','箜'=>'kong','躻'=>'kong','躼'=>'kong','錓'=>'kong','鞚'=>'kong','鵼'=>'kong','㤟'=>'kong','㸜'=>'kong','倦'=>'juan','劵'=>'juan','勌'=>'juan','勬'=>'juan','卷'=>'juan','呟'=>'juan','埍'=>'juan','奆'=>'juan','姢'=>'juan','娟'=>'juan','帣'=>'juan','弮'=>'juan','慻'=>'juan','捐'=>'juan','捲'=>'juan','桊'=>'juan','涓'=>'juan','淃'=>'juan','狷'=>'juan','獧'=>'juan','瓹'=>'juan','眷'=>'juan','睊'=>'juan','睠'=>'juan','絭'=>'juan','絹'=>'juan','绢'=>'juan','罥'=>'juan','羂'=>'juan','脧'=>'juan','臇'=>'juan','菤'=>'juan','蔨'=>'juan','蠲'=>'juan','裐'=>'juan','鄄'=>'juan','鋑'=>'juan','鋗'=>'juan','錈'=>'juan','鎸'=>'juan','鐫'=>'juan','锩'=>'juan','镌'=>'juan','隽'=>'juan','雋'=>'juan','飬'=>'juan','餋'=>'juan','鵑'=>'juan','鹃'=>'juan','㢧'=>'juan','㢾'=>'juan','㪻'=>'juan','㯞'=>'juan','㷷'=>'juan','䄅'=>'juan','䌸'=>'juan','䖭'=>'juan','䚈'=>'juan','䡓'=>'juan','䳪'=>'juan','倮'=>'luo','儸'=>'luo','剆'=>'luo','啰'=>'luo','囉'=>'luo','峈'=>'luo','捋'=>'luo','摞'=>'luo','攞'=>'luo','曪'=>'luo','椤'=>'luo','欏'=>'luo','泺'=>'luo','洛'=>'luo','洜'=>'luo','漯'=>'luo','濼'=>'luo','犖'=>'luo','猡'=>'luo','玀'=>'luo','珞'=>'luo','瘰'=>'luo','癳'=>'luo','砢'=>'luo','笿'=>'luo','箩'=>'luo','籮'=>'luo','絡'=>'luo','纙'=>'luo','络'=>'luo','罗'=>'luo','羅'=>'luo','脶'=>'luo','腡'=>'luo','臝'=>'luo','荦'=>'luo','萝'=>'luo','落'=>'luo','蓏'=>'luo','蘿'=>'luo','螺'=>'luo','蠃'=>'luo','裸'=>'luo','覶'=>'luo','覼'=>'luo','躶'=>'luo','逻'=>'luo','邏'=>'luo','鏍'=>'luo','鑼'=>'luo','锣'=>'luo','镙'=>'luo','雒'=>'luo','頱'=>'luo','饠'=>'luo','駱'=>'luo','騾'=>'luo','驘'=>'luo','骆'=>'luo','骡'=>'luo','鮥'=>'luo','鱳'=>'luo','鵅'=>'luo','鸁'=>'luo','㑩'=>'luo','㒩'=>'luo','㓢'=>'luo','㦬'=>'luo','㩡'=>'luo','㰁'=>'luo','㱻'=>'luo','㴖'=>'luo','㼈'=>'luo','㽋'=>'luo','㿚'=>'luo','䀩'=>'luo','䇔'=>'luo','䈷'=>'luo','䊨'=>'luo','䌱'=>'luo','䌴'=>'luo','䯁'=>'luo','倯'=>'song','傱'=>'song','凇'=>'song','娀'=>'song','宋'=>'song','崧'=>'song','嵩'=>'song','嵷'=>'song','庺'=>'song','忪'=>'song','怂'=>'song','悚'=>'song','愯'=>'song','慫'=>'song','憽'=>'song','捒'=>'song','松'=>'song','枀'=>'song','枩'=>'song','柗'=>'song','梥'=>'song','檧'=>'song','淞'=>'song','濍'=>'song','硹'=>'song','竦'=>'song','耸'=>'song','聳'=>'song','菘'=>'song','蜙'=>'song','訟'=>'song','誦'=>'song','讼'=>'song','诵'=>'song','送'=>'song','鎹'=>'song','頌'=>'song','颂'=>'song','餸'=>'song','駷'=>'song','鬆'=>'song','㕬'=>'song','㧐'=>'song','㨦'=>'song','㩳'=>'song','㮸'=>'song','䉥'=>'song','䛦'=>'song','䜬'=>'song','䢠'=>'song','倰'=>'leng','冷'=>'leng','堎'=>'leng','塄'=>'leng','愣'=>'leng','棱'=>'leng','楞'=>'leng','睖'=>'leng','碐'=>'leng','稜'=>'leng','薐'=>'leng','踜'=>'leng','䉄'=>'leng','䚏'=>'leng','䬋'=>'leng','䮚'=>'leng','倴'=>'ben','坌'=>'ben','奔'=>'ben','奙'=>'ben','捹'=>'ben','撪'=>'ben','本'=>'ben','桳'=>'ben','楍'=>'ben','泍'=>'ben','渀'=>'ben','犇'=>'ben','獖'=>'ben','畚'=>'ben','笨'=>'ben','苯'=>'ben','賁'=>'ben','贲'=>'ben','輽'=>'ben','逩'=>'ben','錛'=>'ben','锛'=>'ben','㡷'=>'ben','㤓'=>'ben','㨧'=>'ben','㮺'=>'ben','㱵'=>'ben','䬱'=>'ben','债'=>'zhai','債'=>'zhai','夈'=>'zhai','宅'=>'zhai','寨'=>'zhai','捚'=>'zhai','摘'=>'zhai','斋'=>'zhai','斎'=>'zhai','斏'=>'zhai','榸'=>'zhai','瘵'=>'zhai','砦'=>'zhai','窄'=>'zhai','粂'=>'zhai','鉙'=>'zhai','齋'=>'zhai','㡯'=>'zhai','㩟'=>'zhai','倾'=>'qing','傾'=>'qing','儬'=>'qing','凊'=>'qing','剠'=>'qing','勍'=>'qing','卿'=>'qing','圊'=>'qing','埥'=>'qing','夝'=>'qing','庆'=>'qing','庼'=>'qing','廎'=>'qing','情'=>'qing','慶'=>'qing','掅'=>'qing','擎'=>'qing','擏'=>'qing','晴'=>'qing','暒'=>'qing','棾'=>'qing','樈'=>'qing','檠'=>'qing','檾'=>'qing','櫦'=>'qing','殑'=>'qing','殸'=>'qing','氢'=>'qing','氫'=>'qing','氰'=>'qing','淸'=>'qing','清'=>'qing','漀'=>'qing','濪'=>'qing','甠'=>'qing','硘'=>'qing','碃'=>'qing','磬'=>'qing','箐'=>'qing','罄'=>'qing','苘'=>'qing','葝'=>'qing','蜻'=>'qing','請'=>'qing','謦'=>'qing','请'=>'qing','軽'=>'qing','輕'=>'qing','轻'=>'qing','郬'=>'qing','鑋'=>'qing','靑'=>'qing','青'=>'qing','靘'=>'qing','頃'=>'qing','顷'=>'qing','鯖'=>'qing','鲭'=>'qing','黥'=>'qing','㯳'=>'qing','㷫'=>'qing','䋜'=>'qing','䌠'=>'qing','䔛'=>'qing','䝼'=>'qing','䞍'=>'qing','䯧'=>'qing','䲔'=>'qing','偀'=>'ying','僌'=>'ying','啨'=>'ying','営'=>'ying','嘤'=>'ying','噟'=>'ying','嚶'=>'ying','塋'=>'ying','婴'=>'ying','媖'=>'ying','媵'=>'ying','嫈'=>'ying','嬰'=>'ying','嬴'=>'ying','孆'=>'ying','孾'=>'ying','巆'=>'ying','巊'=>'ying','应'=>'ying','廮'=>'ying','影'=>'ying','応'=>'ying','愥'=>'ying','應'=>'ying','摬'=>'ying','撄'=>'ying','攍'=>'ying','攖'=>'ying','攚'=>'ying','映'=>'ying','暎'=>'ying','朠'=>'ying','桜'=>'ying','梬'=>'ying','楹'=>'ying','樱'=>'ying','櫻'=>'ying','櫿'=>'ying','浧'=>'ying','渶'=>'ying','溁'=>'ying','溋'=>'ying','滎'=>'ying','滢'=>'ying','潁'=>'ying','潆'=>'ying','濙'=>'ying','濚'=>'ying','濴'=>'ying','瀅'=>'ying','瀛'=>'ying','瀠'=>'ying','瀯'=>'ying','瀴'=>'ying','灐'=>'ying','灜'=>'ying','煐'=>'ying','熒'=>'ying','營'=>'ying','珱'=>'ying','瑛'=>'ying','瑩'=>'ying','璎'=>'ying','瓔'=>'ying','甇'=>'ying','甖'=>'ying','瘿'=>'ying','癭'=>'ying','盁'=>'ying','盈'=>'ying','矨'=>'ying','硬'=>'ying','碤'=>'ying','礯'=>'ying','穎'=>'ying','籝'=>'ying','籯'=>'ying','緓'=>'ying','縈'=>'ying','纓'=>'ying','绬'=>'ying','缨'=>'ying','罂'=>'ying','罃'=>'ying','罌'=>'ying','膡'=>'ying','膺'=>'ying','英'=>'ying','茔'=>'ying','荥'=>'ying','荧'=>'ying','莹'=>'ying','莺'=>'ying','萤'=>'ying','营'=>'ying','萦'=>'ying','萾'=>'ying','蓥'=>'ying','藀'=>'ying','蘡'=>'ying','蛍'=>'ying','蝇'=>'ying','蝧'=>'ying','蝿'=>'ying','螢'=>'ying','蠅'=>'ying','蠳'=>'ying','褮'=>'ying','覮'=>'ying','謍'=>'ying','譍'=>'ying','譻'=>'ying','賏'=>'ying','贏'=>'ying','赢'=>'ying','軈'=>'ying','迎'=>'ying','郢'=>'ying','鎣'=>'ying','鐛'=>'ying','鑍'=>'ying','锳'=>'ying','霙'=>'ying','鞕'=>'ying','韺'=>'ying','頴'=>'ying','颍'=>'ying','颕'=>'ying','颖'=>'ying','鴬'=>'ying','鶧'=>'ying','鶯'=>'ying','鷪'=>'ying','鷹'=>'ying','鸎'=>'ying','鸚'=>'ying','鹦'=>'ying','鹰'=>'ying','㑞'=>'ying','㢍'=>'ying','㨕'=>'ying','㯋'=>'ying','㲟'=>'ying','㴄'=>'ying','㵬'=>'ying','㶈'=>'ying','㹙'=>'ying','㹚'=>'ying','㿘'=>'ying','䀴'=>'ying','䁐'=>'ying','䁝'=>'ying','䃷'=>'ying','䇾'=>'ying','䑉'=>'ying','䕦'=>'ying','䙬'=>'ying','䤝'=>'ying','䨍'=>'ying','䪯'=>'ying','䭊'=>'ying','䭗'=>'ying','偄'=>'ruan','堧'=>'ruan','壖'=>'ruan','媆'=>'ruan','嫰'=>'ruan','愞'=>'ruan','撋'=>'ruan','朊'=>'ruan','瑌'=>'ruan','瓀'=>'ruan','碝'=>'ruan','礝'=>'ruan','緛'=>'ruan','耎'=>'ruan','腝'=>'ruan','蝡'=>'ruan','軟'=>'ruan','輭'=>'ruan','软'=>'ruan','阮'=>'ruan','㼱'=>'ruan','㽭'=>'ruan','䓴'=>'ruan','䞂'=>'ruan','䪭'=>'ruan','偆'=>'chun','唇'=>'chun','堾'=>'chun','媋'=>'chun','惷'=>'chun','旾'=>'chun','春'=>'chun','暙'=>'chun','杶'=>'chun','椿'=>'chun','槆'=>'chun','橁'=>'chun','櫄'=>'chun','浱'=>'chun','淳'=>'chun','湻'=>'chun','滣'=>'chun','漘'=>'chun','犉'=>'chun','瑃'=>'chun','睶'=>'chun','箺'=>'chun','純'=>'chun','纯'=>'chun','脣'=>'chun','莼'=>'chun','萅'=>'chun','萶'=>'chun','蒓'=>'chun','蓴'=>'chun','蝽'=>'chun','蠢'=>'chun','賰'=>'chun','踳'=>'chun','輴'=>'chun','醇'=>'chun','醕'=>'chun','錞'=>'chun','陙'=>'chun','鯙'=>'chun','鰆'=>'chun','鶉'=>'chun','鶞'=>'chun','鹑'=>'chun','㖺'=>'chun','㝄'=>'chun','㝇'=>'chun','㵮'=>'chun','㸪'=>'chun','㿤'=>'chun','䄝'=>'chun','䏛'=>'chun','䏝'=>'chun','䐇'=>'chun','䐏'=>'chun','䓐'=>'chun','䔚'=>'chun','䞐'=>'chun','䣨'=>'chun','䣩'=>'chun','䥎'=>'chun','䦮'=>'chun','䫃'=>'chun','偌'=>'ruo','叒'=>'ruo','婼'=>'ruo','嵶'=>'ruo','弱'=>'ruo','挼'=>'ruo','捼'=>'ruo','楉'=>'ruo','渃'=>'ruo','焫'=>'ruo','爇'=>'ruo','箬'=>'ruo','篛'=>'ruo','若'=>'ruo','蒻'=>'ruo','鄀'=>'ruo','鰙'=>'ruo','鰯'=>'ruo','鶸'=>'ruo','䐞'=>'ruo','偏'=>'pian','囨'=>'pian','媥'=>'pian','楄'=>'pian','楩'=>'pian','片'=>'pian','犏'=>'pian','篇'=>'pian','翩'=>'pian','胼'=>'pian','腁'=>'pian','覑'=>'pian','諚'=>'pian','諞'=>'pian','谝'=>'pian','貵'=>'pian','賆'=>'pian','蹁'=>'pian','駢'=>'pian','騈'=>'pian','騗'=>'pian','騙'=>'pian','骈'=>'pian','骗'=>'pian','骿'=>'pian','魸'=>'pian','鶣'=>'pian','㓲'=>'pian','㛹'=>'pian','㸤'=>'pian','㼐'=>'pian','䏒'=>'pian','䮁'=>'pian','偗'=>'sheng','剩'=>'sheng','剰'=>'sheng','勝'=>'sheng','升'=>'sheng','呏'=>'sheng','圣'=>'sheng','墭'=>'sheng','声'=>'sheng','嵊'=>'sheng','憴'=>'sheng','斘'=>'sheng','昇'=>'sheng','晟'=>'sheng','晠'=>'sheng','曻'=>'sheng','枡'=>'sheng','榺'=>'sheng','橳'=>'sheng','殅'=>'sheng','泩'=>'sheng','渑'=>'sheng','渻'=>'sheng','湦'=>'sheng','澠'=>'sheng','焺'=>'sheng','牲'=>'sheng','珄'=>'sheng','琞'=>'sheng','生'=>'sheng','甥'=>'sheng','盛'=>'sheng','省'=>'sheng','眚'=>'sheng','竔'=>'sheng','笙'=>'sheng','縄'=>'sheng','繩'=>'sheng','绳'=>'sheng','聖'=>'sheng','聲'=>'sheng','胜'=>'sheng','苼'=>'sheng','蕂'=>'sheng','譝'=>'sheng','貹'=>'sheng','賸'=>'sheng','鉎'=>'sheng','鍟'=>'sheng','阩'=>'sheng','陞'=>'sheng','陹'=>'sheng','鱦'=>'sheng','鵿'=>'sheng','鼪'=>'sheng','㗂'=>'sheng','㼳'=>'sheng','㾪'=>'sheng','䁞'=>'sheng','䎴'=>'sheng','䚇'=>'sheng','䞉'=>'sheng','䪿'=>'sheng','䱆'=>'sheng','偟'=>'huang','兤'=>'huang','凰'=>'huang','喤'=>'huang','堭'=>'huang','塃'=>'huang','墴'=>'huang','奛'=>'huang','媓'=>'huang','宺'=>'huang','崲'=>'huang','巟'=>'huang','幌'=>'huang','徨'=>'huang','怳'=>'huang','恍'=>'huang','惶'=>'huang','愰'=>'huang','慌'=>'huang','揘'=>'huang','晃'=>'huang','晄'=>'huang','曂'=>'huang','朚'=>'huang','楻'=>'huang','榥'=>'huang','櫎'=>'huang','湟'=>'huang','滉'=>'huang','潢'=>'huang','炾'=>'huang','煌'=>'huang','熀'=>'huang','熿'=>'huang','獚'=>'huang','瑝'=>'huang','璜'=>'huang','癀'=>'huang','皇'=>'huang','皝'=>'huang','皩'=>'huang','磺'=>'huang','穔'=>'huang','篁'=>'huang','簧'=>'huang','縨'=>'huang','肓'=>'huang','艎'=>'huang','荒'=>'huang','葟'=>'huang','蝗'=>'huang','蟥'=>'huang','衁'=>'huang','詤'=>'huang','諻'=>'huang','謊'=>'huang','谎'=>'huang','趪'=>'huang','遑'=>'huang','鍠'=>'huang','鎤'=>'huang','鐄'=>'huang','锽'=>'huang','隍'=>'huang','韹'=>'huang','餭'=>'huang','騜'=>'huang','鰉'=>'huang','鱑'=>'huang','鳇'=>'huang','鷬'=>'huang','黃'=>'huang','黄'=>'huang','㞷'=>'huang','㤺'=>'huang','㨪'=>'huang','㬻'=>'huang','㾠'=>'huang','㾮'=>'huang','䁜'=>'huang','䅣'=>'huang','䊗'=>'huang','䊣'=>'huang','䌙'=>'huang','䍿'=>'huang','䐠'=>'huang','䐵'=>'huang','䑟'=>'huang','䞹'=>'huang','䪄'=>'huang','䮲'=>'huang','䳨'=>'huang','偳'=>'duan','塅'=>'duan','媏'=>'duan','断'=>'duan','斷'=>'duan','椴'=>'duan','段'=>'duan','毈'=>'duan','煅'=>'duan','瑖'=>'duan','短'=>'duan','碫'=>'duan','端'=>'duan','簖'=>'duan','籪'=>'duan','緞'=>'duan','缎'=>'duan','耑'=>'duan','腶'=>'duan','葮'=>'duan','褍'=>'duan','躖'=>'duan','鍛'=>'duan','鍴'=>'duan','锻'=>'duan','㫁'=>'duan','㱭'=>'duan','䠪'=>'duan','偺'=>'zan','儧'=>'zan','儹'=>'zan','兂'=>'zan','咱'=>'zan','喒'=>'zan','囋'=>'zan','寁'=>'zan','撍'=>'zan','攒'=>'zan','攢'=>'zan','昝'=>'zan','暂'=>'zan','暫'=>'zan','濽'=>'zan','灒'=>'zan','瓉'=>'zan','瓒'=>'zan','瓚'=>'zan','禶'=>'zan','簪'=>'zan','簮'=>'zan','糌'=>'zan','襸'=>'zan','讃'=>'zan','讚'=>'zan','賛'=>'zan','贊'=>'zan','赞'=>'zan','趱'=>'zan','趲'=>'zan','蹔'=>'zan','鄼'=>'zan','酂'=>'zan','酇'=>'zan','錾'=>'zan','鏨'=>'zan','鐕'=>'zan','饡'=>'zan','㜺'=>'zan','㟛'=>'zan','㣅'=>'zan','㤰'=>'zan','偻'=>'lou','僂'=>'lou','喽'=>'lou','嘍'=>'lou','塿'=>'lou','娄'=>'lou','婁'=>'lou','屚'=>'lou','嵝'=>'lou','嶁'=>'lou','廔'=>'lou','慺'=>'lou','搂'=>'lou','摟'=>'lou','楼'=>'lou','樓'=>'lou','溇'=>'lou','漊'=>'lou','漏'=>'lou','熡'=>'lou','甊'=>'lou','瘘'=>'lou','瘺'=>'lou','瘻'=>'lou','瞜'=>'lou','篓'=>'lou','簍'=>'lou','耧'=>'lou','耬'=>'lou','艛'=>'lou','蒌'=>'lou','蔞'=>'lou','蝼'=>'lou','螻'=>'lou','謱'=>'lou','軁'=>'lou','遱'=>'lou','鏤'=>'lou','镂'=>'lou','陋'=>'lou','鞻'=>'lou','髅'=>'lou','髏'=>'lou','㔷'=>'lou','㟺'=>'lou','㥪'=>'lou','㪹'=>'lou','㲎'=>'lou','㺏'=>'lou','䁖'=>'lou','䄛'=>'lou','䅹'=>'lou','䝏'=>'lou','䣚'=>'lou','䫫'=>'lou','䮫'=>'lou','䱾'=>'lou','傁'=>'sou','凁'=>'sou','叜'=>'sou','叟'=>'sou','嗖'=>'sou','嗾'=>'sou','廀'=>'sou','廋'=>'sou','捜'=>'sou','搜'=>'sou','摗'=>'sou','擞'=>'sou','擻'=>'sou','櫢'=>'sou','溲'=>'sou','獀'=>'sou','瘶'=>'sou','瞍'=>'sou','艘'=>'sou','蒐'=>'sou','蓃'=>'sou','薮'=>'sou','藪'=>'sou','螋'=>'sou','鄋'=>'sou','醙'=>'sou','鎪'=>'sou','锼'=>'sou','颼'=>'sou','飕'=>'sou','餿'=>'sou','馊'=>'sou','騪'=>'sou','㖩'=>'sou','㛐'=>'sou','㵻'=>'sou','䈹'=>'sou','䉤'=>'sou','䏂'=>'sou','䮟'=>'sou','傆'=>'yuan','元'=>'yuan','冤'=>'yuan','剈'=>'yuan','原'=>'yuan','厡'=>'yuan','厵'=>'yuan','员'=>'yuan','員'=>'yuan','噮'=>'yuan','囦'=>'yuan','园'=>'yuan','圆'=>'yuan','圎'=>'yuan','園'=>'yuan','圓'=>'yuan','圜'=>'yuan','垣'=>'yuan','垸'=>'yuan','塬'=>'yuan','夗'=>'yuan','妴'=>'yuan','媛'=>'yuan','媴'=>'yuan','嫄'=>'yuan','嬽'=>'yuan','寃'=>'yuan','弲'=>'yuan','怨'=>'yuan','悁'=>'yuan','惌'=>'yuan','愿'=>'yuan','掾'=>'yuan','援'=>'yuan','杬'=>'yuan','棩'=>'yuan','榞'=>'yuan','榬'=>'yuan','橼'=>'yuan','櫞'=>'yuan','沅'=>'yuan','淵'=>'yuan','渁'=>'yuan','渆'=>'yuan','渊'=>'yuan','渕'=>'yuan','湲'=>'yuan','源'=>'yuan','溒'=>'yuan','灁'=>'yuan','爰'=>'yuan','猨'=>'yuan','猿'=>'yuan','獂'=>'yuan','瑗'=>'yuan','盶'=>'yuan','眢'=>'yuan','禐'=>'yuan','笎'=>'yuan','箢'=>'yuan','緣'=>'yuan','縁'=>'yuan','缘'=>'yuan','羱'=>'yuan','肙'=>'yuan','苑'=>'yuan','葾'=>'yuan','蒝'=>'yuan','蒬'=>'yuan','薗'=>'yuan','蚖'=>'yuan','蜎'=>'yuan','蜵'=>'yuan','蝝'=>'yuan','蝯'=>'yuan','螈'=>'yuan','衏'=>'yuan','袁'=>'yuan','裫'=>'yuan','褑'=>'yuan','褤'=>'yuan','謜'=>'yuan','貟'=>'yuan','贠'=>'yuan','轅'=>'yuan','辕'=>'yuan','远'=>'yuan','逺'=>'yuan','遠'=>'yuan','邍'=>'yuan','邧'=>'yuan','酛'=>'yuan','鈨'=>'yuan','鋺'=>'yuan','鎱'=>'yuan','院'=>'yuan','願'=>'yuan','駌'=>'yuan','騵'=>'yuan','魭'=>'yuan','鳶'=>'yuan','鴛'=>'yuan','鵷'=>'yuan','鶢'=>'yuan','鶰'=>'yuan','鸢'=>'yuan','鸳'=>'yuan','鹓'=>'yuan','黿'=>'yuan','鼋'=>'yuan','鼘'=>'yuan','鼝'=>'yuan','㟶'=>'yuan','㤪'=>'yuan','㥐'=>'yuan','㥳'=>'yuan','㭇'=>'yuan','㹉'=>'yuan','䅈'=>'yuan','䏍'=>'yuan','䖠'=>'yuan','䛄'=>'yuan','䛇'=>'yuan','䩩'=>'yuan','䬇'=>'yuan','䬧'=>'yuan','䬼'=>'yuan','䲮'=>'yuan','䳒'=>'yuan','䳣'=>'yuan','傇'=>'rong','冗'=>'rong','媶'=>'rong','嫆'=>'rong','嬫'=>'rong','宂'=>'rong','容'=>'rong','峵'=>'rong','嵘'=>'rong','嵤'=>'rong','嶸'=>'rong','戎'=>'rong','搈'=>'rong','搑'=>'rong','摉'=>'rong','曧'=>'rong','栄'=>'rong','榕'=>'rong','榮'=>'rong','榵'=>'rong','毧'=>'rong','氄'=>'rong','溶'=>'rong','瀜'=>'rong','烿'=>'rong','熔'=>'rong','爃'=>'rong','狨'=>'rong','瑢'=>'rong','穁'=>'rong','穃'=>'rong','絨'=>'rong','縙'=>'rong','绒'=>'rong','羢'=>'rong','肜'=>'rong','茙'=>'rong','茸'=>'rong','荣'=>'rong','蓉'=>'rong','蝾'=>'rong','融'=>'rong','螎'=>'rong','蠑'=>'rong','褣'=>'rong','軵'=>'rong','鎔'=>'rong','镕'=>'rong','駥'=>'rong','髶'=>'rong','㘇'=>'rong','㝐'=>'rong','㣑'=>'rong','㭜'=>'rong','㲓'=>'rong','㲝'=>'rong','㲨'=>'rong','㺎'=>'rong','㼸'=>'rong','䇀'=>'rong','䇯'=>'rong','䈶'=>'rong','䘬'=>'rong','䠜'=>'rong','䡆'=>'rong','䡥'=>'rong','䢇'=>'rong','䤊'=>'rong','䩸'=>'rong','傋'=>'jiang','僵'=>'jiang','勥'=>'jiang','匞'=>'jiang','匠'=>'jiang','壃'=>'jiang','夅'=>'jiang','奖'=>'jiang','奨'=>'jiang','奬'=>'jiang','姜'=>'jiang','将'=>'jiang','將'=>'jiang','嵹'=>'jiang','弜'=>'jiang','弶'=>'jiang','彊'=>'jiang','摪'=>'jiang','摾'=>'jiang','杢'=>'jiang','桨'=>'jiang','槳'=>'jiang','橿'=>'jiang','櫤'=>'jiang','殭'=>'jiang','江'=>'jiang','洚'=>'jiang','浆'=>'jiang','滰'=>'jiang','漿'=>'jiang','犟'=>'jiang','獎'=>'jiang','畕'=>'jiang','畺'=>'jiang','疅'=>'jiang','疆'=>'jiang','礓'=>'jiang','糡'=>'jiang','糨'=>'jiang','絳'=>'jiang','繮'=>'jiang','绛'=>'jiang','缰'=>'jiang','翞'=>'jiang','耩'=>'jiang','膙'=>'jiang','茳'=>'jiang','葁'=>'jiang','蒋'=>'jiang','蔣'=>'jiang','薑'=>'jiang','螀'=>'jiang','螿'=>'jiang','袶'=>'jiang','講'=>'jiang','謽'=>'jiang','讲'=>'jiang','豇'=>'jiang','酱'=>'jiang','醤'=>'jiang','醬'=>'jiang','降'=>'jiang','韁'=>'jiang','顜'=>'jiang','鱂'=>'jiang','鳉'=>'jiang','㢡'=>'jiang','㯍'=>'jiang','䁰'=>'jiang','䉃'=>'jiang','䋌'=>'jiang','䒂'=>'jiang','䕭'=>'jiang','䕯'=>'jiang','䙹'=>'jiang','䞪'=>'jiang','傍'=>'bang','垹'=>'bang','塝'=>'bang','峀'=>'bang','帮'=>'bang','幇'=>'bang','幚'=>'bang','幫'=>'bang','徬'=>'bang','捠'=>'bang','梆'=>'bang','棒'=>'bang','棓'=>'bang','榜'=>'bang','浜'=>'bang','牓'=>'bang','玤'=>'bang','硥'=>'bang','磅'=>'bang','稖'=>'bang','綁'=>'bang','縍'=>'bang','绑'=>'bang','膀'=>'bang','艕'=>'bang','蒡'=>'bang','蚌'=>'bang','蜯'=>'bang','謗'=>'bang','谤'=>'bang','邦'=>'bang','邫'=>'bang','鎊'=>'bang','镑'=>'bang','鞤'=>'bang','㔙'=>'bang','㭋'=>'bang','㮄'=>'bang','㯁'=>'bang','㾦'=>'bang','䂜'=>'bang','䎧'=>'bang','䖫'=>'bang','䟺'=>'bang','䧛'=>'bang','䰷'=>'bang','傐'=>'hao','儫'=>'hao','兞'=>'hao','号'=>'hao','哠'=>'hao','嗥'=>'hao','嘷'=>'hao','噑'=>'hao','嚆'=>'hao','嚎'=>'hao','壕'=>'hao','好'=>'hao','恏'=>'hao','悎'=>'hao','昊'=>'hao','昦'=>'hao','晧'=>'hao','暤'=>'hao','暭'=>'hao','曍'=>'hao','椃'=>'hao','毫'=>'hao','浩'=>'hao','淏'=>'hao','滈'=>'hao','澔'=>'hao','濠'=>'hao','灏'=>'hao','灝'=>'hao','獆'=>'hao','獋'=>'hao','皓'=>'hao','皜'=>'hao','皞'=>'hao','皡'=>'hao','皥'=>'hao','秏'=>'hao','竓'=>'hao','籇'=>'hao','耗'=>'hao','聕'=>'hao','茠'=>'hao','蒿'=>'hao','薃'=>'hao','薅'=>'hao','薧'=>'hao','號'=>'hao','蚝'=>'hao','蠔'=>'hao','譹'=>'hao','豪'=>'hao','郝'=>'hao','顥'=>'hao','颢'=>'hao','鰝'=>'hao','㕺'=>'hao','㘪'=>'hao','㙱'=>'hao','㚪'=>'hao','㝀'=>'hao','㞻'=>'hao','㠙'=>'hao','㩝'=>'hao','㬔'=>'hao','㬶'=>'hao','㵆'=>'hao','䒵'=>'hao','䚽'=>'hao','䝞'=>'hao','䝥'=>'hao','䧫'=>'hao','䪽'=>'hao','䬉'=>'hao','䯫'=>'hao','傓'=>'shan','僐'=>'shan','删'=>'shan','刪'=>'shan','剡'=>'shan','剼'=>'shan','善'=>'shan','嘇'=>'shan','圸'=>'shan','埏'=>'shan','墠'=>'shan','墡'=>'shan','姍'=>'shan','姗'=>'shan','嬗'=>'shan','山'=>'shan','幓'=>'shan','彡'=>'shan','扇'=>'shan','挻'=>'shan','搧'=>'shan','擅'=>'shan','敾'=>'shan','晱'=>'shan','曑'=>'shan','杉'=>'shan','杣'=>'shan','椫'=>'shan','樿'=>'shan','檆'=>'shan','汕'=>'shan','潸'=>'shan','澘'=>'shan','灗'=>'shan','炶'=>'shan','烻'=>'shan','煔'=>'shan','煽'=>'shan','熌'=>'shan','狦'=>'shan','珊'=>'shan','疝'=>'shan','痁'=>'shan','睒'=>'shan','磰'=>'shan','笘'=>'shan','縿'=>'shan','繕'=>'shan','缮'=>'shan','羴'=>'shan','羶'=>'shan','脠'=>'shan','膳'=>'shan','膻'=>'shan','舢'=>'shan','芟'=>'shan','苫'=>'shan','蔪'=>'shan','蟮'=>'shan','蟺'=>'shan','衫'=>'shan','覢'=>'shan','訕'=>'shan','謆'=>'shan','譱'=>'shan','讪'=>'shan','贍'=>'shan','赡'=>'shan','赸'=>'shan','跚'=>'shan','軕'=>'shan','邖'=>'shan','鄯'=>'shan','釤'=>'shan','銏'=>'shan','鐥'=>'shan','钐'=>'shan','閃'=>'shan','閊'=>'shan','闪'=>'shan','陕'=>'shan','陝'=>'shan','饍'=>'shan','騸'=>'shan','骟'=>'shan','鯅'=>'shan','鱓'=>'shan','鱔'=>'shan','鳝'=>'shan','㚒'=>'shan','㣌'=>'shan','㣣'=>'shan','㨛'=>'shan','㪎'=>'shan','㪨'=>'shan','㶒'=>'shan','䄠'=>'shan','䆄'=>'shan','䚲'=>'shan','䠾'=>'shan','䥇'=>'shan','䦂'=>'shan','䦅'=>'shan','䱇'=>'shan','䱉'=>'shan','䴮'=>'shan','傞'=>'suo','唆'=>'suo','唢'=>'suo','嗦'=>'suo','嗩'=>'suo','娑'=>'suo','惢'=>'suo','所'=>'suo','挲'=>'suo','摍'=>'suo','暛'=>'suo','桫'=>'suo','梭'=>'suo','溑'=>'suo','溹'=>'suo','琐'=>'suo','琑'=>'suo','瑣'=>'suo','睃'=>'suo','簑'=>'suo','簔'=>'suo','索'=>'suo','縮'=>'suo','缩'=>'suo','羧'=>'suo','莏'=>'suo','蓑'=>'suo','蜶'=>'suo','趖'=>'suo','逤'=>'suo','鎍'=>'suo','鎖'=>'suo','鎻'=>'suo','鎼'=>'suo','鏁'=>'suo','锁'=>'suo','髿'=>'suo','鮻'=>'suo','㪽'=>'suo','䂹'=>'suo','䅴'=>'suo','䈗'=>'suo','䐝'=>'suo','䖛'=>'suo','䗢'=>'suo','䞆'=>'suo','䞽'=>'suo','䣔'=>'suo','䵀'=>'suo','傤'=>'zai','儎'=>'zai','再'=>'zai','哉'=>'zai','在'=>'zai','宰'=>'zai','崽'=>'zai','扗'=>'zai','栽'=>'zai','洅'=>'zai','渽'=>'zai','溨'=>'zai','災'=>'zai','灾'=>'zai','烖'=>'zai','甾'=>'zai','睵'=>'zai','縡'=>'zai','菑'=>'zai','賳'=>'zai','載'=>'zai','载'=>'zai','酨'=>'zai','㞨'=>'zai','㱰'=>'zai','㴓'=>'zai','䏁'=>'zai','䣬'=>'zai','䮨'=>'zai','䵧'=>'zai','傧'=>'bin','儐'=>'bin','宾'=>'bin','彬'=>'bin','摈'=>'bin','擯'=>'bin','斌'=>'bin','椕'=>'bin','槟'=>'bin','殡'=>'bin','殯'=>'bin','氞'=>'bin','汃'=>'bin','滨'=>'bin','濒'=>'bin','濱'=>'bin','濵'=>'bin','瀕'=>'bin','瑸'=>'bin','璸'=>'bin','砏'=>'bin','繽'=>'bin','缤'=>'bin','膑'=>'bin','臏'=>'bin','虨'=>'bin','蠙'=>'bin','豩'=>'bin','豳'=>'bin','賓'=>'bin','賔'=>'bin','邠'=>'bin','鑌'=>'bin','镔'=>'bin','霦'=>'bin','顮'=>'bin','髌'=>'bin','髕'=>'bin','髩'=>'bin','鬂'=>'bin','鬓'=>'bin','鬢'=>'bin','䐔'=>'bin','傩'=>'nuo','儺'=>'nuo','喏'=>'nuo','懦'=>'nuo','懧'=>'nuo','挪'=>'nuo','掿'=>'nuo','搦'=>'nuo','搻'=>'nuo','桛'=>'nuo','梛'=>'nuo','榒'=>'nuo','橠'=>'nuo','燶'=>'nuo','硸'=>'nuo','稬'=>'nuo','穤'=>'nuo','糑'=>'nuo','糥'=>'nuo','糯'=>'nuo','諾'=>'nuo','诺'=>'nuo','蹃'=>'nuo','逽'=>'nuo','郍'=>'nuo','鍩'=>'nuo','锘'=>'nuo','黁'=>'nuo','㐡'=>'nuo','㑚'=>'nuo','㔮'=>'nuo','㛂'=>'nuo','㡅'=>'nuo','㰙'=>'nuo','䚥'=>'nuo','傪'=>'can','儏'=>'can','参'=>'can','參'=>'can','叄'=>'can','叅'=>'can','喰'=>'can','噆'=>'can','嬠'=>'can','惨'=>'can','惭'=>'can','慘'=>'can','慙'=>'can','慚'=>'can','憯'=>'can','朁'=>'can','残'=>'can','殘'=>'can','湌'=>'can','澯'=>'can','灿'=>'can','燦'=>'can','爘'=>'can','璨'=>'can','穇'=>'can','粲'=>'can','薒'=>'can','蚕'=>'can','蝅'=>'can','蠶'=>'can','蠺'=>'can','謲'=>'can','飡'=>'can','餐'=>'can','驂'=>'can','骖'=>'can','黪'=>'can','黲'=>'can','㘔'=>'can','㛑'=>'can','㜗'=>'can','㣓'=>'can','㥇'=>'can','㦧'=>'can','㨻'=>'can','㱚'=>'can','㺑'=>'can','㻮'=>'can','㽩'=>'can','㿊'=>'can','䅟'=>'can','䍼'=>'can','䏼'=>'can','䑶'=>'can','䗝'=>'can','䗞'=>'can','䘉'=>'can','䙁'=>'can','䛹'=>'can','䝳'=>'can','䣟'=>'can','䫮'=>'can','䬫'=>'can','䳻'=>'can','傫'=>'lei','儡'=>'lei','儽'=>'lei','厽'=>'lei','嘞'=>'lei','垒'=>'lei','塁'=>'lei','壘'=>'lei','壨'=>'lei','嫘'=>'lei','擂'=>'lei','攂'=>'lei','樏'=>'lei','檑'=>'lei','櫐'=>'lei','櫑'=>'lei','欙'=>'lei','泪'=>'lei','洡'=>'lei','涙'=>'lei','淚'=>'lei','灅'=>'lei','瓃'=>'lei','畾'=>'lei','癗'=>'lei','矋'=>'lei','磊'=>'lei','磥'=>'lei','礌'=>'lei','礧'=>'lei','礨'=>'lei','禷'=>'lei','类'=>'lei','累'=>'lei','絫'=>'lei','縲'=>'lei','纇'=>'lei','纍'=>'lei','纝'=>'lei','缧'=>'lei','罍'=>'lei','羸'=>'lei','耒'=>'lei','肋'=>'lei','脷'=>'lei','蔂'=>'lei','蕌'=>'lei','蕾'=>'lei','藟'=>'lei','蘱'=>'lei','蘲'=>'lei','蘽'=>'lei','虆'=>'lei','蠝'=>'lei','誄'=>'lei','讄'=>'lei','诔'=>'lei','轠'=>'lei','酹'=>'lei','銇'=>'lei','錑'=>'lei','鐳'=>'lei','鑘'=>'lei','鑸'=>'lei','镭'=>'lei','雷'=>'lei','靁'=>'lei','頛'=>'lei','頪'=>'lei','類'=>'lei','颣'=>'lei','鱩'=>'lei','鸓'=>'lei','鼺'=>'lei','㑍'=>'lei','㒍'=>'lei','㒦'=>'lei','㔣'=>'lei','㙼'=>'lei','㡞'=>'lei','㭩'=>'lei','㲕'=>'lei','㴃'=>'lei','㵢'=>'lei','㶟'=>'lei','㹎'=>'lei','㼍'=>'lei','㿔'=>'lei','䉂'=>'lei','䉓'=>'lei','䉪'=>'lei','䍣'=>'lei','䍥'=>'lei','䐯'=>'lei','䒹'=>'lei','䛶'=>'lei','䢮'=>'lei','䣂'=>'lei','䣦'=>'lei','䨓'=>'lei','䮑'=>'lei','䴎'=>'lei','傮'=>'zao','凿'=>'zao','唕'=>'zao','唣'=>'zao','喿'=>'zao','噪'=>'zao','慥'=>'zao','早'=>'zao','枣'=>'zao','栆'=>'zao','梍'=>'zao','棗'=>'zao','澡'=>'zao','灶'=>'zao','煰'=>'zao','燥'=>'zao','璅'=>'zao','璪'=>'zao','皁'=>'zao','皂'=>'zao','竃'=>'zao','竈'=>'zao','簉'=>'zao','糟'=>'zao','艁'=>'zao','薻'=>'zao','藻'=>'zao','蚤'=>'zao','譟'=>'zao','趮'=>'zao','蹧'=>'zao','躁'=>'zao','造'=>'zao','遭'=>'zao','醩'=>'zao','鑿'=>'zao','㲧'=>'zao','㿷'=>'zao','䜊'=>'zao','䥣'=>'zao','䲃'=>'zao','傲'=>'ao','凹'=>'ao','厫'=>'ao','嗷'=>'ao','嗸'=>'ao','坳'=>'ao','垇'=>'ao','墺'=>'ao','奡'=>'ao','奥'=>'ao','奧'=>'ao','媪'=>'ao','媼'=>'ao','嫯'=>'ao','岙'=>'ao','岰'=>'ao','嶅'=>'ao','嶴'=>'ao','廒'=>'ao','慠'=>'ao','懊'=>'ao','扷'=>'ao','抝'=>'ao','拗'=>'ao','摮'=>'ao','擙'=>'ao','敖'=>'ao','柪'=>'ao','滶'=>'ao','澚'=>'ao','澳'=>'ao','熬'=>'ao','爊'=>'ao','獒'=>'ao','獓'=>'ao','璈'=>'ao','磝'=>'ao','翱'=>'ao','翶'=>'ao','翺'=>'ao','聱'=>'ao','芺'=>'ao','蔜'=>'ao','螯'=>'ao','袄'=>'ao','襖'=>'ao','謷'=>'ao','謸'=>'ao','軪'=>'ao','遨'=>'ao','鏊'=>'ao','鏖'=>'ao','镺'=>'ao','隞'=>'ao','驁'=>'ao','骜'=>'ao','鰲'=>'ao','鳌'=>'ao','鷔'=>'ao','鼇'=>'ao','㑃'=>'ao','㕭'=>'ao','㘬'=>'ao','㘭'=>'ao','㜜'=>'ao','㜩'=>'ao','㟼'=>'ao','㠂'=>'ao','㠗'=>'ao','㤇'=>'ao','㥿'=>'ao','㿰'=>'ao','䁱'=>'ao','䐿'=>'ao','䚫'=>'ao','䜒'=>'ao','䞝'=>'ao','䥝'=>'ao','䦋'=>'ao','䫨'=>'ao','䮯'=>'ao','䯠'=>'ao','䴈'=>'ao','䵅'=>'ao','傸'=>'chuang','刅'=>'chuang','创'=>'chuang','刱'=>'chuang','剏'=>'chuang','剙'=>'chuang','創'=>'chuang','噇'=>'chuang','幢'=>'chuang','床'=>'chuang','怆'=>'chuang','愴'=>'chuang','摐'=>'chuang','漺'=>'chuang','牀'=>'chuang','牎'=>'chuang','牕'=>'chuang','疮'=>'chuang','瘡'=>'chuang','磢'=>'chuang','窓'=>'chuang','窗'=>'chuang','窻'=>'chuang','闖'=>'chuang','闯'=>'chuang','㡖'=>'chuang','㵂'=>'chuang','䃥'=>'chuang','䆫'=>'chuang','䇬'=>'chuang','䎫'=>'chuang','䚒'=>'chuang','䡴'=>'chuang','䭚'=>'chuang','僄'=>'piao','剽'=>'piao','勡'=>'piao','嘌'=>'piao','嫖'=>'piao','彯'=>'piao','徱'=>'piao','慓'=>'piao','旚'=>'piao','殍'=>'piao','漂'=>'piao','犥'=>'piao','瓢'=>'piao','皫'=>'piao','瞟'=>'piao','磦'=>'piao','票'=>'piao','篻'=>'piao','縹'=>'piao','缥'=>'piao','翲'=>'piao','薸'=>'piao','螵'=>'piao','醥'=>'piao','闝'=>'piao','顠'=>'piao','飃'=>'piao','飄'=>'piao','飘'=>'piao','魒'=>'piao','㩠'=>'piao','㬓'=>'piao','㵱'=>'piao','㹾'=>'piao','㺓'=>'piao','㼼'=>'piao','䏇'=>'piao','䴩'=>'piao','僈'=>'man','墁'=>'man','姏'=>'man','嫚'=>'man','屘'=>'man','幔'=>'man','悗'=>'man','慢'=>'man','慲'=>'man','摱'=>'man','曼'=>'man','槾'=>'man','樠'=>'man','満'=>'man','满'=>'man','滿'=>'man','漫'=>'man','澫'=>'man','澷'=>'man','熳'=>'man','獌'=>'man','睌'=>'man','瞒'=>'man','瞞'=>'man','矕'=>'man','縵'=>'man','缦'=>'man','蔄'=>'man','蔓'=>'man','蘰'=>'man','蛮'=>'man','螨'=>'man','蟃'=>'man','蟎'=>'man','蠻'=>'man','襔'=>'man','謾'=>'man','谩'=>'man','鄤'=>'man','鏋'=>'man','鏝'=>'man','镘'=>'man','鞔'=>'man','顢'=>'man','颟'=>'man','饅'=>'man','馒'=>'man','鬗'=>'man','鬘'=>'man','鰻'=>'man','鳗'=>'man','㒼'=>'man','㗄'=>'man','㗈'=>'man','㙢'=>'man','㛧'=>'man','㡢'=>'man','㬅'=>'man','㵘'=>'man','䅼'=>'man','䊡'=>'man','䐽'=>'man','䑱'=>'man','䕕'=>'man','䛲'=>'man','䜱'=>'man','䝡'=>'man','䝢'=>'man','䟂'=>'man','䡬'=>'man','䯶'=>'man','䰋'=>'man','僔'=>'zun','噂'=>'zun','尊'=>'zun','嶟'=>'zun','捘'=>'zun','撙'=>'zun','樽'=>'zun','繜'=>'zun','罇'=>'zun','譐'=>'zun','遵'=>'zun','銌'=>'zun','鐏'=>'zun','鱒'=>'zun','鳟'=>'zun','鶎'=>'zun','鷷'=>'zun','僜'=>'deng','凳'=>'deng','噔'=>'deng','墱'=>'deng','嬁'=>'deng','嶝'=>'deng','戥'=>'deng','櫈'=>'deng','灯'=>'deng','燈'=>'deng','璒'=>'deng','登'=>'deng','瞪'=>'deng','磴'=>'deng','竳'=>'deng','等'=>'deng','簦'=>'deng','艠'=>'deng','覴'=>'deng','豋'=>'deng','蹬'=>'deng','邓'=>'deng','鄧'=>'deng','鐙'=>'deng','镫'=>'deng','隥'=>'deng','䃶'=>'deng','䒭'=>'deng','䠬'=>'deng','䮴'=>'deng','僣'=>'tie','呫'=>'tie','帖'=>'tie','怗'=>'tie','聑'=>'tie','萜'=>'tie','蛈'=>'tie','貼'=>'tie','贴'=>'tie','跕'=>'tie','鉄'=>'tie','銕'=>'tie','鐡'=>'tie','鐢'=>'tie','鐵'=>'tie','铁'=>'tie','飻'=>'tie','餮'=>'tie','驖'=>'tie','鴩'=>'tie','䥫'=>'tie','䴴'=>'tie','䵿'=>'tie','僧'=>'seng','僶'=>'min','冧'=>'min','冺'=>'min','刡'=>'min','勄'=>'min','垊'=>'min','姄'=>'min','岷'=>'min','崏'=>'min','忞'=>'min','怋'=>'min','悯'=>'min','愍'=>'min','慜'=>'min','憫'=>'min','抿'=>'min','捪'=>'min','敃'=>'min','敏'=>'min','敯'=>'min','旻'=>'min','旼'=>'min','暋'=>'min','民'=>'min','泯'=>'min','湣'=>'min','潣'=>'min','玟'=>'min','珉'=>'min','琘'=>'min','琝'=>'min','瑉'=>'min','痻'=>'min','皿'=>'min','盿'=>'min','碈'=>'min','笢'=>'min','笽'=>'min','簢'=>'min','緍'=>'min','緡'=>'min','缗'=>'min','罠'=>'min','苠'=>'min','蠠'=>'min','賯'=>'min','鈱'=>'min','錉'=>'min','鍲'=>'min','閔'=>'min','閩'=>'min','闵'=>'min','闽'=>'min','鰵'=>'min','鳘'=>'min','鴖'=>'min','黽'=>'min','㞶'=>'min','㟩'=>'min','㟭'=>'min','㢯'=>'min','㥸'=>'min','㨉'=>'min','䁕'=>'min','䂥'=>'min','䃉'=>'min','䋋'=>'min','䟨'=>'min','䡅'=>'min','䡑'=>'min','䡻'=>'min','䪸'=>'min','䲄'=>'min','僿'=>'sai','嗮'=>'sai','嘥'=>'sai','噻'=>'sai','塞'=>'sai','愢'=>'sai','揌'=>'sai','毢'=>'sai','毸'=>'sai','簺'=>'sai','腮'=>'sai','虄'=>'sai','賽'=>'sai','赛'=>'sai','顋'=>'sai','鰓'=>'sai','鳃'=>'sai','㗷'=>'sai','䈢'=>'sai','儅'=>'dang','党'=>'dang','凼'=>'dang','噹'=>'dang','圵'=>'dang','垱'=>'dang','壋'=>'dang','婸'=>'dang','宕'=>'dang','当'=>'dang','挡'=>'dang','擋'=>'dang','攩'=>'dang','档'=>'dang','檔'=>'dang','欓'=>'dang','氹'=>'dang','潒'=>'dang','澢'=>'dang','灙'=>'dang','珰'=>'dang','璗'=>'dang','璫'=>'dang','瓽'=>'dang','當'=>'dang','盪'=>'dang','瞊'=>'dang','砀'=>'dang','碭'=>'dang','礑'=>'dang','筜'=>'dang','簜'=>'dang','簹'=>'dang','艡'=>'dang','荡'=>'dang','菪'=>'dang','蕩'=>'dang','蘯'=>'dang','蟷'=>'dang','裆'=>'dang','襠'=>'dang','譡'=>'dang','讜'=>'dang','谠'=>'dang','趤'=>'dang','逿'=>'dang','闣'=>'dang','雼'=>'dang','黨'=>'dang','䑗'=>'dang','䣊'=>'dang','䣣'=>'dang','䦒'=>'dang','儇'=>'xuan','吅'=>'xuan','咺'=>'xuan','喧'=>'xuan','塇'=>'xuan','媗'=>'xuan','嫙'=>'xuan','嬛'=>'xuan','宣'=>'xuan','怰'=>'xuan','悬'=>'xuan','愃'=>'xuan','愋'=>'xuan','懸'=>'xuan','揎'=>'xuan','旋'=>'xuan','昍'=>'xuan','昡'=>'xuan','晅'=>'xuan','暄'=>'xuan','暅'=>'xuan','暶'=>'xuan','梋'=>'xuan','楥'=>'xuan','楦'=>'xuan','檈'=>'xuan','泫'=>'xuan','渲'=>'xuan','漩'=>'xuan','炫'=>'xuan','烜'=>'xuan','煊'=>'xuan','玄'=>'xuan','玹'=>'xuan','琁'=>'xuan','琄'=>'xuan','瑄'=>'xuan','璇'=>'xuan','璿'=>'xuan','痃'=>'xuan','癣'=>'xuan','癬'=>'xuan','眩'=>'xuan','眴'=>'xuan','睻'=>'xuan','矎'=>'xuan','碹'=>'xuan','禤'=>'xuan','箮'=>'xuan','絢'=>'xuan','縼'=>'xuan','繏'=>'xuan','绚'=>'xuan','翧'=>'xuan','翾'=>'xuan','萱'=>'xuan','萲'=>'xuan','蓒'=>'xuan','蔙'=>'xuan','蕿'=>'xuan','藼'=>'xuan','蘐'=>'xuan','蜁'=>'xuan','蝖'=>'xuan','蠉'=>'xuan','衒'=>'xuan','袨'=>'xuan','諠'=>'xuan','諼'=>'xuan','譞'=>'xuan','讂'=>'xuan','谖'=>'xuan','贙'=>'xuan','軒'=>'xuan','轩'=>'xuan','选'=>'xuan','選'=>'xuan','鉉'=>'xuan','鍹'=>'xuan','鏇'=>'xuan','铉'=>'xuan','镟'=>'xuan','鞙'=>'xuan','颴'=>'xuan','駽'=>'xuan','鰚'=>'xuan','㘣'=>'xuan','㧦'=>'xuan','㳙'=>'xuan','㳬'=>'xuan','㹡'=>'xuan','㾌'=>'xuan','䁢'=>'xuan','䍗'=>'xuan','䍻'=>'xuan','䗠'=>'xuan','䘩'=>'xuan','䝮'=>'xuan','䠣'=>'xuan','䧎'=>'xuan','䩙'=>'xuan','䩰'=>'xuan','䮄'=>'xuan','䲂'=>'xuan','䲻'=>'xuan','䴉'=>'xuan','䴋'=>'xuan','儓'=>'tai','冭'=>'tai','台'=>'tai','囼'=>'tai','坮'=>'tai','太'=>'tai','夳'=>'tai','嬯'=>'tai','孡'=>'tai','忲'=>'tai','态'=>'tai','態'=>'tai','抬'=>'tai','擡'=>'tai','旲'=>'tai','檯'=>'tai','汰'=>'tai','泰'=>'tai','溙'=>'tai','炱'=>'tai','炲'=>'tai','燤'=>'tai','珆'=>'tai','箈'=>'tai','籉'=>'tai','粏'=>'tai','肽'=>'tai','胎'=>'tai','臺'=>'tai','舦'=>'tai','苔'=>'tai','菭'=>'tai','薹'=>'tai','跆'=>'tai','邰'=>'tai','酞'=>'tai','鈦'=>'tai','钛'=>'tai','颱'=>'tai','駘'=>'tai','骀'=>'tai','鮐'=>'tai','鲐'=>'tai','㑷'=>'tai','㒗'=>'tai','㘆'=>'tai','㙵'=>'tai','㣍'=>'tai','㥭'=>'tai','㬃'=>'tai','㷘'=>'tai','㸀'=>'tai','䈚'=>'tai','䑓'=>'tai','䢰'=>'tai','䣭'=>'tai','儖'=>'lan','兰'=>'lan','厱'=>'lan','嚂'=>'lan','囒'=>'lan','壈'=>'lan','壏'=>'lan','婪'=>'lan','嬾'=>'lan','孄'=>'lan','孏'=>'lan','岚'=>'lan','嵐'=>'lan','幱'=>'lan','懒'=>'lan','懢'=>'lan','懶'=>'lan','拦'=>'lan','揽'=>'lan','擥'=>'lan','攔'=>'lan','攬'=>'lan','斓'=>'lan','斕'=>'lan','栏'=>'lan','榄'=>'lan','欄'=>'lan','欖'=>'lan','欗'=>'lan','浨'=>'lan','滥'=>'lan','漤'=>'lan','澜'=>'lan','濫'=>'lan','瀾'=>'lan','灆'=>'lan','灠'=>'lan','灡'=>'lan','烂'=>'lan','燗'=>'lan','燣'=>'lan','爁'=>'lan','爛'=>'lan','爤'=>'lan','爦'=>'lan','璼'=>'lan','瓓'=>'lan','礷'=>'lan','篮'=>'lan','籃'=>'lan','籣'=>'lan','糷'=>'lan','繿'=>'lan','纜'=>'lan','缆'=>'lan','罱'=>'lan','葻'=>'lan','蓝'=>'lan','蓞'=>'lan','藍'=>'lan','蘭'=>'lan','褴'=>'lan','襕'=>'lan','襤'=>'lan','襴'=>'lan','襽'=>'lan','覧'=>'lan','覽'=>'lan','览'=>'lan','譋'=>'lan','讕'=>'lan','谰'=>'lan','躝'=>'lan','醂'=>'lan','鑭'=>'lan','钄'=>'lan','镧'=>'lan','闌'=>'lan','阑'=>'lan','韊'=>'lan','㑣'=>'lan','㘓'=>'lan','㛦'=>'lan','㜮'=>'lan','㞩'=>'lan','㦨'=>'lan','㨫'=>'lan','㩜'=>'lan','㰖'=>'lan','㱫'=>'lan','㳕'=>'lan','䃹'=>'lan','䆾'=>'lan','䊖'=>'lan','䌫'=>'lan','䍀'=>'lan','䑌'=>'lan','䦨'=>'lan','䪍'=>'lan','䰐'=>'lan','䳿'=>'lan','儚'=>'meng','冡'=>'meng','勐'=>'meng','夢'=>'meng','夣'=>'meng','孟'=>'meng','幪'=>'meng','庬'=>'meng','懜'=>'meng','懞'=>'meng','懵'=>'meng','掹'=>'meng','擝'=>'meng','曚'=>'meng','朦'=>'meng','梦'=>'meng','橗'=>'meng','檬'=>'meng','氋'=>'meng','溕'=>'meng','濛'=>'meng','猛'=>'meng','獴'=>'meng','瓾'=>'meng','甍'=>'meng','甿'=>'meng','盟'=>'meng','瞢'=>'meng','矇'=>'meng','矒'=>'meng','礞'=>'meng','罞'=>'meng','艋'=>'meng','艨'=>'meng','莔'=>'meng','萌'=>'meng','萠'=>'meng','蒙'=>'meng','蕄'=>'meng','虻'=>'meng','蜢'=>'meng','蝱'=>'meng','蠓'=>'meng','鄳'=>'meng','鄸'=>'meng','錳'=>'meng','锰'=>'meng','雺'=>'meng','霥'=>'meng','霿'=>'meng','靀'=>'meng','顭'=>'meng','饛'=>'meng','鯍'=>'meng','鯭'=>'meng','鸏'=>'meng','鹲'=>'meng','鼆'=>'meng','㙹'=>'meng','㚞'=>'meng','㜴'=>'meng','㝱'=>'meng','㠓'=>'meng','㩚'=>'meng','䀄'=>'meng','䇇'=>'meng','䉚'=>'meng','䏵'=>'meng','䑃'=>'meng','䑅'=>'meng','䒐'=>'meng','䓝'=>'meng','䗈'=>'meng','䙦'=>'meng','䙩'=>'meng','䠢'=>'meng','䤓'=>'meng','䥂'=>'meng','䥰'=>'meng','䰒'=>'meng','䲛'=>'meng','䴌'=>'meng','䴿'=>'meng','䵆'=>'meng','儝'=>'qiong','卭'=>'qiong','宆'=>'qiong','惸'=>'qiong','憌'=>'qiong','桏'=>'qiong','橩'=>'qiong','焪'=>'qiong','焭'=>'qiong','煢'=>'qiong','熍'=>'qiong','琼'=>'qiong','璚'=>'qiong','瓊'=>'qiong','瓗'=>'qiong','睘'=>'qiong','瞏'=>'qiong','穷'=>'qiong','穹'=>'qiong','窮'=>'qiong','竆'=>'qiong','笻'=>'qiong','筇'=>'qiong','舼'=>'qiong','茕'=>'qiong','藑'=>'qiong','藭'=>'qiong','蛩'=>'qiong','蛬'=>'qiong','赹'=>'qiong','跫'=>'qiong','邛'=>'qiong','銎'=>'qiong','㒌'=>'qiong','㧭'=>'qiong','㮪'=>'qiong','㷀'=>'qiong','㼇'=>'qiong','䅃'=>'qiong','䆳'=>'qiong','䊄'=>'qiong','䓖'=>'qiong','䛪'=>'qiong','䠻'=>'qiong','儠'=>'lie','冽'=>'lie','列'=>'lie','劣'=>'lie','劽'=>'lie','咧'=>'lie','埒'=>'lie','埓'=>'lie','姴'=>'lie','峢'=>'lie','巤'=>'lie','挒'=>'lie','挘'=>'lie','捩'=>'lie','擸'=>'lie','毟'=>'lie','洌'=>'lie','浖'=>'lie','烈'=>'lie','烮'=>'lie','煭'=>'lie','犣'=>'lie','猎'=>'lie','猟'=>'lie','獵'=>'lie','睙'=>'lie','聗'=>'lie','脟'=>'lie','茢'=>'lie','蛚'=>'lie','裂'=>'lie','趔'=>'lie','躐'=>'lie','迾'=>'lie','颲'=>'lie','鬛'=>'lie','鬣'=>'lie','鮤'=>'lie','鱲'=>'lie','鴷'=>'lie','㤠'=>'lie','㧜'=>'lie','㬯'=>'lie','㭞'=>'lie','㯿'=>'lie','㲱'=>'lie','㸹'=>'lie','㼲'=>'lie','㽟'=>'lie','䁽'=>'lie','䅀'=>'lie','䉭'=>'lie','䓟'=>'lie','䜲'=>'lie','䟩'=>'lie','䟹'=>'lie','䢪'=>'lie','䴕'=>'lie','儣'=>'kuang','况'=>'kuang','劻'=>'kuang','匡'=>'kuang','匩'=>'kuang','哐'=>'kuang','圹'=>'kuang','壙'=>'kuang','夼'=>'kuang','岲'=>'kuang','恇'=>'kuang','懬'=>'kuang','懭'=>'kuang','抂'=>'kuang','旷'=>'kuang','昿'=>'kuang','曠'=>'kuang','框'=>'kuang','況'=>'kuang','洭'=>'kuang','爌'=>'kuang','狂'=>'kuang','狅'=>'kuang','眖'=>'kuang','眶'=>'kuang','矌'=>'kuang','矿'=>'kuang','砿'=>'kuang','礦'=>'kuang','穬'=>'kuang','筐'=>'kuang','筺'=>'kuang','絋'=>'kuang','絖'=>'kuang','纊'=>'kuang','纩'=>'kuang','誆'=>'kuang','誑'=>'kuang','诓'=>'kuang','诳'=>'kuang','貺'=>'kuang','贶'=>'kuang','軖'=>'kuang','軠'=>'kuang','軦'=>'kuang','軭'=>'kuang','邝'=>'kuang','邼'=>'kuang','鄺'=>'kuang','鉱'=>'kuang','鋛'=>'kuang','鑛'=>'kuang','鵟'=>'kuang','黋'=>'kuang','㤮'=>'kuang','䊯'=>'kuang','䵃'=>'kuang','儭'=>'chen','嗔'=>'chen','嚫'=>'chen','塵'=>'chen','墋'=>'chen','夦'=>'chen','宸'=>'chen','尘'=>'chen','忱'=>'chen','愖'=>'chen','抻'=>'chen','揨'=>'chen','敐'=>'chen','晨'=>'chen','曟'=>'chen','棽'=>'chen','榇'=>'chen','樄'=>'chen','櫬'=>'chen','沉'=>'chen','烥'=>'chen','煁'=>'chen','琛'=>'chen','疢'=>'chen','瘎'=>'chen','瞋'=>'chen','硶'=>'chen','碜'=>'chen','磣'=>'chen','稱'=>'chen','綝'=>'chen','臣'=>'chen','茞'=>'chen','莀'=>'chen','莐'=>'chen','蔯'=>'chen','薼'=>'chen','螴'=>'chen','衬'=>'chen','襯'=>'chen','訦'=>'chen','諃'=>'chen','諶'=>'chen','謓'=>'chen','讖'=>'chen','谌'=>'chen','谶'=>'chen','賝'=>'chen','贂'=>'chen','趁'=>'chen','趂'=>'chen','趻'=>'chen','踸'=>'chen','軙'=>'chen','辰'=>'chen','迧'=>'chen','郴'=>'chen','鈂'=>'chen','陈'=>'chen','陳'=>'chen','霃'=>'chen','鷐'=>'chen','麎'=>'chen','齓'=>'chen','齔'=>'chen','龀'=>'chen','㕴'=>'chen','㧱'=>'chen','㫳'=>'chen','㲀'=>'chen','㴴'=>'chen','㽸'=>'chen','䆣'=>'chen','䒞'=>'chen','䚘'=>'chen','䜟'=>'chen','䞋'=>'chen','䟢'=>'chen','䢅'=>'chen','䢈'=>'chen','䢻'=>'chen','䣅'=>'chen','䤟'=>'chen','䫖'=>'chen','儯'=>'teng','唞'=>'teng','幐'=>'teng','朰'=>'teng','滕'=>'teng','漛'=>'teng','疼'=>'teng','痋'=>'teng','籐'=>'teng','籘'=>'teng','縢'=>'teng','腾'=>'teng','膯'=>'teng','藤'=>'teng','虅'=>'teng','螣'=>'teng','誊'=>'teng','謄'=>'teng','邆'=>'teng','霯'=>'teng','駦'=>'teng','騰'=>'teng','驣'=>'teng','鰧'=>'teng','鼟'=>'teng','䒅'=>'teng','䕨'=>'teng','䠮'=>'teng','䲍'=>'teng','䲢'=>'teng','儱'=>'long','咙'=>'long','哢'=>'long','嚨'=>'long','垄'=>'long','垅'=>'long','壟'=>'long','壠'=>'long','屸'=>'long','嶐'=>'long','巃'=>'long','巄'=>'long','徿'=>'long','拢'=>'long','攏'=>'long','昽'=>'long','曨'=>'long','朧'=>'long','栊'=>'long','梇'=>'long','槞'=>'long','櫳'=>'long','泷'=>'long','湰'=>'long','漋'=>'long','瀧'=>'long','爖'=>'long','珑'=>'long','瓏'=>'long','癃'=>'long','眬'=>'long','矓'=>'long','砻'=>'long','硦'=>'long','礱'=>'long','礲'=>'long','窿'=>'long','竉'=>'long','竜'=>'long','笼'=>'long','篭'=>'long','籠'=>'long','聋'=>'long','聾'=>'long','胧'=>'long','茏'=>'long','蕯'=>'long','蘢'=>'long','蠪'=>'long','蠬'=>'long','衖'=>'long','襱'=>'long','豅'=>'long','贚'=>'long','躘'=>'long','鏧'=>'long','鑨'=>'long','陇'=>'long','隆'=>'long','隴'=>'long','霳'=>'long','靇'=>'long','驡'=>'long','鸗'=>'long','龍'=>'long','龒'=>'long','龓'=>'long','龙'=>'long','㑝'=>'long','㙙'=>'long','㚅'=>'long','㛞'=>'long','㝫'=>'long','㟖'=>'long','㡣'=>'long','㢅'=>'long','㦕'=>'long','㰍'=>'long','㴳'=>'long','䃧'=>'long','䏊'=>'long','䙪'=>'long','䡁'=>'long','䥢'=>'long','䪊'=>'long','儴'=>'rang','勷'=>'rang','嚷'=>'rang','壌'=>'rang','壤'=>'rang','懹'=>'rang','攘'=>'rang','瀼'=>'rang','爙'=>'rang','獽'=>'rang','瓤'=>'rang','禳'=>'rang','穣'=>'rang','穰'=>'rang','纕'=>'rang','蘘'=>'rang','譲'=>'rang','讓'=>'rang','让'=>'rang','躟'=>'rang','鬤'=>'rang','㚂'=>'rang','䉴'=>'rang','兄'=>'xiong','兇'=>'xiong','凶'=>'xiong','匈'=>'xiong','哅'=>'xiong','夐'=>'xiong','忷'=>'xiong','恟'=>'xiong','敻'=>'xiong','汹'=>'xiong','洶'=>'xiong','熊'=>'xiong','胷'=>'xiong','胸'=>'xiong','芎'=>'xiong','訩'=>'xiong','詗'=>'xiong','詾'=>'xiong','讻'=>'xiong','诇'=>'xiong','雄'=>'xiong','㐫'=>'xiong','䧺'=>'xiong','充'=>'chong','冲'=>'chong','嘃'=>'chong','埫'=>'chong','宠'=>'chong','寵'=>'chong','崇'=>'chong','崈'=>'chong','徸'=>'chong','忡'=>'chong','憃'=>'chong','憧'=>'chong','揰'=>'chong','摏'=>'chong','沖'=>'chong','浺'=>'chong','漴'=>'chong','爞'=>'chong','珫'=>'chong','緟'=>'chong','罿'=>'chong','翀'=>'chong','舂'=>'chong','艟'=>'chong','茺'=>'chong','虫'=>'chong','蝩'=>'chong','蟲'=>'chong','衝'=>'chong','褈'=>'chong','蹖'=>'chong','銃'=>'chong','铳'=>'chong','隀'=>'chong','㓽'=>'chong','㧤'=>'chong','㹐'=>'chong','䌬'=>'chong','䖝'=>'chong','䳯'=>'chong','兊'=>'dui','兌'=>'dui','兑'=>'dui','叾'=>'dui','垖'=>'dui','堆'=>'dui','塠'=>'dui','对'=>'dui','対'=>'dui','對'=>'dui','嵟'=>'dui','怼'=>'dui','憝'=>'dui','懟'=>'dui','濧'=>'dui','瀩'=>'dui','痽'=>'dui','碓'=>'dui','磓'=>'dui','祋'=>'dui','綐'=>'dui','薱'=>'dui','譈'=>'dui','譵'=>'dui','鐓'=>'dui','鐜'=>'dui','镦'=>'dui','队'=>'dui','陮'=>'dui','隊'=>'dui','頧'=>'dui','鴭'=>'dui','㙂'=>'dui','㟋'=>'dui','㠚'=>'dui','㬣'=>'dui','㳔'=>'dui','㵽'=>'dui','䇏'=>'dui','䇤'=>'dui','䔪'=>'dui','䨴'=>'dui','䨺'=>'dui','䬈'=>'dui','䬽'=>'dui','䯟'=>'dui','克'=>'ke','刻'=>'ke','剋'=>'ke','勀'=>'ke','勊'=>'ke','匼'=>'ke','可'=>'ke','咳'=>'ke','嗑'=>'ke','坷'=>'ke','堁'=>'ke','壳'=>'ke','娔'=>'ke','客'=>'ke','尅'=>'ke','岢'=>'ke','峇'=>'ke','嵑'=>'ke','嵙'=>'ke','嶱'=>'ke','恪'=>'ke','愙'=>'ke','揢'=>'ke','搕'=>'ke','敤'=>'ke','柯'=>'ke','棵'=>'ke','榼'=>'ke','樖'=>'ke','殻'=>'ke','氪'=>'ke','渇'=>'ke','渴'=>'ke','溘'=>'ke','炣'=>'ke','牁'=>'ke','犐'=>'ke','珂'=>'ke','疴'=>'ke','痾'=>'ke','瞌'=>'ke','碦'=>'ke','磕'=>'ke','礊'=>'ke','礚'=>'ke','科'=>'ke','稞'=>'ke','窠'=>'ke','緙'=>'ke','缂'=>'ke','翗'=>'ke','胢'=>'ke','苛'=>'ke','萪'=>'ke','薖'=>'ke','蝌'=>'ke','課'=>'ke','课'=>'ke','趷'=>'ke','軻'=>'ke','轲'=>'ke','醘'=>'ke','鈳'=>'ke','錁'=>'ke','钶'=>'ke','锞'=>'ke','頦'=>'ke','顆'=>'ke','颏'=>'ke','颗'=>'ke','騍'=>'ke','骒'=>'ke','髁'=>'ke','㕉'=>'ke','㞹'=>'ke','㤩'=>'ke','㪃'=>'ke','㪙'=>'ke','㪡'=>'ke','㪼'=>'ke','㰤'=>'ke','㵣'=>'ke','㾧'=>'ke','䙐'=>'ke','䶗'=>'ke','兎'=>'tu','兔'=>'tu','凃'=>'tu','凸'=>'tu','吐'=>'tu','唋'=>'tu','図'=>'tu','图'=>'tu','圖'=>'tu','圗'=>'tu','土'=>'tu','圡'=>'tu','堍'=>'tu','堗'=>'tu','塗'=>'tu','屠'=>'tu','峹'=>'tu','嵞'=>'tu','嶀'=>'tu','庩'=>'tu','廜'=>'tu','徒'=>'tu','怢'=>'tu','悇'=>'tu','捈'=>'tu','捸'=>'tu','揬'=>'tu','梌'=>'tu','汢'=>'tu','涂'=>'tu','涋'=>'tu','湥'=>'tu','潳'=>'tu','痜'=>'tu','瘏'=>'tu','禿'=>'tu','秃'=>'tu','稌'=>'tu','突'=>'tu','筡'=>'tu','腯'=>'tu','荼'=>'tu','莵'=>'tu','菟'=>'tu','葖'=>'tu','蒤'=>'tu','跿'=>'tu','迌'=>'tu','途'=>'tu','酴'=>'tu','釷'=>'tu','鈯'=>'tu','鋵'=>'tu','鍎'=>'tu','钍'=>'tu','馟'=>'tu','駼'=>'tu','鵌'=>'tu','鵚'=>'tu','鵵'=>'tu','鶟'=>'tu','鷋'=>'tu','鷵'=>'tu','鼵'=>'tu','㭸'=>'tu','㻌'=>'tu','㻠'=>'tu','㻬'=>'tu','㻯'=>'tu','䅷'=>'tu','䖘'=>'tu','䠈'=>'tu','䣄'=>'tu','䣝'=>'tu','䤅'=>'tu','䳜'=>'tu','兛'=>'qiang','呛'=>'qiang','唴'=>'qiang','嗆'=>'qiang','嗴'=>'qiang','墏'=>'qiang','墙'=>'qiang','墻'=>'qiang','嫱'=>'qiang','嬙'=>'qiang','嶈'=>'qiang','廧'=>'qiang','強'=>'qiang','强'=>'qiang','戕'=>'qiang','戗'=>'qiang','戧'=>'qiang','抢'=>'qiang','搶'=>'qiang','摤'=>'qiang','斨'=>'qiang','枪'=>'qiang','椌'=>'qiang','槍'=>'qiang','樯'=>'qiang','檣'=>'qiang','溬'=>'qiang','漒'=>'qiang','炝'=>'qiang','熗'=>'qiang','牄'=>'qiang','牆'=>'qiang','猐'=>'qiang','獇'=>'qiang','玱'=>'qiang','琷'=>'qiang','瑲'=>'qiang','瓩'=>'qiang','篬'=>'qiang','繈'=>'qiang','繦'=>'qiang','羌'=>'qiang','羗'=>'qiang','羟'=>'qiang','羥'=>'qiang','羫'=>'qiang','羻'=>'qiang','腔'=>'qiang','艢'=>'qiang','蔃'=>'qiang','蔷'=>'qiang','薔'=>'qiang','蘠'=>'qiang','蜣'=>'qiang','襁'=>'qiang','謒'=>'qiang','跄'=>'qiang','蹌'=>'qiang','蹡'=>'qiang','錆'=>'qiang','鎗'=>'qiang','鏘'=>'qiang','鏹'=>'qiang','锖'=>'qiang','锵'=>'qiang','镪'=>'qiang','㛨'=>'qiang','㩖'=>'qiang','䅚'=>'qiang','䵁'=>'qiang','內'=>'nei','内'=>'nei','娞'=>'nei','氝'=>'nei','焾'=>'nei','腇'=>'nei','餒'=>'nei','馁'=>'nei','鮾'=>'nei','鯘'=>'nei','㕯'=>'nei','㖏'=>'nei','㘨'=>'nei','㨅'=>'nei','㼏'=>'nei','䡾'=>'nei','䲎'=>'nei','䳖'=>'nei','六'=>'liu','刘'=>'liu','劉'=>'liu','嚠'=>'liu','囖'=>'liu','塯'=>'liu','媹'=>'liu','嬼'=>'liu','嵧'=>'liu','廇'=>'liu','懰'=>'liu','旈'=>'liu','旒'=>'liu','柳'=>'liu','栁'=>'liu','桞'=>'liu','桺'=>'liu','榴'=>'liu','橊'=>'liu','橮'=>'liu','沠'=>'liu','流'=>'liu','浏'=>'liu','溜'=>'liu','澑'=>'liu','瀏'=>'liu','熘'=>'liu','熮'=>'liu','珋'=>'liu','琉'=>'liu','瑠'=>'liu','瑬'=>'liu','璢'=>'liu','瓼'=>'liu','甅'=>'liu','畄'=>'liu','留'=>'liu','畱'=>'liu','疁'=>'liu','瘤'=>'liu','癅'=>'liu','硫'=>'liu','磂'=>'liu','磟'=>'liu','綹'=>'liu','绺'=>'liu','罶'=>'liu','羀'=>'liu','翏'=>'liu','蒥'=>'liu','蓅'=>'liu','藰'=>'liu','蟉'=>'liu','裗'=>'liu','蹓'=>'liu','遛'=>'liu','鋶'=>'liu','鎏'=>'liu','鎦'=>'liu','鏐'=>'liu','鐂'=>'liu','锍'=>'liu','镏'=>'liu','镠'=>'liu','雡'=>'liu','霤'=>'liu','飀'=>'liu','飂'=>'liu','飅'=>'liu','飗'=>'liu','餾'=>'liu','馏'=>'liu','駠'=>'liu','駵'=>'liu','騮'=>'liu','驑'=>'liu','骝'=>'liu','鬸'=>'liu','鰡'=>'liu','鶹'=>'liu','鷚'=>'liu','鹠'=>'liu','鹨'=>'liu','麍'=>'liu','㐬'=>'liu','㙀'=>'liu','㨨'=>'liu','㶯'=>'liu','㽌'=>'liu','㽞'=>'liu','䄂'=>'liu','䉧'=>'liu','䋷'=>'liu','䗜'=>'liu','䚧'=>'liu','䬟'=>'liu','䭷'=>'liu','䰘'=>'liu','䱖'=>'liu','䱞'=>'liu','䶉'=>'liu','兺'=>'pou','咅'=>'pou','哛'=>'pou','哣'=>'pou','堷'=>'pou','婄'=>'pou','抔'=>'pou','抙'=>'pou','捊'=>'pou','掊'=>'pou','犃'=>'pou','箁'=>'pou','裒'=>'pou','颒'=>'pou','㕻'=>'pou','㧵'=>'pou','兽'=>'shou','収'=>'shou','受'=>'shou','售'=>'shou','垨'=>'shou','壽'=>'shou','夀'=>'shou','守'=>'shou','寿'=>'shou','手'=>'shou','扌'=>'shou','授'=>'shou','收'=>'shou','涭'=>'shou','狩'=>'shou','獣'=>'shou','獸'=>'shou','痩'=>'shou','瘦'=>'shou','綬'=>'shou','绶'=>'shou','膄'=>'shou','艏'=>'shou','鏉'=>'shou','首'=>'shou','㖟'=>'shou','㝊'=>'shou','㥅'=>'shou','䛵'=>'shou','䭭'=>'shou','冃'=>'mao','冇'=>'mao','冐'=>'mao','冒'=>'mao','卯'=>'mao','唜'=>'mao','堥'=>'mao','夘'=>'mao','媢'=>'mao','峁'=>'mao','帽'=>'mao','愗'=>'mao','懋'=>'mao','戼'=>'mao','旄'=>'mao','昴'=>'mao','暓'=>'mao','枆'=>'mao','楙'=>'mao','毛'=>'mao','毜'=>'mao','毝'=>'mao','毷'=>'mao','泖'=>'mao','渵'=>'mao','牦'=>'mao','猫'=>'mao','瑁'=>'mao','皃'=>'mao','眊'=>'mao','瞀'=>'mao','矛'=>'mao','笷'=>'mao','緢'=>'mao','耄'=>'mao','芼'=>'mao','茂'=>'mao','茅'=>'mao','茆'=>'mao','蓩'=>'mao','蛑'=>'mao','蝐'=>'mao','蝥'=>'mao','蟊'=>'mao','袤'=>'mao','覒'=>'mao','貌'=>'mao','貓'=>'mao','貿'=>'mao','贸'=>'mao','軞'=>'mao','鄚'=>'mao','鄮'=>'mao','酕'=>'mao','鉚'=>'mao','錨'=>'mao','铆'=>'mao','锚'=>'mao','髦'=>'mao','髳'=>'mao','鶜'=>'mao','㒵'=>'mao','㒻'=>'mao','㚹'=>'mao','㝟'=>'mao','㡌'=>'mao','㧇'=>'mao','㧌'=>'mao','㪞'=>'mao','㫯'=>'mao','㮘'=>'mao','㲠'=>'mao','㴘'=>'mao','㺺'=>'mao','㿞'=>'mao','䀤'=>'mao','䅦'=>'mao','䋃'=>'mao','䓮'=>'mao','䡚'=>'mao','䫉'=>'mao','冄'=>'ran','冉'=>'ran','呥'=>'ran','嘫'=>'ran','姌'=>'ran','媣'=>'ran','染'=>'ran','橪'=>'ran','然'=>'ran','燃'=>'ran','珃'=>'ran','繎'=>'ran','肰'=>'ran','苒'=>'ran','蒅'=>'ran','蚦'=>'ran','蚺'=>'ran','衻'=>'ran','袇'=>'ran','袡'=>'ran','髥'=>'ran','髯'=>'ran','㚩'=>'ran','㜣'=>'ran','㯗'=>'ran','㲯'=>'ran','㸐'=>'ran','㾆'=>'ran','㿵'=>'ran','䎃'=>'ran','䑙'=>'ran','䒣'=>'ran','䖄'=>'ran','䡮'=>'ran','䣸'=>'ran','䤡'=>'ran','䫇'=>'ran','冈'=>'gang','冮'=>'gang','刚'=>'gang','剛'=>'gang','堈'=>'gang','堽'=>'gang','岗'=>'gang','岡'=>'gang','崗'=>'gang','戆'=>'gang','戇'=>'gang','掆'=>'gang','杠'=>'gang','棡'=>'gang','槓'=>'gang','港'=>'gang','焵'=>'gang','牨'=>'gang','犅'=>'gang','疘'=>'gang','矼'=>'gang','筻'=>'gang','綱'=>'gang','纲'=>'gang','缸'=>'gang','罁'=>'gang','罓'=>'gang','罡'=>'gang','肛'=>'gang','釭'=>'gang','鋼'=>'gang','鎠'=>'gang','钢'=>'gang','阬'=>'gang','㟠'=>'gang','㟵'=>'gang','㽘'=>'gang','䴚'=>'gang','冎'=>'gua','刮'=>'gua','剐'=>'gua','剮'=>'gua','劀'=>'gua','卦'=>'gua','叧'=>'gua','呱'=>'gua','啩'=>'gua','坬'=>'gua','寡'=>'gua','挂'=>'gua','掛'=>'gua','歄'=>'gua','焻'=>'gua','煱'=>'gua','瓜'=>'gua','絓'=>'gua','緺'=>'gua','罣'=>'gua','罫'=>'gua','胍'=>'gua','苽'=>'gua','褂'=>'gua','詿'=>'gua','诖'=>'gua','趏'=>'gua','銽'=>'gua','颪'=>'gua','颳'=>'gua','騧'=>'gua','鴰'=>'gua','鸹'=>'gua','㒷'=>'gua','䈑'=>'gua','冦'=>'kou','剾'=>'kou','劶'=>'kou','口'=>'kou','叩'=>'kou','宼'=>'kou','寇'=>'kou','廤'=>'kou','彄'=>'kou','怐'=>'kou','扣'=>'kou','抠'=>'kou','摳'=>'kou','敂'=>'kou','滱'=>'kou','眍'=>'kou','瞉'=>'kou','瞘'=>'kou','窛'=>'kou','筘'=>'kou','簆'=>'kou','芤'=>'kou','蔲'=>'kou','蔻'=>'kou','釦'=>'kou','鷇'=>'kou','㓂'=>'kou','㔚'=>'kou','㰯'=>'kou','㲄'=>'kou','㽛'=>'kou','䳟'=>'kou','䳹'=>'kou','冸'=>'pan','判'=>'pan','叛'=>'pan','坢'=>'pan','媻'=>'pan','幋'=>'pan','搫'=>'pan','攀'=>'pan','柈'=>'pan','槃'=>'pan','沜'=>'pan','泮'=>'pan','溿'=>'pan','潘'=>'pan','瀊'=>'pan','炍'=>'pan','爿'=>'pan','牉'=>'pan','畔'=>'pan','畨'=>'pan','盘'=>'pan','盤'=>'pan','盼'=>'pan','眅'=>'pan','磐'=>'pan','縏'=>'pan','蒰'=>'pan','蟠'=>'pan','袢'=>'pan','襻'=>'pan','詊'=>'pan','跘'=>'pan','蹒'=>'pan','蹣'=>'pan','鋬'=>'pan','鎜'=>'pan','鑻'=>'pan','鞶'=>'pan','頖'=>'pan','鵥'=>'pan','㐴'=>'pan','㳪'=>'pan','䃑'=>'pan','䃲'=>'pan','䈲'=>'pan','䰉'=>'pan','䰔'=>'pan','冾'=>'qia','圶'=>'qia','帢'=>'qia','恰'=>'qia','愘'=>'qia','拤'=>'qia','掐'=>'qia','殎'=>'qia','洽'=>'qia','硈'=>'qia','葜'=>'qia','跒'=>'qia','酠'=>'qia','鞐'=>'qia','髂'=>'qia','㓣'=>'qia','㡊'=>'qia','㤉'=>'qia','䜑'=>'qia','䠍'=>'qia','䨐'=>'qia','䯊'=>'qia','䶝'=>'qia','凂'=>'mei','呅'=>'mei','嚜'=>'mei','堳'=>'mei','塺'=>'mei','妹'=>'mei','媄'=>'mei','媒'=>'mei','媚'=>'mei','媺'=>'mei','嬍'=>'mei','寐'=>'mei','嵄'=>'mei','嵋'=>'mei','徾'=>'mei','抺'=>'mei','挴'=>'mei','攗'=>'mei','攟'=>'mei','昧'=>'mei','枚'=>'mei','栂'=>'mei','梅'=>'mei','楣'=>'mei','楳'=>'mei','槑'=>'mei','毎'=>'mei','每'=>'mei','沒'=>'mei','没'=>'mei','沬'=>'mei','浼'=>'mei','渼'=>'mei','湄'=>'mei','湈'=>'mei','煝'=>'mei','煤'=>'mei','燘'=>'mei','猸'=>'mei','玫'=>'mei','珻'=>'mei','瑂'=>'mei','痗'=>'mei','眉'=>'mei','眛'=>'mei','睂'=>'mei','睸'=>'mei','矀'=>'mei','祙'=>'mei','禖'=>'mei','篃'=>'mei','美'=>'mei','脄'=>'mei','脢'=>'mei','腜'=>'mei','苺'=>'mei','莓'=>'mei','葿'=>'mei','蘪'=>'mei','蝞'=>'mei','袂'=>'mei','跊'=>'mei','躾'=>'mei','郿'=>'mei','酶'=>'mei','鋂'=>'mei','鎂'=>'mei','鎇'=>'mei','镁'=>'mei','镅'=>'mei','霉'=>'mei','韎'=>'mei','鬽'=>'mei','魅'=>'mei','鶥'=>'mei','鹛'=>'mei','黣'=>'mei','黴'=>'mei','㭑'=>'mei','㶬'=>'mei','㺳'=>'mei','䀛'=>'mei','䆀'=>'mei','䉋'=>'mei','䊈'=>'mei','䊊'=>'mei','䍙'=>'mei','䒽'=>'mei','䓺'=>'mei','䜸'=>'mei','䤂'=>'mei','䰨'=>'mei','䰪'=>'mei','䵢'=>'mei','准'=>'zhun','凖'=>'zhun','埻'=>'zhun','宒'=>'zhun','準'=>'zhun','稕'=>'zhun','窀'=>'zhun','綧'=>'zhun','肫'=>'zhun','衠'=>'zhun','訰'=>'zhun','諄'=>'zhun','谆'=>'zhun','迍'=>'zhun','凑'=>'cou','楱'=>'cou','湊'=>'cou','腠'=>'cou','輳'=>'cou','辏'=>'cou','㫶'=>'cou','凟'=>'du','剢'=>'du','匵'=>'du','厾'=>'du','嘟'=>'du','堵'=>'du','妒'=>'du','妬'=>'du','嬻'=>'du','帾'=>'du','度'=>'du','杜'=>'du','椟'=>'du','櫝'=>'du','殬'=>'du','殰'=>'du','毒'=>'du','涜'=>'du','渎'=>'du','渡'=>'du','瀆'=>'du','牍'=>'du','牘'=>'du','犊'=>'du','犢'=>'du','独'=>'du','獨'=>'du','琽'=>'du','瓄'=>'du','皾'=>'du','督'=>'du','睹'=>'du','秺'=>'du','笃'=>'du','篤'=>'du','肚'=>'du','芏'=>'du','荰'=>'du','蝳'=>'du','螙'=>'du','蠧'=>'du','蠹'=>'du','裻'=>'du','覩'=>'du','読'=>'du','讀'=>'du','讟'=>'du','读'=>'du','豄'=>'du','賭'=>'du','贕'=>'du','赌'=>'du','都'=>'du','醏'=>'du','錖'=>'du','鍍'=>'du','鑟'=>'du','镀'=>'du','闍'=>'du','阇'=>'du','靯'=>'du','韇'=>'du','韣'=>'du','韥'=>'du','騳'=>'du','髑'=>'du','黩'=>'du','黷'=>'du','㱩'=>'du','㸿'=>'du','㾄'=>'du','䀾'=>'du','䄍'=>'du','䅊'=>'du','䈞'=>'du','䐗'=>'du','䓯'=>'du','䙱'=>'du','䟻'=>'du','䢱'=>'du','䪅'=>'du','䫳'=>'du','䮷'=>'du','䲧'=>'du','刌'=>'cun','吋'=>'cun','墫'=>'cun','存'=>'cun','寸'=>'cun','忖'=>'cun','拵'=>'cun','村'=>'cun','澊'=>'cun','皴'=>'cun','竴'=>'cun','籿'=>'cun','踆'=>'cun','邨'=>'cun','䍎'=>'cun','刎'=>'wen','吻'=>'wen','呚'=>'wen','呡'=>'wen','問'=>'wen','塭'=>'wen','妏'=>'wen','彣'=>'wen','忟'=>'wen','抆'=>'wen','揾'=>'wen','搵'=>'wen','文'=>'wen','桽'=>'wen','榅'=>'wen','榲'=>'wen','殟'=>'wen','汶'=>'wen','渂'=>'wen','温'=>'wen','溫'=>'wen','炆'=>'wen','珳'=>'wen','瑥'=>'wen','璺'=>'wen','瘒'=>'wen','瘟'=>'wen','砇'=>'wen','稳'=>'wen','穏'=>'wen','穩'=>'wen','紊'=>'wen','紋'=>'wen','絻'=>'wen','纹'=>'wen','聞'=>'wen','肳'=>'wen','脕'=>'wen','脗'=>'wen','芠'=>'wen','莬'=>'wen','蚉'=>'wen','蚊'=>'wen','螡'=>'wen','蟁'=>'wen','豱'=>'wen','輼'=>'wen','轀'=>'wen','辒'=>'wen','鈫'=>'wen','鎾'=>'wen','閺'=>'wen','閿'=>'wen','闅'=>'wen','闦'=>'wen','闧'=>'wen','问'=>'wen','闻'=>'wen','阌'=>'wen','雯'=>'wen','顐'=>'wen','饂'=>'wen','馼'=>'wen','魰'=>'wen','鰛'=>'wen','鰮'=>'wen','鳁'=>'wen','鳼'=>'wen','鴍'=>'wen','鼤'=>'wen','㒚'=>'wen','㖧'=>'wen','㗃'=>'wen','㝧'=>'wen','㳷'=>'wen','䎹'=>'wen','䎽'=>'wen','䘇'=>'wen','䰚'=>'wen','划'=>'hua','劃'=>'hua','化'=>'hua','华'=>'hua','哗'=>'hua','嘩'=>'hua','埖'=>'hua','姡'=>'hua','婲'=>'hua','婳'=>'hua','嫿'=>'hua','嬅'=>'hua','崋'=>'hua','摦'=>'hua','撶'=>'hua','杹'=>'hua','桦'=>'hua','椛'=>'hua','槬'=>'hua','樺'=>'hua','滑'=>'hua','澅'=>'hua','猾'=>'hua','璍'=>'hua','画'=>'hua','畫'=>'hua','畵'=>'hua','硴'=>'hua','磆'=>'hua','糀'=>'hua','繣'=>'hua','舙'=>'hua','花'=>'hua','芲'=>'hua','華'=>'hua','蕐'=>'hua','蘤'=>'hua','蘳'=>'hua','螖'=>'hua','觟'=>'hua','話'=>'hua','誮'=>'hua','諙'=>'hua','諣'=>'hua','譁'=>'hua','话'=>'hua','鋘'=>'hua','錵'=>'hua','鏵'=>'hua','铧'=>'hua','驊'=>'hua','骅'=>'hua','鷨'=>'hua','黊'=>'hua','㓰'=>'hua','㕦'=>'hua','㕲'=>'hua','㕷'=>'hua','㚌'=>'hua','㟆'=>'hua','㠏'=>'hua','㠢'=>'hua','㦊'=>'hua','㦎'=>'hua','㩇'=>'hua','㭉'=>'hua','㮯'=>'hua','䅿'=>'hua','䏦'=>'hua','䔢'=>'hua','䛡'=>'hua','䠉'=>'hua','䱻'=>'hua','䶤'=>'hua','刖'=>'yue','嬳'=>'yue','岄'=>'yue','岳'=>'yue','嶽'=>'yue','彟'=>'yue','彠'=>'yue','恱'=>'yue','悅'=>'yue','悦'=>'yue','戉'=>'yue','抈'=>'yue','捳'=>'yue','曰'=>'yue','曱'=>'yue','月'=>'yue','枂'=>'yue','樾'=>'yue','汋'=>'yue','瀹'=>'yue','爚'=>'yue','玥'=>'yue','矱'=>'yue','礿'=>'yue','禴'=>'yue','箹'=>'yue','篗'=>'yue','籆'=>'yue','籥'=>'yue','籰'=>'yue','粤'=>'yue','粵'=>'yue','約'=>'yue','约'=>'yue','蘥'=>'yue','蚎'=>'yue','蚏'=>'yue','越'=>'yue','跀'=>'yue','跃'=>'yue','躍'=>'yue','軏'=>'yue','鈅'=>'yue','鉞'=>'yue','钥'=>'yue','钺'=>'yue','閱'=>'yue','閲'=>'yue','阅'=>'yue','鸑'=>'yue','鸙'=>'yue','黦'=>'yue','龠'=>'yue','龥'=>'yue','㜧'=>'yue','㜰'=>'yue','㬦'=>'yue','㰛'=>'yue','㹊'=>'yue','䋐'=>'yue','䖃'=>'yue','䟠'=>'yue','䠯'=>'yue','䡇'=>'yue','䢁'=>'yue','䢲'=>'yue','䤦'=>'yue','䥃'=>'yue','䶳'=>'yue','別'=>'bie','别'=>'bie','咇'=>'bie','彆'=>'bie','徶'=>'bie','憋'=>'bie','瘪'=>'bie','癟'=>'bie','莂'=>'bie','虌'=>'bie','蛂'=>'bie','蟞'=>'bie','襒'=>'bie','蹩'=>'bie','鱉'=>'bie','鳖'=>'bie','鼈'=>'bie','龞'=>'bie','㢼'=>'bie','㿜'=>'bie','䉲'=>'bie','䋢'=>'bie','䏟'=>'bie','䠥'=>'bie','䭱'=>'bie','刨'=>'pao','匏'=>'pao','咆'=>'pao','垉'=>'pao','奅'=>'pao','庖'=>'pao','抛'=>'pao','拋'=>'pao','泡'=>'pao','炮'=>'pao','炰'=>'pao','爮'=>'pao','狍'=>'pao','疱'=>'pao','皰'=>'pao','砲'=>'pao','礟'=>'pao','礮'=>'pao','脬'=>'pao','萢'=>'pao','蚫'=>'pao','袍'=>'pao','褜'=>'pao','跑'=>'pao','軳'=>'pao','鞄'=>'pao','麅'=>'pao','麭'=>'pao','㘐'=>'pao','㚿'=>'pao','㯡'=>'pao','䛌'=>'pao','䩝'=>'pao','䶌'=>'pao','刷'=>'shua','唰'=>'shua','耍'=>'shua','誜'=>'shua','剉'=>'cuo','剒'=>'cuo','厝'=>'cuo','夎'=>'cuo','嵯'=>'cuo','嵳'=>'cuo','挫'=>'cuo','措'=>'cuo','搓'=>'cuo','撮'=>'cuo','棤'=>'cuo','瑳'=>'cuo','痤'=>'cuo','睉'=>'cuo','矬'=>'cuo','磋'=>'cuo','脞'=>'cuo','莝'=>'cuo','莡'=>'cuo','蒫'=>'cuo','蓌'=>'cuo','蔖'=>'cuo','虘'=>'cuo','蹉'=>'cuo','逪'=>'cuo','遳'=>'cuo','醝'=>'cuo','銼'=>'cuo','錯'=>'cuo','锉'=>'cuo','错'=>'cuo','髊'=>'cuo','鹺'=>'cuo','鹾'=>'cuo','齹'=>'cuo','㟇'=>'cuo','㽨'=>'cuo','䂳'=>'cuo','䐣'=>'cuo','䟶'=>'cuo','䠡'=>'cuo','䣜'=>'cuo','䱜'=>'cuo','䴾'=>'cuo','剌'=>'la','啦'=>'la','喇'=>'la','嚹'=>'la','垃'=>'la','拉'=>'la','揦'=>'la','揧'=>'la','搚'=>'la','攋'=>'la','旯'=>'la','柆'=>'la','楋'=>'la','櫴'=>'la','溂'=>'la','爉'=>'la','瓎'=>'la','瘌'=>'la','砬'=>'la','磖'=>'la','翋'=>'la','腊'=>'la','臈'=>'la','臘'=>'la','菈'=>'la','藞'=>'la','蜡'=>'la','蝋'=>'la','蝲'=>'la','蠟'=>'la','辢'=>'la','辣'=>'la','邋'=>'la','鑞'=>'la','镴'=>'la','鞡'=>'la','鬎'=>'la','鯻'=>'la','㕇'=>'la','㸊'=>'la','㻋'=>'la','㻝'=>'la','䂰'=>'la','䃳'=>'la','䏀'=>'la','䓥'=>'la','䗶'=>'la','䝓'=>'la','䟑'=>'la','䪉'=>'la','䱫'=>'la','䶛'=>'la','剖'=>'po','叵'=>'po','哱'=>'po','嘙'=>'po','坡'=>'po','奤'=>'po','娝'=>'po','婆'=>'po','尀'=>'po','岥'=>'po','岶'=>'po','廹'=>'po','敀'=>'po','昢'=>'po','櫇'=>'po','泼'=>'po','洦'=>'po','溌'=>'po','潑'=>'po','烞'=>'po','珀'=>'po','皤'=>'po','破'=>'po','砶'=>'po','笸'=>'po','粕'=>'po','蒪'=>'po','蔢'=>'po','謈'=>'po','迫'=>'po','鄱'=>'po','酦'=>'po','醱'=>'po','釙'=>'po','鉕'=>'po','鏺'=>'po','钋'=>'po','钷'=>'po','頗'=>'po','颇'=>'po','駊'=>'po','魄'=>'po','㛘'=>'po','㨇'=>'po','㰴'=>'po','䄸'=>'po','䎊'=>'po','䞟'=>'po','䣪'=>'po','䣮'=>'po','䨰'=>'po','䪖'=>'po','䯙'=>'po','剬'=>'tuan','剸'=>'tuan','团'=>'tuan','団'=>'tuan','圕'=>'tuan','團'=>'tuan','塼'=>'tuan','彖'=>'tuan','慱'=>'tuan','抟'=>'tuan','摶'=>'tuan','槫'=>'tuan','檲'=>'tuan','湍'=>'tuan','湪'=>'tuan','漙'=>'tuan','煓'=>'tuan','猯'=>'tuan','疃'=>'tuan','篿'=>'tuan','糰'=>'tuan','褖'=>'tuan','貒'=>'tuan','鏄'=>'tuan','鷒'=>'tuan','鷻'=>'tuan','㩛'=>'tuan','䊜'=>'tuan','䜝'=>'tuan','䵯'=>'tuan','劗'=>'zuan','揝'=>'zuan','攥'=>'zuan','籫'=>'zuan','繤'=>'zuan','纂'=>'zuan','纉'=>'zuan','纘'=>'zuan','缵'=>'zuan','躜'=>'zuan','躦'=>'zuan','鑚'=>'zuan','鑽'=>'zuan','钻'=>'zuan','䂎'=>'zuan','䌣'=>'zuan','䎱'=>'zuan','䤸'=>'zuan','劭'=>'shao','勺'=>'shao','卲'=>'shao','哨'=>'shao','娋'=>'shao','少'=>'shao','弰'=>'shao','捎'=>'shao','旓'=>'shao','柖'=>'shao','梢'=>'shao','潲'=>'shao','烧'=>'shao','焼'=>'shao','焽'=>'shao','燒'=>'shao','玿'=>'shao','稍'=>'shao','筲'=>'shao','紹'=>'shao','綤'=>'shao','绍'=>'shao','艄'=>'shao','芍'=>'shao','苕'=>'shao','莦'=>'shao','萔'=>'shao','蕱'=>'shao','蛸'=>'shao','袑'=>'shao','輎'=>'shao','邵'=>'shao','韶'=>'shao','颵'=>'shao','髾'=>'shao','鮹'=>'shao','㪢'=>'shao','㲈'=>'shao','㷹'=>'shao','㸛'=>'shao','䏴'=>'shao','䒚'=>'shao','䔠'=>'shao','䙼'=>'shao','䬰'=>'shao','勂'=>'gao','吿'=>'gao','告'=>'gao','夰'=>'gao','峼'=>'gao','搞'=>'gao','暠'=>'gao','杲'=>'gao','槀'=>'gao','槁'=>'gao','槔'=>'gao','槹'=>'gao','橰'=>'gao','檺'=>'gao','櫜'=>'gao','滜'=>'gao','獔'=>'gao','皋'=>'gao','皐'=>'gao','睪'=>'gao','睾'=>'gao','祮'=>'gao','祰'=>'gao','禞'=>'gao','稁'=>'gao','稾'=>'gao','稿'=>'gao','筶'=>'gao','篙'=>'gao','糕'=>'gao','縞'=>'gao','缟'=>'gao','羔'=>'gao','羙'=>'gao','膏'=>'gao','臯'=>'gao','菒'=>'gao','藁'=>'gao','藳'=>'gao','誥'=>'gao','诰'=>'gao','郜'=>'gao','鋯'=>'gao','鎬'=>'gao','锆'=>'gao','镐'=>'gao','韟'=>'gao','餻'=>'gao','高'=>'gao','髙'=>'gao','鷎'=>'gao','鷱'=>'gao','鼛'=>'gao','㚏'=>'gao','㚖'=>'gao','㾸'=>'gao','䗣'=>'gao','勆'=>'lang','唥'=>'lang','啷'=>'lang','埌'=>'lang','塱'=>'lang','嫏'=>'lang','崀'=>'lang','廊'=>'lang','悢'=>'lang','朖'=>'lang','朗'=>'lang','朤'=>'lang','桹'=>'lang','榔'=>'lang','樃'=>'lang','欴'=>'lang','浪'=>'lang','烺'=>'lang','狼'=>'lang','琅'=>'lang','瑯'=>'lang','硠'=>'lang','稂'=>'lang','筤'=>'lang','艆'=>'lang','莨'=>'lang','蒗'=>'lang','蓈'=>'lang','蓢'=>'lang','蜋'=>'lang','螂'=>'lang','誏'=>'lang','躴'=>'lang','郎'=>'lang','郒'=>'lang','郞'=>'lang','鋃'=>'lang','鎯'=>'lang','锒'=>'lang','閬'=>'lang','阆'=>'lang','駺'=>'lang','㓪'=>'lang','㙟'=>'lang','㝗'=>'lang','㟍'=>'lang','㢃'=>'lang','㫰'=>'lang','㮾'=>'lang','㱢'=>'lang','㾗'=>'lang','㾿'=>'lang','䀶'=>'lang','䁁'=>'lang','䆡'=>'lang','䍚'=>'lang','䕞'=>'lang','䡙'=>'lang','䯖'=>'lang','䱶'=>'lang','勜'=>'weng','嗡'=>'weng','塕'=>'weng','奣'=>'weng','嵡'=>'weng','暡'=>'weng','滃'=>'weng','瓮'=>'weng','甕'=>'weng','瞈'=>'weng','罋'=>'weng','翁'=>'weng','聬'=>'weng','蓊'=>'weng','蕹'=>'weng','螉'=>'weng','鎓'=>'weng','鶲'=>'weng','鹟'=>'weng','齆'=>'weng','㘢'=>'weng','㜲'=>'weng','䐥'=>'weng','䤰'=>'weng','匁'=>'mang','厖'=>'mang','吂'=>'mang','哤'=>'mang','壾'=>'mang','娏'=>'mang','尨'=>'mang','忙'=>'mang','恾'=>'mang','杗'=>'mang','杧'=>'mang','氓'=>'mang','汒'=>'mang','浝'=>'mang','漭'=>'mang','牤'=>'mang','牻'=>'mang','狵'=>'mang','痝'=>'mang','盲'=>'mang','硭'=>'mang','笀'=>'mang','芒'=>'mang','茫'=>'mang','茻'=>'mang','莽'=>'mang','莾'=>'mang','蘉'=>'mang','蛖'=>'mang','蟒'=>'mang','蠎'=>'mang','邙'=>'mang','釯'=>'mang','鋩'=>'mang','铓'=>'mang','駹'=>'mang','㙁'=>'mang','㝑'=>'mang','㟌'=>'mang','㟐'=>'mang','㟿'=>'mang','㡛'=>'mang','㬒'=>'mang','㻊'=>'mang','䀮'=>'mang','䁳'=>'mang','䅒'=>'mang','䈍'=>'mang','䒎'=>'mang','䖟'=>'mang','䟥'=>'mang','䵨'=>'mang','匘'=>'nao','呶'=>'nao','垴'=>'nao','堖'=>'nao','夒'=>'nao','婥'=>'nao','嫐'=>'nao','孬'=>'nao','峱'=>'nao','嶩'=>'nao','巎'=>'nao','怓'=>'nao','恼'=>'nao','悩'=>'nao','惱'=>'nao','挠'=>'nao','撓'=>'nao','檂'=>'nao','淖'=>'nao','猱'=>'nao','獶'=>'nao','獿'=>'nao','瑙'=>'nao','硇'=>'nao','碙'=>'nao','碯'=>'nao','脑'=>'nao','脳'=>'nao','腦'=>'nao','臑'=>'nao','蛲'=>'nao','蟯'=>'nao','詉'=>'nao','譊'=>'nao','鐃'=>'nao','铙'=>'nao','閙'=>'nao','闹'=>'nao','鬧'=>'nao','㑎'=>'nao','㛴'=>'nao','㞪'=>'nao','㺀'=>'nao','㺁'=>'nao','䃩'=>'nao','䄩'=>'nao','䑋'=>'nao','䛝'=>'nao','䜀'=>'nao','䜧'=>'nao','䫸'=>'nao','䴃'=>'nao','匝'=>'za','咂'=>'za','囐'=>'za','帀'=>'za','拶'=>'za','杂'=>'za','桚'=>'za','沞'=>'za','沯'=>'za','砸'=>'za','磼'=>'za','紥'=>'za','紮'=>'za','臜'=>'za','臢'=>'za','襍'=>'za','鉔'=>'za','雑'=>'za','雜'=>'za','雥'=>'za','韴'=>'za','魳'=>'za','䕹'=>'za','䞙'=>'za','䪞'=>'za','匴'=>'suan','狻'=>'suan','痠'=>'suan','祘'=>'suan','笇'=>'suan','筭'=>'suan','算'=>'suan','蒜'=>'suan','酸'=>'suan','㔯'=>'suan','卄'=>'nian','哖'=>'nian','埝'=>'nian','姩'=>'nian','年'=>'nian','廿'=>'nian','念'=>'nian','拈'=>'nian','捻'=>'nian','撚'=>'nian','撵'=>'nian','攆'=>'nian','涊'=>'nian','淰'=>'nian','碾'=>'nian','秊'=>'nian','秥'=>'nian','簐'=>'nian','艌'=>'nian','蔫'=>'nian','蹨'=>'nian','躎'=>'nian','輦'=>'nian','辇'=>'nian','鮎'=>'nian','鯰'=>'nian','鲇'=>'nian','鲶'=>'nian','鵇'=>'nian','黏'=>'nian','㘝'=>'nian','㞋'=>'nian','㲽'=>'nian','䄭'=>'nian','䄹'=>'nian','䚓'=>'nian','䩞'=>'nian','䬯'=>'nian','卛'=>'shuai','帅'=>'shuai','帥'=>'shuai','摔'=>'shuai','甩'=>'shuai','蟀'=>'shuai','衰'=>'shuai','䢦'=>'shuai','却'=>'que','卻'=>'que','埆'=>'que','塙'=>'que','墧'=>'que','崅'=>'que','悫'=>'que','愨'=>'que','慤'=>'que','搉'=>'que','榷'=>'que','毃'=>'que','炔'=>'que','燩'=>'que','瘸'=>'que','皵'=>'que','硞'=>'que','确'=>'que','碏'=>'que','確'=>'que','礐'=>'que','礭'=>'que','缺'=>'que','舃'=>'que','蒛'=>'que','趞'=>'que','闋'=>'que','闕'=>'que','阕'=>'que','阙'=>'que','雀'=>'que','鵲'=>'que','鹊'=>'que','㕁'=>'que','㩁'=>'que','㰌'=>'que','㱋'=>'que','㱿'=>'que','㴶'=>'que','㾡'=>'que','䇎'=>'que','䦬'=>'que','䧿'=>'que','厇'=>'zhe','哲'=>'zhe','啠'=>'zhe','喆'=>'zhe','嗻'=>'zhe','嚞'=>'zhe','埑'=>'zhe','嫬'=>'zhe','悊'=>'zhe','折'=>'zhe','摺'=>'zhe','晢'=>'zhe','晣'=>'zhe','柘'=>'zhe','棏'=>'zhe','樀'=>'zhe','樜'=>'zhe','歽'=>'zhe','浙'=>'zhe','淛'=>'zhe','矺'=>'zhe','砓'=>'zhe','磔'=>'zhe','籷'=>'zhe','粍'=>'zhe','者'=>'zhe','蔗'=>'zhe','虴'=>'zhe','蛰'=>'zhe','蜇'=>'zhe','蟄'=>'zhe','蟅'=>'zhe','袩'=>'zhe','褶'=>'zhe','襵'=>'zhe','詟'=>'zhe','謫'=>'zhe','謺'=>'zhe','讁'=>'zhe','讋'=>'zhe','谪'=>'zhe','赭'=>'zhe','輒'=>'zhe','輙'=>'zhe','轍'=>'zhe','辄'=>'zhe','辙'=>'zhe','这'=>'zhe','這'=>'zhe','遮'=>'zhe','銸'=>'zhe','鍺'=>'zhe','锗'=>'zhe','鮿'=>'zhe','鷓'=>'zhe','鹧'=>'zhe','㞏'=>'zhe','㪿'=>'zhe','㯰'=>'zhe','䂞'=>'zhe','䊞'=>'zhe','䎲'=>'zhe','䏳'=>'zhe','䐑'=>'zhe','䐲'=>'zhe','䓆'=>'zhe','䗪'=>'zhe','䝃'=>'zhe','䝕'=>'zhe','䠦'=>'zhe','䩾'=>'zhe','䵭'=>'zhe','厑'=>'a','吖'=>'a','啊'=>'a','嗄'=>'a','錒'=>'a','锕'=>'a','阿'=>'a','厜'=>'zui','嗺'=>'zui','嘴'=>'zui','噿'=>'zui','嶊'=>'zui','嶵'=>'zui','晬'=>'zui','最'=>'zui','朘'=>'zui','枠'=>'zui','栬'=>'zui','樶'=>'zui','檇'=>'zui','檌'=>'zui','欈'=>'zui','濢'=>'zui','璻'=>'zui','祽'=>'zui','穝'=>'zui','絊'=>'zui','纗'=>'zui','罪'=>'zui','蕞'=>'zui','蟕'=>'zui','辠'=>'zui','酔'=>'zui','酻'=>'zui','醉'=>'zui','鋷'=>'zui','錊'=>'zui','㝡'=>'zui','㠑'=>'zui','㰎'=>'zui','䘹'=>'zui','䮔'=>'zui','厹'=>'rou','媃'=>'rou','宍'=>'rou','揉'=>'rou','柔'=>'rou','楺'=>'rou','渘'=>'rou','煣'=>'rou','瑈'=>'rou','瓇'=>'rou','禸'=>'rou','粈'=>'rou','糅'=>'rou','肉'=>'rou','腬'=>'rou','葇'=>'rou','蝚'=>'rou','蹂'=>'rou','輮'=>'rou','鍒'=>'rou','鞣'=>'rou','韖'=>'rou','騥'=>'rou','鰇'=>'rou','鶔'=>'rou','㖻'=>'rou','㽥'=>'rou','䄾'=>'rou','䐓'=>'rou','䧷'=>'rou','䰆'=>'rou','双'=>'shuang','塽'=>'shuang','孀'=>'shuang','孇'=>'shuang','慡'=>'shuang','樉'=>'shuang','欆'=>'shuang','滝'=>'shuang','灀'=>'shuang','爽'=>'shuang','礵'=>'shuang','縔'=>'shuang','艭'=>'shuang','鏯'=>'shuang','雙'=>'shuang','霜'=>'shuang','騻'=>'shuang','驦'=>'shuang','骦'=>'shuang','鷞'=>'shuang','鸘'=>'shuang','鹴'=>'shuang','㦼'=>'shuang','㼽'=>'shuang','䗮'=>'shuang','䡯'=>'shuang','䫪'=>'shuang','叠'=>'die','哋'=>'die','啑'=>'die','喋'=>'die','嚸'=>'die','垤'=>'die','堞'=>'die','峌'=>'die','嵽'=>'die','幉'=>'die','恎'=>'die','惵'=>'die','戜'=>'die','挕'=>'die','揲'=>'die','昳'=>'die','曡'=>'die','曢'=>'die','殜'=>'die','氎'=>'die','爹'=>'die','牃'=>'die','牒'=>'die','瓞'=>'die','畳'=>'die','疂'=>'die','疉'=>'die','疊'=>'die','眣'=>'die','眰'=>'die','碟'=>'die','絰'=>'die','绖'=>'die','耊'=>'die','耋'=>'die','胅'=>'die','臷'=>'die','艓'=>'die','苵'=>'die','蜨'=>'die','蝶'=>'die','褋'=>'die','褺'=>'die','詄'=>'die','諜'=>'die','谍'=>'die','趃'=>'die','跌'=>'die','蹀'=>'die','迭'=>'die','镻'=>'die','鰈'=>'die','鲽'=>'die','㑙'=>'die','㥈'=>'die','㦶'=>'die','㩸'=>'die','㩹'=>'die','㫼'=>'die','㬪'=>'die','㭯'=>'die','㲲'=>'die','㲳'=>'die','㷸'=>'die','㻡'=>'die','䘭'=>'die','䞇'=>'die','䞕'=>'die','䠟'=>'die','䪥'=>'die','䮢'=>'die','䲀'=>'die','䳀'=>'die','䴑'=>'die','叡'=>'rui','壡'=>'rui','枘'=>'rui','桵'=>'rui','橤'=>'rui','汭'=>'rui','瑞'=>'rui','甤'=>'rui','睿'=>'rui','緌'=>'rui','繠'=>'rui','芮'=>'rui','蕊'=>'rui','蕋'=>'rui','蕤'=>'rui','蘂'=>'rui','蘃'=>'rui','蚋'=>'rui','蜹'=>'rui','銳'=>'rui','鋭'=>'rui','锐'=>'rui','㓹'=>'rui','㛱'=>'rui','㪫'=>'rui','㮃'=>'rui','㲊'=>'rui','䅑'=>'rui','䌼'=>'rui','䓲'=>'rui','吞'=>'tun','呑'=>'tun','啍'=>'tun','坉'=>'tun','屯'=>'tun','忳'=>'tun','旽'=>'tun','暾'=>'tun','朜'=>'tun','氽'=>'tun','涒'=>'tun','焞'=>'tun','畽'=>'tun','臀'=>'tun','臋'=>'tun','芚'=>'tun','豘'=>'tun','豚'=>'tun','軘'=>'tun','霕'=>'tun','飩'=>'tun','饨'=>'tun','魨'=>'tun','鲀'=>'tun','黗'=>'tun','㖔'=>'tun','㞘'=>'tun','㩔'=>'tun','㹠'=>'tun','㼊'=>'tun','否'=>'fou','垺'=>'fou','妚'=>'fou','紑'=>'fou','缶'=>'fou','缹'=>'fou','缻'=>'fou','雬'=>'fou','鴀'=>'fou','䳕'=>'fou','吮'=>'shun','瞬'=>'shun','舜'=>'shun','顺'=>'shun','㥧'=>'shun','䀢'=>'shun','䀵'=>'shun','䑞'=>'shun','呙'=>'guo','咼'=>'guo','啯'=>'guo','嘓'=>'guo','囯'=>'guo','囶'=>'guo','囻'=>'guo','国'=>'guo','圀'=>'guo','國'=>'guo','埚'=>'guo','堝'=>'guo','墎'=>'guo','崞'=>'guo','帼'=>'guo','幗'=>'guo','彉'=>'guo','彍'=>'guo','惈'=>'guo','慖'=>'guo','掴'=>'guo','摑'=>'guo','果'=>'guo','椁'=>'guo','楇'=>'guo','槨'=>'guo','淉'=>'guo','漍'=>'guo','濄'=>'guo','猓'=>'guo','瘑'=>'guo','粿'=>'guo','綶'=>'guo','聒'=>'guo','聝'=>'guo','腂'=>'guo','腘'=>'guo','膕'=>'guo','菓'=>'guo','蔮'=>'guo','虢'=>'guo','蜾'=>'guo','蝈'=>'guo','蟈'=>'guo','裹'=>'guo','褁'=>'guo','輠'=>'guo','过'=>'guo','過'=>'guo','郭'=>'guo','鈛'=>'guo','鍋'=>'guo','鐹'=>'guo','锅'=>'guo','餜'=>'guo','馃'=>'guo','馘'=>'guo','㕵'=>'guo','㖪'=>'guo','㚍'=>'guo','㞅'=>'guo','㳀'=>'guo','㶁'=>'guo','䂸'=>'guo','䆐'=>'guo','䐸'=>'guo','䙨'=>'guo','䤋'=>'guo','䬎'=>'guo','䴹'=>'guo','呠'=>'pen','喯'=>'pen','喷'=>'pen','噴'=>'pen','歕'=>'pen','湓'=>'pen','濆'=>'pen','瓫'=>'pen','盆'=>'pen','翉'=>'pen','翸'=>'pen','葐'=>'pen','呢'=>'ne','抐'=>'ne','疒'=>'ne','眲'=>'ne','訥'=>'ne','讷'=>'ne','䎪'=>'ne','䭆'=>'ne','呣'=>'m','嘸'=>'m','咶'=>'huai','坏'=>'huai','壊'=>'huai','壞'=>'huai','徊'=>'huai','怀'=>'huai','懐'=>'huai','懷'=>'huai','槐'=>'huai','櫰'=>'huai','淮'=>'huai','瀤'=>'huai','耲'=>'huai','蘹'=>'huai','蘾'=>'huai','褢'=>'huai','褱'=>'huai','踝'=>'huai','㜳'=>'huai','䈭'=>'huai','䴜'=>'huai','品'=>'pin','嚬'=>'pin','姘'=>'pin','娉'=>'pin','嫔'=>'pin','嬪'=>'pin','拼'=>'pin','朩'=>'pin','榀'=>'pin','汖'=>'pin','牝'=>'pin','玭'=>'pin','琕'=>'pin','矉'=>'pin','礗'=>'pin','穦'=>'pin','聘'=>'pin','薲'=>'pin','貧'=>'pin','贫'=>'pin','頻'=>'pin','顰'=>'pin','频'=>'pin','颦'=>'pin','馪'=>'pin','驞'=>'pin','㰋'=>'pin','䀻'=>'pin','哟'=>'yo','唷'=>'yo','喲'=>'yo','哦'=>'o','哾'=>'shui','帨'=>'shui','楯'=>'shui','橓'=>'shui','水'=>'shui','氵'=>'shui','氺'=>'shui','涗'=>'shui','涚'=>'shui','睡'=>'shui','瞚'=>'shui','瞤'=>'shui','祱'=>'shui','稅'=>'shui','税'=>'shui','脽'=>'shui','蕣'=>'shui','裞'=>'shui','說'=>'shui','説'=>'shui','誰'=>'shui','谁'=>'shui','閖'=>'shui','順'=>'shui','鬊'=>'shui','㽷'=>'shui','䭨'=>'shui','唤'=>'huan','喚'=>'huan','喛'=>'huan','嚾'=>'huan','堚'=>'huan','奂'=>'huan','奐'=>'huan','宦'=>'huan','寏'=>'huan','寰'=>'huan','峘'=>'huan','嵈'=>'huan','幻'=>'huan','患'=>'huan','愌'=>'huan','懁'=>'huan','懽'=>'huan','换'=>'huan','換'=>'huan','擐'=>'huan','攌'=>'huan','桓'=>'huan','梙'=>'huan','槵'=>'huan','欢'=>'huan','欥'=>'huan','歓'=>'huan','歡'=>'huan','洹'=>'huan','浣'=>'huan','涣'=>'huan','渙'=>'huan','漶'=>'huan','澣'=>'huan','澴'=>'huan','烉'=>'huan','焕'=>'huan','煥'=>'huan','狟'=>'huan','獾'=>'huan','环'=>'huan','瑍'=>'huan','環'=>'huan','瓛'=>'huan','痪'=>'huan','瘓'=>'huan','睆'=>'huan','瞣'=>'huan','糫'=>'huan','絙'=>'huan','綄'=>'huan','緩'=>'huan','繯'=>'huan','缓'=>'huan','缳'=>'huan','羦'=>'huan','肒'=>'huan','荁'=>'huan','萈'=>'huan','萑'=>'huan','藧'=>'huan','讙'=>'huan','豢'=>'huan','豲'=>'huan','貆'=>'huan','貛'=>'huan','輐'=>'huan','轘'=>'huan','还'=>'huan','逭'=>'huan','還'=>'huan','郇'=>'huan','酄'=>'huan','鍰'=>'huan','鐶'=>'huan','锾'=>'huan','镮'=>'huan','闤'=>'huan','阛'=>'huan','雈'=>'huan','驩'=>'huan','鬟'=>'huan','鯇'=>'huan','鯶'=>'huan','鰀'=>'huan','鲩'=>'huan','鴅'=>'huan','鵍'=>'huan','鹮'=>'huan','㓉'=>'huan','㕕'=>'huan','㡲'=>'huan','㣪'=>'huan','㦥'=>'huan','㪱'=>'huan','㬇'=>'huan','㬊'=>'huan','㵹'=>'huan','㶎'=>'huan','㹖'=>'huan','㼫'=>'huan','㿪'=>'huan','䀓'=>'huan','䀨'=>'huan','䆠'=>'huan','䈠'=>'huan','䍺'=>'huan','䝠'=>'huan','䥧'=>'huan','䦡'=>'huan','䭴'=>'huan','䮝'=>'huan','䯘'=>'huan','䴟'=>'huan','啂'=>'nou','槈'=>'nou','檽'=>'nou','獳'=>'nou','羺'=>'nou','耨'=>'nou','譨'=>'nou','譳'=>'nou','鎒'=>'nou','鐞'=>'nou','㝹'=>'nou','䅶'=>'nou','䘫'=>'nou','䨲'=>'nou','䰭'=>'nou','啃'=>'ken','垦'=>'ken','墾'=>'ken','恳'=>'ken','懇'=>'ken','掯'=>'ken','肎'=>'ken','肯'=>'ken','肻'=>'ken','裉'=>'ken','褃'=>'ken','豤'=>'ken','貇'=>'ken','錹'=>'ken','㸧'=>'ken','啜'=>'chuai','嘬'=>'chuai','揣'=>'chuai','膗'=>'chuai','踹'=>'chuai','㪓'=>'chuai','㪜'=>'chuai','䦟'=>'chuai','䦤'=>'chuai','䦷'=>'chuai','啪'=>'pa','妑'=>'pa','帊'=>'pa','帕'=>'pa','怕'=>'pa','掱'=>'pa','杷'=>'pa','潖'=>'pa','爬'=>'pa','琶'=>'pa','皅'=>'pa','筢'=>'pa','舥'=>'pa','葩'=>'pa','袙'=>'pa','趴'=>'pa','䯲'=>'pa','䶕'=>'pa','啬'=>'se','嗇'=>'se','懎'=>'se','擌'=>'se','栜'=>'se','槮'=>'se','歮'=>'se','歰'=>'se','洓'=>'se','涩'=>'se','渋'=>'se','澀'=>'se','澁'=>'se','濇'=>'se','濏'=>'se','瀒'=>'se','琗'=>'se','瑟'=>'se','璱'=>'se','瘷'=>'se','穑'=>'se','穡'=>'se','穯'=>'se','篸'=>'se','縇'=>'se','繬'=>'se','聓'=>'se','色'=>'se','裇'=>'se','襂'=>'se','譅'=>'se','轖'=>'se','銫'=>'se','鏼'=>'se','铯'=>'se','閪'=>'se','雭'=>'se','飋'=>'se','鬙'=>'se','㒊'=>'se','㥶'=>'se','㮦'=>'se','㱇'=>'se','㴔'=>'se','㻭'=>'se','䉢'=>'se','䔼'=>'se','䨛'=>'se','啮'=>'nie','喦'=>'nie','嗫'=>'nie','噛'=>'nie','嚙'=>'nie','囁'=>'nie','囓'=>'nie','圼'=>'nie','孼'=>'nie','孽'=>'nie','嵲'=>'nie','嶭'=>'nie','巕'=>'nie','帇'=>'nie','惗'=>'nie','捏'=>'nie','揑'=>'nie','摰'=>'nie','敜'=>'nie','枿'=>'nie','槷'=>'nie','櫱'=>'nie','涅'=>'nie','篞'=>'nie','籋'=>'nie','糱'=>'nie','糵'=>'nie','聂'=>'nie','聶'=>'nie','肀'=>'nie','臬'=>'nie','臲'=>'nie','苶'=>'nie','菍'=>'nie','蘖'=>'nie','蠥'=>'nie','讘'=>'nie','踂'=>'nie','踗'=>'nie','踙'=>'nie','蹑'=>'nie','躡'=>'nie','鉩'=>'nie','錜'=>'nie','鎳'=>'nie','鑷'=>'nie','钀'=>'nie','镊'=>'nie','镍'=>'nie','闑'=>'nie','陧'=>'nie','隉'=>'nie','顳'=>'nie','颞'=>'nie','齧'=>'nie','㖖'=>'nie','㘿'=>'nie','㙞'=>'nie','㚔'=>'nie','㜸'=>'nie','㡪'=>'nie','㩶'=>'nie','㮆'=>'nie','㴪'=>'nie','㸎'=>'nie','䂼'=>'nie','䄒'=>'nie','䌜'=>'nie','䜓'=>'nie','䯀'=>'nie','䯅'=>'nie','䯵'=>'nie','啱'=>'n','嗯'=>'n','莻'=>'n','鈪'=>'n','銰'=>'n','㐻'=>'n','喎'=>'wai','外'=>'wai','崴'=>'wai','歪'=>'wai','竵'=>'wai','顡'=>'wai','㖞'=>'wai','䠿'=>'wai','喵'=>'miao','妙'=>'miao','媌'=>'miao','嫹'=>'miao','庙'=>'miao','庿'=>'miao','廟'=>'miao','描'=>'miao','杪'=>'miao','淼'=>'miao','渺'=>'miao','玅'=>'miao','眇'=>'miao','瞄'=>'miao','秒'=>'miao','竗'=>'miao','篎'=>'miao','緲'=>'miao','缈'=>'miao','苗'=>'miao','藐'=>'miao','邈'=>'miao','鱙'=>'miao','鶓'=>'miao','鹋'=>'miao','㑤'=>'miao','㠺'=>'miao','㦝'=>'miao','䁧'=>'miao','䅺'=>'miao','䖢'=>'miao','嗍'=>'shuo','妁'=>'shuo','搠'=>'shuo','朔'=>'shuo','槊'=>'shuo','欶'=>'shuo','烁'=>'shuo','爍'=>'shuo','獡'=>'shuo','矟'=>'shuo','硕'=>'shuo','碩'=>'shuo','箾'=>'shuo','蒴'=>'shuo','说'=>'shuo','鎙'=>'shuo','鑠'=>'shuo','铄'=>'shuo','䀥'=>'shuo','䈾'=>'shuo','䌃'=>'shuo','嗲'=>'dia','嘈'=>'cao','嶆'=>'cao','愺'=>'cao','懆'=>'cao','撡'=>'cao','操'=>'cao','曹'=>'cao','曺'=>'cao','槽'=>'cao','漕'=>'cao','糙'=>'cao','肏'=>'cao','艚'=>'cao','艸'=>'cao','艹'=>'cao','草'=>'cao','蓸'=>'cao','螬'=>'cao','褿'=>'cao','襙'=>'cao','鄵'=>'cao','鏪'=>'cao','騲'=>'cao','鼜'=>'cao','㜖'=>'cao','㯥'=>'cao','䄚'=>'cao','䏆'=>'cao','䐬'=>'cao','䒃'=>'cao','䒑'=>'cao','嘚'=>'de','得'=>'de','徳'=>'de','德'=>'de','恴'=>'de','悳'=>'de','惪'=>'de','淂'=>'de','的'=>'de','鍀'=>'de','锝'=>'de','㝵'=>'de','㤫'=>'de','㥀'=>'de','㥁'=>'de','㯖'=>'de','䙷'=>'de','䙸'=>'de','嘿'=>'hei','嬒'=>'hei','潶'=>'hei','黑'=>'hei','黒'=>'hei','噋'=>'kuo','廓'=>'kuo','懖'=>'kuo','扩'=>'kuo','拡'=>'kuo','括'=>'kuo','挄'=>'kuo','擴'=>'kuo','栝'=>'kuo','桰'=>'kuo','濶'=>'kuo','穒'=>'kuo','筈'=>'kuo','萿'=>'kuo','葀'=>'kuo','蛞'=>'kuo','闊'=>'kuo','阔'=>'kuo','霩'=>'kuo','鞟'=>'kuo','鞹'=>'kuo','韕'=>'kuo','頢'=>'kuo','髺'=>'kuo','鬠'=>'kuo','㗥'=>'kuo','䟯'=>'kuo','䦢'=>'kuo','䯺'=>'kuo','嚓'=>'ca','囃'=>'ca','擦'=>'ca','攃'=>'ca','礤'=>'ca','礸'=>'ca','遪'=>'ca','䟃'=>'ca','䵽'=>'ca','嚽'=>'chuo','娕'=>'chuo','娖'=>'chuo','惙'=>'chuo','戳'=>'chuo','擉'=>'chuo','歠'=>'chuo','涰'=>'chuo','磭'=>'chuo','綽'=>'chuo','绰'=>'chuo','腏'=>'chuo','趠'=>'chuo','踔'=>'chuo','輟'=>'chuo','辍'=>'chuo','辵'=>'chuo','辶'=>'chuo','逴'=>'chuo','酫'=>'chuo','鑡'=>'chuo','齪'=>'chuo','齱'=>'chuo','龊'=>'chuo','㚟'=>'chuo','㲋'=>'chuo','䂐'=>'chuo','䃗'=>'chuo','䄪'=>'chuo','䆯'=>'chuo','䇍'=>'chuo','䋘'=>'chuo','䍳'=>'chuo','䓎'=>'chuo','䮕'=>'chuo','囎'=>'zen','怎'=>'zen','譖'=>'zen','譛'=>'zen','谮'=>'zen','䫈'=>'zen','囜'=>'nin','您'=>'nin','拰'=>'nin','脌'=>'nin','㤛'=>'nin','䋻'=>'nin','䚾'=>'nin','䛘'=>'nin','困'=>'kun','坤'=>'kun','堃'=>'kun','堒'=>'kun','壸'=>'kun','壼'=>'kun','婫'=>'kun','尡'=>'kun','崐'=>'kun','崑'=>'kun','悃'=>'kun','捆'=>'kun','昆'=>'kun','晜'=>'kun','梱'=>'kun','涃'=>'kun','潉'=>'kun','焜'=>'kun','熴'=>'kun','猑'=>'kun','琨'=>'kun','瑻'=>'kun','睏'=>'kun','硱'=>'kun','祵'=>'kun','稇'=>'kun','稛'=>'kun','綑'=>'kun','臗'=>'kun','菎'=>'kun','蜫'=>'kun','裈'=>'kun','裍'=>'kun','裩'=>'kun','褌'=>'kun','醌'=>'kun','錕'=>'kun','锟'=>'kun','閫'=>'kun','閸'=>'kun','阃'=>'kun','騉'=>'kun','髠'=>'kun','髡'=>'kun','髨'=>'kun','鯤'=>'kun','鲲'=>'kun','鵾'=>'kun','鶤'=>'kun','鹍'=>'kun','㩲'=>'kun','㫻'=>'kun','䠅'=>'kun','囷'=>'qun','夋'=>'qun','宭'=>'qun','峮'=>'qun','帬'=>'qun','羣'=>'qun','群'=>'qun','裙'=>'qun','裠'=>'qun','輑'=>'qun','逡'=>'qun','㪊'=>'qun','㿏'=>'qun','䭽'=>'qun','囸'=>'ri','日'=>'ri','釰'=>'ri','鈤'=>'ri','馹'=>'ri','驲'=>'ri','䒤'=>'ri','圙'=>'lve','擽'=>'lve','畧'=>'lve','稤'=>'lve','稥'=>'lve','鋝'=>'lve','鋢'=>'lve','锊'=>'lve','㑼'=>'lve','㔀'=>'lve','㨼'=>'lve','䂮'=>'lve','䌎'=>'lve','䛚'=>'lve','䤣'=>'lve','坠'=>'zhui','墜'=>'zhui','娷'=>'zhui','惴'=>'zhui','椎'=>'zhui','沝'=>'zhui','甀'=>'zhui','畷'=>'zhui','硾'=>'zhui','礈'=>'zhui','笍'=>'zhui','綴'=>'zhui','縋'=>'zhui','缀'=>'zhui','缒'=>'zhui','膇'=>'zhui','諈'=>'zhui','贅'=>'zhui','赘'=>'zhui','轛'=>'zhui','追'=>'zhui','醊'=>'zhui','錐'=>'zhui','錣'=>'zhui','鑆'=>'zhui','锥'=>'zhui','隹'=>'zhui','餟'=>'zhui','騅'=>'zhui','骓'=>'zhui','鵻'=>'zhui','䄌'=>'zhui','垳'=>'hang','夯'=>'hang','妔'=>'hang','斻'=>'hang','杭'=>'hang','沆'=>'hang','笐'=>'hang','筕'=>'hang','絎'=>'hang','绗'=>'hang','航'=>'hang','苀'=>'hang','蚢'=>'hang','貥'=>'hang','迒'=>'hang','頏'=>'hang','颃'=>'hang','魧'=>'hang','㤚'=>'hang','䀪'=>'hang','䘕'=>'hang','䟘'=>'hang','䣈'=>'hang','䦳'=>'hang','䲳'=>'hang','䴂'=>'hang','埽'=>'sao','嫂'=>'sao','慅'=>'sao','扫'=>'sao','掃'=>'sao','掻'=>'sao','搔'=>'sao','氉'=>'sao','溞'=>'sao','瘙'=>'sao','矂'=>'sao','繅'=>'sao','缫'=>'sao','臊'=>'sao','颾'=>'sao','騒'=>'sao','騷'=>'sao','骚'=>'sao','髞'=>'sao','鰠'=>'sao','鱢'=>'sao','鳋'=>'sao','㛮'=>'sao','㿋'=>'sao','䐹'=>'sao','䕅'=>'sao','䖣'=>'sao','塟'=>'zang','奘'=>'zang','弉'=>'zang','牂'=>'zang','羘'=>'zang','脏'=>'zang','臓'=>'zang','臟'=>'zang','臧'=>'zang','葬'=>'zang','賍'=>'zang','賘'=>'zang','贓'=>'zang','贜'=>'zang','赃'=>'zang','銺'=>'zang','駔'=>'zang','驵'=>'zang','髒'=>'zang','㘸'=>'zang','増'=>'zeng','增'=>'zeng','憎'=>'zeng','曽'=>'zeng','曾'=>'zeng','橧'=>'zeng','熷'=>'zeng','璔'=>'zeng','甑'=>'zeng','矰'=>'zeng','磳'=>'zeng','繒'=>'zeng','缯'=>'zeng','罾'=>'zeng','譄'=>'zeng','贈'=>'zeng','赠'=>'zeng','鄫'=>'zeng','鋥'=>'zeng','锃'=>'zeng','鱛'=>'zeng','㽪'=>'zeng','䙢'=>'zeng','䰝'=>'zeng','奀'=>'en','峎'=>'en','恩'=>'en','摁'=>'en','煾'=>'en','蒽'=>'en','䅰'=>'en','䊐'=>'en','䬶'=>'en','䭓'=>'en','䭡'=>'en','奏'=>'zou','媰'=>'zou','掫'=>'zou','揍'=>'zou','棷'=>'zou','棸'=>'zou','箃'=>'zou','緅'=>'zou','菆'=>'zou','諏'=>'zou','诹'=>'zou','走'=>'zou','赱'=>'zou','邹'=>'zou','郰'=>'zou','鄒'=>'zou','鄹'=>'zou','陬'=>'zou','騶'=>'zou','驺'=>'zou','鯐'=>'zou','鯫'=>'zou','鲰'=>'zou','黀'=>'zou','齺'=>'zou','㔿'=>'zou','㵵'=>'zou','䠫'=>'zou','女'=>'nv','恧'=>'nv','朒'=>'nv','籹'=>'nv','衂'=>'nv','衄'=>'nv','釹'=>'nv','钕'=>'nv','㵖'=>'nv','䖡'=>'nv','䘐'=>'nv','䚼'=>'nv','䶊'=>'nv','奻'=>'nuan','暖'=>'nuan','渜'=>'nuan','煖'=>'nuan','煗'=>'nuan','餪'=>'nuan','㬉'=>'nuan','䎡'=>'nuan','䙇'=>'nuan','妞'=>'niu','忸'=>'niu','扭'=>'niu','杻'=>'niu','汼'=>'niu','沑'=>'niu','炄'=>'niu','牛'=>'niu','牜'=>'niu','狃'=>'niu','紐'=>'niu','纽'=>'niu','莥'=>'niu','鈕'=>'niu','钮'=>'niu','靵'=>'niu','㺲'=>'niu','䀔'=>'niu','䋴'=>'niu','䏔'=>'niu','䒜'=>'niu','娆'=>'rao','嬈'=>'rao','扰'=>'rao','擾'=>'rao','桡'=>'rao','橈'=>'rao','犪'=>'rao','繞'=>'rao','绕'=>'rao','荛'=>'rao','蕘'=>'rao','襓'=>'rao','遶'=>'rao','隢'=>'rao','饒'=>'rao','饶'=>'rao','㑱'=>'rao','㹛'=>'rao','䫞'=>'rao','娘'=>'niang','嬢'=>'niang','孃'=>'niang','酿'=>'niang','醸'=>'niang','釀'=>'niang','䖆'=>'niang','嫋'=>'niao','嬝'=>'niao','嬲'=>'niao','尿'=>'niao','脲'=>'niao','茑'=>'niao','茒'=>'niao','蔦'=>'niao','袅'=>'niao','裊'=>'niao','褭'=>'niao','鳥'=>'niao','鸟'=>'niao','㒟'=>'niao','㜵'=>'niao','㞙'=>'niao','㠡'=>'niao','㭤'=>'niao','㳮'=>'niao','䃵'=>'niao','䐁'=>'niao','䙚'=>'niao','䦊'=>'niao','䮍'=>'niao','嫩'=>'nen','㜛'=>'nen','㯎'=>'nen','㶧'=>'nen','孙'=>'sun','孫'=>'sun','巺'=>'sun','损'=>'sun','損'=>'sun','搎'=>'sun','榫'=>'sun','槂'=>'sun','潠'=>'sun','狲'=>'sun','猻'=>'sun','畃'=>'sun','笋'=>'sun','筍'=>'sun','箰'=>'sun','簨'=>'sun','荪'=>'sun','蓀'=>'sun','蕵'=>'sun','薞'=>'sun','鎨'=>'sun','隼'=>'sun','飧'=>'sun','飱'=>'sun','鶽'=>'sun','㔼'=>'sun','㡄'=>'sun','㦏'=>'sun','䁚'=>'sun','宽'=>'kuan','寛'=>'kuan','寬'=>'kuan','梡'=>'kuan','欵'=>'kuan','款'=>'kuan','歀'=>'kuan','窽'=>'kuan','窾'=>'kuan','鑧'=>'kuan','髋'=>'kuan','髖'=>'kuan','㯘'=>'kuan','䕀'=>'kuan','䤭'=>'kuan','䥗'=>'kuan','䲌'=>'kuan','岃'=>'yen','膶'=>'yen','岇'=>'ang','昂'=>'ang','昻'=>'ang','枊'=>'ang','盎'=>'ang','肮'=>'ang','醠'=>'ang','骯'=>'ang','㦹'=>'ang','㭿'=>'ang','㼜'=>'ang','䀚'=>'ang','䍩'=>'ang','䒢'=>'ang','䩕'=>'ang','䭹'=>'ang','䭺'=>'ang','岑'=>'cen','嵾'=>'cen','梣'=>'cen','涔'=>'cen','笒'=>'cen','膥'=>'cen','㞥'=>'cen','㻸'=>'cen','䃡'=>'cen','䅾'=>'cen','䤁'=>'cen','䨙'=>'cen','䯔'=>'cen','䲋'=>'cen','巑'=>'cuan','撺'=>'cuan','攅'=>'cuan','攛'=>'cuan','櫕'=>'cuan','欑'=>'cuan','殩'=>'cuan','汆'=>'cuan','熶'=>'cuan','爨'=>'cuan','穳'=>'cuan','窜'=>'cuan','竄'=>'cuan','篡'=>'cuan','篹'=>'cuan','簒'=>'cuan','蹿'=>'cuan','躥'=>'cuan','鑹'=>'cuan','㠝'=>'cuan','㭫'=>'cuan','㵀'=>'cuan','㸑'=>'cuan','䆘'=>'cuan','䰖'=>'cuan','忑'=>'te','忒'=>'te','慝'=>'te','特'=>'te','犆'=>'te','脦'=>'te','蟘'=>'te','貣'=>'te','鋱'=>'te','铽'=>'te','㥂'=>'te','㧹'=>'te','惹'=>'re','热'=>'re','熱'=>'re','扥'=>'den','扽'=>'den','揼'=>'den','抓'=>'zhua','檛'=>'zhua','爪'=>'zhua','簻'=>'zhua','膼'=>'zhua','髽'=>'zhua','拴'=>'shuan','栓'=>'shuan','涮'=>'shuan','腨'=>'shuan','閂'=>'shuan','闩'=>'shuan','䧠'=>'shuan','拽'=>'zhuai','跩'=>'zhuai','掠'=>'lue','略'=>'lue','晒'=>'shai','曬'=>'shai','筛'=>'shai','篩'=>'shai','簁'=>'shai','簛'=>'shai','㩄'=>'shai','㬠'=>'shai','森'=>'sen','橍'=>'run','润'=>'run','潤'=>'run','閏'=>'run','閠'=>'run','闰'=>'run','㠈'=>'run','䦞'=>'run','疟'=>'nue','虐'=>'nue','瘧'=>'nve','䖈'=>'nve','䖋'=>'nve','䨋'=>'nve','給'=>'gei','给'=>'gei','繆'=>'miu','缪'=>'miu','謬'=>'miu','谬'=>'miu','能'=>'neng','㲌'=>'neng','㴰'=>'neng','䏻'=>'neng','蠈'=>'zei','賊'=>'zei','贼'=>'zei','鰂'=>'zei','鱡'=>'zei','鲗'=>'zei','覅'=>'fiao','鞥'=>'eng','㕶'=>'ng','䫄'=>'chua'); + + /** + * 将中文编码成拼音 + * @param string $str utf8字符串 + * @param string $ret_format 返回格式 [all:全拼音|head:首字母|one:仅第一字符首字母] + * @param string $placeholder 无法识别的字符占位符 + * @param string $allow_chars 允许的非中文字符 + * @return string 拼音字符串 + */ + public static function encode($str, $ret_format = 'head', $placeholder = '*', $allow_chars = '/[a-zA-Z\d]/'){ + $str = trim($str); + $len = mb_strlen($str, 'UTF-8'); + $rs = ''; + for ($i = 0; $i < $len; $i++) { + $chr = mb_substr($str, $i, 1, 'UTF-8'); + $asc = ord($chr); + if ($asc < 0x80) { // 0-127 + if (preg_match($allow_chars, $chr)) { // 用参数控制正则 + $rs .= $chr; // 0-9 a-z A-Z 空格 + } else { // 其他字符用填充符代替 + $rs .= $placeholder; + } + } else { // 128-255 + if (isset(self::$_aMaps[$chr])) { + $rs .= 'head' === $ret_format ? self::$_aMaps[$chr][0] : (self::$_aMaps[$chr].''); + } else { + $rs .= $placeholder; + } + } + if ('one' === $ret_format && '' !== $rs) { + return $rs[0]; + } + } + return $rs; + } +} +?> \ No newline at end of file diff --git a/serve/extend/org/ttfs/1.ttf b/serve/extend/org/ttfs/1.ttf new file mode 100644 index 0000000..9eae6f2 Binary files /dev/null and b/serve/extend/org/ttfs/1.ttf differ diff --git a/serve/extend/org/ttfs/2.ttf b/serve/extend/org/ttfs/2.ttf new file mode 100644 index 0000000..6386c6b Binary files /dev/null and b/serve/extend/org/ttfs/2.ttf differ diff --git a/serve/extend/org/ttfs/3.ttf b/serve/extend/org/ttfs/3.ttf new file mode 100644 index 0000000..678a491 Binary files /dev/null and b/serve/extend/org/ttfs/3.ttf differ diff --git a/serve/extend/org/ttfs/4.ttf b/serve/extend/org/ttfs/4.ttf new file mode 100644 index 0000000..db43334 Binary files /dev/null and b/serve/extend/org/ttfs/4.ttf differ diff --git a/serve/extend/org/ttfs/5.ttf b/serve/extend/org/ttfs/5.ttf new file mode 100644 index 0000000..8c082c8 Binary files /dev/null and b/serve/extend/org/ttfs/5.ttf differ diff --git a/serve/extend/org/ttfs/6.ttf b/serve/extend/org/ttfs/6.ttf new file mode 100644 index 0000000..45a038b Binary files /dev/null and b/serve/extend/org/ttfs/6.ttf differ diff --git a/serve/extend/wechat/WxPay.Api.php b/serve/extend/wechat/WxPay.Api.php new file mode 100644 index 0000000..bd94623 --- /dev/null +++ b/serve/extend/wechat/WxPay.Api.php @@ -0,0 +1,616 @@ +IsOut_trade_noSet()) { + throw new WxPayException("缺少统一支付接口必填参数out_trade_no!"); + }else if(!$inputObj->IsBodySet()){ + throw new WxPayException("缺少统一支付接口必填参数body!"); + }else if(!$inputObj->IsTotal_feeSet()) { + throw new WxPayException("缺少统一支付接口必填参数total_fee!"); + }else if(!$inputObj->IsTrade_typeSet()) { + throw new WxPayException("缺少统一支付接口必填参数trade_type!"); + } + + //关联参数 + if($inputObj->GetTrade_type() == "JSAPI" && !$inputObj->IsOpenidSet()){ + throw new WxPayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"); + } + if($inputObj->GetTrade_type() == "NATIVE" && !$inputObj->IsProduct_idSet()){ + throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!"); + } + + //异步通知url未设置,则使用配置文件中的url + if(!$inputObj->IsNotify_urlSet() && $config->GetNotifyUrl() != ""){ + $inputObj->SetNotify_url($config->GetNotifyUrl());//异步通知url + } + + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetSpbill_create_ip($_SERVER['REMOTE_ADDR']);//终端ip + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + //签名 + $inputObj->SetSign($config); + $xml = $inputObj->ToXml(); + + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, false, $timeOut); + $result = WxPayResults::Init($config, $response); + self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 + + return $result; + } + + /** + * + * 查询订单,WxPayOrderQuery中out_trade_no、transaction_id至少填一个 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayOrderQuery $inputObj + * @param int $timeOut + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public static function orderQuery($config, $inputObj, $timeOut = 6) + { + $url = "https://api.mch.weixin.qq.com/pay/orderquery"; + //检测必填参数 + if(!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) { + throw new WxPayException("订单查询接口中,out_trade_no、transaction_id至少填一个!"); + } + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, false, $timeOut); + $result = WxPayResults::Init($config, $response); + self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 + + return $result; + } + + /** + * + * 关闭订单,WxPayCloseOrder中out_trade_no必填 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayCloseOrder $inputObj + * @param int $timeOut + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public static function closeOrder($config, $inputObj, $timeOut = 6) + { + $url = "https://api.mch.weixin.qq.com/pay/closeorder"; + //检测必填参数 + if(!$inputObj->IsOut_trade_noSet()) { + throw new WxPayException("订单查询接口中,out_trade_no必填!"); + } + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, false, $timeOut); + $result = WxPayResults::Init($config, $response); + self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 + + return $result; + } + + /** + * + * 申请退款,WxPayRefund中out_trade_no、transaction_id至少填一个且 + * out_refund_no、total_fee、refund_fee、op_user_id为必填参数 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayRefund $inputObj + * @param int $timeOut + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public static function refund($config, $inputObj, $timeOut = 6) + { + $url = "https://api.mch.weixin.qq.com/secapi/pay/refund"; + //检测必填参数 + if(!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) { + throw new WxPayException("退款申请接口中,out_trade_no、transaction_id至少填一个!"); + }else if(!$inputObj->IsOut_refund_noSet()){ + throw new WxPayException("退款申请接口中,缺少必填参数out_refund_no!"); + }else if(!$inputObj->IsTotal_feeSet()){ + throw new WxPayException("退款申请接口中,缺少必填参数total_fee!"); + }else if(!$inputObj->IsRefund_feeSet()){ + throw new WxPayException("退款申请接口中,缺少必填参数refund_fee!"); + }else if(!$inputObj->IsOp_user_idSet()){ + throw new WxPayException("退款申请接口中,缺少必填参数op_user_id!"); + } + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, true, $timeOut); + $result = WxPayResults::Init($config, $response); + self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 + + return $result; + } + + /** + * + * 查询退款 + * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时, + * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。 + * WxPayRefundQuery中out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayRefundQuery $inputObj + * @param int $timeOut + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public static function refundQuery($config, $inputObj, $timeOut = 6) + { + $url = "https://api.mch.weixin.qq.com/pay/refundquery"; + //检测必填参数 + if(!$inputObj->IsOut_refund_noSet() && + !$inputObj->IsOut_trade_noSet() && + !$inputObj->IsTransaction_idSet() && + !$inputObj->IsRefund_idSet()) { + throw new WxPayException("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!"); + } + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, false, $timeOut); + $result = WxPayResults::Init($config, $response); + self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 + + return $result; + } + + /** + * 下载对账单,WxPayDownloadBill中bill_date为必填参数 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayDownloadBill $inputObj + * @param int $timeOut + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public static function downloadBill($config, $inputObj, $timeOut = 6) + { + $url = "https://api.mch.weixin.qq.com/pay/downloadbill"; + //检测必填参数 + if(!$inputObj->IsBill_dateSet()) { + throw new WxPayException("对账单接口中,缺少必填参数bill_date!"); + } + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + + $response = self::postXmlCurl($config, $xml, $url, false, $timeOut); + if(substr($response, 0 , 5) == ""){ + return ""; + } + return $response; + } + + /** + * 提交被扫支付API + * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台, + * 由商户收银台或者商户后台调用该接口发起支付。 + * WxPayWxPayMicroPay中body、out_trade_no、total_fee、auth_code参数必填 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayWxPayMicroPay $inputObj + * @param int $timeOut + */ + public static function micropay($config, $inputObj, $timeOut = 10) + { + $url = "https://api.mch.weixin.qq.com/pay/micropay"; + //检测必填参数 + if(!$inputObj->IsBodySet()) { + throw new WxPayException("提交被扫支付API接口中,缺少必填参数body!"); + } else if(!$inputObj->IsOut_trade_noSet()) { + throw new WxPayException("提交被扫支付API接口中,缺少必填参数out_trade_no!"); + } else if(!$inputObj->IsTotal_feeSet()) { + throw new WxPayException("提交被扫支付API接口中,缺少必填参数total_fee!"); + } else if(!$inputObj->IsAuth_codeSet()) { + throw new WxPayException("提交被扫支付API接口中,缺少必填参数auth_code!"); + } + + $inputObj->SetSpbill_create_ip($_SERVER['REMOTE_ADDR']);//终端ip + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, false, $timeOut); + $result = WxPayResults::Init($config, $response); + self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 + + return $result; + } + + /** + * + * 撤销订单API接口,WxPayReverse中参数out_trade_no和transaction_id必须填写一个 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayReverse $inputObj + * @param int $timeOut + * @throws WxPayException + */ + public static function reverse($config, $inputObj, $timeOut = 6) + { + $url = "https://api.mch.weixin.qq.com/secapi/pay/reverse"; + //检测必填参数 + if(!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) { + throw new WxPayException("撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!"); + } + + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, true, $timeOut); + $result = WxPayResults::Init($config, $response); + self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 + + return $result; + } + + /** + * + * 测速上报,该方法内部封装在report中,使用时请注意异常流程 + * WxPayReport中interface_url、return_code、result_code、user_ip、execute_time_必填 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayReport $inputObj + * @param int $timeOut + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public static function report($config, $inputObj, $timeOut = 1) + { + $url = "https://api.mch.weixin.qq.com/payitil/report"; + //检测必填参数 + if(!$inputObj->IsInterface_urlSet()) { + throw new WxPayException("接口URL,缺少必填参数interface_url!"); + } if(!$inputObj->IsReturn_codeSet()) { + throw new WxPayException("返回状态码,缺少必填参数return_code!"); + } if(!$inputObj->IsResult_codeSet()) { + throw new WxPayException("业务结果,缺少必填参数result_code!"); + } if(!$inputObj->IsUser_ipSet()) { + throw new WxPayException("访问接口IP,缺少必填参数user_ip!"); + } if(!$inputObj->IsExecute_time_Set()) { + throw new WxPayException("接口耗时,缺少必填参数execute_time_!"); + } + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetUser_ip($_SERVER['REMOTE_ADDR']);//终端ip + $inputObj->SetTime(date("YmdHis"));//商户上报时间 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, false, $timeOut); + return $response; + } + + /** + * + * 生成二维码规则,模式一生成支付二维码 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayBizPayUrl $inputObj + * @param int $timeOut + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public static function bizpayurl($config, $inputObj, $timeOut = 6) + { + if(!$inputObj->IsProduct_idSet()){ + throw new WxPayException("生成二维码,缺少必填参数product_id!"); + } + + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetTime_stamp(time());//时间戳 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + + return $inputObj->GetValues(); + } + + /** + * + * 转换短链接 + * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX), + * 减小二维码数据量,提升扫描速度和精确度。 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayShortUrl $inputObj + * @param int $timeOut + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public static function shorturl($config, $inputObj, $timeOut = 6) + { + $url = "https://api.mch.weixin.qq.com/tools/shorturl"; + //检测必填参数 + if(!$inputObj->IsLong_urlSet()) { + throw new WxPayException("需要转换的URL,签名用原串,传输需URL encode!"); + } + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, false, $timeOut); + $result = WxPayResults::Init($config, $response); + self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 + + return $result; + } + + /** + * + * 支付结果通用通知 + * @param function $callback + * 直接回调函数使用方法: notify(you_function); + * 回调类成员函数方法:notify(array($this, you_function)); + * $callback 原型为:function function_name($data){} + */ + public static function notify($config, $callback, &$msg) + { + //获取通知的数据 + $xml = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input"); + if (empty($xml)) { + # 如果没有数据,直接返回失败 + return false; + } + + //如果返回成功则验证签名 + try { + $result = WxPayNotifyResults::Init($config, $xml); + } catch (WxPayException $e){ + $msg = $e->errorMessage(); + return false; + } + + return call_user_func($callback, $result); + } + + /** + * + * 产生随机字符串,不长于32位 + * @param int $length + * @return 产生的随机字符串 + */ + public static function getNonceStr($length = 32) + { + $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; + $str =""; + for ( $i = 0; $i < $length; $i++ ) { + $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); + } + return $str; + } + + /** + * 直接输出xml + * @param string $xml + */ + public static function replyNotify($xml) + { + echo $xml; + } + + /** + * + * 上报数据, 上报的时候将屏蔽所有异常流程 + * @param WxPayConfigInterface $config 配置对象 + * @param string $usrl + * @param int $startTimeStamp + * @param array $data + */ + private static function reportCostTime($config, $url, $startTimeStamp, $data) + { + //如果不需要上报数据 + $reportLevenl = $config->GetReportLevenl(); + if($reportLevenl == 0){ + return; + } + //如果仅失败上报 + if($reportLevenl == 1 && + array_key_exists("return_code", $data) && + $data["return_code"] == "SUCCESS" && + array_key_exists("result_code", $data) && + $data["result_code"] == "SUCCESS") + { + return; + } + + //上报逻辑 + $endTimeStamp = self::getMillisecond(); + $objInput = new WxPayReport(); + $objInput->SetInterface_url($url); + $objInput->SetExecute_time_($endTimeStamp - $startTimeStamp); + //返回状态码 + if(array_key_exists("return_code", $data)){ + $objInput->SetReturn_code($data["return_code"]); + } + //返回信息 + if(array_key_exists("return_msg", $data)){ + $objInput->SetReturn_msg($data["return_msg"]); + } + //业务结果 + if(array_key_exists("result_code", $data)){ + $objInput->SetResult_code($data["result_code"]); + } + //错误代码 + if(array_key_exists("err_code", $data)){ + $objInput->SetErr_code($data["err_code"]); + } + //错误代码描述 + if(array_key_exists("err_code_des", $data)){ + $objInput->SetErr_code_des($data["err_code_des"]); + } + //商户订单号 + if(array_key_exists("out_trade_no", $data)){ + $objInput->SetOut_trade_no($data["out_trade_no"]); + } + //设备号 + if(array_key_exists("device_info", $data)){ + $objInput->SetDevice_info($data["device_info"]); + } + + try{ + self::report($config, $objInput); + } catch (WxPayException $e){ + //不做任何处理 + } + } + + /** + * 以post方式提交xml到对应的接口url + * + * @param WxPayConfigInterface $config 配置对象 + * @param string $xml 需要post的xml数据 + * @param string $url url + * @param bool $useCert 是否需要证书,默认不需要 + * @param int $second url执行超时时间,默认30s + * @throws WxPayException + */ + private static function postXmlCurl($config, $xml, $url, $useCert = false, $second = 30) + { + $ch = curl_init(); + $curlVersion = curl_version(); + $ua = "WXPaySDK/".self::$VERSION." (".PHP_OS.") PHP/".PHP_VERSION." CURL/".$curlVersion['version']." " + .$config->GetMerchantId(); + + //设置超时 + curl_setopt($ch, CURLOPT_TIMEOUT, $second); + + $proxyHost = "0.0.0.0"; + $proxyPort = 0; + $config->GetProxy($proxyHost, $proxyPort); + //如果有配置代理这里就设置代理 + if($proxyHost != "0.0.0.0" && $proxyPort != 0){ + curl_setopt($ch,CURLOPT_PROXY, $proxyHost); + curl_setopt($ch,CURLOPT_PROXYPORT, $proxyPort); + } + curl_setopt($ch,CURLOPT_URL, $url); + curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); + curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验 + curl_setopt($ch,CURLOPT_USERAGENT, $ua); + //设置header + curl_setopt($ch, CURLOPT_HEADER, FALSE); + //要求结果为字符串且输出到屏幕上 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + + if($useCert == true){ + //设置证书 + //使用证书:cert 与 key 分别属于两个.pem文件 + //证书文件请放入服务器的非web目录下 + $sslCertPath = ""; + $sslKeyPath = ""; + $config->GetSSLCertPath($sslCertPath, $sslKeyPath); + curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); + curl_setopt($ch,CURLOPT_SSLCERT, $sslCertPath); + curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); + curl_setopt($ch,CURLOPT_SSLKEY, $sslKeyPath); + } + //post提交方式 + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); + //运行curl + $data = curl_exec($ch); + //返回结果 + if($data){ + curl_close($ch); + return $data; + } else { + $error = curl_errno($ch); + curl_close($ch); + throw new WxPayException("curl出错,错误码:$error"); + } + } + + /** + * 获取毫秒级别的时间戳 + */ + private static function getMillisecond() + { + //获取毫秒的时间戳 + $time = explode ( " ", microtime () ); + $time = $time[1] . ($time[0] * 1000); + $time2 = explode( ".", $time ); + $time = $time2[0]; + return $time; + } +} + diff --git a/serve/extend/wechat/WxPay.Config.Interface.php b/serve/extend/wechat/WxPay.Config.Interface.php new file mode 100644 index 0000000..5f02e5b --- /dev/null +++ b/serve/extend/wechat/WxPay.Config.Interface.php @@ -0,0 +1,76 @@ +appId; + } + + //商户号 + public function GetMerchantId(){ + return $this->merchantId; + } + + //异步通知地址 + public function GetNotifyUrl(){ + return $this->notifyUrl; + } + + //签名方式 + public function GetSignType(){ + return $this->signType; + } + + //代理信息 + public function GetProxy(&$proxyHost, &$proxyPort){ + $proxyHost = $this->proxyHost; + $proxyPort = $this->proxyPort; + } + + //错误上报等级 + public function GetReportLevenl(){ + return $this->reportLevenl; + } + + //支付密钥 + public function GetKey(){ + return $this->key; + } + + //公众帐号secert + public function GetAppSecret(){ + return $this->appSecret; + } + + //证书路径 + public function GetSSLCertPath(&$sslCertPath, &$sslKeyPath){ + $sslCertPath = $this->sslCertPath; + $sslKeyPath = $this->sslKeyPath; + } +} diff --git a/serve/extend/wechat/WxPay.Data.php b/serve/extend/wechat/WxPay.Data.php new file mode 100644 index 0000000..fcb4390 --- /dev/null +++ b/serve/extend/wechat/WxPay.Data.php @@ -0,0 +1,3094 @@ +values['sign_type'] = $sign_type; + return $sign_type; + } + + /** + * 设置签名,详见签名生成算法 + * @param string $value + **/ + public function SetSign($config) + { + $sign = $this->MakeSign($config); + $this->values['sign'] = $sign; + return $sign; + } + + /** + * 获取签名,详见签名生成算法的值 + * @return 值 + **/ + public function GetSign() + { + return $this->values['sign']; + } + + /** + * 判断签名,详见签名生成算法是否存在 + * @return true 或 false + **/ + public function IsSignSet() + { + return array_key_exists('sign', $this->values); + } + + /** + * 输出xml字符 + * @throws WxPayException + **/ + public function ToXml() + { + if(!is_array($this->values) || count($this->values) <= 0) + { + throw new WxPayException("数组数据异常!"); + } + + $xml = ""; + foreach ($this->values as $key=>$val) + { + if (is_numeric($val)){ + $xml.="<".$key.">".$val.""; + }else{ + $xml.="<".$key.">"; + } + } + $xml.=""; + return $xml; + } + + /** + * 将xml转为array + * @param string $xml + * @throws WxPayException + */ + public function FromXml($xml) + { + if(!$xml){ + throw new WxPayException("xml数据异常!"); + } + //将XML转为array + //禁止引用外部xml实体 + libxml_disable_entity_loader(true); + $this->values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); + return $this->values; + } + + /** + * 格式化参数格式化成url参数 + */ + public function ToUrlParams() + { + $buff = ""; + foreach ($this->values as $k => $v) + { + if($k != "sign" && $v != "" && !is_array($v)){ + $buff .= $k . "=" . $v . "&"; + } + } + + $buff = trim($buff, "&"); + return $buff; + } + + /** + * 生成签名 + * @param WxPayConfigInterface $config 配置对象 + * @param bool $needSignType 是否需要补signtype + * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值 + */ + public function MakeSign($config, $needSignType = true) + { + if($needSignType) { + $this->SetSignType($config->GetSignType()); + } + //签名步骤一:按字典序排序参数 + ksort($this->values); + $string = $this->ToUrlParams(); + //签名步骤二:在string后加入KEY + $string = $string . "&key=".$config->GetKey(); + //签名步骤三:MD5加密或者HMAC-SHA256 + if($config->GetSignType() == "MD5"){ + $string = md5($string); + } else if($config->GetSignType() == "HMAC-SHA256") { + $string = hash_hmac("sha256",$string ,$config->GetKey()); + } else { + throw new WxPayException("签名类型不支持!"); + } + + //签名步骤四:所有字符转为大写 + $result = strtoupper($string); + return $result; + } + + /** + * 获取设置的值 + */ + public function GetValues() + { + return $this->values; + } +} + +/** + * + * 只使用md5算法进行签名, 不管配置的是什么签名方式,都只支持md5签名方式 + * +**/ +class WxPayDataBaseSignMd5 extends WxPayDataBase +{ + /** + * 生成签名 - 重写该方法 + * @param WxPayConfigInterface $config 配置对象 + * @param bool $needSignType 是否需要补signtype + * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值 + */ + public function MakeSign($config, $needSignType = false) + { + if($needSignType) { + $this->SetSignType($config->GetSignType()); + } + //签名步骤一:按字典序排序参数 + ksort($this->values); + $string = $this->ToUrlParams(); + //签名步骤二:在string后加入KEY + $string = $string . "&key=".$config->GetKey(); + //签名步骤三:MD5加密 + $string = md5($string); + //签名步骤四:所有字符转为大写 + $result = strtoupper($string); + return $result; + } +} + +/** + * + * 接口调用结果类 + * @author widyhu + * + */ +class WxPayResults extends WxPayDataBase +{ + /** + * 生成签名 - 重写该方法 + * @param WxPayConfigInterface $config 配置对象 + * @param bool $needSignType 是否需要补signtype + * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值 + */ + public function MakeSign($config, $needSignType = false) + { + //签名步骤一:按字典序排序参数 + ksort($this->values); + $string = $this->ToUrlParams(); + //签名步骤二:在string后加入KEY + $string = $string . "&key=".$config->GetKey(); + //签名步骤三:MD5加密或者HMAC-SHA256 + if(strlen($this->GetSign()) <= 32){ + //如果签名小于等于32个,则使用md5验证 + $string = md5($string); + } else { + //是用sha256校验 + $string = hash_hmac("sha256",$string ,$config->GetKey()); + } + //签名步骤四:所有字符转为大写 + $result = strtoupper($string); + return $result; + } + + /** + * @param WxPayConfigInterface $config 配置对象 + * 检测签名 + */ + public function CheckSign($config) + { + if(!$this->IsSignSet()){ + throw new WxPayException("签名错误!"); + } + + $sign = $this->MakeSign($config, false); + if($this->GetSign() == $sign){ + //签名正确 + return true; + } + throw new WxPayException("签名错误!"); + } + + /** + * + * 使用数组初始化 + * @param array $array + */ + public function FromArray($array) + { + $this->values = $array; + } + + /** + * + * 使用数组初始化对象 + * @param array $array + * @param 是否检测签名 $noCheckSign + */ + public static function InitFromArray($config, $array, $noCheckSign = false) + { + $obj = new self(); + $obj->FromArray($array); + if($noCheckSign == false){ + $obj->CheckSign($config); + } + return $obj; + } + + /** + * + * 设置参数 + * @param string $key + * @param string $value + */ + public function SetData($key, $value) + { + $this->values[$key] = $value; + } + + /** + * 将xml转为array + * @param WxPayConfigInterface $config 配置对象 + * @param string $xml + * @throws WxPayException + */ + public static function Init($config, $xml) + { + $obj = new self(); + $obj->FromXml($xml); + //失败则直接返回失败 + if($obj->values['return_code'] != 'SUCCESS') { + foreach ($obj->values as $key => $value) { + #除了return_code和return_msg之外其他的参数存在,则报错 + if($key != "return_code" && $key != "return_msg"){ + throw new WxPayException("输入数据存在异常!"); + return false; + } + } + return $obj->GetValues(); + } + $obj->CheckSign($config); + return $obj->GetValues(); + } +} + +/** + * + * 回调回包数据基类 + * + **/ +class WxPayNotifyResults extends WxPayResults +{ + /** + * 将xml转为array + * @param WxPayConfigInterface $config + * @param string $xml + * @return WxPayNotifyResults + * @throws WxPayException + */ + public static function Init($config, $xml) + { + $obj = new self(); + $obj->FromXml($xml); + //失败则直接返回失败 + $obj->CheckSign($config); + return $obj; + } +} + +/** + * + * 回调基础类 + * @author widyhu + * + */ +class WxPayNotifyReply extends WxPayDataBaseSignMd5 +{ + /** + * + * 设置错误码 FAIL 或者 SUCCESS + * @param string + */ + public function SetReturn_code($return_code) + { + $this->values['return_code'] = $return_code; + } + + /** + * + * 获取错误码 FAIL 或者 SUCCESS + * @return string $return_code + */ + public function GetReturn_code() + { + return $this->values['return_code']; + } + + /** + * + * 设置错误信息 + * @param string $return_code + */ + public function SetReturn_msg($return_msg) + { + $this->values['return_msg'] = $return_msg; + } + + /** + * + * 获取错误信息 + * @return string + */ + public function GetReturn_msg() + { + return $this->values['return_msg']; + } + + /** + * + * 设置返回参数 + * @param string $key + * @param string $value + */ + public function SetData($key, $value) + { + $this->values[$key] = $value; + } +} + +/** + * + * 统一下单输入对象 + * @author widyhu + * + */ +class WxPayUnifiedOrder extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置微信支付分配的终端设备号,商户自定义 + * @param string $value + **/ + public function SetDevice_info($value) + { + $this->values['device_info'] = $value; + } + /** + * 获取微信支付分配的终端设备号,商户自定义的值 + * @return 值 + **/ + public function GetDevice_info() + { + return $this->values['device_info']; + } + /** + * 判断微信支付分配的终端设备号,商户自定义是否存在 + * @return true 或 false + **/ + public function IsDevice_infoSet() + { + return array_key_exists('device_info', $this->values); + } + + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } + + /** + * 设置商品或支付单简要描述 + * @param string $value + **/ + public function SetBody($value) + { + $this->values['body'] = $value; + } + /** + * 获取商品或支付单简要描述的值 + * @return 值 + **/ + public function GetBody() + { + return $this->values['body']; + } + /** + * 判断商品或支付单简要描述是否存在 + * @return true 或 false + **/ + public function IsBodySet() + { + return array_key_exists('body', $this->values); + } + + + /** + * 设置商品名称明细列表 + * @param string $value + **/ + public function SetDetail($value) + { + $this->values['detail'] = $value; + } + /** + * 获取商品名称明细列表的值 + * @return 值 + **/ + public function GetDetail() + { + return $this->values['detail']; + } + /** + * 判断商品名称明细列表是否存在 + * @return true 或 false + **/ + public function IsDetailSet() + { + return array_key_exists('detail', $this->values); + } + + + /** + * 设置附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 + * @param string $value + **/ + public function SetAttach($value) + { + $this->values['attach'] = $value; + } + /** + * 获取附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据的值 + * @return 值 + **/ + public function GetAttach() + { + return $this->values['attach']; + } + /** + * 判断附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据是否存在 + * @return true 或 false + **/ + public function IsAttachSet() + { + return array_key_exists('attach', $this->values); + } + + + /** + * 设置商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号 + * @param string $value + **/ + public function SetOut_trade_no($value) + { + $this->values['out_trade_no'] = $value; + } + /** + * 获取商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号的值 + * @return 值 + **/ + public function GetOut_trade_no() + { + return $this->values['out_trade_no']; + } + /** + * 判断商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号是否存在 + * @return true 或 false + **/ + public function IsOut_trade_noSet() + { + return array_key_exists('out_trade_no', $this->values); + } + + + /** + * 设置符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 + * @param string $value + **/ + public function SetFee_type($value) + { + $this->values['fee_type'] = $value; + } + /** + * 获取符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型的值 + * @return 值 + **/ + public function GetFee_type() + { + return $this->values['fee_type']; + } + /** + * 判断符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型是否存在 + * @return true 或 false + **/ + public function IsFee_typeSet() + { + return array_key_exists('fee_type', $this->values); + } + + + /** + * 设置订单总金额,只能为整数,详见支付金额 + * @param string $value + **/ + public function SetTotal_fee($value) + { + $this->values['total_fee'] = $value; + } + /** + * 获取订单总金额,只能为整数,详见支付金额的值 + * @return 值 + **/ + public function GetTotal_fee() + { + return $this->values['total_fee']; + } + /** + * 判断订单总金额,只能为整数,详见支付金额是否存在 + * @return true 或 false + **/ + public function IsTotal_feeSet() + { + return array_key_exists('total_fee', $this->values); + } + + + /** + * 设置APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。 + * @param string $value + **/ + public function SetSpbill_create_ip($value) + { + $this->values['spbill_create_ip'] = $value; + } + /** + * 获取APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。的值 + * @return 值 + **/ + public function GetSpbill_create_ip() + { + return $this->values['spbill_create_ip']; + } + /** + * 判断APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。是否存在 + * @return true 或 false + **/ + public function IsSpbill_create_ipSet() + { + return array_key_exists('spbill_create_ip', $this->values); + } + + + /** + * 设置订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则 + * @param string $value + **/ + public function SetTime_start($value) + { + $this->values['time_start'] = $value; + } + /** + * 获取订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则的值 + * @return 值 + **/ + public function GetTime_start() + { + return $this->values['time_start']; + } + /** + * 判断订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则是否存在 + * @return true 或 false + **/ + public function IsTime_startSet() + { + return array_key_exists('time_start', $this->values); + } + + + /** + * 设置订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则 + * @param string $value + **/ + public function SetTime_expire($value) + { + $this->values['time_expire'] = $value; + } + /** + * 获取订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则的值 + * @return 值 + **/ + public function GetTime_expire() + { + return $this->values['time_expire']; + } + /** + * 判断订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则是否存在 + * @return true 或 false + **/ + public function IsTime_expireSet() + { + return array_key_exists('time_expire', $this->values); + } + + + /** + * 设置商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠 + * @param string $value + **/ + public function SetGoods_tag($value) + { + $this->values['goods_tag'] = $value; + } + /** + * 获取商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠的值 + * @return 值 + **/ + public function GetGoods_tag() + { + return $this->values['goods_tag']; + } + /** + * 判断商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠是否存在 + * @return true 或 false + **/ + public function IsGoods_tagSet() + { + return array_key_exists('goods_tag', $this->values); + } + + + /** + * 设置接收微信支付异步通知回调地址 + * @param string $value + **/ + public function SetNotify_url($value) + { + $this->values['notify_url'] = $value; + } + /** + * 获取接收微信支付异步通知回调地址的值 + * @return 值 + **/ + public function GetNotify_url() + { + return $this->values['notify_url']; + } + /** + * 判断接收微信支付异步通知回调地址是否存在 + * @return true 或 false + **/ + public function IsNotify_urlSet() + { + return array_key_exists('notify_url', $this->values); + } + + + /** + * 设置取值如下:JSAPI,NATIVE,APP,详细说明见参数规定 + * @param string $value + **/ + public function SetTrade_type($value) + { + $this->values['trade_type'] = $value; + } + /** + * 获取取值如下:JSAPI,NATIVE,APP,详细说明见参数规定的值 + * @return 值 + **/ + public function GetTrade_type() + { + return $this->values['trade_type']; + } + /** + * 判断取值如下:JSAPI,NATIVE,APP,详细说明见参数规定是否存在 + * @return true 或 false + **/ + public function IsTrade_typeSet() + { + return array_key_exists('trade_type', $this->values); + } + + + /** + * 设置trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。 + * @param string $value + **/ + public function SetProduct_id($value) + { + $this->values['product_id'] = $value; + } + /** + * 获取trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。的值 + * @return 值 + **/ + public function GetProduct_id() + { + return $this->values['product_id']; + } + /** + * 判断trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。是否存在 + * @return true 或 false + **/ + public function IsProduct_idSet() + { + return array_key_exists('product_id', $this->values); + } + + + /** + * 设置trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 + * @param string $value + **/ + public function SetOpenid($value) + { + $this->values['openid'] = $value; + } + /** + * 获取trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 的值 + * @return 值 + **/ + public function GetOpenid() + { + return $this->values['openid']; + } + /** + * 判断trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。 是否存在 + * @return true 或 false + **/ + public function IsOpenidSet() + { + return array_key_exists('openid', $this->values); + } +} + +/** + * + * 订单查询输入对象 + * @author widyhu + * + */ +class WxPayOrderQuery extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置微信的订单号,优先使用 + * @param string $value + **/ + public function SetTransaction_id($value) + { + $this->values['transaction_id'] = $value; + } + /** + * 获取微信的订单号,优先使用的值 + * @return 值 + **/ + public function GetTransaction_id() + { + return $this->values['transaction_id']; + } + /** + * 判断微信的订单号,优先使用是否存在 + * @return true 或 false + **/ + public function IsTransaction_idSet() + { + return array_key_exists('transaction_id', $this->values); + } + + + /** + * 设置商户系统内部的订单号,当没提供transaction_id时需要传这个。 + * @param string $value + **/ + public function SetOut_trade_no($value) + { + $this->values['out_trade_no'] = $value; + } + /** + * 获取商户系统内部的订单号,当没提供transaction_id时需要传这个。的值 + * @return 值 + **/ + public function GetOut_trade_no() + { + return $this->values['out_trade_no']; + } + /** + * 判断商户系统内部的订单号,当没提供transaction_id时需要传这个。是否存在 + * @return true 或 false + **/ + public function IsOut_trade_noSet() + { + return array_key_exists('out_trade_no', $this->values); + } + + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } +} + +/** + * + * 关闭订单输入对象 + * @author widyhu + * + */ +class WxPayCloseOrder extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置商户系统内部的订单号 + * @param string $value + **/ + public function SetOut_trade_no($value) + { + $this->values['out_trade_no'] = $value; + } + /** + * 获取商户系统内部的订单号的值 + * @return 值 + **/ + public function GetOut_trade_no() + { + return $this->values['out_trade_no']; + } + /** + * 判断商户系统内部的订单号是否存在 + * @return true 或 false + **/ + public function IsOut_trade_noSet() + { + return array_key_exists('out_trade_no', $this->values); + } + + + /** + * 设置商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } +} + +/** + * + * 提交退款输入对象 + * @author widyhu + * + */ +class WxPayRefund extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置微信支付分配的终端设备号,与下单一致 + * @param string $value + **/ + public function SetDevice_info($value) + { + $this->values['device_info'] = $value; + } + /** + * 获取微信支付分配的终端设备号,与下单一致的值 + * @return 值 + **/ + public function GetDevice_info() + { + return $this->values['device_info']; + } + /** + * 判断微信支付分配的终端设备号,与下单一致是否存在 + * @return true 或 false + **/ + public function IsDevice_infoSet() + { + return array_key_exists('device_info', $this->values); + } + + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } + + /** + * 设置微信订单号 + * @param string $value + **/ + public function SetTransaction_id($value) + { + $this->values['transaction_id'] = $value; + } + /** + * 获取微信订单号的值 + * @return 值 + **/ + public function GetTransaction_id() + { + return $this->values['transaction_id']; + } + /** + * 判断微信订单号是否存在 + * @return true 或 false + **/ + public function IsTransaction_idSet() + { + return array_key_exists('transaction_id', $this->values); + } + + + /** + * 设置商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no + * @param string $value + **/ + public function SetOut_trade_no($value) + { + $this->values['out_trade_no'] = $value; + } + /** + * 获取商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no的值 + * @return 值 + **/ + public function GetOut_trade_no() + { + return $this->values['out_trade_no']; + } + /** + * 判断商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no是否存在 + * @return true 或 false + **/ + public function IsOut_trade_noSet() + { + return array_key_exists('out_trade_no', $this->values); + } + + + /** + * 设置商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔 + * @param string $value + **/ + public function SetOut_refund_no($value) + { + $this->values['out_refund_no'] = $value; + } + /** + * 获取商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔的值 + * @return 值 + **/ + public function GetOut_refund_no() + { + return $this->values['out_refund_no']; + } + /** + * 判断商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔是否存在 + * @return true 或 false + **/ + public function IsOut_refund_noSet() + { + return array_key_exists('out_refund_no', $this->values); + } + + + /** + * 设置订单总金额,单位为分,只能为整数,详见支付金额 + * @param string $value + **/ + public function SetTotal_fee($value) + { + $this->values['total_fee'] = $value; + } + /** + * 获取订单总金额,单位为分,只能为整数,详见支付金额的值 + * @return 值 + **/ + public function GetTotal_fee() + { + return $this->values['total_fee']; + } + /** + * 判断订单总金额,单位为分,只能为整数,详见支付金额是否存在 + * @return true 或 false + **/ + public function IsTotal_feeSet() + { + return array_key_exists('total_fee', $this->values); + } + + + /** + * 设置退款总金额,订单总金额,单位为分,只能为整数,详见支付金额 + * @param string $value + **/ + public function SetRefund_fee($value) + { + $this->values['refund_fee'] = $value; + } + /** + * 获取退款总金额,订单总金额,单位为分,只能为整数,详见支付金额的值 + * @return 值 + **/ + public function GetRefund_fee() + { + return $this->values['refund_fee']; + } + /** + * 判断退款总金额,订单总金额,单位为分,只能为整数,详见支付金额是否存在 + * @return true 或 false + **/ + public function IsRefund_feeSet() + { + return array_key_exists('refund_fee', $this->values); + } + + + /** + * 设置货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 + * @param string $value + **/ + public function SetRefund_fee_type($value) + { + $this->values['refund_fee_type'] = $value; + } + /** + * 获取货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型的值 + * @return 值 + **/ + public function GetRefund_fee_type() + { + return $this->values['refund_fee_type']; + } + /** + * 判断货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型是否存在 + * @return true 或 false + **/ + public function IsRefund_fee_typeSet() + { + return array_key_exists('refund_fee_type', $this->values); + } + + + /** + * 设置操作员帐号, 默认为商户号 + * @param string $value + **/ + public function SetOp_user_id($value) + { + $this->values['op_user_id'] = $value; + } + /** + * 获取操作员帐号, 默认为商户号的值 + * @return 值 + **/ + public function GetOp_user_id() + { + return $this->values['op_user_id']; + } + /** + * 判断操作员帐号, 默认为商户号是否存在 + * @return true 或 false + **/ + public function IsOp_user_idSet() + { + return array_key_exists('op_user_id', $this->values); + } +} + +/** + * + * 退款查询输入对象 + * @author widyhu + * + */ +class WxPayRefundQuery extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置微信支付分配的终端设备号 + * @param string $value + **/ + public function SetDevice_info($value) + { + $this->values['device_info'] = $value; + } + /** + * 获取微信支付分配的终端设备号的值 + * @return 值 + **/ + public function GetDevice_info() + { + return $this->values['device_info']; + } + /** + * 判断微信支付分配的终端设备号是否存在 + * @return true 或 false + **/ + public function IsDevice_infoSet() + { + return array_key_exists('device_info', $this->values); + } + + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } + + /** + * 设置微信订单号 + * @param string $value + **/ + public function SetTransaction_id($value) + { + $this->values['transaction_id'] = $value; + } + /** + * 获取微信订单号的值 + * @return 值 + **/ + public function GetTransaction_id() + { + return $this->values['transaction_id']; + } + /** + * 判断微信订单号是否存在 + * @return true 或 false + **/ + public function IsTransaction_idSet() + { + return array_key_exists('transaction_id', $this->values); + } + + + /** + * 设置商户系统内部的订单号 + * @param string $value + **/ + public function SetOut_trade_no($value) + { + $this->values['out_trade_no'] = $value; + } + /** + * 获取商户系统内部的订单号的值 + * @return 值 + **/ + public function GetOut_trade_no() + { + return $this->values['out_trade_no']; + } + /** + * 判断商户系统内部的订单号是否存在 + * @return true 或 false + **/ + public function IsOut_trade_noSet() + { + return array_key_exists('out_trade_no', $this->values); + } + + + /** + * 设置商户退款单号 + * @param string $value + **/ + public function SetOut_refund_no($value) + { + $this->values['out_refund_no'] = $value; + } + /** + * 获取商户退款单号的值 + * @return 值 + **/ + public function GetOut_refund_no() + { + return $this->values['out_refund_no']; + } + /** + * 判断商户退款单号是否存在 + * @return true 或 false + **/ + public function IsOut_refund_noSet() + { + return array_key_exists('out_refund_no', $this->values); + } + + + /** + * 设置微信退款单号refund_id、out_refund_no、out_trade_no、transaction_id四个参数必填一个,如果同时存在优先级为:refund_id>out_refund_no>transaction_id>out_trade_no + * @param string $value + **/ + public function SetRefund_id($value) + { + $this->values['refund_id'] = $value; + } + /** + * 获取微信退款单号refund_id、out_refund_no、out_trade_no、transaction_id四个参数必填一个,如果同时存在优先级为:refund_id>out_refund_no>transaction_id>out_trade_no的值 + * @return 值 + **/ + public function GetRefund_id() + { + return $this->values['refund_id']; + } + /** + * 判断微信退款单号refund_id、out_refund_no、out_trade_no、transaction_id四个参数必填一个,如果同时存在优先级为:refund_id>out_refund_no>transaction_id>out_trade_no是否存在 + * @return true 或 false + **/ + public function IsRefund_idSet() + { + return array_key_exists('refund_id', $this->values); + } +} + +/** + * + * 下载对账单输入对象 + * @author widyhu + * + */ +class WxPayDownloadBill extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单 + * @param string $value + **/ + public function SetDevice_info($value) + { + $this->values['device_info'] = $value; + } + /** + * 获取微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单的值 + * @return 值 + **/ + public function GetDevice_info() + { + return $this->values['device_info']; + } + /** + * 判断微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单是否存在 + * @return true 或 false + **/ + public function IsDevice_infoSet() + { + return array_key_exists('device_info', $this->values); + } + + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } + + /** + * 设置下载对账单的日期,格式:20140603 + * @param string $value + **/ + public function SetBill_date($value) + { + $this->values['bill_date'] = $value; + } + /** + * 获取下载对账单的日期,格式:20140603的值 + * @return 值 + **/ + public function GetBill_date() + { + return $this->values['bill_date']; + } + /** + * 判断下载对账单的日期,格式:20140603是否存在 + * @return true 或 false + **/ + public function IsBill_dateSet() + { + return array_key_exists('bill_date', $this->values); + } + + + /** + * 设置ALL,返回当日所有订单信息,默认值SUCCESS,返回当日成功支付的订单REFUND,返回当日退款订单REVOKED,已撤销的订单 + * @param string $value + **/ + public function SetBill_type($value) + { + $this->values['bill_type'] = $value; + } + /** + * 获取ALL,返回当日所有订单信息,默认值SUCCESS,返回当日成功支付的订单REFUND,返回当日退款订单REVOKED,已撤销的订单的值 + * @return 值 + **/ + public function GetBill_type() + { + return $this->values['bill_type']; + } + /** + * 判断ALL,返回当日所有订单信息,默认值SUCCESS,返回当日成功支付的订单REFUND,返回当日退款订单REVOKED,已撤销的订单是否存在 + * @return true 或 false + **/ + public function IsBill_typeSet() + { + return array_key_exists('bill_type', $this->values); + } +} + +/** + * + * 测速上报输入对象 + * @author widyhu + * + */ +class WxPayReport extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置微信支付分配的终端设备号,商户自定义 + * @param string $value + **/ + public function SetDevice_info($value) + { + $this->values['device_info'] = $value; + } + /** + * 获取微信支付分配的终端设备号,商户自定义的值 + * @return 值 + **/ + public function GetDevice_info() + { + return $this->values['device_info']; + } + /** + * 判断微信支付分配的终端设备号,商户自定义是否存在 + * @return true 或 false + **/ + public function IsDevice_infoSet() + { + return array_key_exists('device_info', $this->values); + } + + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } + + + /** + * 设置上报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder对于被扫支付,为更好的和商户共同分析一次业务行为的整体耗时情况,对于两种接入模式,请都在门店侧对一次被扫行为进行一次单独的整体上报,上报URL指定为:https://api.mch.weixin.qq.com/pay/micropay/total关于两种接入模式具体可参考本文档章节:被扫支付商户接入模式其它接口调用仍然按照调用一次,上报一次来进行。 + * @param string $value + **/ + public function SetInterface_url($value) + { + $this->values['interface_url'] = $value; + } + /** + * 获取上报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder对于被扫支付,为更好的和商户共同分析一次业务行为的整体耗时情况,对于两种接入模式,请都在门店侧对一次被扫行为进行一次单独的整体上报,上报URL指定为:https://api.mch.weixin.qq.com/pay/micropay/total关于两种接入模式具体可参考本文档章节:被扫支付商户接入模式其它接口调用仍然按照调用一次,上报一次来进行。的值 + * @return 值 + **/ + public function GetInterface_url() + { + return $this->values['interface_url']; + } + /** + * 判断上报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder对于被扫支付,为更好的和商户共同分析一次业务行为的整体耗时情况,对于两种接入模式,请都在门店侧对一次被扫行为进行一次单独的整体上报,上报URL指定为:https://api.mch.weixin.qq.com/pay/micropay/total关于两种接入模式具体可参考本文档章节:被扫支付商户接入模式其它接口调用仍然按照调用一次,上报一次来进行。是否存在 + * @return true 或 false + **/ + public function IsInterface_urlSet() + { + return array_key_exists('interface_url', $this->values); + } + + + /** + * 设置接口耗时情况,单位为毫秒 + * @param string $value + **/ + public function SetExecute_time_($value) + { + $this->values['execute_time_'] = $value; + } + /** + * 获取接口耗时情况,单位为毫秒的值 + * @return 值 + **/ + public function GetExecute_time_() + { + return $this->values['execute_time_']; + } + /** + * 判断接口耗时情况,单位为毫秒是否存在 + * @return true 或 false + **/ + public function IsExecute_time_Set() + { + return array_key_exists('execute_time_', $this->values); + } + + + /** + * 设置SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看trade_state来判断 + * @param string $value + **/ + public function SetReturn_code($value) + { + $this->values['return_code'] = $value; + } + /** + * 获取SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看trade_state来判断的值 + * @return 值 + **/ + public function GetReturn_code() + { + return $this->values['return_code']; + } + /** + * 判断SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看trade_state来判断是否存在 + * @return true 或 false + **/ + public function IsReturn_codeSet() + { + return array_key_exists('return_code', $this->values); + } + + + /** + * 设置返回信息,如非空,为错误原因签名失败参数格式校验错误 + * @param string $value + **/ + public function SetReturn_msg($value) + { + $this->values['return_msg'] = $value; + } + /** + * 获取返回信息,如非空,为错误原因签名失败参数格式校验错误的值 + * @return 值 + **/ + public function GetReturn_msg() + { + return $this->values['return_msg']; + } + /** + * 判断返回信息,如非空,为错误原因签名失败参数格式校验错误是否存在 + * @return true 或 false + **/ + public function IsReturn_msgSet() + { + return array_key_exists('return_msg', $this->values); + } + + + /** + * 设置SUCCESS/FAIL + * @param string $value + **/ + public function SetResult_code($value) + { + $this->values['result_code'] = $value; + } + /** + * 获取SUCCESS/FAIL的值 + * @return 值 + **/ + public function GetResult_code() + { + return $this->values['result_code']; + } + /** + * 判断SUCCESS/FAIL是否存在 + * @return true 或 false + **/ + public function IsResult_codeSet() + { + return array_key_exists('result_code', $this->values); + } + + + /** + * 设置ORDERNOTEXIST—订单不存在SYSTEMERROR—系统错误 + * @param string $value + **/ + public function SetErr_code($value) + { + $this->values['err_code'] = $value; + } + /** + * 获取ORDERNOTEXIST—订单不存在SYSTEMERROR—系统错误的值 + * @return 值 + **/ + public function GetErr_code() + { + return $this->values['err_code']; + } + /** + * 判断ORDERNOTEXIST—订单不存在SYSTEMERROR—系统错误是否存在 + * @return true 或 false + **/ + public function IsErr_codeSet() + { + return array_key_exists('err_code', $this->values); + } + + + /** + * 设置结果信息描述 + * @param string $value + **/ + public function SetErr_code_des($value) + { + $this->values['err_code_des'] = $value; + } + /** + * 获取结果信息描述的值 + * @return 值 + **/ + public function GetErr_code_des() + { + return $this->values['err_code_des']; + } + /** + * 判断结果信息描述是否存在 + * @return true 或 false + **/ + public function IsErr_code_desSet() + { + return array_key_exists('err_code_des', $this->values); + } + + + /** + * 设置商户系统内部的订单号,商户可以在上报时提供相关商户订单号方便微信支付更好的提高服务质量。 + * @param string $value + **/ + public function SetOut_trade_no($value) + { + $this->values['out_trade_no'] = $value; + } + /** + * 获取商户系统内部的订单号,商户可以在上报时提供相关商户订单号方便微信支付更好的提高服务质量。 的值 + * @return 值 + **/ + public function GetOut_trade_no() + { + return $this->values['out_trade_no']; + } + /** + * 判断商户系统内部的订单号,商户可以在上报时提供相关商户订单号方便微信支付更好的提高服务质量。 是否存在 + * @return true 或 false + **/ + public function IsOut_trade_noSet() + { + return array_key_exists('out_trade_no', $this->values); + } + + + /** + * 设置发起接口调用时的机器IP + * @param string $value + **/ + public function SetUser_ip($value) + { + $this->values['user_ip'] = $value; + } + /** + * 获取发起接口调用时的机器IP 的值 + * @return 值 + **/ + public function GetUser_ip() + { + return $this->values['user_ip']; + } + /** + * 判断发起接口调用时的机器IP 是否存在 + * @return true 或 false + **/ + public function IsUser_ipSet() + { + return array_key_exists('user_ip', $this->values); + } + + + /** + * 设置系统时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则 + * @param string $value + **/ + public function SetTime($value) + { + $this->values['time'] = $value; + } + /** + * 获取系统时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则的值 + * @return 值 + **/ + public function GetTime() + { + return $this->values['time']; + } + /** + * 判断系统时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则是否存在 + * @return true 或 false + **/ + public function IsTimeSet() + { + return array_key_exists('time', $this->values); + } +} + +/** + * + * 短链转换输入对象 + * @author widyhu + * + */ +class WxPayShortUrl extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置需要转换的URL,签名用原串,传输需URL encode + * @param string $value + **/ + public function SetLong_url($value) + { + $this->values['long_url'] = $value; + } + /** + * 获取需要转换的URL,签名用原串,传输需URL encode的值 + * @return 值 + **/ + public function GetLong_url() + { + return $this->values['long_url']; + } + /** + * 判断需要转换的URL,签名用原串,传输需URL encode是否存在 + * @return true 或 false + **/ + public function IsLong_urlSet() + { + return array_key_exists('long_url', $this->values); + } + + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } +} + +/** + * + * 提交被扫输入对象 + * @author widyhu + * + */ +class WxPayMicroPay extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置终端设备号(商户自定义,如门店编号) + * @param string $value + **/ + public function SetDevice_info($value) + { + $this->values['device_info'] = $value; + } + /** + * 获取终端设备号(商户自定义,如门店编号)的值 + * @return 值 + **/ + public function GetDevice_info() + { + return $this->values['device_info']; + } + /** + * 判断终端设备号(商户自定义,如门店编号)是否存在 + * @return true 或 false + **/ + public function IsDevice_infoSet() + { + return array_key_exists('device_info', $this->values); + } + + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } + + /** + * 设置商品或支付单简要描述 + * @param string $value + **/ + public function SetBody($value) + { + $this->values['body'] = $value; + } + /** + * 获取商品或支付单简要描述的值 + * @return 值 + **/ + public function GetBody() + { + return $this->values['body']; + } + /** + * 判断商品或支付单简要描述是否存在 + * @return true 或 false + **/ + public function IsBodySet() + { + return array_key_exists('body', $this->values); + } + + + /** + * 设置商品名称明细列表 + * @param string $value + **/ + public function SetDetail($value) + { + $this->values['detail'] = $value; + } + /** + * 获取商品名称明细列表的值 + * @return 值 + **/ + public function GetDetail() + { + return $this->values['detail']; + } + /** + * 判断商品名称明细列表是否存在 + * @return true 或 false + **/ + public function IsDetailSet() + { + return array_key_exists('detail', $this->values); + } + + + /** + * 设置附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 + * @param string $value + **/ + public function SetAttach($value) + { + $this->values['attach'] = $value; + } + /** + * 获取附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据的值 + * @return 值 + **/ + public function GetAttach() + { + return $this->values['attach']; + } + /** + * 判断附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据是否存在 + * @return true 或 false + **/ + public function IsAttachSet() + { + return array_key_exists('attach', $this->values); + } + + + /** + * 设置商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号 + * @param string $value + **/ + public function SetOut_trade_no($value) + { + $this->values['out_trade_no'] = $value; + } + /** + * 获取商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号的值 + * @return 值 + **/ + public function GetOut_trade_no() + { + return $this->values['out_trade_no']; + } + /** + * 判断商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号是否存在 + * @return true 或 false + **/ + public function IsOut_trade_noSet() + { + return array_key_exists('out_trade_no', $this->values); + } + + + /** + * 设置订单总金额,单位为分,只能为整数,详见支付金额 + * @param string $value + **/ + public function SetTotal_fee($value) + { + $this->values['total_fee'] = $value; + } + /** + * 获取订单总金额,单位为分,只能为整数,详见支付金额的值 + * @return 值 + **/ + public function GetTotal_fee() + { + return $this->values['total_fee']; + } + /** + * 判断订单总金额,单位为分,只能为整数,详见支付金额是否存在 + * @return true 或 false + **/ + public function IsTotal_feeSet() + { + return array_key_exists('total_fee', $this->values); + } + + + /** + * 设置符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 + * @param string $value + **/ + public function SetFee_type($value) + { + $this->values['fee_type'] = $value; + } + /** + * 获取符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型的值 + * @return 值 + **/ + public function GetFee_type() + { + return $this->values['fee_type']; + } + /** + * 判断符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型是否存在 + * @return true 或 false + **/ + public function IsFee_typeSet() + { + return array_key_exists('fee_type', $this->values); + } + + + /** + * 设置调用微信支付API的机器IP + * @param string $value + **/ + public function SetSpbill_create_ip($value) + { + $this->values['spbill_create_ip'] = $value; + } + /** + * 获取调用微信支付API的机器IP 的值 + * @return 值 + **/ + public function GetSpbill_create_ip() + { + return $this->values['spbill_create_ip']; + } + /** + * 判断调用微信支付API的机器IP 是否存在 + * @return true 或 false + **/ + public function IsSpbill_create_ipSet() + { + return array_key_exists('spbill_create_ip', $this->values); + } + + /** + * 设置订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。详见时间规则 + * @param string $value + **/ + public function SetTime_start($value) + { + $this->values['time_start'] = $value; + } + /** + * 获取订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。详见时间规则的值 + * @return 值 + **/ + public function GetTime_start() + { + return $this->values['time_start']; + } + /** + * 判断订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。详见时间规则是否存在 + * @return true 或 false + **/ + public function IsTime_startSet() + { + return array_key_exists('time_start', $this->values); + } + + + /** + * 设置订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。详见时间规则 + * @param string $value + **/ + public function SetTime_expire($value) + { + $this->values['time_expire'] = $value; + } + /** + * 获取订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。详见时间规则的值 + * @return 值 + **/ + public function GetTime_expire() + { + return $this->values['time_expire']; + } + /** + * 判断订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。详见时间规则是否存在 + * @return true 或 false + **/ + public function IsTime_expireSet() + { + return array_key_exists('time_expire', $this->values); + } + + + /** + * 设置商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠 + * @param string $value + **/ + public function SetGoods_tag($value) + { + $this->values['goods_tag'] = $value; + } + /** + * 获取商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠的值 + * @return 值 + **/ + public function GetGoods_tag() + { + return $this->values['goods_tag']; + } + /** + * 判断商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠是否存在 + * @return true 或 false + **/ + public function IsGoods_tagSet() + { + return array_key_exists('goods_tag', $this->values); + } + + + /** + * 设置扫码支付授权码,设备读取用户微信中的条码或者二维码信息 + * @param string $value + **/ + public function SetAuth_code($value) + { + $this->values['auth_code'] = $value; + } + /** + * 获取扫码支付授权码,设备读取用户微信中的条码或者二维码信息的值 + * @return 值 + **/ + public function GetAuth_code() + { + return $this->values['auth_code']; + } + /** + * 判断扫码支付授权码,设备读取用户微信中的条码或者二维码信息是否存在 + * @return true 或 false + **/ + public function IsAuth_codeSet() + { + return array_key_exists('auth_code', $this->values); + } +} + +/** + * + * 撤销输入对象 + * @author widyhu + * + */ +class WxPayReverse extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + + /** + * 设置微信的订单号,优先使用 + * @param string $value + **/ + public function SetTransaction_id($value) + { + $this->values['transaction_id'] = $value; + } + /** + * 获取微信的订单号,优先使用的值 + * @return 值 + **/ + public function GetTransaction_id() + { + return $this->values['transaction_id']; + } + /** + * 判断微信的订单号,优先使用是否存在 + * @return true 或 false + **/ + public function IsTransaction_idSet() + { + return array_key_exists('transaction_id', $this->values); + } + + + /** + * 设置商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no + * @param string $value + **/ + public function SetOut_trade_no($value) + { + $this->values['out_trade_no'] = $value; + } + /** + * 获取商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no的值 + * @return 值 + **/ + public function GetOut_trade_no() + { + return $this->values['out_trade_no']; + } + /** + * 判断商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no是否存在 + * @return true 或 false + **/ + public function IsOut_trade_noSet() + { + return array_key_exists('out_trade_no', $this->values); + } + + + /** + * 设置随机字符串,不长于32位。推荐随机数生成算法 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串,不长于32位。推荐随机数生成算法的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串,不长于32位。推荐随机数生成算法是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } +} + +/** + * + * 提交JSAPI输入对象 + * @author widyhu + * + */ +class WxPayJsApiPay extends WxPayDataBase +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appId'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appId']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appId', $this->values); + } + + + /** + * 设置支付时间戳 + * @param string $value + **/ + public function SetTimeStamp($value) + { + $this->values['timeStamp'] = $value; + } + /** + * 获取支付时间戳的值 + * @return 值 + **/ + public function GetTimeStamp() + { + return $this->values['timeStamp']; + } + /** + * 判断支付时间戳是否存在 + * @return true 或 false + **/ + public function IsTimeStampSet() + { + return array_key_exists('timeStamp', $this->values); + } + + /** + * 随机字符串 + * @param string $value + **/ + public function SetNonceStr($value) + { + $this->values['nonceStr'] = $value; + } + /** + * 获取notify随机字符串值 + * @return 值 + **/ + public function GetReturn_code() + { + return $this->values['nonceStr']; + } + /** + * 判断随机字符串是否存在 + * @return true 或 false + **/ + public function IsReturn_codeSet() + { + return array_key_exists('nonceStr', $this->values); + } + + + /** + * 设置订单详情扩展字符串 + * @param string $value + **/ + public function SetPackage($value) + { + $this->values['package'] = $value; + } + /** + * 获取订单详情扩展字符串的值 + * @return 值 + **/ + public function GetPackage() + { + return $this->values['package']; + } + /** + * 判断订单详情扩展字符串是否存在 + * @return true 或 false + **/ + public function IsPackageSet() + { + return array_key_exists('package', $this->values); + } + + /** + * 设置签名方式 + * @param string $value + **/ + public function SetSignType($value) + { + $this->values['signType'] = $value; + } + /** + * 获取签名方式 + * @return 值 + **/ + public function GetSignType() + { + return $this->values['signType']; + } + /** + * 判断签名方式是否存在 + * @return true 或 false + **/ + public function IsSignTypeSet() + { + return array_key_exists('signType', $this->values); + } + + /** + * 设置签名方式 + * @param string $value + **/ + public function SetPaySign($value) + { + $this->values['paySign'] = $value; + } + /** + * 获取签名方式 + * @return 值 + **/ + public function GetPaySign() + { + return $this->values['paySign']; + } + /** + * 判断签名方式是否存在 + * @return true 或 false + **/ + public function IsPaySignSet() + { + return array_key_exists('paySign', $this->values); + } +} + +/** + * + * 扫码支付模式一生成二维码参数 + * @author widyhu + * + */ +class WxPayBizPayUrl extends WxPayDataBaseSignMd5 +{ + /** + * 设置微信分配的公众账号ID + * @param string $value + **/ + public function SetAppid($value) + { + $this->values['appid'] = $value; + } + /** + * 获取微信分配的公众账号ID的值 + * @return 值 + **/ + public function GetAppid() + { + return $this->values['appid']; + } + /** + * 判断微信分配的公众账号ID是否存在 + * @return true 或 false + **/ + public function IsAppidSet() + { + return array_key_exists('appid', $this->values); + } + + + /** + * 设置微信支付分配的商户号 + * @param string $value + **/ + public function SetMch_id($value) + { + $this->values['mch_id'] = $value; + } + /** + * 获取微信支付分配的商户号的值 + * @return 值 + **/ + public function GetMch_id() + { + return $this->values['mch_id']; + } + /** + * 判断微信支付分配的商户号是否存在 + * @return true 或 false + **/ + public function IsMch_idSet() + { + return array_key_exists('mch_id', $this->values); + } + + /** + * 设置支付时间戳 + * @param string $value + **/ + public function SetTime_stamp($value) + { + $this->values['time_stamp'] = $value; + } + /** + * 获取支付时间戳的值 + * @return 值 + **/ + public function GetTime_stamp() + { + return $this->values['time_stamp']; + } + /** + * 判断支付时间戳是否存在 + * @return true 或 false + **/ + public function IsTime_stampSet() + { + return array_key_exists('time_stamp', $this->values); + } + + /** + * 设置随机字符串 + * @param string $value + **/ + public function SetNonce_str($value) + { + $this->values['nonce_str'] = $value; + } + /** + * 获取随机字符串的值 + * @return 值 + **/ + public function GetNonce_str() + { + return $this->values['nonce_str']; + } + /** + * 判断随机字符串是否存在 + * @return true 或 false + **/ + public function IsNonce_strSet() + { + return array_key_exists('nonce_str', $this->values); + } + + /** + * 设置商品ID + * @param string $value + **/ + public function SetProduct_id($value) + { + $this->values['product_id'] = $value; + } + /** + * 获取商品ID的值 + * @return 值 + **/ + public function GetProduct_id() + { + return $this->values['product_id']; + } + /** + * 判断商品ID是否存在 + * @return true 或 false + **/ + public function IsProduct_idSet() + { + return array_key_exists('product_id', $this->values); + } +} + diff --git a/serve/extend/wechat/WxPay.Exception.php b/serve/extend/wechat/WxPay.Exception.php new file mode 100644 index 0000000..dbe0853 --- /dev/null +++ b/serve/extend/wechat/WxPay.Exception.php @@ -0,0 +1,13 @@ +getMessage(); + } +} diff --git a/serve/extend/wechat/WxPay.Notify.php b/serve/extend/wechat/WxPay.Notify.php new file mode 100644 index 0000000..b3ca623 --- /dev/null +++ b/serve/extend/wechat/WxPay.Notify.php @@ -0,0 +1,105 @@ +config = $config; + $msg = "OK"; + //当返回false的时候,表示notify中调用NotifyCallBack回调失败获取签名校验失败,此时直接回复失败 + $result = WxpayApi::notify($config, array($this, 'NotifyCallBack'), $msg); + if($result == false){ + $this->SetReturn_code("FAIL"); + $this->SetReturn_msg($msg); + $this->ReplyNotify(false); + return; + } else { + //该分支在成功回调到NotifyCallBack方法,处理完成之后流程 + $this->SetReturn_code("SUCCESS"); + $this->SetReturn_msg("OK"); + } + $this->ReplyNotify($needSign); + } + + /** + * + * 回调方法入口,子类可重写该方法 + //TODO 1、进行参数校验 + //TODO 2、进行签名验证 + //TODO 3、处理业务逻辑 + * 注意: + * 1、微信回调超时时间为2s,建议用户使用异步处理流程,确认成功之后立刻回复微信服务器 + * 2、微信服务器在调用失败或者接到回包为非确认包的时候,会发起重试,需确保你的回调是可以重入 + * @param WxPayNotifyResults $objData 回调解释出的参数 + * @param WxPayConfigInterface $config + * @param string $msg 如果回调处理失败,可以将错误信息输出到该方法 + * @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调 + */ + public function NotifyProcess($objData, $config, &$msg) + { + //TODO 用户基础该类之后需要重写该方法,成功的时候返回true,失败返回false + return false; + } + + /** + * + * 业务可以继承该方法,打印XML方便定位. + * @param string $xmlData 返回的xml参数 + * + **/ + public function LogAfterProcess($xmlData) + { + return; + } + + /** + * + * notify回调方法,该方法中需要赋值需要输出的参数,不可重写 + * @param array $data + * @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调 + */ + final public function NotifyCallBack($data) + { + $msg = "OK"; + $result = $this->NotifyProcess($data, $this->config, $msg); + + if($result == true){ + $this->SetReturn_code("SUCCESS"); + $this->SetReturn_msg("OK"); + } else { + $this->SetReturn_code("FAIL"); + $this->SetReturn_msg($msg); + } + return $result; + } + + /** + * + * 回复通知 + * @param bool $needSign 是否需要签名输出 + */ + final private function ReplyNotify($needSign = true) + { + //如果需要签名 + if($needSign == true && + $this->GetReturn_code() == "SUCCESS") + { + $this->SetSign($this->config); + } + + $xml = $this->ToXml(); + $this->LogAfterProcess($xml); + WxpayApi::replyNotify($xml); + } +} \ No newline at end of file diff --git a/serve/favicon.ico b/serve/favicon.ico new file mode 100644 index 0000000..b4bdb9d Binary files /dev/null and b/serve/favicon.ico differ diff --git a/serve/index.php b/serve/index.php new file mode 100644 index 0000000..3ef963a --- /dev/null +++ b/serve/index.php @@ -0,0 +1,30 @@ + +// +---------------------------------------------------------------------- + +// [ 应用入口文件 ] +namespace think; +//安装向导 +if(is_dir('install')){ + if (!file_exists('install/install.lock')) { + header("Location:/install"); + exit; + } +} +require __DIR__ . '/vendor/autoload.php'; + +// 执行HTTP应用并响应 +$http = (new App())->http; + +$response = $http->run(); + +$response->send(); + +$http->end($response); diff --git a/serve/install/css/lib.css b/serve/install/css/lib.css new file mode 100644 index 0000000..aad140a --- /dev/null +++ b/serve/install/css/lib.css @@ -0,0 +1,117 @@ +*{ + margin: 0; + padding: 0; +} +body { + font: 14px "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif; + background: #f9f9f9; +} +header{ + height:80px; + background: #0F86EA; +} +.container{ + width: 820px; + margin: 0 auto; +} +.title{ + color: #fff; + position: relative; +} +.title .name{ + font-size: 18px; + line-height: 80px; +} +.title .product{ + position: absolute; + right: 0; + bottom: 6px; +} +.box{ + margin-top: 32px; + padding: 9px 12px; + border-radius: 2px; + background: #fcfcfc; + border: 1px solid #ccc; +} +.box > div{ + display: none; +} +.box button{ + padding: 2px 6px; +} +fieldset { + padding: 9px 12px; + border: 1px solid #eee; + background: #fafafa; +} +legend { + color: #4275a5; + font-weight: bold; +} +.success{ + color: #009933; +} +.success i{ + background: url(../img/success.png) 0 no-repeat; +} +.warning{ + color: #f00; +} +.warning i{ + background: url(../img/warning.png) 0 no-repeat; +} +#content1 > *{ + color: #333; + line-height: 24px; +} +#content2 > *{ + margin-bottom: 12px; +} +#content2 ul{ + width: 90%; + margin: 0 auto; + list-style-type:none; +} +#content2 li{ + width: 30%; + float: left; + line-height: 36px; +} +#content2 li i{ + float: right; + margin-right: 20%; +} +#content2 li span{ + width: 200px; +} +#content2 .group{ + text-align: center; +} +#content2 .group button{ + display: inline; +} +#content3{ + color: #333; +} +#content3 > *{ + margin-bottom: 12px; +} +#content3 .form{ + margin-left: 16%; +} +#content3 .form .row{ + line-height: 36px; +} +#content3 .form tip{ + color: #999; +} +#content4 > *{ + text-align: center; + margin-bottom: 12px; +} +footer p{ + margin: 15px 0; + font-size: 12px; + text-align: center; +} \ No newline at end of file diff --git a/serve/install/img/success.png b/serve/install/img/success.png new file mode 100644 index 0000000..fc5029a Binary files /dev/null and b/serve/install/img/success.png differ diff --git a/serve/install/img/warning.png b/serve/install/img/warning.png new file mode 100644 index 0000000..348e447 Binary files /dev/null and b/serve/install/img/warning.png differ diff --git a/serve/install/index.php b/serve/install/index.php new file mode 100644 index 0000000..6a1edd3 --- /dev/null +++ b/serve/install/index.php @@ -0,0 +1,144 @@ + + + + + + 点可云软件安装向导 + + + +
+
+
+ [ 点可云软件中心 ] + 进销存软件 +
+
+
+
+
+
+
+

最终用户授权许可协议

+

感谢您选择点可云系列软件(以下简称本软件),我们致力于让办公简单、轻松、自动化,为云端办公而不懈努力!

+

本《最终用户授权许可协议》(以下简称本协议)是您(自然人、法人或其他组织)有关安装、复制、修改、使用本软件的法律协议,同时本协议亦适用于任何有关本软件的后期更新和升级。一旦以任何方式使用本软件,即表明您同意接受本协议各项条款的约束。

+

如果您不同意本协议中的条款,必须删除本软件及相关资料。

+

协议许可范围声明:

+

1. 本软件适用于学习与交流用途,不可用于商业用途,商业用途包括但不限于销售,转售,二次开发,OEM等,如需商业用途必须取得专属授权。

+

2.本软件允许免费使用,禁止对软件修改后二次发布,构成恶意传播的将一律视为侵权。

+

3.为了更好服务,本软件可能会收集您的域名等信息,并承诺不会收集除此之外的任何数据信息。

+

有限担保和免责声明:

+

1.本软件和附带的资料是作为不提供任何明确的或隐含的赔偿或担保的形式提供的。

+

2.用户出于自愿而使用本软件,您必须了解使用本软件系统的风险,在尚未获得合法授权前,我们不承诺提供任何形式的使用担保、技术支持,同时也不承担任何因使用本软件而产生的问题或损失的相关责任。

+

3.我方不对使用本软件构建的任何站点的任何信息内容导致的任何版权纠纷和法律争议及后果承担责任。

+

4.本协议的电子文档形式同双方书面签署协议一样,具有完全的和等同的法律效力。您一旦开始确认本协议并安装本软件,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的权力的同时受到相关的约束和限制。

+

5.本协议许可范围以外的行为,将直接违反本协议并构成侵权,我们有权随时终止授权、责令停止损害,并保留追究相关责任的权力。

+

6.本软件著作权所有者享有最终解释权。

+ 点可云软件中心 +
+ +
+
+

请检查您的服务器是否支持安装本软件,请在继续安装前消除警告信息。

+
+ 环境检测结果 +

+      + 解析引擎 + +

+

+      + PHP版本 + +

+
+
+ 目录权限与函数库 +

要能正常使用本软件,需要将如下文件或目录清单CHMOD设置为 777 或 666,并启用相关支持函数库。

+
    + +
  • +

    + +      +

    +
  • + + +
  • +

    + +      +

    +
  • + +
  • +

    "> + pdo_mysql +      +

    +
  • +
  • +

    "> + openssl +      +

    +
  • +
+
+
+ + +
+
+
+

您需要在下方输入数据库相关配置信息。

+
+ 数据库配置 +
+
+ 数据库地址: + + 数据库地址,一般无需更改。 +
+
+ 数据库名称: + + 数据库名称,请确保用字母开头。 +
+
+ 数据库账号: + +
+
+ 数据库密码: + +
+
+
+ +
+
+

:) 恭喜您,安装成功。

+

从今天开始,点可云软件将为您服务,感谢您的信任与支持。

+

默认登陆账号:admin 密码:admin888 登陆系统后您可以自行更改密码。

+

建议您删除 install 目录,以防止再次安装而覆盖数据。

+ 点此登陆系统 +
+
+
+
+ + + + + diff --git a/serve/install/js/jquery.js b/serve/install/js/jquery.js new file mode 100644 index 0000000..a1c07fd --- /dev/null +++ b/serve/install/js/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0 div').hide(); + var target = hash == "" ? 1 : hash.charAt(hash.length - 1); + $('.box > div').eq(target - 1).show(); + target != 1 && (location.hash = '#' + target); +} +function save() { + $('#save').attr("disabled",true); + $.ajax({ + type: 'post', + url: '/install/lib/base.php?act=install', + data: { + dbhost:$('#dbhost').val(), + dbname:$('#dbname').val(), + dbuser:$('#dbuser').val(), + dbpwd:$('#dbpwd').val(), + }, + dataType: "json", + success: function(resule){ + $('#save').attr("disabled",false); + if(resule.state=='success'){ + showHash('#4'); + }else{ + alert(resule.info); + $('#save').attr("disabled",false); + } + }, + error: function(resule) { + console.log(resule); + alert('[ Error ] 请求处理失败,错误信息已输出控制台!'); + $('#save').attr("disabled",false); + }, + }); +} \ No newline at end of file diff --git a/serve/install/lib/base.php b/serve/install/lib/base.php new file mode 100644 index 0000000..72dcec8 --- /dev/null +++ b/serve/install/lib/base.php @@ -0,0 +1,79 @@ +'error','info'=>'配置信息填写不完全!']); + $conn = @mysqli_connect($dbhost,$dbuser,$dbpwd); + !$conn && returnJson(['state'=>'error','info'=>'连接数据库失败,请核实配置信息!']); + mysqli_query($conn,"SET NAMES 'utf8', character_set_client=binary, sql_mode='', interactive_timeout=3600;"); + $list = mysqli_query($conn,'show Databases'); + while ($row = mysqli_fetch_array($list)) { + $dbname_arr[] = $row['Database']; + } + if (!in_array($dbname,$dbname_arr)) { + !mysqli_query($conn,'CREATE DATABASE '.$dbname.'') && returnJson(['state'=>'error','info'=>'创建数据库失败!']); + } + mysqli_select_db($conn,$dbname); + $sql = fetchFile('mysql.sql'); + $sqlarr = explode(";\n",$sql); + foreach ($sqlarr as $sql) { + mysqli_query($conn,$sql); + } + //创建数据库连接文件 + $database = fetchFile('database.ini'); + $database = str_replace('{db_host}',$dbhost,$database); + $database = str_replace('{db_user}',$dbuser,$database); + $database = str_replace('{db_pwd}',$dbpwd,$database); + $database = str_replace('{db_name}',$dbname,$database); + if (!writeFile('../../config/database.php',$database)) { + returnJson(['state'=>'error','info'=>'数据库连接文件创建失败!']); + } + writeFile('../install.lock','软件已正确安装,重新安装请删除本文件。'); + returnJson(['state'=>'success']); + } +?> \ No newline at end of file diff --git a/serve/install/lib/database.ini b/serve/install/lib/database.ini new file mode 100644 index 0000000..f874d68 --- /dev/null +++ b/serve/install/lib/database.ini @@ -0,0 +1,56 @@ + Env::get('database.driver', 'mysql'), + // 自定义时间查询规则 + 'time_query_rule' => [], + // 自动写入时间戳字段 + // true为自动识别类型 false关闭 + // 字符串则明确指定时间字段类型 支持 int timestamp datetime date + 'auto_timestamp' => true, + // 时间字段取出后的默认时间格式 + 'datetime_format' => 'Y-m-d H:i:s', + // 数据库连接配置信息 + 'connections' => [ + 'mysql' => [ + // 数据库类型 + 'type' => Env::get('database.type', 'mysql'), + // 服务器地址 + 'hostname' => Env::get('database.hostname', '{db_host}'), + // 数据库名 + 'database' => Env::get('database.database', '{db_name}'), + // 用户名 + 'username' => Env::get('database.username', '{db_user}'), + // 密码 + 'password' => Env::get('database.password', '{db_pwd}'), + // 端口 + 'hostport' => Env::get('database.hostport', '3306'), + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 + 'charset' => Env::get('database.charset', 'utf8'), + // 数据库表前缀 + 'prefix' => Env::get('database.prefix', 'is_'), + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 是否需要断线重连 + 'break_reconnect' => false, + // 监听SQL + 'trigger_sql' => true, + // 开启字段缓存 + 'fields_cache' => false, + // 字段缓存路径 + 'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR, + ], + // 更多的数据库配置信息 + ] +]; diff --git a/serve/install/lib/mysql.sql b/serve/install/lib/mysql.sql new file mode 100644 index 0000000..b84a734 --- /dev/null +++ b/serve/install/lib/mysql.sql @@ -0,0 +1,1648 @@ +-- Adminer 4.7.7 MySQL dump + +SET NAMES utf8; +SET time_zone = '+00:00'; +SET foreign_key_checks = 0; +SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; + +DROP TABLE IF EXISTS `is_account`; +CREATE TABLE `is_account` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '账户名称', + `number` varchar(32) NOT NULL COMMENT '账户编号', + `frame` int(11) NOT NULL COMMENT '所属组织', + `time` int(11) NOT NULL COMMENT '余额日期', + `initial` decimal(16,4) NOT NULL COMMENT '期初余额', + `balance` decimal(16,4) DEFAULT '0.0000' COMMENT '账户余额', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `frame` (`frame`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='资金账户'; + + +DROP TABLE IF EXISTS `is_account_info`; +CREATE TABLE `is_account_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属账户', + `type` varchar(32) NOT NULL COMMENT '单据类型', + `class` int(11) NOT NULL COMMENT '所属类', + `time` int(11) NOT NULL COMMENT '单据时间', + `direction` tinyint(1) NOT NULL COMMENT '方向[0:出|1:入]', + `money` decimal(16,4) NOT NULL COMMENT '金额', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `class` (`class`), + KEY `time` (`time`), + KEY `direction` (`direction`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='资金详情'; + + +DROP TABLE IF EXISTS `is_allot`; +CREATE TABLE `is_allot` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `frame` int(11) NOT NULL COMMENT '所属组织', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `people` (`people`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='转账单'; + + +DROP TABLE IF EXISTS `is_allot_info`; +CREATE TABLE `is_allot_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `account` int(11) NOT NULL COMMENT '转出账户', + `tat` int(11) NOT NULL COMMENT '转入账户', + `money` decimal(12,4) NOT NULL COMMENT '结算金额', + `settle` varchar(256) DEFAULT '' COMMENT '结算号', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `account` (`account`), + KEY `tat` (`tat`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='转账单详情'; + + +DROP TABLE IF EXISTS `is_attr`; +CREATE TABLE `is_attr` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属商品', + `name` varchar(64) NOT NULL COMMENT '属性名称', + `buy` decimal(12,4) NOT NULL COMMENT '采购价格', + `sell` decimal(12,4) NOT NULL COMMENT '销售价格', + `code` varchar(64) NOT NULL COMMENT '条形码', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `code` (`code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='辅助属性[商品]'; + + +DROP TABLE IF EXISTS `is_attribute`; +CREATE TABLE `is_attribute` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '属性名称', + `sort` int(11) NOT NULL COMMENT '属性排序', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `sort` (`sort`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='辅助属性[基础]'; + + +DROP TABLE IF EXISTS `is_attribute_info`; +CREATE TABLE `is_attribute_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属属性', + `name` varchar(32) NOT NULL COMMENT '属性名称', + PRIMARY KEY (`id`), + KEY `pid` (`pid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='属性详情表'; + +DROP TABLE IF EXISTS `is_batch`; +CREATE TABLE `is_batch` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `room` int(11) NOT NULL COMMENT '所属仓储', + `warehouse` int(11) NOT NULL COMMENT '所属仓库', + `goods` int(11) NOT NULL COMMENT '所属商品', + `number` varchar(64) NOT NULL COMMENT '批次号', + `time` int(11) DEFAULT '0' COMMENT '生产日期', + `nums` decimal(12,4) NOT NULL COMMENT '库存数量', + PRIMARY KEY (`id`), + KEY `room` (`room`), + KEY `warehouse` (`warehouse`), + KEY `goods` (`goods`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='批次号'; + + +DROP TABLE IF EXISTS `is_batch_info`; +CREATE TABLE `is_batch_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属批次', + `type` varchar(32) NOT NULL COMMENT '单据类型', + `class` int(11) NOT NULL COMMENT '所属类', + `info` int(11) NOT NULL COMMENT '所属详情', + `direction` tinyint(1) NOT NULL COMMENT '方向[0:出|1:入]', + `nums` decimal(12,4) NOT NULL COMMENT '出入数量', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `type` (`type`), + KEY `direction` (`direction`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='批次号详情'; + + +DROP TABLE IF EXISTS `is_bill`; +CREATE TABLE `is_bill` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `frame` int(11) NOT NULL COMMENT '所属组织', + `customer` int(11) NOT NULL COMMENT '客户', + `supplier` int(11) NOT NULL COMMENT '供应商', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `type` tinyint(1) NOT NULL COMMENT '核销类型[0:预收冲应收|1:预付冲应付|2:应收冲应付|3:销退冲销售|4:购退冲采购]', + `pmy` decimal(16,4) NOT NULL COMMENT '总核金额', + `smp` decimal(16,4) NOT NULL COMMENT '总销金额', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `customer` (`customer`), + KEY `time` (`time`), + KEY `type` (`type`), + KEY `people` (`people`), + KEY `examine` (`examine`), + KEY `user` (`user`), + KEY `supplier` (`supplier`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='核销单'; + + +DROP TABLE IF EXISTS `is_bill_info`; +CREATE TABLE `is_bill_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `source` int(11) NOT NULL COMMENT '关联单据', + `bill` varchar(32) NOT NULL COMMENT '核销类型', + `mold` varchar(32) NOT NULL COMMENT '单据类型', + `money` decimal(12,4) NOT NULL COMMENT '核销金额', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `source` (`source`), + KEY `mold` (`mold`), + KEY `bill` (`bill`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='核销单详情'; + + +DROP TABLE IF EXISTS `is_bor`; +CREATE TABLE `is_bor` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `source` int(11) NOT NULL COMMENT '关联单据|Sor', + `frame` int(11) NOT NULL COMMENT '所属组织', + `supplier` int(11) NOT NULL COMMENT '供应商', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `actual` decimal(16,4) NOT NULL COMMENT '实际金额', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `arrival` int(11) NOT NULL COMMENT '到货时间', + `logistics` text COMMENT '物流信息', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `state` tinyint(1) NOT NULL COMMENT '入库状态[0:未入库|1:部分入库|2:已入库|3:关闭]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `supplier` (`supplier`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `state` (`state`), + KEY `source` (`source`), + KEY `people` (`people`), + KEY `arrival` (`arrival`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采购订单'; + + +DROP TABLE IF EXISTS `is_bor_info`; +CREATE TABLE `is_bor_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `unit` varchar(32) NOT NULL COMMENT '单位', + `warehouse` int(11) DEFAULT '0' COMMENT '仓库', + `price` decimal(12,4) NOT NULL COMMENT '单价', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + `discount` decimal(5,2) NOT NULL COMMENT '折扣率', + `dsc` decimal(12,4) NOT NULL COMMENT '折扣额', + `total` decimal(12,4) NOT NULL COMMENT '金额', + `tax` decimal(5,2) NOT NULL COMMENT '税率', + `tat` decimal(12,4) NOT NULL COMMENT '税额', + `tpt` decimal(12,4) NOT NULL COMMENT '价税合计', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `handle` decimal(12,4) DEFAULT '0.0000' COMMENT '入库数量', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采购订单详情'; + + +DROP TABLE IF EXISTS `is_bre`; +CREATE TABLE `is_bre` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `source` int(11) NOT NULL COMMENT '关联单据|BUY', + `frame` int(11) NOT NULL COMMENT '所属组织', + `supplier` int(11) NOT NULL COMMENT '供应商', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `actual` decimal(16,4) NOT NULL COMMENT '实际金额', + `money` decimal(16,4) NOT NULL COMMENT '实收金额', + `cost` decimal(16,4) NOT NULL COMMENT '单据费用', + `account` int(11) DEFAULT '0' COMMENT '结算账户', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `logistics` text COMMENT '物流信息', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `nucleus` tinyint(1) NOT NULL COMMENT '核销状态[0:未核销|1:部分核销|2:已核销]', + `cse` tinyint(1) NOT NULL COMMENT '费用状态[0:未结算|1:部分结算|2:已结算|3:无需结算]', + `invoice` tinyint(1) NOT NULL COMMENT '发票状态[0:未开票|1:部分开票|2:已开票|3:无需开具]', + `check` tinyint(1) NOT NULL COMMENT '核对状态[0:未核对|1:已核对]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `supplier` (`supplier`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `nucleus` (`nucleus`), + KEY `source` (`source`), + KEY `people` (`people`), + KEY `cse` (`cse`), + KEY `invoice` (`invoice`), + KEY `check` (`check`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采购退货单'; + + +DROP TABLE IF EXISTS `is_bre_bill`; +CREATE TABLE `is_bre_bill` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属单据', + `type` varchar(32) NOT NULL COMMENT '核销类型', + `source` int(11) NOT NULL COMMENT '关联单据', + `time` int(11) NOT NULL COMMENT '单据时间', + `money` decimal(16,4) NOT NULL COMMENT '核销金额', + PRIMARY KEY (`id`), + KEY `pid_account_user` (`pid`), + KEY `type` (`type`), + KEY `source` (`source`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采购退货单核销详情'; + + +DROP TABLE IF EXISTS `is_bre_info`; +CREATE TABLE `is_bre_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `source` int(11) NOT NULL COMMENT '关联详情|BUY', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `unit` varchar(32) NOT NULL COMMENT '单位', + `warehouse` int(11) DEFAULT '0' COMMENT '仓库', + `batch` varchar(32) NOT NULL COMMENT '批次号', + `mfd` int(11) DEFAULT '0' COMMENT '生产日期', + `price` decimal(12,4) NOT NULL COMMENT '单价', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + `serial` text NOT NULL COMMENT '序列号', + `discount` decimal(5,2) NOT NULL COMMENT '折扣率', + `dsc` decimal(12,4) NOT NULL COMMENT '折扣额', + `total` decimal(12,4) NOT NULL COMMENT '金额', + `tax` decimal(5,2) NOT NULL COMMENT '税率', + `tat` decimal(12,4) NOT NULL COMMENT '税额', + `tpt` decimal(12,4) NOT NULL COMMENT '价税合计', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `source` (`source`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采购退货单详情'; + + +DROP TABLE IF EXISTS `is_buy`; +CREATE TABLE `is_buy` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `source` int(11) NOT NULL COMMENT '关联单据|BOR', + `frame` int(11) NOT NULL COMMENT '所属组织', + `supplier` int(11) NOT NULL COMMENT '供应商', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `actual` decimal(16,4) NOT NULL COMMENT '实际金额', + `money` decimal(16,4) NOT NULL COMMENT '实付金额', + `cost` decimal(16,4) NOT NULL COMMENT '单据费用', + `account` int(11) DEFAULT '0' COMMENT '结算账户', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `logistics` text COMMENT '物流信息', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `nucleus` tinyint(1) NOT NULL COMMENT '核销状态[0:未核销|1:部分核销|2:已核销]', + `cse` tinyint(1) NOT NULL COMMENT '费用状态[0:未结算|1:部分结算|2:已结算|3:无需结算]', + `invoice` tinyint(1) NOT NULL COMMENT '发票状态[0:未开票|1:部分开票|2:已开票|3:无需开具]', + `check` tinyint(1) NOT NULL COMMENT '核对状态[0:未核对|1:已核对]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `supplier` (`supplier`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `nucleus` (`nucleus`), + KEY `source` (`source`), + KEY `people` (`people`), + KEY `cse` (`cse`), + KEY `invoice` (`invoice`), + KEY `check` (`check`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采购单'; + + +DROP TABLE IF EXISTS `is_buy_bill`; +CREATE TABLE `is_buy_bill` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属单据', + `type` varchar(32) NOT NULL COMMENT '核销类型', + `source` int(11) NOT NULL COMMENT '关联单据', + `time` int(11) NOT NULL COMMENT '单据时间', + `money` decimal(16,4) NOT NULL COMMENT '核销金额', + PRIMARY KEY (`id`), + KEY `pid_account_user` (`pid`), + KEY `type` (`type`), + KEY `source` (`source`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采购单核销详情'; + + +DROP TABLE IF EXISTS `is_buy_info`; +CREATE TABLE `is_buy_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `source` int(11) NOT NULL COMMENT '关联详情|BOR', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `unit` varchar(32) NOT NULL COMMENT '单位', + `warehouse` int(11) DEFAULT '0' COMMENT '仓库', + `batch` varchar(32) NOT NULL COMMENT '批次号', + `mfd` int(11) DEFAULT '0' COMMENT '生产日期', + `price` decimal(12,4) NOT NULL COMMENT '单价', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + `serial` text NOT NULL COMMENT '序列号', + `discount` decimal(5,2) NOT NULL COMMENT '折扣率', + `dsc` decimal(12,4) NOT NULL COMMENT '折扣额', + `total` decimal(12,4) NOT NULL COMMENT '金额', + `tax` decimal(5,2) NOT NULL COMMENT '税率', + `tat` decimal(12,4) NOT NULL COMMENT '税额', + `tpt` decimal(12,4) NOT NULL COMMENT '价税合计', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `retreat` decimal(12,4) DEFAULT '0.0000' COMMENT '退货数量', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `source` (`source`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采购单详情'; + + +DROP TABLE IF EXISTS `is_category`; +CREATE TABLE `is_category` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属类别', + `name` varchar(32) NOT NULL COMMENT '类别名称', + `sort` int(11) DEFAULT '0' COMMENT '类别排序', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `sort` (`sort`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品类别'; + +INSERT INTO `is_category` (`id`, `pid`, `name`, `sort`, `data`) VALUES +(0, -1, '默认类别', 0, '隐藏类别'); + +DROP TABLE IF EXISTS `is_code`; +CREATE TABLE `is_code` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL, + `info` varchar(64) NOT NULL, + `type` tinyint(1) NOT NULL COMMENT '条码类型[0:条形码 | 1:二维码]', + `data` varchar(256) NOT NULL, + PRIMARY KEY (`id`), + KEY `type` (`type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='条码'; + + +DROP TABLE IF EXISTS `is_cost`; +CREATE TABLE `is_cost` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `type` varchar(32) NOT NULL COMMENT '单据类型', + `class` int(11) NOT NULL COMMENT '所属类', + `time` int(11) NOT NULL COMMENT '单据时间', + `iet` int(11) NOT NULL COMMENT '所属收支', + `money` decimal(16,4) NOT NULL COMMENT '金额', + `data` varchar(256) DEFAULT '' COMMENT '备注', + `settle` decimal(16,4) DEFAULT '0.0000' COMMENT '结算金额', + `state` tinyint(1) DEFAULT NULL COMMENT '结算状态[0:未结算|1:部分结算|2:已结算]', + PRIMARY KEY (`id`), + KEY `type` (`type`), + KEY `class` (`class`), + KEY `time` (`time`), + KEY `iet` (`iet`), + KEY `state` (`state`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='单据费用'; + + +DROP TABLE IF EXISTS `is_cost_info`; +CREATE TABLE `is_cost_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `oce` int(11) NOT NULL COMMENT '所属支出', + `time` int(11) NOT NULL COMMENT '单据时间', + `money` decimal(16,4) NOT NULL COMMENT '结算金额', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `oce` (`oce`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='单据费用详情'; + + +DROP TABLE IF EXISTS `is_customer`; +CREATE TABLE `is_customer` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '客户名称', + `py` varchar(32) NOT NULL COMMENT '拼音信息', + `number` varchar(32) NOT NULL COMMENT '客户编号', + `frame` int(11) NOT NULL COMMENT '所属组织', + `user` int(11) NOT NULL COMMENT '所属用户', + `category` varchar(32) NOT NULL COMMENT '客户类别', + `grade` varchar(32) NOT NULL COMMENT '客户等级', + `bank` varchar(32) NOT NULL COMMENT '开户银行', + `account` varchar(64) NOT NULL COMMENT '银行账号', + `tax` varchar(64) NOT NULL COMMENT '纳税号码', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `contacts` text NOT NULL COMMENT '联系资料', + `balance` decimal(16,4) DEFAULT '0.0000' COMMENT '应收款余额', + `more` text NOT NULL COMMENT '扩展信息', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `user` (`user`), + KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='客户'; + + + + +SET NAMES utf8mb4; + +DROP TABLE IF EXISTS `is_entry`; +CREATE TABLE `is_entry` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `supplier` int(11) NOT NULL COMMENT '供应商', + `frame` int(11) NOT NULL COMMENT '所属组织', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) CHARACTER SET utf8mb4 NOT NULL COMMENT '单据编号', + `type` tinyint(1) NOT NULL COMMENT '单据类型[0:其它入库单|1:盘盈单]', + `total` decimal(16,4) NOT NULL COMMENT '单据成本', + `cost` decimal(16,4) NOT NULL COMMENT '单据费用', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `logistics` text COMMENT '物流信息', + `file` text COMMENT '单据附件', + `data` varchar(265) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `cse` tinyint(1) NOT NULL COMMENT '费用状态[0:未结算|1:部分结算|2:已结算|3:无需结算]', + `check` tinyint(1) NOT NULL COMMENT '核对状态[0:未核对|1:已核对]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `supplier` (`supplier`), + KEY `frame` (`frame`), + KEY `time` (`time`), + KEY `type` (`type`), + KEY `people` (`people`), + KEY `examine` (`examine`), + KEY `cse` (`cse`), + KEY `check` (`check`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它入库单'; + + +DROP TABLE IF EXISTS `is_entry_info`; +CREATE TABLE `is_entry_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `unit` varchar(32) NOT NULL COMMENT '单位', + `warehouse` int(11) DEFAULT '0' COMMENT '仓库', + `batch` varchar(32) NOT NULL COMMENT '批次号', + `mfd` int(11) DEFAULT '0' COMMENT '生产日期', + `price` decimal(12,4) NOT NULL COMMENT '成本', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + `serial` text NOT NULL COMMENT '序列号', + `total` decimal(12,4) NOT NULL COMMENT '总成本', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它入库单详情'; + + +DROP TABLE IF EXISTS `is_extry`; +CREATE TABLE `is_extry` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `customer` int(11) NOT NULL COMMENT '客户', + `frame` int(11) NOT NULL COMMENT '所属组织', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) CHARACTER SET utf8mb4 NOT NULL COMMENT '单据编号', + `type` tinyint(1) NOT NULL COMMENT '单据类型[0:其它出库单|1:盘亏单]', + `total` decimal(16,4) NOT NULL COMMENT '单据成本', + `cost` decimal(16,4) NOT NULL COMMENT '单据费用', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `logistics` text COMMENT '物流信息', + `file` text COMMENT '单据附件', + `data` varchar(265) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `cse` tinyint(1) NOT NULL COMMENT '费用状态[0:未结算|1:部分结算|2:已结算|3:无需结算]', + `check` tinyint(1) NOT NULL COMMENT '核对状态[0:未核对|1:已核对]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `customer` (`customer`), + KEY `frame` (`frame`), + KEY `time` (`time`), + KEY `type` (`type`), + KEY `people` (`people`), + KEY `examine` (`examine`), + KEY `cse` (`cse`), + KEY `check` (`check`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它出库单'; + + +DROP TABLE IF EXISTS `is_extry_info`; +CREATE TABLE `is_extry_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `unit` varchar(32) NOT NULL COMMENT '单位', + `warehouse` int(11) DEFAULT '0' COMMENT '仓库', + `batch` varchar(32) NOT NULL COMMENT '批次号', + `mfd` int(11) DEFAULT '0' COMMENT '生产日期', + `price` decimal(12,4) NOT NULL COMMENT '成本', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + `serial` text NOT NULL COMMENT '序列号', + `total` decimal(12,4) NOT NULL COMMENT '总成本', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它出库单详情'; + + +DROP TABLE IF EXISTS `is_field`; +CREATE TABLE `is_field` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '模块名称', + `key` varchar(32) NOT NULL COMMENT '模块标识', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `fields` text NOT NULL COMMENT '字段数据', + PRIMARY KEY (`id`), + KEY `key` (`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='表单字段'; + + +DROP TABLE IF EXISTS `is_fifo`; +CREATE TABLE `is_fifo` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `out` int(11) NOT NULL COMMENT '所属出', + `in` int(11) NOT NULL COMMENT '所属进', + `handle` decimal(12,4) NOT NULL COMMENT '处理数量', + PRIMARY KEY (`id`), + KEY `out` (`out`), + KEY `in` (`in`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='先进先出记录'; + + +DROP TABLE IF EXISTS `is_frame`; +CREATE TABLE `is_frame` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `name` varchar(32) NOT NULL COMMENT '组织名称', + `sort` int(11) DEFAULT '0' COMMENT '组织排序', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid_sort` (`pid`,`sort`), + KEY `sort` (`sort`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='组织机构'; + +INSERT INTO `is_frame` (`id`, `pid`, `name`, `sort`, `data`) VALUES +(0, -1, '默认组织', 0, '隐藏组织'); + +DROP TABLE IF EXISTS `is_goods`; +CREATE TABLE `is_goods` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '商品名称', + `py` varchar(32) NOT NULL COMMENT '拼音信息', + `number` varchar(32) NOT NULL COMMENT '商品编号', + `spec` varchar(32) NOT NULL COMMENT '规格型号', + `category` int(11) NOT NULL COMMENT '商品类别', + `brand` varchar(32) NOT NULL COMMENT '商品品牌', + `unit` varchar(32) NOT NULL COMMENT '商品单位[*:常规单位|-1:多单位]', + `buy` decimal(12,4) NOT NULL COMMENT '采购价格', + `sell` decimal(12,4) NOT NULL COMMENT '销售价格', + `code` varchar(64) NOT NULL COMMENT '商品条码', + `location` varchar(64) NOT NULL COMMENT '商品货位', + `stock` decimal(12,4) NOT NULL COMMENT '库存阈值', + `type` tinyint(1) NOT NULL COMMENT '产品类型[0:常规商品|1:服务商品]', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `imgs` text NOT NULL COMMENT '商品图像', + `details` text NOT NULL COMMENT '图文详情', + `units` text NOT NULL COMMENT '多单位配置', + `strategy` text NOT NULL COMMENT '折扣策略', + `serial` tinyint(1) DEFAULT '0' COMMENT '序列产品[0:关闭|1:启用]', + `batch` tinyint(1) DEFAULT '0' COMMENT '批次产品[0:关闭|1:启用]', + `validity` tinyint(1) DEFAULT '0' COMMENT '有效期[0:关闭|1:启用]', + `protect` smallint(1) DEFAULT '0' COMMENT '保质期', + `threshold` smallint(1) DEFAULT '0' COMMENT '预警阀值', + `more` text NOT NULL COMMENT '扩展信息', + PRIMARY KEY (`id`), + KEY `number` (`number`), + KEY `name_py` (`name`,`py`), + KEY `category` (`category`), + KEY `code` (`code`), + KEY `type` (`type`), + KEY `brand` (`brand`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品'; + + +DROP TABLE IF EXISTS `is_ice`; +CREATE TABLE `is_ice` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `frame` int(11) NOT NULL COMMENT '所属组织', + `customer` int(11) DEFAULT '0' COMMENT '客户', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `actual` decimal(16,4) NOT NULL COMMENT '实际金额', + `money` decimal(16,4) NOT NULL COMMENT '实收金额', + `account` int(11) NOT NULL COMMENT '结算账户', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `nucleus` tinyint(1) NOT NULL COMMENT '核销状态[0:未核销|1:部分核销|2:已核销]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `people` (`people`), + KEY `customer` (`customer`), + KEY `account` (`account`), + KEY `nucleus` (`nucleus`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它收入单'; + + +DROP TABLE IF EXISTS `is_ice_bill`; +CREATE TABLE `is_ice_bill` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属单据', + `type` varchar(32) NOT NULL COMMENT '核销类型', + `source` int(11) NOT NULL COMMENT '关联单据', + `time` int(11) NOT NULL COMMENT '单据时间', + `money` decimal(16,4) NOT NULL COMMENT '核销金额', + PRIMARY KEY (`id`), + KEY `pid_account_user` (`pid`), + KEY `type` (`type`), + KEY `source` (`source`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它收入单核销详情'; + + +DROP TABLE IF EXISTS `is_ice_info`; +CREATE TABLE `is_ice_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `iet` int(11) NOT NULL COMMENT '收支类型', + `money` decimal(12,4) NOT NULL COMMENT '结算金额', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `iet` (`iet`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它收入单详情'; + + +DROP TABLE IF EXISTS `is_iet`; +CREATE TABLE `is_iet` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '类别名称', + `type` tinyint(1) NOT NULL COMMENT '收支类型[0:收入:1支出]', + `sort` int(11) NOT NULL COMMENT '类别排序', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `sort` (`sort`), + KEY `name` (`name`), + KEY `type` (`type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='收支类别'; + + +DROP TABLE IF EXISTS `is_imy`; +CREATE TABLE `is_imy` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `frame` int(11) NOT NULL COMMENT '所属组织', + `customer` int(11) NOT NULL COMMENT '客户', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `nucleus` tinyint(1) NOT NULL COMMENT '核销状态[0:未核销|1:部分核销|2:已核销]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `supplier` (`customer`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `nucleus` (`nucleus`), + KEY `people` (`people`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='收款单'; + + +DROP TABLE IF EXISTS `is_imy_bill`; +CREATE TABLE `is_imy_bill` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属单据', + `type` varchar(32) NOT NULL COMMENT '核销类型', + `source` int(11) NOT NULL COMMENT '关联单据', + `time` int(11) NOT NULL COMMENT '单据时间', + `money` decimal(16,4) NOT NULL COMMENT '核销金额', + PRIMARY KEY (`id`), + KEY `pid_account_user` (`pid`), + KEY `type` (`type`), + KEY `source` (`source`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='收款单核销详情'; + + +DROP TABLE IF EXISTS `is_imy_info`; +CREATE TABLE `is_imy_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `account` int(11) DEFAULT '0' COMMENT '结算账户', + `money` decimal(12,4) NOT NULL COMMENT '结算金额', + `settle` varchar(256) NOT NULL COMMENT '结算号', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `account` (`account`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='收款单详情'; + +DROP TABLE IF EXISTS `is_invoice`; +CREATE TABLE `is_invoice` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `type` varchar(32) NOT NULL COMMENT '单据类型', + `class` int(11) NOT NULL COMMENT '所属单据', + `time` int(11) NOT NULL COMMENT '开票时间', + `number` varchar(64) NOT NULL COMMENT '发票号码', + `title` varchar(64) NOT NULL COMMENT '发票抬头', + `money` decimal(16,4) NOT NULL COMMENT '开票金额', + `file` text NOT NULL COMMENT '发票附件', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `type` (`type`), + KEY `class` (`class`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='发票详情'; + + +DROP TABLE IF EXISTS `is_log`; +CREATE TABLE `is_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `time` int(11) NOT NULL COMMENT '操作时间', + `user` int(11) NOT NULL COMMENT '所属用户', + `info` varchar(256) NOT NULL COMMENT '操作内容', + PRIMARY KEY (`id`), + KEY `time` (`time`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='操作日志'; + + +DROP TABLE IF EXISTS `is_menu`; +CREATE TABLE `is_menu` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属菜单', + `name` varchar(32) NOT NULL COMMENT '菜单名称', + `key` varchar(32) NOT NULL COMMENT '菜单标识', + `model` tinyint(1) NOT NULL COMMENT '菜单模式[0:标签模式|1:新页模式]', + `type` tinyint(1) NOT NULL COMMENT '菜单类型[0:独立菜单|1:附属菜单]', + `resource` varchar(128) NOT NULL COMMENT '菜单地址', + `sort` int(11) DEFAULT '0' COMMENT '菜单排序', + `ico` varchar(32) NOT NULL COMMENT '菜单图标', + `root` varchar(32) NOT NULL COMMENT '权限标识', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `name` (`name`), + KEY `model` (`model`), + KEY `type` (`type`), + KEY `sort` (`sort`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='菜单信息'; + +INSERT INTO `is_menu` (`id`, `pid`, `name`, `key`, `model`, `type`, `resource`, `sort`, `ico`, `root`, `data`) VALUES +(0, -1, '默认菜单', '', 0, 0, '#group', 0, '', '', '隐藏菜单'), +(18, 0, '系统参数', 'system', 0, 0, '#group', 7, 'el-icon-menu', '', '系统设置组'), +(35, 64, '菜单管理', 'menu', 0, 0, '/develop/menu', 4, '', 'admin', '管理专属'), +(58, 0, '首页', 'home', 0, 0, '/home', 0, 'el-icon-monitor', '', '主页'), +(63, 18, '基础资料', 'base', 0, 0, '#group', 1, '', '', '基础资料组'), +(64, 0, '系统配置', 'develop', 0, 0, '#group', 8, 'el-icon-setting', '', '开发工具组'), +(66, 18, '辅助资料', 'assist', 0, 0, '#group', 2, '', 'form', '辅助资料组'), +(67, 18, '高级设置', 'senior', 0, 0, '#group', 3, '', '', '高级设置组'), +(68, 63, '客户管理', 'customer', 0, 0, '/system/customer', 1, '', 'base', ''), +(69, 63, '供应商管理', 'supplier', 0, 0, '/system/supplier', 2, '', 'base', ''), +(70, 67, '组织机构', 'frame', 0, 0, '/system/frame', 2, '', 'senior', ''), +(71, 67, '用户角色', 'role', 0, 0, '/system/role', 3, '', 'senior', ''), +(72, 67, '用户管理', 'user', 0, 0, '/system/user', 4, '', 'senior', ''), +(73, 64, '表单字段', 'field', 0, 0, '/develop/field', 3, '', 'admin', '管理专属'), +(74, 67, '操作日志', 'log', 0, 0, '/system/log', 6, '', 'senior', ''), +(75, 67, '系统设置', 'sys', 0, 0, '/system/sys', 1, '', 'senior', ''), +(76, 67, '数据备份', 'backup', 0, 0, '/system/backup', 9, '', 'senior', ''), +(77, 66, '商品类别', 'category', 0, 0, '/system/category', 1, '', 'assist', ''), +(78, 66, '条码管理', 'code', 0, 0, '/system/code', 2, '', 'assist', ''), +(79, 66, '辅助属性', 'attribute', 0, 0, '/system/attribute', 3, '', 'assist', ''), +(80, 66, '常用功能', 'often', 0, 0, '/system/often', 4, '', 'assist', ''), +(81, 63, '仓库管理', 'warehouse', 0, 0, '/system/warehouse', 4, '', 'base', ''), +(82, 63, '资金账户', 'account', 0, 0, '/system/account', 5, '', 'base', ''), +(83, 63, '商品管理', 'goods', 0, 0, '/system/goods', 3, '', 'base', ''), +(85, 0, '采购', 'purchase', 0, 0, '#group', 1, 'el-icon-shopping-cart-2', '', '采购组'), +(86, 85, '采购订单', 'bor', 0, 0, '/purchase/bor', 0, '', 'bor|add', ''), +(87, 86, '报表|采购订单报表', 'borForm', 0, 1, '/purchase/borForm', 0, '', 'bor', ''), +(88, 85, '采购单', 'buy', 0, 0, '/purchase/buy', 1, '', 'buy|add', ''), +(89, 88, '报表|采购单报表', 'buyForm', 0, 1, '/purchase/buyForm', 0, '', 'buy', ''), +(90, 85, '采购退货单', 'bre', 0, 0, '/purchase/bre', 2, '', 'bre|add', ''), +(91, 90, '报表|采购退货单报表', 'breForm', 0, 1, '/purchase/breForm', 0, '', 'bre', ''), +(92, 0, '销售', 'sale', 0, 0, '#group', 2, 'el-icon-shopping-cart-full', '', '销售组'), +(93, 92, '销售订单', 'sor', 0, 0, '/sale/sor', 0, '', 'sor|add', ''), +(94, 93, '报表|销售订单报表', 'sorForm', 0, 1, '/sale/sorForm', 0, '', 'sor', ''), +(95, 92, '销售单', 'sell', 0, 0, '/sale/sell', 1, '', 'sell|add', ''), +(96, 95, '报表|销售单报表', 'sellForm', 0, 1, '/sale/sellForm', 0, '', 'sell', ''), +(97, 92, '销售退货单', 'sre', 0, 0, '/sale/sre', 2, '', 'sre|add', ''), +(98, 97, '报表|销售退货单报表', 'sreForm', 0, 1, '/sale/sreForm', 0, '', 'sre', ''), +(102, 0, '仓库', 'room', 0, 0, '#group', 4, 'el-icon-house', '', '仓库组'), +(103, 102, '其它入库单', 'entry', 0, 0, '/room/entry', 6, '', 'entry|add', ''), +(104, 103, '报表|其它入库单报表', 'entryForm', 0, 1, '/room/entryForm', 0, '', 'entry', ''), +(105, 102, '其它出库单', 'extry', 0, 0, '/room/extry', 7, '', 'extry|add', ''), +(106, 105, '报表|其它出库单报表', 'extryForm', 0, 1, '/room/extryForm', 0, '', 'extry', ''), +(108, 102, '调拨单', 'swap', 0, 0, '/room/swap', 5, '', 'swap|add', ''), +(109, 108, '报表|调拨单报表', 'swapForm', 0, 1, '/room/swapForm', 0, '', 'swap', ''), +(116, 102, '库存查询', 'stock', 0, 0, '/room/stock', 1, '', 'stock', ''), +(117, 102, '库存盘点', 'inventory', 0, 0, '/room/inventory', 4, '', 'inventory', ''), +(118, 102, '批次查询', 'batch', 0, 0, '/room/batch', 2, '', 'batch', ''), +(119, 102, '序列查询', 'serial', 0, 0, '/room/serial', 3, '', 'serial', ''), +(120, 0, '资金', 'fund', 0, 0, '#group', 5, 'el-icon-coin', '', '资金组'), +(121, 120, '收款单', 'imy', 0, 0, '/fund/imy', 1, '', 'imy|add', ''), +(122, 121, '报表|收款单报表', 'imyForm', 0, 1, '/fund/imyForm', 0, '', 'imy', ''), +(123, 120, '付款单', 'omy', 0, 0, '/fund/omy', 2, '', 'omy|add', ''), +(124, 123, '报表|付款单报表', 'omyForm', 0, 1, '/fund/omyForm', 0, '', 'omy', ''), +(125, 120, '核销单', 'bill', 0, 0, '/fund/bill', 3, '', 'bill|add', ''), +(126, 125, '报表|核销单报表', 'billForm', 0, 1, '/fund/billForm', 0, '', 'bill', ''), +(127, 120, '其它收入单', 'ice', 0, 0, '/fund/ice', 5, '', 'ice|add', ''), +(128, 127, '报表|其它收入单报表 ', 'iceForm', 0, 1, '/fund/iceForm', 0, '', 'ice', ''), +(129, 120, '其它支出单', 'oce', 0, 0, '/fund/oce', 6, '', 'oce|add', ''), +(130, 129, '报表|其它支出单报表', 'oceForm', 0, 1, '/fund/oceForm', 0, '', 'oce', ''), +(131, 120, '转账单', 'allot', 0, 0, '/fund/allot', 4, '', 'allot|add', ''), +(132, 131, '报表|转账单报表', 'allotForm', 0, 1, '/fund/allotForm', 0, '', 'allot', ''), +(133, 67, '人员管理', 'people', 0, 0, '/system/people', 5, '', 'senior', ''), +(134, 0, '报表', 'sheet', 0, 0, '#group', 6, 'el-icon-tickets', '', '报表组'), +(135, 134, '采购报表', 'brt', 0, 0, '#group', 1, '', '', '采购报表组'), +(136, 135, '采购订单跟踪表', 'btt', 0, 0, '/sheet/btt', 1, '', 'brt', ''), +(137, 135, '采购明细表', 'blt', 0, 0, '/sheet/blt', 2, '', 'brt', ''), +(138, 135, '采购汇总表', 'bsy', 0, 0, '/sheet/bsy', 3, '', 'brt', ''), +(140, 135, '采购付款表', 'bbt', 0, 0, '/sheet/bbt', 4, '', 'brt', ''), +(141, 134, '销售报表', 'srt', 0, 0, '#group', 2, '', '', '销售报表组'), +(142, 141, '销售订单跟踪表', 'stt', 0, 0, '/sheet/stt', 1, '', 'srt', ''), +(143, 141, '销售明细表', 'slt', 0, 0, '/sheet/slt', 2, '', 'srt', ''), +(144, 141, '销售汇总表', 'ssy', 0, 0, '/sheet/ssy', 3, '', 'srt', ''), +(148, 141, '销售收款表', 'sbt', 0, 0, '/sheet/sbt', 4, '', 'srt', ''), +(149, 165, '销售利润表', 'mpt', 0, 0, '/sheet/mpt', 1, '', 'mrt', ''), +(150, 165, '销售排行表', 'mot', 0, 0, '/sheet/mot', 2, '', 'mrt', ''), +(151, 134, '仓库报表', 'wrf', 0, 0, '#group', 5, '', '', '仓库报表组'), +(152, 134, '资金报表', 'crt', 0, 0, '#group', 6, '', '', '资金报表组'), +(153, 151, '商品库存余额表', 'wbs', 0, 0, '/sheet/wbs', 1, '', 'wrf', ''), +(154, 151, '商品收发明细表', 'wds', 0, 0, '/sheet/wds', 2, '', 'wrf', ''), +(155, 151, '商品收发汇总表', 'wss', 0, 0, '/sheet/wss', 3, '', 'wrf', ''), +(156, 152, '现金银行报表', 'cbf', 0, 0, '/sheet/cbf', 1, '', 'crt', ''), +(157, 152, '应付账款明细表', 'cps', 0, 0, '/sheet/cps', 3, '', 'crt', ''), +(158, 152, '应收账款明细表', 'crs', 0, 0, '/sheet/crs', 2, '', 'crt', ''), +(159, 152, '客户对账单', 'cct', 0, 0, '/sheet/cct', 4, '', 'crt', ''), +(160, 152, '供应商对账单', 'cst', 0, 0, '/sheet/cst', 5, '', 'crt', ''), +(161, 152, '其它收支明细表', 'cos', 0, 0, '/sheet/cos', 6, '', 'crt', ''), +(162, 152, '利润表', 'cit', 0, 0, '/sheet/cit', 7, '', 'crt', ''), +(163, 152, '往来单位欠款表', 'cds', 0, 0, '/sheet/cds', 8, '', 'crt', ''), +(165, 134, '销售报表', 'mrt', 0, 0, '#group', 4, '', '', '销售报表组'), +(168, 135, '采购排行表', 'bot', 0, 0, '/sheet/bot', 5, '', 'brt', ''), +(170, 66, '收支类别', 'iet', 0, 0, '/system/iet', 1, '', 'assist', ''), +(171, 120, '购销发票', 'invoice', 0, 0, '/fund/invoice', 8, '', 'invoice', ''), +(172, 171, '报表|购销发票报表', 'invoiceForm', 0, 1, '/fund/invoiceForm', 0, '', 'invoice', ''), +(173, 120, '购销费用', 'cost', 0, 0, '/fund/cost', 7, '', 'cost', ''), +(174, 173, '报表|购销费用报表', 'costForm', 0, 1, '/fund/costForm', 0, '', 'cost', ''), +(175, 67, '数据核准', 'summary', 0, 0, '/system/summary', 8, '', 'senior', ''), +(176, 67, '结账管理', 'period', 0, 0, '/system/period', 7, '', 'senior', ''); + + +DROP TABLE IF EXISTS `is_oce`; +CREATE TABLE `is_oce` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `frame` int(11) NOT NULL COMMENT '所属组织', + `supplier` int(11) NOT NULL COMMENT '供应商', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `actual` decimal(16,4) NOT NULL COMMENT '实际金额', + `money` decimal(16,4) NOT NULL COMMENT '实付金额', + `account` int(11) NOT NULL COMMENT '结算账户', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `nucleus` tinyint(1) NOT NULL COMMENT '核销状态[0:未核销|1:部分核销|2:已核销]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `people` (`people`), + KEY `supplier` (`supplier`), + KEY `account` (`account`), + KEY `nucleus` (`nucleus`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它支出单'; + + +DROP TABLE IF EXISTS `is_oce_bill`; +CREATE TABLE `is_oce_bill` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属单据', + `type` varchar(32) NOT NULL COMMENT '核销类型', + `source` int(11) NOT NULL COMMENT '关联单据', + `time` int(11) NOT NULL COMMENT '单据时间', + `money` decimal(16,4) NOT NULL COMMENT '核销金额', + PRIMARY KEY (`id`), + KEY `pid_account_user` (`pid`), + KEY `type` (`type`), + KEY `source` (`source`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它支出单核销详情'; + + +DROP TABLE IF EXISTS `is_oce_info`; +CREATE TABLE `is_oce_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `source` int(11) NOT NULL COMMENT '所属费用', + `iet` int(11) NOT NULL COMMENT '收支类型', + `money` decimal(12,4) NOT NULL COMMENT '结算金额', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `source` (`source`), + KEY `iet` (`iet`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='其它支出单详情'; + + +DROP TABLE IF EXISTS `is_often`; +CREATE TABLE `is_often` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user` int(11) NOT NULL COMMENT '所属用户', + `name` varchar(64) NOT NULL COMMENT '功能名称', + `key` varchar(32) NOT NULL COMMENT '功能标识', + PRIMARY KEY (`id`), + KEY `user` (`user`), + KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='常用功能'; + + +DROP TABLE IF EXISTS `is_omy`; +CREATE TABLE `is_omy` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `frame` int(11) NOT NULL COMMENT '所属组织', + `supplier` int(11) NOT NULL COMMENT '供应商', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `nucleus` tinyint(1) NOT NULL COMMENT '核销状态[0:未核销|1:部分核销|2:已核销]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `supplier` (`supplier`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `nucleus` (`nucleus`), + KEY `people` (`people`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='付款单'; + + +DROP TABLE IF EXISTS `is_omy_bill`; +CREATE TABLE `is_omy_bill` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属单据', + `type` varchar(32) NOT NULL COMMENT '核销类型', + `source` int(11) NOT NULL COMMENT '关联单据', + `time` int(11) NOT NULL COMMENT '单据时间', + `money` decimal(16,4) NOT NULL COMMENT '核销金额', + PRIMARY KEY (`id`), + KEY `pid_account_user` (`pid`), + KEY `type` (`type`), + KEY `source` (`source`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='付款单核销详情'; + + +DROP TABLE IF EXISTS `is_omy_info`; +CREATE TABLE `is_omy_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `account` int(11) DEFAULT '0' COMMENT '结算账户', + `money` decimal(12,4) NOT NULL COMMENT '结算金额', + `settle` varchar(256) NOT NULL COMMENT '结算号', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `account` (`account`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='付款单详情'; + + +DROP TABLE IF EXISTS `is_people`; +CREATE TABLE `is_people` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '人员名称', + `py` varchar(32) NOT NULL COMMENT '拼音信息', + `number` varchar(32) NOT NULL COMMENT '人员编号', + `frame` int(11) NOT NULL COMMENT '所属组织', + `sex` tinyint(1) NOT NULL COMMENT '人员性别[0:女|1:男]', + `tel` varchar(32) NOT NULL COMMENT '联系电话', + `add` varchar(64) NOT NULL COMMENT '联系地址', + `card` varchar(32) NOT NULL COMMENT '身份证号', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `more` text NOT NULL COMMENT '扩展信息', + PRIMARY KEY (`id`), + KEY `name_py` (`name`,`py`), + KEY `frame` (`frame`), + KEY `user` (`sex`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='人员管理'; + + +DROP TABLE IF EXISTS `is_period`; +CREATE TABLE `is_period` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `date` int(11) NOT NULL COMMENT '结账日期', + `time` int(11) NOT NULL COMMENT '操作日期', + `user` int(11) NOT NULL COMMENT '操作人', + PRIMARY KEY (`id`), + KEY `date` (`date`), + KEY `time` (`time`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='结账表'; + + +DROP TABLE IF EXISTS `is_record`; +CREATE TABLE `is_record` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `type` varchar(32) NOT NULL COMMENT '单据类型', + `source` int(11) NOT NULL COMMENT '关联单据', + `time` int(11) NOT NULL COMMENT '事件时间', + `user` int(11) NOT NULL COMMENT '事件用户', + `info` varchar(64) NOT NULL COMMENT '事件内容', + PRIMARY KEY (`id`), + KEY `type` (`type`), + KEY `source` (`source`), + KEY `time` (`time`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='单据记录'; + + +DROP TABLE IF EXISTS `is_role`; +CREATE TABLE `is_role` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '角色名称', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `root` text NOT NULL COMMENT '功能数据', + `auth` text NOT NULL COMMENT '数据权限', + PRIMARY KEY (`id`), + KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色'; + + +DROP TABLE IF EXISTS `is_room`; +CREATE TABLE `is_room` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `warehouse` int(11) NOT NULL COMMENT '所属仓库', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `nums` decimal(12,4) NOT NULL COMMENT '库存数量', + PRIMARY KEY (`id`), + KEY `warehouse` (`warehouse`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='仓储信息'; + + +DROP TABLE IF EXISTS `is_room_info`; +CREATE TABLE `is_room_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属仓储', + `type` varchar(32) NOT NULL COMMENT '单据类型', + `class` int(11) NOT NULL COMMENT '所属类', + `info` int(11) NOT NULL COMMENT '所属详情', + `time` int(11) NOT NULL COMMENT '单据时间', + `direction` tinyint(1) NOT NULL COMMENT '方向[0:出|1:入]', + `price` decimal(12,4) NOT NULL COMMENT '基础单价', + `nums` decimal(12,4) NOT NULL COMMENT '基础数量', + PRIMARY KEY (`id`), + KEY `room_attr` (`pid`), + KEY `type` (`type`), + KEY `class` (`class`), + KEY `info` (`info`), + KEY `time` (`time`), + KEY `direction` (`direction`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='仓储详情'; + + +DROP TABLE IF EXISTS `is_sell`; +CREATE TABLE `is_sell` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `source` int(11) NOT NULL COMMENT '关联单据|SOR', + `frame` int(11) NOT NULL COMMENT '所属组织', + `customer` int(11) NOT NULL COMMENT '客户', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `actual` decimal(16,4) NOT NULL COMMENT '实际金额', + `money` decimal(16,4) NOT NULL COMMENT '实收金额', + `cost` decimal(16,4) NOT NULL COMMENT '单据费用', + `account` int(11) DEFAULT '0' COMMENT '结算账户', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `logistics` text COMMENT '物流信息', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `nucleus` tinyint(1) NOT NULL COMMENT '核销状态[0:未核销|1:部分核销|2:已核销]', + `cse` tinyint(1) NOT NULL COMMENT '费用状态[0:未结算|1:部分结算|2:已结算|3:无需结算]', + `invoice` tinyint(1) NOT NULL COMMENT '发票状态[0:未开票|1:部分开票|2:已开票|3:无需开具]', + `check` tinyint(1) NOT NULL COMMENT '核对状态[0:未核对|1:已核对]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `supplier` (`customer`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `nucleus` (`nucleus`), + KEY `people` (`people`), + KEY `cse` (`cse`), + KEY `invoice` (`invoice`), + KEY `check` (`check`), + KEY `user` (`user`), + KEY `account` (`account`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='销售单'; + + +DROP TABLE IF EXISTS `is_sell_bill`; +CREATE TABLE `is_sell_bill` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属单据', + `type` varchar(32) NOT NULL COMMENT '核销类型', + `source` int(11) NOT NULL COMMENT '关联单据', + `time` int(11) NOT NULL COMMENT '单据时间', + `money` decimal(16,4) NOT NULL COMMENT '核销金额', + PRIMARY KEY (`id`), + KEY `pid_account_user` (`pid`), + KEY `type` (`type`), + KEY `source` (`source`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='销售单核销详情'; + + +DROP TABLE IF EXISTS `is_sell_info`; +CREATE TABLE `is_sell_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `source` int(11) NOT NULL COMMENT '关联详情|SOR', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `unit` varchar(32) NOT NULL COMMENT '单位', + `warehouse` int(11) DEFAULT '0' COMMENT '仓库', + `batch` varchar(32) NOT NULL COMMENT '批次号', + `mfd` int(11) DEFAULT '0' COMMENT '生产日期', + `price` decimal(12,4) NOT NULL COMMENT '单价', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + `serial` text NOT NULL COMMENT '序列号', + `discount` decimal(5,2) NOT NULL COMMENT '折扣率', + `dsc` decimal(12,4) NOT NULL COMMENT '折扣额', + `total` decimal(12,4) NOT NULL COMMENT '金额', + `tax` decimal(5,2) NOT NULL COMMENT '税率', + `tat` decimal(12,4) NOT NULL COMMENT '税额', + `tpt` decimal(12,4) NOT NULL COMMENT '价税合计', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `retreat` decimal(12,4) DEFAULT '0.0000' COMMENT '退货数量', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `source` (`source`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='销售单详情'; + + +DROP TABLE IF EXISTS `is_serial`; +CREATE TABLE `is_serial` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `room` int(11) NOT NULL COMMENT '所属仓储', + `warehouse` int(11) NOT NULL COMMENT '所属仓库', + `batch` int(11) DEFAULT '0' COMMENT '所属批次', + `goods` int(11) NOT NULL COMMENT '所属商品', + `number` varchar(64) NOT NULL COMMENT '序列号', + `state` tinyint(1) NOT NULL COMMENT '状态[0:未销售|1:已销售|2:已调拨|3:已退货]', + PRIMARY KEY (`id`), + KEY `room_attr` (`room`), + KEY `number` (`number`), + KEY `state` (`state`), + KEY `warehouse` (`warehouse`), + KEY `batch` (`batch`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='序列号'; + + +DROP TABLE IF EXISTS `is_serial_info`; +CREATE TABLE `is_serial_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属序列', + `type` varchar(32) NOT NULL COMMENT '单据类型', + `class` int(11) NOT NULL COMMENT '所属类', + `info` int(11) NOT NULL COMMENT '所属详情', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `type` (`type`), + KEY `class` (`class`), + KEY `info` (`info`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='序列号详情'; + + +DROP TABLE IF EXISTS `is_serve`; +CREATE TABLE `is_serve` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `nums` decimal(12,4) NOT NULL COMMENT '累计数量', + PRIMARY KEY (`id`), + KEY `goods_attr` (`goods`,`attr`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='服务信息'; + + +DROP TABLE IF EXISTS `is_serve_info`; +CREATE TABLE `is_serve_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `type` varchar(32) NOT NULL COMMENT '单据类型', + `class` int(11) NOT NULL COMMENT '所属类', + `info` int(11) NOT NULL COMMENT '所属详情', + `time` int(11) NOT NULL COMMENT '单据时间', + `price` decimal(12,4) NOT NULL COMMENT '单价', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `type_info` (`type`,`info`), + KEY `class` (`class`), + KEY `info` (`info`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='服务详情'; + + +DROP TABLE IF EXISTS `is_sor`; +CREATE TABLE `is_sor` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `frame` int(11) NOT NULL COMMENT '所属组织', + `customer` int(11) NOT NULL COMMENT '客户', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `actual` decimal(16,4) NOT NULL COMMENT '实际金额', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `arrival` int(11) NOT NULL COMMENT '到货日期', + `logistics` text COMMENT '物流信息', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `state` tinyint(1) NOT NULL COMMENT '出库状态[0:未出库|1:部分出库|2:已出库|3:关闭]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `supplier` (`customer`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `state` (`state`), + KEY `people` (`people`), + KEY `user` (`user`), + KEY `arrival` (`arrival`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='销售订单'; + + +DROP TABLE IF EXISTS `is_sor_info`; +CREATE TABLE `is_sor_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `unit` varchar(32) NOT NULL COMMENT '单位', + `warehouse` int(11) DEFAULT '0' COMMENT '仓库', + `price` decimal(12,4) NOT NULL COMMENT '单价', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + `discount` decimal(5,2) NOT NULL COMMENT '折扣率', + `dsc` decimal(12,4) NOT NULL COMMENT '折扣额', + `total` decimal(12,4) NOT NULL COMMENT '金额', + `tax` decimal(5,2) NOT NULL COMMENT '税率', + `tat` decimal(12,4) NOT NULL COMMENT '税额', + `tpt` decimal(12,4) NOT NULL COMMENT '价税合计', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `handle` decimal(12,4) DEFAULT '0.0000' COMMENT '出库数量', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='销售订单详情'; + + +DROP TABLE IF EXISTS `is_sre`; +CREATE TABLE `is_sre` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `source` int(11) NOT NULL COMMENT '关联单据|SELL', + `frame` int(11) NOT NULL COMMENT '所属组织', + `customer` int(11) NOT NULL COMMENT '客户', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据金额', + `actual` decimal(16,4) NOT NULL COMMENT '实际金额', + `money` decimal(16,4) NOT NULL COMMENT '实付金额', + `cost` decimal(16,4) NOT NULL COMMENT '单据费用', + `account` int(11) DEFAULT '0' COMMENT '结算账户', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `logistics` text COMMENT '物流信息', + `file` text COMMENT '单据附件', + `data` varchar(256) DEFAULT '' COMMENT '备注信息', + `more` text COMMENT '扩展信息', + `examine` tinyint(1) NOT NULL COMMENT '审核状态[0:未审核|1:已审核]', + `nucleus` tinyint(1) NOT NULL COMMENT '核销状态[0:未核销|1:部分核销|2:已核销]', + `cse` tinyint(1) NOT NULL COMMENT '费用状态[0:未结算|1:部分结算|2:已结算|3:无需结算]', + `invoice` tinyint(1) NOT NULL COMMENT '发票状态[0:未开票|1:部分开票|2:已开票|3:无需开具]', + `check` tinyint(1) NOT NULL COMMENT '核对状态[0:未核对|1:已核对]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `time` (`time`), + KEY `examine` (`examine`), + KEY `nucleus` (`nucleus`), + KEY `source` (`source`), + KEY `people` (`people`), + KEY `customer` (`customer`), + KEY `account` (`account`), + KEY `cse` (`cse`), + KEY `invoice` (`invoice`), + KEY `check` (`check`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='销售退货单'; + + +DROP TABLE IF EXISTS `is_sre_bill`; +CREATE TABLE `is_sre_bill` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属单据', + `type` varchar(32) NOT NULL COMMENT '核销类型', + `source` int(11) NOT NULL COMMENT '关联单据', + `time` int(11) NOT NULL COMMENT '单据时间', + `money` decimal(16,4) NOT NULL COMMENT '核销金额', + PRIMARY KEY (`id`), + KEY `pid_account_user` (`pid`), + KEY `type` (`type`), + KEY `source` (`source`), + KEY `time` (`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='销售退货单核销详情'; + + +DROP TABLE IF EXISTS `is_sre_info`; +CREATE TABLE `is_sre_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `source` int(11) NOT NULL COMMENT '关联详情|SELL', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `unit` varchar(32) NOT NULL COMMENT '单位', + `warehouse` int(11) DEFAULT '0' COMMENT '仓库', + `batch` varchar(32) NOT NULL COMMENT '批次号', + `mfd` int(11) DEFAULT '0' COMMENT '生产日期', + `price` decimal(12,4) NOT NULL COMMENT '单价', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + `serial` text NOT NULL COMMENT '序列号', + `discount` decimal(5,2) NOT NULL COMMENT '折扣率', + `dsc` decimal(12,4) NOT NULL COMMENT '折扣额', + `total` decimal(12,4) NOT NULL COMMENT '金额', + `tax` decimal(5,2) NOT NULL COMMENT '税率', + `tat` decimal(12,4) NOT NULL COMMENT '税额', + `tpt` decimal(12,4) NOT NULL COMMENT '价税合计', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `source` (`source`), + KEY `goods` (`goods`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='销售退货单详情'; + + +DROP TABLE IF EXISTS `is_summary`; +CREATE TABLE `is_summary` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '仓储详情', + `type` varchar(32) NOT NULL COMMENT '单据类型', + `class` int(11) NOT NULL COMMENT '所属单据', + `info` int(11) NOT NULL COMMENT '所属详情', + `time` int(11) NOT NULL COMMENT '单据时间', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `warehouse` int(11) NOT NULL COMMENT '所属仓库', + `batch` varchar(64) NOT NULL COMMENT '批次', + `mfd` int(11) NOT NULL COMMENT '生产日期', + `serial` text NOT NULL COMMENT '序列号', + `direction` tinyint(1) NOT NULL COMMENT '方向[0:出|1:入]', + `price` decimal(12,4) NOT NULL COMMENT '基础单价', + `nums` decimal(12,4) NOT NULL COMMENT '基础数量', + `uct` decimal(12,4) NOT NULL COMMENT '单位成本', + `bct` decimal(12,4) NOT NULL COMMENT '基础成本', + `exist` text NOT NULL COMMENT '结存组', + `balance` text NOT NULL COMMENT '结余组', + `handle` decimal(12,4) NOT NULL COMMENT '先进先出', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `type` (`type`), + KEY `class` (`class`), + KEY `info` (`info`), + KEY `time` (`time`), + KEY `goods` (`goods`), + KEY `direction` (`direction`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='收发统计表'; + + +DROP TABLE IF EXISTS `is_supplier`; +CREATE TABLE `is_supplier` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '供应商名称', + `py` varchar(32) NOT NULL COMMENT '拼音信息', + `number` varchar(32) NOT NULL COMMENT '供应商编号', + `frame` int(11) NOT NULL COMMENT '所属组织', + `user` int(11) NOT NULL COMMENT '所属用户', + `category` varchar(32) NOT NULL COMMENT '供应商类别', + `rate` decimal(5,2) NOT NULL COMMENT '增值税税率', + `bank` varchar(32) NOT NULL COMMENT '开户银行', + `account` varchar(64) NOT NULL COMMENT '银行账号', + `tax` varchar(64) NOT NULL COMMENT '纳税号码', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `contacts` text NOT NULL COMMENT '联系资料', + `balance` decimal(16,4) DEFAULT '0.0000' COMMENT '应付款余额', + `more` text NOT NULL COMMENT '扩展信息', + PRIMARY KEY (`id`), + KEY `name_py` (`name`,`py`), + KEY `frame` (`frame`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='供应商'; + + +DROP TABLE IF EXISTS `is_swap`; +CREATE TABLE `is_swap` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `frame` int(11) NOT NULL COMMENT '所属组织', + `time` int(11) NOT NULL COMMENT '单据时间', + `number` varchar(32) CHARACTER SET utf8mb4 NOT NULL COMMENT '单据编号', + `total` decimal(16,4) NOT NULL COMMENT '单据成本', + `cost` decimal(16,4) NOT NULL COMMENT '单据费用', + `logistics` text NOT NULL COMMENT '物流信息', + `people` int(11) DEFAULT '0' COMMENT '关联人员', + `file` text NOT NULL COMMENT '单据附件', + `data` varchar(265) NOT NULL COMMENT '备注信息', + `more` text NOT NULL COMMENT '扩展信息', + `examine` tinyint(1) DEFAULT '0' COMMENT '审核状态[0:未审核|1:已审核]', + `cse` tinyint(1) DEFAULT NULL COMMENT '费用状态[0:未结算|1:部分结算|2:已结算|3:无需结算]', + `user` int(11) NOT NULL COMMENT '制单人', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `time` (`time`), + KEY `people` (`people`), + KEY `examine` (`examine`), + KEY `cse` (`cse`), + KEY `user` (`user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='调拨单'; + + +DROP TABLE IF EXISTS `is_swap_info`; +CREATE TABLE `is_swap_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pid` int(11) NOT NULL COMMENT '所属ID', + `goods` int(11) NOT NULL COMMENT '所属商品', + `attr` varchar(64) NOT NULL COMMENT '辅助属性', + `unit` varchar(32) NOT NULL COMMENT '单位', + `warehouse` int(11) NOT NULL COMMENT '调出仓库', + `storehouse` int(11) NOT NULL COMMENT '调入仓库', + `batch` varchar(32) NOT NULL COMMENT '批次号', + `mfd` int(11) DEFAULT '0' COMMENT '生产日期', + `price` decimal(12,4) NOT NULL COMMENT '成本', + `nums` decimal(12,4) NOT NULL COMMENT '数量', + `serial` text NOT NULL COMMENT '序列号', + `total` decimal(12,4) NOT NULL COMMENT '总成本', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `goods` (`goods`), + KEY `warehouse` (`warehouse`), + KEY `storehouse` (`storehouse`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='调拨单详情'; + + +DROP TABLE IF EXISTS `is_sys`; +CREATE TABLE `is_sys` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '配置名称', + `info` text NOT NULL COMMENT '配置内容', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统配置'; + +INSERT INTO `is_sys` (`id`, `name`, `info`, `data`) VALUES +(1, 'name', '点可云进销存软件', '软件名称'), +(2, 'company', '山西点可云科技有限公司', '公司名称'), +(3, 'icp', '晋备000000-0', '备案信息'), +(4, 'notice', '欢迎使用点可云进销存系统\n官网地址:www.nodcloud.com\n反馈邮箱:ceo@nodcloud.com', '公告信息'), +(5, 'brand', '[]', '商品品牌'), +(6, 'unit', '[]', '计量单位'), +(7, 'crCategory', '[\"\\u5e38\\u89c4\\u7c7b\\u522b\"]', '客户类别'), +(8, 'crGrade', '[\"\\u5e38\\u89c4\\u7b49\\u7ea7\"]', '客户等级'), +(9, 'srCategory', '[\"\\u5e38\\u89c4\\u7c7b\\u522b\"]', '供应商类别'), +(10, 'fun', '{\"examine\":false,\"tax\":false,\"rate\":0,\"contain\":false,\"overflow\":false,\"valuation\":\"base\",\"branch\":0,\"rule\":\"def\",\"digit\":{\"nums\":0,\"money\":2},\"days\":\"30\"}', '功能参数'), +(11, 'logistics', '[{\"key\":\"auto\",\"name\":\"\\u81ea\\u52a8\\u8bc6\\u522b\",\"enable\":true},{\"key\":\"debangwuliu\",\"name\":\"\\u5fb7\\u90a6\\u7269\\u6d41\",\"enable\":true},{\"key\":\"ems\",\"name\":\"\\u90ae\\u653f\\u5feb\\u9012\",\"enable\":true},{\"key\":\"kuaijiesudi\",\"name\":\"\\u5feb\\u6377\\u901f\\u9012\",\"enable\":true},{\"key\":\"quanfengkuaidi\",\"name\":\"\\u5168\\u5cf0\\u5feb\\u9012\",\"enable\":true},{\"key\":\"shentong\",\"name\":\"\\u7533\\u901a\\u901f\\u9012\",\"enable\":true},{\"key\":\"shunfeng\",\"name\":\"\\u987a\\u4e30\\u901f\\u9012\",\"enable\":true},{\"key\":\"tiantian\",\"name\":\"\\u5929\\u5929\\u5feb\\u9012\",\"enable\":true},{\"key\":\"youshuwuliu\",\"name\":\"\\u4f18\\u901f\\u7269\\u6d41\",\"enable\":true},{\"key\":\"yuantong\",\"name\":\"\\u5706\\u901a\\u901f\\u9012\",\"enable\":true},{\"key\":\"yunda\",\"name\":\"\\u97f5\\u8fbe\\u5feb\\u8fd0\",\"enable\":true},{\"key\":\"zhongtong\",\"name\":\"\\u4e2d\\u901a\\u901f\\u9012\",\"enable\":true},{\"key\":\"htky\",\"name\":\"\\u767e\\u4e16\\u5feb\\u9012\",\"enable\":true}]', '物流配置'); + + +DROP TABLE IF EXISTS `is_user`; +CREATE TABLE `is_user` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '用户名称', + `py` varchar(32) NOT NULL COMMENT '拼音信息', + `tel` varchar(11) NOT NULL COMMENT '手机号码', + `frame` int(11) NOT NULL COMMENT '所属组织', + `role` int(11) NOT NULL COMMENT '所属角色', + `user` varchar(32) NOT NULL COMMENT '登陆账号', + `pwd` varchar(32) NOT NULL COMMENT '登陆密码', + `img` text NOT NULL COMMENT '用户头像', + `token` varchar(32) DEFAULT '' COMMENT '秘钥信息', + `expire` int(11) NOT NULL COMMENT '秘钥时效', + `data` varchar(256) NOT NULL COMMENT '备注信息', + `more` text NOT NULL COMMENT '扩展信息', + PRIMARY KEY (`id`), + KEY `name_py` (`name`,`py`), + KEY `frame` (`frame`), + KEY `tel` (`tel`), + KEY `role` (`role`), + KEY `user` (`user`), + KEY `expire` (`expire`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户'; + +INSERT INTO `is_user` (`id`, `name`, `py`, `tel`, `frame`, `role`, `user`, `pwd`, `img`, `token`, `expire`, `data`, `more`) VALUES +(1, '管理员', 'gly', '18800000000', 0, 0, 'admin', '7fef6171469e80d32c0559f88b377245', '', '', 0, '管理员', ''); + +DROP TABLE IF EXISTS `is_warehouse`; +CREATE TABLE `is_warehouse` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) NOT NULL COMMENT '仓库名称', + `number` varchar(32) NOT NULL COMMENT '仓库编号', + `frame` int(11) NOT NULL COMMENT '所属组织', + `contacts` varchar(32) NOT NULL COMMENT '联系人员', + `tel` varchar(32) NOT NULL COMMENT '联系电话', + `add` varchar(64) NOT NULL COMMENT '仓库地址', + `data` varchar(256) NOT NULL COMMENT '备注信息', + PRIMARY KEY (`id`), + KEY `frame` (`frame`), + KEY `name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='仓库'; + + +-- 2021-04-11 01:54:46 diff --git a/serve/robots.txt b/serve/robots.txt new file mode 100644 index 0000000..6f27bb6 --- /dev/null +++ b/serve/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: \ No newline at end of file diff --git a/serve/route/app.php b/serve/route/app.php new file mode 100644 index 0000000..7b2f51b --- /dev/null +++ b/serve/route/app.php @@ -0,0 +1,12 @@ + +// +---------------------------------------------------------------------- +use think\facade\Route; + diff --git a/serve/runtime/.gitignore b/serve/runtime/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/runtime/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/serve.zip b/serve/serve.zip new file mode 100644 index 0000000..27112e0 Binary files /dev/null and b/serve/serve.zip differ diff --git a/serve/static/backup/.gitignore b/serve/static/backup/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/backup/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/code/ewm/.gitignore b/serve/static/code/ewm/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/code/ewm/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/code/font/Arial.ttf b/serve/static/code/font/Arial.ttf new file mode 100644 index 0000000..886789b Binary files /dev/null and b/serve/static/code/font/Arial.ttf differ diff --git a/serve/static/code/txm/.gitignore b/serve/static/code/txm/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/code/txm/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/file/mould/.gitignore b/serve/static/file/mould/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/file/mould/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/file/xlsx/.gitignore b/serve/static/file/xlsx/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/file/xlsx/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/file/zip/.gitignore b/serve/static/file/zip/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/file/zip/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/barter/.gitignore b/serve/static/upload/barter/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/barter/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/bor/.gitignore b/serve/static/upload/bor/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/bor/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/bre/.gitignore b/serve/static/upload/bre/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/bre/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/buy/.gitignore b/serve/static/upload/buy/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/buy/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/editor/.gitignore b/serve/static/upload/editor/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/editor/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/entry/.gitignore b/serve/static/upload/entry/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/entry/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/extry/.gitignore b/serve/static/upload/extry/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/extry/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/field/.gitignore b/serve/static/upload/field/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/field/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/goods/.gitignore b/serve/static/upload/goods/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/goods/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/mould/.gitignore b/serve/static/upload/mould/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/mould/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/sell/.gitignore b/serve/static/upload/sell/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/sell/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/sor/.gitignore b/serve/static/upload/sor/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/sor/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/sre/.gitignore b/serve/static/upload/sre/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/sre/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/swap/.gitignore b/serve/static/upload/swap/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/swap/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/user/.gitignore b/serve/static/upload/user/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/user/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/vend/.gitignore b/serve/static/upload/vend/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/vend/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/vre/.gitignore b/serve/static/upload/vre/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/vre/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/static/upload/xlsx/.gitignore b/serve/static/upload/xlsx/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/serve/static/upload/xlsx/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/serve/think b/serve/think new file mode 100644 index 0000000..2429d22 --- /dev/null +++ b/serve/think @@ -0,0 +1,10 @@ +#!/usr/bin/env php +console->run(); \ No newline at end of file diff --git a/serve/vendor/adbario/php-dot-notation/LICENSE.md b/serve/vendor/adbario/php-dot-notation/LICENSE.md new file mode 100644 index 0000000..fe01323 --- /dev/null +++ b/serve/vendor/adbario/php-dot-notation/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) 2016-2019 Riku Särkinen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/serve/vendor/adbario/php-dot-notation/composer.json b/serve/vendor/adbario/php-dot-notation/composer.json new file mode 100644 index 0000000..b7b82cb --- /dev/null +++ b/serve/vendor/adbario/php-dot-notation/composer.json @@ -0,0 +1,29 @@ +{ + "name": "adbario/php-dot-notation", + "description": "PHP dot notation access to arrays", + "keywords": ["dotnotation", "arrayaccess"], + "homepage": "https://github.com/adbario/php-dot-notation", + "license": "MIT", + "authors": [ + { + "name": "Riku Särkinen", + "email": "riku@adbar.io" + } + ], + "require": { + "php": ">=5.5", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0|^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Adbar\\": "src" + } + } +} diff --git a/serve/vendor/adbario/php-dot-notation/src/Dot.php b/serve/vendor/adbario/php-dot-notation/src/Dot.php new file mode 100644 index 0000000..8d504d9 --- /dev/null +++ b/serve/vendor/adbario/php-dot-notation/src/Dot.php @@ -0,0 +1,601 @@ + + * @link https://github.com/adbario/php-dot-notation + * @license https://github.com/adbario/php-dot-notation/blob/2.x/LICENSE.md (MIT License) + */ +namespace Adbar; + +use Countable; +use ArrayAccess; +use ArrayIterator; +use JsonSerializable; +use IteratorAggregate; + +/** + * Dot + * + * This class provides a dot notation access and helper functions for + * working with arrays of data. Inspired by Laravel Collection. + */ +class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable +{ + /** + * The stored items + * + * @var array + */ + protected $items = []; + + /** + * Create a new Dot instance + * + * @param mixed $items + */ + public function __construct($items = []) + { + $this->items = $this->getArrayItems($items); + } + + /** + * Set a given key / value pair or pairs + * if the key doesn't exist already + * + * @param array|int|string $keys + * @param mixed $value + */ + public function add($keys, $value = null) + { + if (is_array($keys)) { + foreach ($keys as $key => $value) { + $this->add($key, $value); + } + } elseif (is_null($this->get($keys))) { + $this->set($keys, $value); + } + } + + /** + * Return all the stored items + * + * @return array + */ + public function all() + { + return $this->items; + } + + /** + * Delete the contents of a given key or keys + * + * @param array|int|string|null $keys + */ + public function clear($keys = null) + { + if (is_null($keys)) { + $this->items = []; + + return; + } + + $keys = (array) $keys; + + foreach ($keys as $key) { + $this->set($key, []); + } + } + + /** + * Delete the given key or keys + * + * @param array|int|string $keys + */ + public function delete($keys) + { + $keys = (array) $keys; + + foreach ($keys as $key) { + if ($this->exists($this->items, $key)) { + unset($this->items[$key]); + + continue; + } + + $items = &$this->items; + $segments = explode('.', $key); + $lastSegment = array_pop($segments); + + foreach ($segments as $segment) { + if (!isset($items[$segment]) || !is_array($items[$segment])) { + continue 2; + } + + $items = &$items[$segment]; + } + + unset($items[$lastSegment]); + } + } + + /** + * Checks if the given key exists in the provided array. + * + * @param array $array Array to validate + * @param int|string $key The key to look for + * + * @return bool + */ + protected function exists($array, $key) + { + return array_key_exists($key, $array); + } + + /** + * Flatten an array with the given character as a key delimiter + * + * @param string $delimiter + * @param array|null $items + * @param string $prepend + * @return array + */ + public function flatten($delimiter = '.', $items = null, $prepend = '') + { + $flatten = []; + + if (is_null($items)) { + $items = $this->items; + } + + foreach ($items as $key => $value) { + if (is_array($value) && !empty($value)) { + $flatten = array_merge( + $flatten, + $this->flatten($delimiter, $value, $prepend.$key.$delimiter) + ); + } else { + $flatten[$prepend.$key] = $value; + } + } + + return $flatten; + } + + /** + * Return the value of a given key + * + * @param int|string|null $key + * @param mixed $default + * @return mixed + */ + public function get($key = null, $default = null) + { + if (is_null($key)) { + return $this->items; + } + + if ($this->exists($this->items, $key)) { + return $this->items[$key]; + } + + if (strpos($key, '.') === false) { + return $default; + } + + $items = $this->items; + + foreach (explode('.', $key) as $segment) { + if (!is_array($items) || !$this->exists($items, $segment)) { + return $default; + } + + $items = &$items[$segment]; + } + + return $items; + } + + /** + * Return the given items as an array + * + * @param mixed $items + * @return array + */ + protected function getArrayItems($items) + { + if (is_array($items)) { + return $items; + } elseif ($items instanceof self) { + return $items->all(); + } + + return (array) $items; + } + + /** + * Check if a given key or keys exists + * + * @param array|int|string $keys + * @return bool + */ + public function has($keys) + { + $keys = (array) $keys; + + if (!$this->items || $keys === []) { + return false; + } + + foreach ($keys as $key) { + $items = $this->items; + + if ($this->exists($items, $key)) { + continue; + } + + foreach (explode('.', $key) as $segment) { + if (!is_array($items) || !$this->exists($items, $segment)) { + return false; + } + + $items = $items[$segment]; + } + } + + return true; + } + + /** + * Check if a given key or keys are empty + * + * @param array|int|string|null $keys + * @return bool + */ + public function isEmpty($keys = null) + { + if (is_null($keys)) { + return empty($this->items); + } + + $keys = (array) $keys; + + foreach ($keys as $key) { + if (!empty($this->get($key))) { + return false; + } + } + + return true; + } + + /** + * Merge a given array or a Dot object with the given key + * or with the whole Dot object + * + * @param array|string|self $key + * @param array|self $value + */ + public function merge($key, $value = []) + { + if (is_array($key)) { + $this->items = array_merge($this->items, $key); + } elseif (is_string($key)) { + $items = (array) $this->get($key); + $value = array_merge($items, $this->getArrayItems($value)); + + $this->set($key, $value); + } elseif ($key instanceof self) { + $this->items = array_merge($this->items, $key->all()); + } + } + + /** + * Recursively merge a given array or a Dot object with the given key + * or with the whole Dot object. + * + * Duplicate keys are converted to arrays. + * + * @param array|string|self $key + * @param array|self $value + */ + public function mergeRecursive($key, $value = []) + { + if (is_array($key)) { + $this->items = array_merge_recursive($this->items, $key); + } elseif (is_string($key)) { + $items = (array) $this->get($key); + $value = array_merge_recursive($items, $this->getArrayItems($value)); + + $this->set($key, $value); + } elseif ($key instanceof self) { + $this->items = array_merge_recursive($this->items, $key->all()); + } + } + + /** + * Recursively merge a given array or a Dot object with the given key + * or with the whole Dot object. + * + * Instead of converting duplicate keys to arrays, the value from + * given array will replace the value in Dot object. + * + * @param array|string|self $key + * @param array|self $value + */ + public function mergeRecursiveDistinct($key, $value = []) + { + if (is_array($key)) { + $this->items = $this->arrayMergeRecursiveDistinct($this->items, $key); + } elseif (is_string($key)) { + $items = (array) $this->get($key); + $value = $this->arrayMergeRecursiveDistinct($items, $this->getArrayItems($value)); + + $this->set($key, $value); + } elseif ($key instanceof self) { + $this->items = $this->arrayMergeRecursiveDistinct($this->items, $key->all()); + } + } + + /** + * Merges two arrays recursively. In contrast to array_merge_recursive, + * duplicate keys are not converted to arrays but rather overwrite the + * value in the first array with the duplicate value in the second array. + * + * @param array $array1 Initial array to merge + * @param array $array2 Array to recursively merge + * @return array + */ + protected function arrayMergeRecursiveDistinct(array $array1, array $array2) + { + $merged = &$array1; + + foreach ($array2 as $key => $value) { + if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) { + $merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value); + } else { + $merged[$key] = $value; + } + } + + return $merged; + } + + /** + * Return the value of a given key and + * delete the key + * + * @param int|string|null $key + * @param mixed $default + * @return mixed + */ + public function pull($key = null, $default = null) + { + if (is_null($key)) { + $value = $this->all(); + $this->clear(); + + return $value; + } + + $value = $this->get($key, $default); + $this->delete($key); + + return $value; + } + + /** + * Push a given value to the end of the array + * in a given key + * + * @param mixed $key + * @param mixed $value + */ + public function push($key, $value = null) + { + if (is_null($value)) { + $this->items[] = $key; + + return; + } + + $items = $this->get($key); + + if (is_array($items) || is_null($items)) { + $items[] = $value; + $this->set($key, $items); + } + } + + /** + * Replace all values or values within the given key + * with an array or Dot object + * + * @param array|string|self $key + * @param array|self $value + */ + public function replace($key, $value = []) + { + if (is_array($key)) { + $this->items = array_replace($this->items, $key); + } elseif (is_string($key)) { + $items = (array) $this->get($key); + $value = array_replace($items, $this->getArrayItems($value)); + + $this->set($key, $value); + } elseif ($key instanceof self) { + $this->items = array_replace($this->items, $key->all()); + } + } + + /** + * Set a given key / value pair or pairs + * + * @param array|int|string $keys + * @param mixed $value + */ + public function set($keys, $value = null) + { + if (is_array($keys)) { + foreach ($keys as $key => $value) { + $this->set($key, $value); + } + + return; + } + + $items = &$this->items; + + foreach (explode('.', $keys) as $key) { + if (!isset($items[$key]) || !is_array($items[$key])) { + $items[$key] = []; + } + + $items = &$items[$key]; + } + + $items = $value; + } + + /** + * Replace all items with a given array + * + * @param mixed $items + */ + public function setArray($items) + { + $this->items = $this->getArrayItems($items); + } + + /** + * Replace all items with a given array as a reference + * + * @param array $items + */ + public function setReference(array &$items) + { + $this->items = &$items; + } + + /** + * Return the value of a given key or all the values as JSON + * + * @param mixed $key + * @param int $options + * @return string + */ + public function toJson($key = null, $options = 0) + { + if (is_string($key)) { + return json_encode($this->get($key), $options); + } + + $options = $key === null ? 0 : $key; + + return json_encode($this->items, $options); + } + + /* + * -------------------------------------------------------------- + * ArrayAccess interface + * -------------------------------------------------------------- + */ + + /** + * Check if a given key exists + * + * @param int|string $key + * @return bool + */ + public function offsetExists($key) + { + return $this->has($key); + } + + /** + * Return the value of a given key + * + * @param int|string $key + * @return mixed + */ + public function offsetGet($key) + { + return $this->get($key); + } + + /** + * Set a given value to the given key + * + * @param int|string|null $key + * @param mixed $value + */ + public function offsetSet($key, $value) + { + if (is_null($key)) { + $this->items[] = $value; + + return; + } + + $this->set($key, $value); + } + + /** + * Delete the given key + * + * @param int|string $key + */ + public function offsetUnset($key) + { + $this->delete($key); + } + + /* + * -------------------------------------------------------------- + * Countable interface + * -------------------------------------------------------------- + */ + + /** + * Return the number of items in a given key + * + * @param int|string|null $key + * @return int + */ + public function count($key = null) + { + return count($this->get($key)); + } + + /* + * -------------------------------------------------------------- + * IteratorAggregate interface + * -------------------------------------------------------------- + */ + + /** + * Get an iterator for the stored items + * + * @return \ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->items); + } + + /* + * -------------------------------------------------------------- + * JsonSerializable interface + * -------------------------------------------------------------- + */ + + /** + * Return items for JSON serialization + * + * @return array + */ + public function jsonSerialize() + { + return $this->items; + } +} diff --git a/serve/vendor/adbario/php-dot-notation/src/helpers.php b/serve/vendor/adbario/php-dot-notation/src/helpers.php new file mode 100644 index 0000000..ffdc826 --- /dev/null +++ b/serve/vendor/adbario/php-dot-notation/src/helpers.php @@ -0,0 +1,23 @@ + + * @link https://github.com/adbario/php-dot-notation + * @license https://github.com/adbario/php-dot-notation/blob/2.x/LICENSE.md (MIT License) + */ + +use Adbar\Dot; + +if (! function_exists('dot')) { + /** + * Create a new Dot object with the given items + * + * @param mixed $items + * @return \Adbar\Dot + */ + function dot($items) + { + return new Dot($items); + } +} diff --git a/serve/vendor/alibabacloud/tea-fileform/.gitignore b/serve/vendor/alibabacloud/tea-fileform/.gitignore new file mode 100644 index 0000000..84837df --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/.gitignore @@ -0,0 +1,12 @@ +composer.phar +/vendor/ + +# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control +# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file +composer.lock + +.idea +.DS_Store + +cache/ +*.cache diff --git a/serve/vendor/alibabacloud/tea-fileform/.php_cs.dist b/serve/vendor/alibabacloud/tea-fileform/.php_cs.dist new file mode 100644 index 0000000..8617ec2 --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/.php_cs.dist @@ -0,0 +1,65 @@ +setRiskyAllowed(true) + ->setIndent(' ') + ->setRules([ + '@PSR2' => true, + '@PhpCsFixer' => true, + '@Symfony:risky' => true, + 'concat_space' => ['spacing' => 'one'], + 'array_syntax' => ['syntax' => 'short'], + 'array_indentation' => true, + 'combine_consecutive_unsets' => true, + 'method_separation' => true, + 'single_quote' => true, + 'declare_equal_normalize' => true, + 'function_typehint_space' => true, + 'hash_to_slash_comment' => true, + 'include' => true, + 'lowercase_cast' => true, + 'no_multiline_whitespace_before_semicolons' => true, + 'no_leading_import_slash' => true, + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_spaces_around_offset' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unused_imports' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'object_operator_without_whitespace' => true, + 'single_blank_line_before_namespace' => true, + 'single_class_element_per_statement' => true, + 'space_after_semicolon' => true, + 'standardize_not_equals' => true, + 'ternary_operator_spaces' => true, + 'trailing_comma_in_multiline_array' => true, + 'trim_array_spaces' => true, + 'unary_operator_spaces' => true, + 'whitespace_after_comma_in_array' => true, + 'no_extra_consecutive_blank_lines' => [ + 'curly_brace_block', + 'extra', + 'parenthesis_brace_block', + 'square_brace_block', + 'throw', + 'use', + ], + 'binary_operator_spaces' => [ + 'align_double_arrow' => true, + 'align_equals' => true, + ], + 'braces' => [ + 'allow_single_line_closure' => true, + ], + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->exclude('vendor') + ->exclude('tests') + ->in(__DIR__) + ); diff --git a/serve/vendor/alibabacloud/tea-fileform/README-CN.md b/serve/vendor/alibabacloud/tea-fileform/README-CN.md new file mode 100644 index 0000000..8d25238 --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/README-CN.md @@ -0,0 +1,31 @@ +English | [简体中文](README-CN.md) + +![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg) + +## Alibaba Cloud Tea File Library for PHP + +## Installation + +### Composer + +```bash +composer require alibabacloud/tea-fileform +``` + +## Issues + +[Opening an Issue](https://github.com/aliyun/tea-fileform/issues/new), Issues not conforming to the guidelines may be closed immediately. + +## Changelog + +Detailed changes for each release are documented in the [release notes](./ChangeLog.txt). + +## References + +* [Latest Release](https://github.com/aliyun/tea-fileform) + +## License + +[Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) + +Copyright (c) 2009-present, Alibaba Cloud All rights reserved. diff --git a/serve/vendor/alibabacloud/tea-fileform/README.md b/serve/vendor/alibabacloud/tea-fileform/README.md new file mode 100644 index 0000000..9917f3c --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/README.md @@ -0,0 +1,31 @@ +[English](README.md) | 简体中文 + +![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg) + +## Alibaba Cloud Tea File Library for PHP + +## 安装 + +### Composer + +```bash +composer require alibabacloud/tea-fileform +``` + +## 问题 + +[提交 Issue](https://github.com/aliyun/tea-fileform/issues/new),不符合指南的问题可能会立即关闭。 + +## 发行说明 + +每个版本的详细更改记录在[发行说明](./ChangeLog.txt)中。 + +## 相关 + +* [最新源码](https://github.com/aliyun/tea-fileform) + +## 许可证 + +[Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) + +Copyright (c) 2009-present, Alibaba Cloud All rights reserved. diff --git a/serve/vendor/alibabacloud/tea-fileform/composer.json b/serve/vendor/alibabacloud/tea-fileform/composer.json new file mode 100644 index 0000000..151fe7b --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/composer.json @@ -0,0 +1,44 @@ +{ + "name": "alibabacloud/tea-fileform", + "description": "Alibaba Cloud Tea File Library for PHP", + "type": "library", + "license": "Apache-2.0", + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "require": { + "php": ">5.5", + "alibabacloud/tea": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\FileForm\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "AlibabaCloud\\Tea\\FileForm\\Tests\\": "tests" + } + }, + "scripts": { + "fixer": "php-cs-fixer fix ./", + "test": [ + "@clearCache", + "phpunit --colors=always" + ], + "clearCache": "rm -rf cache/*" + }, + "config": { + "sort-packages": true, + "preferred-install": "dist", + "optimize-autoloader": true + }, + "prefer-stable": true, + "minimum-stability": "dev" +} diff --git a/serve/vendor/alibabacloud/tea-fileform/phpunit.xml b/serve/vendor/alibabacloud/tea-fileform/phpunit.xml new file mode 100644 index 0000000..8306a79 --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/phpunit.xml @@ -0,0 +1,32 @@ + + + + + + tests + + + ./tests/Unit + + + + + + integration + + + + + + + + + + + + ./src + + + diff --git a/serve/vendor/alibabacloud/tea-fileform/src/FileForm.php b/serve/vendor/alibabacloud/tea-fileform/src/FileForm.php new file mode 100644 index 0000000..ee44cbb --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/src/FileForm.php @@ -0,0 +1,16 @@ +_required = [ + 'filename' => true, + 'contentType' => true, + 'content' => true, + ]; + parent::__construct($config); + } +} diff --git a/serve/vendor/alibabacloud/tea-fileform/src/FileFormStream.php b/serve/vendor/alibabacloud/tea-fileform/src/FileFormStream.php new file mode 100644 index 0000000..a2cc246 --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/src/FileFormStream.php @@ -0,0 +1,321 @@ +stream = fopen('php://memory', 'a+'); + $this->form = $map; + $this->boundary = $boundary; + $this->keys = array_keys($map); + do { + $read = $this->readForm(1024); + } while (null !== $read); + $meta = stream_get_meta_data($this->stream); + $this->seekable = $meta['seekable']; + $this->uri = $this->getMetadata('uri'); + $this->seek(0); + $this->seek(0); + } + + /** + * Closes the stream when the destructed. + */ + public function __destruct() + { + $this->close(); + } + + public function __toString() + { + try { + $this->seek(0); + + return (string) stream_get_contents($this->stream); + } catch (\Exception $e) { + return ''; + } + } + + /** + * @param int $length + * + * @return false|int|string + */ + public function readForm($length) + { + if ($this->streaming) { + if (null !== $this->currStream) { + // @var string $content + $content = $this->currStream->read($length); + if (false !== $content && '' !== $content) { + fwrite($this->stream, $content); + + return $content; + } + + return $this->next("\r\n"); + } + + return $this->next(); + } + $keysCount = \count($this->keys); + if ($this->index > $keysCount) { + return null; + } + if ($keysCount > 0) { + if ($this->index < $keysCount) { + $this->streaming = true; + + $name = $this->keys[$this->index]; + $field = $this->form[$name]; + if (!empty($field) && $field instanceof FileField) { + if (!empty($field->content)) { + $this->currStream = $field->content; + + $str = '--' . $this->boundary . "\r\n" . + 'Content-Disposition: form-data; name="' . $name . '"; filename="' . $field->filename . "\"\r\n" . + 'Content-Type: ' . $field->contentType . "\r\n\r\n"; + $this->write($str); + + return $str; + } + + return $this->next(); + } + $val = $field; + $str = '--' . $this->boundary . "\r\n" . + 'Content-Disposition: form-data; name="' . $name . "\"\r\n\r\n" . + $val . "\r\n"; + fwrite($this->stream, $str); + + return $str; + } + if ($this->index == $keysCount) { + return $this->next('--' . $this->boundary . "--\r\n"); + } + + return null; + } + + return null; + } + + public function getContents() + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + + $contents = stream_get_contents($this->stream); + + if (false === $contents) { + throw new \RuntimeException('Unable to read stream contents'); + } + + return $contents; + } + + public function close() + { + if (isset($this->stream)) { + if (\is_resource($this->stream)) { + fclose($this->stream); + } + $this->detach(); + } + } + + public function detach() + { + if (!isset($this->stream)) { + return null; + } + + $result = $this->stream; + unset($this->stream); + $this->size = $this->uri = null; + + return $result; + } + + public function getSize() + { + if (null !== $this->size) { + return $this->size; + } + + if (!isset($this->stream)) { + return null; + } + + // Clear the stat cache if the stream has a URI + if ($this->uri) { + clearstatcache(true, $this->uri); + } + + $stats = fstat($this->stream); + if (isset($stats['size'])) { + $this->size = $stats['size']; + + return $this->size; + } + + return null; + } + + public function isReadable() + { + return $this->readable; + } + + public function isWritable() + { + return $this->writable; + } + + public function isSeekable() + { + return $this->seekable; + } + + public function eof() + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + + return feof($this->stream); + } + + public function tell() + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + + $result = ftell($this->stream); + + if (false === $result) { + throw new \RuntimeException('Unable to determine stream position'); + } + + return $result; + } + + public function rewind() + { + $this->seek(0); + } + + public function seek($offset, $whence = SEEK_SET) + { + $whence = (int) $whence; + + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + if (!$this->seekable) { + throw new \RuntimeException('Stream is not seekable'); + } + if (-1 === fseek($this->stream, $offset, $whence)) { + throw new \RuntimeException('Unable to seek to stream position ' . $offset . ' with whence ' . var_export($whence, true)); + } + } + + public function read($length) + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + if (!$this->readable) { + throw new \RuntimeException('Cannot read from non-readable stream'); + } + if ($length < 0) { + throw new \RuntimeException('Length parameter cannot be negative'); + } + + if (0 === $length) { + return ''; + } + + $string = fread($this->stream, $length); + if (false === $string) { + throw new \RuntimeException('Unable to read from stream'); + } + + return $string; + } + + public function write($string) + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + if (!$this->writable) { + throw new \RuntimeException('Cannot write to a non-writable stream'); + } + + // We can't know the size after writing anything + $this->size = null; + $result = fwrite($this->stream, $string); + + if (false === $result) { + throw new \RuntimeException('Unable to write to stream'); + } + + return $result; + } + + public function getMetadata($key = null) + { + if (!isset($this->stream)) { + return $key ? null : []; + } + + $meta = stream_get_meta_data($this->stream); + + return isset($meta[$key]) ? $meta[$key] : null; + } + + private function next($endStr = '') + { + $this->streaming = false; + ++$this->index; + $this->write($endStr); + $this->currStream = null; + + return $endStr; + } +} diff --git a/serve/vendor/alibabacloud/tea-fileform/tests/FileFormTest.php b/serve/vendor/alibabacloud/tea-fileform/tests/FileFormTest.php new file mode 100644 index 0000000..67d24e8 --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/tests/FileFormTest.php @@ -0,0 +1,81 @@ +assertTrue($stream instanceof FileFormStream); + $stream->write($boundary); + $this->assertTrue(\strlen($boundary) === $stream->getSize()); + } + + public function testSet() + { + $fileField = new FileField([ + 'filename' => 'fake filename', + 'contentType' => 'content type', + 'content' => null, + ]); + + $this->assertEquals('fake filename', $fileField->filename); + $this->assertEquals('content type', $fileField->contentType); + } + + public function testRead() + { + $fileField = new FileField(); + $fileField->filename = 'haveContent'; + $fileField->contentType = 'contentType'; + $fileField->content = new Stream(fopen('data://text/plain;base64,' . base64_encode('This is file test. This sentence must be long'), 'r')); + + $fileFieldNoContent = new FileField(); + $fileFieldNoContent->filename = 'noContent'; + $fileFieldNoContent->contentType = 'contentType'; + $fileFieldNoContent->content = null; + + $map = [ + 'key' => 'value', + 'testKey' => 'testValue', + 'haveFile' => $fileField, + 'noFile' => $fileFieldNoContent, + ]; + + $stream = FileForm::toFileForm($map, 'testBoundary'); + + $result = $stream->getContents(); + $target = "--testBoundary\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nvalue\r\n--testBoundary\r\nContent-Disposition: form-data; name=\"testKey\"\r\n\r\ntestValue\r\n--testBoundary\r\nContent-Disposition: form-data; name=\"haveFile\"; filename=\"haveContent\"\r\nContent-Type: contentType\r\n\r\nThis is file test. This sentence must be long\r\n--testBoundary--\r\n"; + + $this->assertEquals($target, $result); + } + + public function testReadFile() + { + $fileField = new FileField(); + $fileField->filename = 'composer.json'; + $fileField->contentType = 'application/json'; + $fileField->content = new Stream(fopen(__DIR__ . '/../composer.json', 'r')); + $map = [ + 'name' => 'json_file', + 'type' => 'application/json', + 'json_file' => $fileField, + ]; + + $boundary = FileForm::getBoundary(); + $fileStream = FileForm::toFileForm($map, $boundary); + $this->assertTrue(false !== strpos($fileStream->getContents(), 'json_file')); + } +} diff --git a/serve/vendor/alibabacloud/tea-fileform/tests/bootstrap.php b/serve/vendor/alibabacloud/tea-fileform/tests/bootstrap.php new file mode 100644 index 0000000..c62c4e8 --- /dev/null +++ b/serve/vendor/alibabacloud/tea-fileform/tests/bootstrap.php @@ -0,0 +1,3 @@ +setRiskyAllowed(true) + ->setIndent(' ') + ->setRules([ + '@PSR2' => true, + '@PhpCsFixer' => true, + '@Symfony:risky' => true, + 'concat_space' => ['spacing' => 'one'], + 'array_syntax' => ['syntax' => 'short'], + 'array_indentation' => true, + 'combine_consecutive_unsets' => true, + 'method_separation' => true, + 'single_quote' => true, + 'declare_equal_normalize' => true, + 'function_typehint_space' => true, + 'hash_to_slash_comment' => true, + 'include' => true, + 'lowercase_cast' => true, + 'no_multiline_whitespace_before_semicolons' => true, + 'no_leading_import_slash' => true, + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_spaces_around_offset' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unused_imports' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'object_operator_without_whitespace' => true, + 'single_blank_line_before_namespace' => true, + 'single_class_element_per_statement' => true, + 'space_after_semicolon' => true, + 'standardize_not_equals' => true, + 'ternary_operator_spaces' => true, + 'trailing_comma_in_multiline_array' => true, + 'trim_array_spaces' => true, + 'unary_operator_spaces' => true, + 'whitespace_after_comma_in_array' => true, + 'no_extra_consecutive_blank_lines' => [ + 'curly_brace_block', + 'extra', + 'parenthesis_brace_block', + 'square_brace_block', + 'throw', + 'use', + ], + 'binary_operator_spaces' => [ + 'align_double_arrow' => true, + 'align_equals' => true, + ], + 'braces' => [ + 'allow_single_line_closure' => true, + ], + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->exclude('vendor') + ->exclude('tests') + ->in(__DIR__) + ); diff --git a/serve/vendor/alibabacloud/tea/CHANGELOG.md b/serve/vendor/alibabacloud/tea/CHANGELOG.md new file mode 100644 index 0000000..df2bb1f --- /dev/null +++ b/serve/vendor/alibabacloud/tea/CHANGELOG.md @@ -0,0 +1,144 @@ +# CHANGELOG + +## 3.1.21 - 2021-03-15 + +- Supported set proxy&timeout on request. + +## 3.1.20 - 2020-12-02 + +- Fix the warning when the Tea::merge method received empty arguments. + +## 3.1.19 - 2020-10-09 + +- Fix the error when the code value is a string. + +## 3.1.18 - 2020-09-28 + +- Require Guzzle Version 7.0 + +## 3.1.17 - 2020-09-24 + +- TeaUnableRetryError support get error info. + +## 3.1.16 - 2020-08-31 + +- Fix the Maximum function nesting level error when repeated network requests. + +## 3.1.15 - 2020-07-28 + +- Improved validatePattern method. + +## 3.1.14 - 2020-07-03 + +- Supported set properties of TeaError with `ErrorInfo`. + +## 3.1.13 - 2020-06-09 + +- Reduce dependencies. + +## 3.1.12 - 2020-05-13 + +- Add validate method. +- Supported validate maximun&minimun of property. + +## 3.1.11 - 2020-05-07 + +- Fixed error when class is undefined. + +## 3.1.10 - 2020-05-07 + +- Fixed error when '$item' of array is null + +## 3.1.9 - 2020-04-13 + +- TeaUnableRetryError add $lastException param. + +## 3.1.8 - 2020-04-02 + +- Added some static methods of Model to validate fields of Model. + +## 3.1.7 - 2020-03-27 + +- Improve Tea::isRetryable method. + +## 3.1.6 - 2020-03-25 + +- Fixed bug when body is StreamInterface. + +## 3.1.5 - 2020-03-25 + +- Improve Model.toMap method. +- Improve Tea.merge method. +- Fixed tests. + +## 3.1.4 - 2020-03-20 + +- Added Tea::merge method. +- Change Tea::isRetryable method. + +## 3.1.3 - 2020-03-20 + +- Model: added toModel method. + +## 3.1.2 - 2020-03-19 + +- Model constructor supported array type parameter. + +## 3.1.1 - 2020-03-18 + +- Fixed bug : set method failed. +- Fixed bug : get empty contents form body. + +## 3.1.0 - 2020-03-13 + +- TeaUnableRetryError add 'lastRequest' property. +- Change Tea.send() method return. +- Fixed Tea. allowRetry() method. + +## 3.0.0 - 2020-02-14 +- Rename package name. + +## 2.0.3 - 2020-02-14 +- Improved Exception. + +## 2.0.2 - 2019-09-11 +- Supported `String`. + +## 2.0.1 - 2019-08-15 +- Supported `IteratorAggregate`. + +## 2.0.0 - 2019-08-14 +- Design `Request` as a standard `PsrRequest`. + +## 1.0.10 - 2019-08-12 +- Added `__toString` for `Response`. + +## 1.0.9 - 2019-08-01 +- Updated `Middleware`. + +## 1.0.8 - 2019-07-29 +- Supported `TransferStats`. + +## 1.0.7 - 2019-07-27 +- Improved request. + +## 1.0.6 - 2019-07-23 +- Trim key for parameter. + +## 1.0.5 - 2019-07-23 +- Supported default protocol. + +## 1.0.4 - 2019-07-22 +- Added `toArray()`. + +## 1.0.3 - 2019-05-02 +- Improved `Request`. + +## 1.0.2 - 2019-05-02 +- Added getHeader/getHeaders. + +## 1.0.1 - 2019-04-02 +- Improved design. + +## 1.0.0 - 2019-05-02 +- Initial release of the AlibabaCloud Tea Version 1.0.0 on Packagist See for more information. diff --git a/serve/vendor/alibabacloud/tea/LICENSE.md b/serve/vendor/alibabacloud/tea/LICENSE.md new file mode 100644 index 0000000..ec13fcc --- /dev/null +++ b/serve/vendor/alibabacloud/tea/LICENSE.md @@ -0,0 +1,13 @@ +Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/serve/vendor/alibabacloud/tea/README.md b/serve/vendor/alibabacloud/tea/README.md new file mode 100644 index 0000000..a8cbe66 --- /dev/null +++ b/serve/vendor/alibabacloud/tea/README.md @@ -0,0 +1,16 @@ + +## Installation +``` +composer require alibabacloud/tea --optimize-autoloader +``` +> Some users may not be able to install due to network problems, you can try to switch the Composer mirror. + + +## Changelog +Detailed changes for each release are documented in the [release notes](CHANGELOG.md). + + +## License +[Apache-2.0](LICENSE.md) + +Copyright (c) 2009-present, Alibaba Cloud All rights reserved. diff --git a/serve/vendor/alibabacloud/tea/composer.json b/serve/vendor/alibabacloud/tea/composer.json new file mode 100644 index 0000000..87dd0bf --- /dev/null +++ b/serve/vendor/alibabacloud/tea/composer.json @@ -0,0 +1,80 @@ +{ + "name": "alibabacloud/tea", + "homepage": "https://www.alibabacloud.com/", + "description": "Client of Tea for PHP", + "keywords": [ + "tea", + "client", + "alibabacloud", + "cloud" + ], + "type": "library", + "license": "Apache-2.0", + "support": { + "source": "https://github.com/aliyun/tea-php", + "issues": "https://github.com/aliyun/tea-php/issues" + }, + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com", + "homepage": "http://www.alibabacloud.com" + } + ], + "require": { + "php": ">=5.5", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "adbario/php-dot-notation": "^2.2" + }, + "require-dev": { + "symfony/dotenv": "^3.4", + "phpunit/phpunit": "*", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "AlibabaCloud\\Tea\\Tests\\": "tests" + } + }, + "config": { + "sort-packages": true, + "preferred-install": "dist", + "optimize-autoloader": true + }, + "prefer-stable": true, + "minimum-stability": "dev", + "scripts": { + "cs": "phpcs --standard=PSR2 -n ./", + "cbf": "phpcbf --standard=PSR2 -n ./", + "fixer": "php-cs-fixer fix ./", + "test": [ + "@clearCache", + "phpunit --colors=always" + ], + "unit": [ + "@clearCache", + "phpunit --testsuite=Unit --colors=always" + ], + "feature": [ + "@clearCache", + "phpunit --testsuite=Feature --colors=always" + ], + "clearCache": "rm -rf cache/*", + "coverage": "open cache/coverage/index.html" + } +} diff --git a/serve/vendor/alibabacloud/tea/src/Exception/TeaError.php b/serve/vendor/alibabacloud/tea/src/Exception/TeaError.php new file mode 100644 index 0000000..3d8fb9c --- /dev/null +++ b/serve/vendor/alibabacloud/tea/src/Exception/TeaError.php @@ -0,0 +1,47 @@ +errorInfo = $errorInfo; + if (!empty($errorInfo)) { + $properties = ['name', 'message', 'code', 'data']; + foreach ($properties as $property) { + if (isset($errorInfo[$property])) { + $this->{$property} = $errorInfo[$property]; + } + } + } + } + + /** + * @return array + */ + public function getErrorInfo() + { + return $this->errorInfo; + } +} diff --git a/serve/vendor/alibabacloud/tea/src/Exception/TeaRetryError.php b/serve/vendor/alibabacloud/tea/src/Exception/TeaRetryError.php new file mode 100644 index 0000000..30aa7f8 --- /dev/null +++ b/serve/vendor/alibabacloud/tea/src/Exception/TeaRetryError.php @@ -0,0 +1,21 @@ +getErrorInfo(); + } + parent::__construct($error_info, $lastException->getMessage(), $lastException->getCode(), $lastException); + $this->lastRequest = $lastRequest; + $this->lastException = $lastException; + } + + public function getLastRequest() + { + return $this->lastRequest; + } + + public function getLastException() + { + return $this->lastException; + } +} diff --git a/serve/vendor/alibabacloud/tea/src/Helper.php b/serve/vendor/alibabacloud/tea/src/Helper.php new file mode 100644 index 0000000..817cba0 --- /dev/null +++ b/serve/vendor/alibabacloud/tea/src/Helper.php @@ -0,0 +1,68 @@ + $value) { + if (\is_int($key)) { + $result[] = $value; + + continue; + } + + if (isset($result[$key]) && \is_array($result[$key])) { + $result[$key] = self::merge( + [$result[$key], $value] + ); + + continue; + } + + $result[$key] = $value; + } + } + + return $result; + } +} diff --git a/serve/vendor/alibabacloud/tea/src/Model.php b/serve/vendor/alibabacloud/tea/src/Model.php new file mode 100644 index 0000000..538b55c --- /dev/null +++ b/serve/vendor/alibabacloud/tea/src/Model.php @@ -0,0 +1,114 @@ + $v) { + $this->{$k} = $v; + } + } + } + + public function getName($name = null) + { + if (null === $name) { + return $this->_name; + } + + return isset($this->_name[$name]) ? $this->_name[$name] : $name; + } + + public function toMap() + { + $map = get_object_vars($this); + foreach ($map as $k => $m) { + if (0 === strpos($k, '_')) { + unset($map[$k]); + } + } + $res = []; + foreach ($map as $k => $v) { + $name = isset($this->_name[$k]) ? $this->_name[$k] : $k; + $res[$name] = $v; + } + + return $res; + } + + public function validate() + { + $vars = get_object_vars($this); + foreach ($vars as $k => $v) { + if (isset($this->_required[$k]) && $this->_required[$k] && empty($v)) { + throw new \InvalidArgumentException("{$k} is required."); + } + } + } + + public static function validateRequired($fieldName, $field, $val = null) + { + if (true === $val && null === $field) { + throw new \InvalidArgumentException($fieldName . ' is required'); + } + } + + public static function validateMaxLength($fieldName, $field, $val = null) + { + if (null !== $field && \strlen($field) > (int) $val) { + throw new \InvalidArgumentException($fieldName . ' is exceed max-length: ' . $val); + } + } + + public static function validateMinLength($fieldName, $field, $val = null) + { + if (null !== $field && \strlen($field) < (int) $val) { + throw new \InvalidArgumentException($fieldName . ' is less than min-length: ' . $val); + } + } + + public static function validatePattern($fieldName, $field, $regex = '') + { + if (null !== $field && '' !== $field && !preg_match("/^{$regex}$/", $field)) { + throw new \InvalidArgumentException($fieldName . ' is not match ' . $regex); + } + } + + public static function validateMaximum($fieldName, $field, $val) + { + if (null !== $field && $field > $val) { + throw new \InvalidArgumentException($fieldName . ' cannot be greater than ' . $val); + } + } + + public static function validateMinimum($fieldName, $field, $val) + { + if (null !== $field && $field < $val) { + throw new \InvalidArgumentException($fieldName . ' cannot be less than ' . $val); + } + } + + /** + * @param array $map + * @param Model $model + * + * @return mixed + */ + public static function toModel($map, $model) + { + $names = $model->getName(); + $names = array_flip($names); + foreach ($map as $key => $value) { + $name = isset($names[$key]) ? $names[$key] : $key; + $model->{$name} = $value; + } + + return $model; + } +} diff --git a/serve/vendor/alibabacloud/tea/src/Parameter.php b/serve/vendor/alibabacloud/tea/src/Parameter.php new file mode 100644 index 0000000..0718d1e --- /dev/null +++ b/serve/vendor/alibabacloud/tea/src/Parameter.php @@ -0,0 +1,49 @@ +toArray()); + } + + /** + * @return array + */ + public function getRealParameters() + { + $array = []; + $obj = new ReflectionObject($this); + $properties = $obj->getProperties(); + + foreach ($properties as $property) { + $docComment = $property->getDocComment(); + $key = trim(Helper::findFromString($docComment, '@real', "\n")); + $value = $property->getValue($this); + $array[$key] = $value; + } + + return $array; + } + + /** + * @return array + */ + public function toArray() + { + return $this->getRealParameters(); + } +} diff --git a/serve/vendor/alibabacloud/tea/src/Request.php b/serve/vendor/alibabacloud/tea/src/Request.php new file mode 100644 index 0000000..d83f097 --- /dev/null +++ b/serve/vendor/alibabacloud/tea/src/Request.php @@ -0,0 +1,114 @@ +method = $method; + } + + /** + * These fields are compatible if you define other fields. + * Mainly for compatibility situations where the code generator cannot generate set properties. + * + * @return PsrRequest + */ + public function getPsrRequest() + { + $this->assertQuery($this->query); + + $request = clone $this; + + $uri = $request->getUri(); + if ($this->query) { + $uri = $uri->withQuery(http_build_query($this->query)); + } + + if ($this->port) { + $uri = $uri->withPort($this->port); + } + + if ($this->protocol) { + $uri = $uri->withScheme($this->protocol); + } + + if ($this->pathname) { + $uri = $uri->withPath($this->pathname); + } + + if (isset($this->headers['host'])) { + $uri = $uri->withHost($this->headers['host']); + } + + $request = $request->withUri($uri); + $request = $request->withMethod($this->method); + + if ('' !== $this->body && null !== $this->body) { + if ($this->body instanceof StreamInterface) { + $request = $request->withBody($this->body); + } else { + $request = $request->withBody(\GuzzleHttp\Psr7\stream_for($this->body)); + } + } + + if ($this->headers) { + foreach ($this->headers as $key => $value) { + $request = $request->withHeader($key, $value); + } + } + + return $request; + } + + /** + * @param array $query + */ + private function assertQuery($query) + { + if (!\is_array($query)) { + throw new InvalidArgumentException('Query must be array.'); + } + } +} diff --git a/serve/vendor/alibabacloud/tea/src/Response.php b/serve/vendor/alibabacloud/tea/src/Response.php new file mode 100644 index 0000000..1eab91f --- /dev/null +++ b/serve/vendor/alibabacloud/tea/src/Response.php @@ -0,0 +1,366 @@ +getStatusCode(), + $response->getHeaders(), + $response->getBody(), + $response->getProtocolVersion(), + $response->getReasonPhrase() + ); + $this->headers = $response->getHeaders(); + $this->body = $response->getBody(); + $this->statusCode = $response->getStatusCode(); + if ($this->body->isSeekable()) { + $this->body->seek(0); + } + + if (Helper::isJson((string) $this->getBody())) { + $this->dot = new Dot($this->toArray()); + } else { + $this->dot = new Dot(); + } + } + + /** + * @return string + */ + public function __toString() + { + return (string) $this->getBody(); + } + + /** + * @param string $name + * + * @return null|mixed + */ + public function __get($name) + { + $data = $this->dot->all(); + if (!isset($data[$name])) { + return null; + } + + return json_decode(json_encode($data))->{$name}; + } + + /** + * @param string $name + * @param mixed $value + */ + public function __set($name, $value) + { + $this->dot->set($name, $value); + } + + /** + * @param string $name + * + * @return bool + */ + public function __isset($name) + { + return $this->dot->has($name); + } + + /** + * @param $offset + */ + public function __unset($offset) + { + $this->dot->delete($offset); + } + + /** + * @return array + */ + public function toArray() + { + return \GuzzleHttp\json_decode((string) $this->getBody(), true); + } + + /** + * @param array|int|string $keys + * @param mixed $value + */ + public function add($keys, $value = null) + { + return $this->dot->add($keys, $value); + } + + /** + * @return array + */ + public function all() + { + return $this->dot->all(); + } + + /** + * @param null|array|int|string $keys + */ + public function clear($keys = null) + { + return $this->dot->clear($keys); + } + + /** + * @param array|int|string $keys + */ + public function delete($keys) + { + return $this->dot->delete($keys); + } + + /** + * @param string $delimiter + * @param null|array $items + * @param string $prepend + * + * @return array + */ + public function flatten($delimiter = '.', $items = null, $prepend = '') + { + return $this->dot->flatten($delimiter, $items, $prepend); + } + + /** + * @param null|int|string $key + * @param mixed $default + * + * @return mixed + */ + public function get($key = null, $default = null) + { + return $this->dot->get($key, $default); + } + + /** + * @param array|int|string $keys + * + * @return bool + */ + public function has($keys) + { + return $this->dot->has($keys); + } + + /** + * @param null|array|int|string $keys + * + * @return bool + */ + public function isEmpty($keys = null) + { + return $this->dot->isEmpty($keys); + } + + /** + * @param array|self|string $key + * @param array|self $value + */ + public function merge($key, $value = []) + { + return $this->dot->merge($key, $value); + } + + /** + * @param array|self|string $key + * @param array|self $value + */ + public function mergeRecursive($key, $value = []) + { + return $this->dot->mergeRecursive($key, $value); + } + + /** + * @param array|self|string $key + * @param array|self $value + */ + public function mergeRecursiveDistinct($key, $value = []) + { + return $this->dot->mergeRecursiveDistinct($key, $value); + } + + /** + * @param null|int|string $key + * @param mixed $default + * + * @return mixed + */ + public function pull($key = null, $default = null) + { + return $this->dot->pull($key, $default); + } + + /** + * @param null|int|string $key + * @param mixed $value + * + * @return mixed + */ + public function push($key = null, $value = null) + { + return $this->dot->push($key, $value); + } + + /** + * Replace all values or values within the given key + * with an array or Dot object. + * + * @param array|self|string $key + * @param array|self $value + */ + public function replace($key, $value = []) + { + return $this->dot->replace($key, $value); + } + + /** + * Set a given key / value pair or pairs. + * + * @param array|int|string $keys + * @param mixed $value + */ + public function set($keys, $value = null) + { + return $this->dot->set($keys, $value); + } + + /** + * Replace all items with a given array. + * + * @param mixed $items + */ + public function setArray($items) + { + return $this->dot->setArray($items); + } + + /** + * Replace all items with a given array as a reference. + */ + public function setReference(array &$items) + { + return $this->dot->setReference($items); + } + + /** + * Return the value of a given key or all the values as JSON. + * + * @param mixed $key + * @param int $options + * + * @return string + */ + public function toJson($key = null, $options = 0) + { + return $this->dot->toJson($key, $options); + } + + /** + * Retrieve an external iterator. + */ + public function getIterator() + { + return $this->dot->getIterator(); + } + + /** + * Whether a offset exists. + * + * @param $offset + * + * @return bool + */ + public function offsetExists($offset) + { + return $this->dot->offsetExists($offset); + } + + /** + * Offset to retrieve. + * + * @param $offset + * + * @return mixed + */ + public function offsetGet($offset) + { + return $this->dot->offsetGet($offset); + } + + /** + * Offset to set. + * + * @param $offset + * @param $value + */ + public function offsetSet($offset, $value) + { + $this->dot->offsetSet($offset, $value); + } + + /** + * Offset to unset. + * + * @param $offset + */ + public function offsetUnset($offset) + { + $this->dot->offsetUnset($offset); + } + + /** + * Count elements of an object. + * + * @param null $key + * + * @return int + */ + public function count($key = null) + { + return $this->dot->count($key); + } +} diff --git a/serve/vendor/alibabacloud/tea/src/Tea.php b/serve/vendor/alibabacloud/tea/src/Tea.php new file mode 100644 index 0000000..e050f4a --- /dev/null +++ b/serve/vendor/alibabacloud/tea/src/Tea.php @@ -0,0 +1,281 @@ +getPsrRequest(); + } + + $config = self::resolveConfig($config); + + $res = self::client()->send( + $request, + $config + ); + + return new Response($res); + } + + /** + * @return PromiseInterface + */ + public static function sendAsync(RequestInterface $request, array $config = []) + { + if (method_exists($request, 'getPsrRequest')) { + $request = $request->getPsrRequest(); + } + + $config = self::resolveConfig($config); + + return self::client()->sendAsync( + $request, + $config + ); + } + + /** + * @return Client + */ + public static function client(array $config = []) + { + if (isset(self::$config['handler'])) { + $stack = self::$config['handler']; + } else { + $stack = HandlerStack::create(); + $stack->push(Middleware::mapResponse(static function (ResponseInterface $response) { + return new Response($response); + })); + } + + self::$config['handler'] = $stack; + + if (!isset(self::$config['on_stats'])) { + self::$config['on_stats'] = function (TransferStats $stats) { + Response::$info = $stats->getHandlerStats(); + }; + } + + $new_config = Helper::merge([self::$config, $config]); + + return new Client($new_config); + } + + /** + * @param string $method + * @param string|UriInterface $uri + * @param array $options + * + * @throws GuzzleException + * + * @return ResponseInterface + */ + public static function request($method, $uri, $options = []) + { + return self::client()->request($method, $uri, $options); + } + + /** + * @param string $method + * @param string $uri + * @param array $options + * + * @throws GuzzleException + * + * @return string + */ + public static function string($method, $uri, $options = []) + { + return (string) self::client()->request($method, $uri, $options) + ->getBody(); + } + + /** + * @param string $method + * @param string|UriInterface $uri + * @param array $options + * + * @return PromiseInterface + */ + public static function requestAsync($method, $uri, $options = []) + { + return self::client()->requestAsync($method, $uri, $options); + } + + /** + * @param string|UriInterface $uri + * @param array $options + * + * @throws GuzzleException + * + * @return null|mixed + */ + public static function getHeaders($uri, $options = []) + { + return self::request('HEAD', $uri, $options)->getHeaders(); + } + + /** + * @param string|UriInterface $uri + * @param string $key + * @param null|mixed $default + * + * @throws GuzzleException + * + * @return null|mixed + */ + public static function getHeader($uri, $key, $default = null) + { + $headers = self::getHeaders($uri); + + return isset($headers[$key][0]) ? $headers[$key][0] : $default; + } + + /** + * @param int $retryTimes + * @param float $now + * + * @return bool + */ + public static function allowRetry(array $runtime, $retryTimes, $now) + { + unset($now); + if (empty($runtime) || !isset($runtime['maxAttempts'])) { + return false; + } + $maxAttempts = $runtime['maxAttempts']; + $retry = empty($maxAttempts) ? 0 : (int) $maxAttempts; + + return $retry >= $retryTimes; + } + + /** + * @param int $retryTimes + * + * @return int + */ + public static function getBackoffTime(array $runtime, $retryTimes) + { + $backOffTime = 0; + $policy = isset($runtime['policy']) ? $runtime['policy'] : ''; + + if (empty($policy) || 'no' == $policy) { + return $backOffTime; + } + + $period = isset($runtime['period']) ? $runtime['period'] : ''; + if (null !== $period && '' !== $period) { + $backOffTime = (int) $period; + if ($backOffTime <= 0) { + return $retryTimes; + } + } + + return $backOffTime; + } + + public static function sleep($time) + { + sleep($time); + } + + public static function isRetryable($retry, $retryTimes = 0) + { + if ($retry instanceof TeaError) { + return true; + } + if (\is_array($retry)) { + $max = isset($retry['maxAttempts']) ? (int) ($retry['maxAttempts']) : 3; + + return $retryTimes <= $max; + } + + return false; + } + + /** + * @param mixed|Model[] ...$item + * + * @return mixed + */ + public static function merge(...$item) + { + $tmp = []; + $n = 0; + foreach ($item as $i) { + if (\is_object($i)) { + if ($i instanceof Model) { + $i = $i->toMap(); + } else { + $i = json_decode(json_encode($i), true); + } + } + if (null === $i) { + continue; + } + if (\is_array($i)) { + $tmp[$n++] = $i; + } + } + + if (\count($tmp)) { + return \call_user_func_array('array_merge', $tmp); + } + + return []; + } + + private static function resolveConfig(array $config = []) + { + $options = new Dot(['http_errors' => false]); + if (isset($config['httpProxy']) && !empty($config['httpProxy'])) { + $options->set('proxy.http', $config['httpProxy']); + } + if (isset($config['httpsProxy']) && !empty($config['httpsProxy'])) { + $options->set('proxy.https', $config['httpsProxy']); + } + if (isset($config['noProxy']) && !empty($config['noProxy'])) { + $options->set('proxy.no', $config['noProxy']); + } + // readTimeout&connectTimeout unit is millisecond + $read_timeout = isset($config['readTimeout']) && !empty($config['readTimeout']) ? (int) $config['readTimeout'] : 0; + $con_timeout = isset($config['connectTimeout']) && !empty($config['connectTimeout']) ? (int) $config['connectTimeout'] : 0; + // timeout unit is second + $options->set('timeout', ($read_timeout + $con_timeout) / 1000); + + return $options->all(); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/.gitattributes b/serve/vendor/alipaysdk/easysdk/.gitattributes new file mode 100644 index 0000000..dd68a15 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/.gitattributes @@ -0,0 +1 @@ +*.* linguist-language=java diff --git a/serve/vendor/alipaysdk/easysdk/.gitignore b/serve/vendor/alipaysdk/easysdk/.gitignore new file mode 100644 index 0000000..c92a6be --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/.gitignore @@ -0,0 +1,16 @@ +.DS_Store +node_modules +logs +.libraries.json +libraries + +.idea +*.iml +target +dependency-reduced-pom.xml + +bin +obj +.vs + +publish/alipay-easysdk diff --git a/serve/vendor/alipaysdk/easysdk/APIDoc.md b/serve/vendor/alipaysdk/easysdk/APIDoc.md new file mode 100644 index 0000000..fb110e3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/APIDoc.md @@ -0,0 +1,821 @@ +# 基础能力 Base +## 用户授权 OAuth +### 获取授权访问令牌 +* API声明 + +getToken(code: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| code | string | 是 | 授权码,用户对应用授权后得到 | + +* 出参说明 + +可前往[alipay.system.oauth.token](https://docs.open.alipay.com/api_9/alipay.system.oauth.token)查看更加详细的参数说明。 + +### 刷新授权访问令牌 +* API声明 + +refreshToken(refreshToken: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| refreshToken | string | 是 | 刷新令牌,上次换取访问令牌时得到,见出参的refresh_token字段 | + +* 出参说明 + +可前往[alipay.system.oauth.token](https://docs.open.alipay.com/api_9/alipay.system.oauth.token)查看更加详细的参数说明。 + +--- + +## 小程序二维码 Qrcode +### 创建小程序二维码 +* API声明 + +create(urlParam: string, queryParam: string, describe: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| urlParam | string | 是 | 小程序中能访问到的页面路径,例如:page/component/component-pages/view/view | +| queryParam | string | 是 | 小程序的启动参数,打开小程序的query ,在小程序 onLaunch的方法中获取 | +| describe | string | 是 | 二维码描述 | + +* 出参说明 + +可前往[alipay.open.app.qrcode.create](https://docs.open.alipay.com/api_5/alipay.open.app.qrcode.create)查看更加详细的参数说明。 + +--- + +## 图片 Image +### 上传图片 +* API声明 + +upload(imageName: string, imageFilePath: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| imageName | string | 是 | 图片名称 | +| imageFilePath | string | 是 | 待上传的本地图片文件路径 | + +* 出参说明 + +可前往[alipay.offline.material.image.upload](https://docs.open.alipay.com/api_3/alipay.offline.material.image.upload)查看更加详细的参数说明。 + +--- + +## 视频 Video +### 上传视频 +* API声明 + +upload(videoName: string, videoFilePath: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| videoName | string | 是 | 视频名称 | +| videoFilePath | string | 是 | 待上传的本地视频文件路径 | + +* 出参说明 + +可前往[alipay.offline.material.image.upload](https://docs.open.alipay.com/api_3/alipay.offline.material.image.upload)查看更加详细的参数说明。 + +--- + +# 营销能力 Marketing +## 生活号 OpenLife +### 创建图文消息内容 +* API声明 + +createImageTextContent(title: string, cover: string, content: string, contentComment: string, ctype: string, benefit: string, extTags: string, loginIds: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| title | string | 是 | 标题 | +| cover | string | 是 | 封面图URL, 尺寸为996*450,最大不超过3M,支持.jpg、.png格式,请先调用上传图片接口获得图片URL | +| content | string | 是 | 消息正文(支持富文本) | +| contentComment | string | 否 | 是否允许评论,T:允许,F:不允许,默认不允许 | +| ctype | string | 否 | 图文类型:填activity表示活动图文,不填默认普通图文 | +| benefit | string | 否 | 活动利益点,图文类型ctype为activity类型时才需要传,最多10个字符 | +| extTags | string | 否 | 关键词列表,英文逗号分隔,最多不超过5个 | +| loginIds | string | 否 | 可预览支付宝账号列表,需要预览时才填写, 英文逗号分隔,最多不超过10个 | + +* 出参说明 + +可前往[alipay.open.public.message.content.create](https://docs.open.alipay.com/api_6/alipay.open.public.message.content.create)查看更加详细的参数说明。 + +### 更新图文消息内容 +* API声明 + +modifyImageTextContent(contentId: string, title: string, cover: string, content: string, couldComment: string, ctype: string, benefit: string, extTags: string, loginIds: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| contentId | string | 是 | 内容ID,通过创建图文内容消息接口返回 | +| title | string | 是 | 标题 | +| cover | string | 是 | 封面图URL, 尺寸为996*450,最大不超过3M,支持.jpg、.png格式,请先调用上传图片接口获得图片URL | +| content | string | 是 | 消息正文(支持富文本) | +| contentComment | string | 否 | 是否允许评论,T:允许,F:不允许,默认不允许 | +| ctype | string | 否 | 图文类型:填activity表示活动图文,不填默认普通图文 | +| benefit | string | 否 | 活动利益点,图文类型ctype为activity类型时才需要传,最多10个字符 | +| extTags | string | 否 | 关键词列表,英文逗号分隔,最多不超过5个 | +| loginIds | string | 否 | 可预览支付宝账号列表,需要预览时才填写, 英文逗号分隔,最多不超过10个 | + +* 出参说明 + +可前往[alipay.open.public.message.content.modify](https://docs.open.alipay.com/api_6/alipay.open.public.message.content.modify)查看更加详细的参数说明。 + +### 群发本文消息 +* API声明 + +sendText(text: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| text | string | 是 | 文本消息内容 | + +* 出参说明 + +可前往[alipay.open.public.message.total.send](https://docs.open.alipay.com/api_6/alipay.open.public.message.total.send)查看更加详细的参数说明。 + +### 群发图文消息 +* API声明 + +sendImageText(articles: [ Article ]) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| articles | Article数组 | 是 | 图文消息内容 | + +Article对象说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| title | string | 否 | 图文消息标题 | +| desc | string | 是 | 图文消息描述 | +| imageUrl | string | 特殊可选 | 图片链接,对于多条图文消息的第一条消息,该字段不能为空,请先调用上传图片接口获得图片URL | +| url | string | 是 | 点击图文消息跳转的链接 | +| actionName | string | 否 | 链接文字 | + +* 出参说明 + +可前往[alipay.open.public.message.total.send](https://docs.open.alipay.com/api_6/alipay.open.public.message.total.send)查看更加详细的参数说明。 + +### 单发模板消息 +* API声明 + +sendSingleMessage(toUserId: string, template: Template) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| toUserId | string | 是 | 消息接收用户的UserId | +| template | Template | 是 | 消息接收用户的UserId | + +Template对象说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| templateId | string | 是 | 消息模板ID | +| context | Context | 是 | 消息模板上下文,即模板中定义的参数及参数值 | + +Context对象说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| headColor | string | 是 | 顶部色条的色值,比如#85be53 | +| url | string | 是 | 点击消息后承接页的地址 | +| actionName | string | 是 | 底部链接描述文字,如:“查看详情”,最多能传8个汉字或16个英文字符 | +| keyword1 | Keyword | 否 | 模板中占位符的值及文字颜色 | +| keyword2 | Keyword | 否 | 模板中占位符的值及文字颜色 | +| first | Keyword | 否 | 模板中占位符的值及文字颜色 | +| remark | Keyword | 否 | 模板中占位符的值及文字颜色 | + +Keyword对象说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| color | string | 是 | 当前文字颜色,比如#85be53 | +| value | string | 是 | 模板中占位符的值 | + +* 出参说明 + +可前往[alipay.open.public.message.single.send](https://docs.open.alipay.com/api_6/alipay.open.public.message.single.send)查看更加详细的参数说明。 + +### 生活号消息撤回 +* API声明 + +recallMessage(messageId: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| messageId | string | 是 | 消息ID | + +* 出参说明 + +可前往[alipay.open.public.life.msg.recall](https://docs.open.alipay.com/api_6/alipay.open.public.life.msg.recall)查看更加详细的参数说明。 + +### 模板消息行业设置 +* API声明 + +setIndustry(primaryIndustryCode: string, primaryIndustryName: string, secondaryIndustryCode: string, secondaryIndustryName: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| primaryIndustryCode | string | 是 | 服务窗消息模板所属主行业一级编码,查看[行业信息](https://alipay.open.taobao.com/doc2/detail?treeId=197&docType=1&articleId=105043) | +| primaryIndustryName | string | 是 | 服务窗消息模板所属主行业一级名称 | +| secondaryIndustryCode | string | 是 | 服务窗消息模板所属主行业二级编码 | +| secondaryIndustryName | string | 是 | 服务窗消息模板所属主行业二级名称 | + +* 出参说明 + +可前往[alipay.open.public.template.message.industry.modify](https://docs.open.alipay.com/api_6/alipay.open.public.template.message.industry.modify)查看更加详细的参数说明。 + +### 生活号查询行业设置 +* API声明 + +getIndustry() + +* 入参说明 + +无 + +* 出参说明 + +可前往[alipay.open.public.setting.category.query](https://docs.open.alipay.com/api_6/alipay.open.public.setting.category.query)查看更加详细的参数说明。 + +--- + + +## 支付宝卡包 Pass +### 卡券模板创建 +* API声明 + +createTemplate(uniqueId: string, tplContent: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| uniqueId | string | 是 | 商户用于控制模版的唯一性(可以使用时间戳保证唯一性) | +| tplContent | string | 是 | 模板内容信息,遵循JSON规范,详情参见tpl_content[参数说明](https://doc.open.alipay.com/doc2/detail.htm?treeId=193&articleId=105249&docType=1#tpl_content) | + +* 出参说明 + +可前往[alipay.pass.template.add](https://docs.open.alipay.com/api_24/alipay.pass.template.add)查看更加详细的参数说明。 + +### 卡券模板更新 +* API声明 + +updateTemplate(uniqueId: string, tplContent: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| uniqueId | string | 是 | 商户用于控制模版的唯一性(可以使用时间戳保证唯一性) | +| tplContent | string | 是 | 模板内容信息,遵循JSON规范,详情参见tpl_content[参数说明](https://doc.open.alipay.com/doc2/detail.htm?treeId=193&articleId=105249&docType=1#tpl_content) | + +* 出参说明 + +可前往[alipay.pass.template.update](https://docs.open.alipay.com/api_24/alipay.pass.template.update)查看更加详细的参数说明。 + +### 卡券实例发放 +* API声明 + +addInstance(tplId: string, tplParams: string, recognitionType: string, recognitionInfo: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| tplId | string | 是 | 支付宝pass模版ID,即调用模板创建接口时返回的tpl_id | +| tplParams | string | 是 | 模版动态参数信息,对应模板中$变量名$的动态参数,见模板创建接口返回值中的tpl_params字段。示例: | +| recognitionType | string | 是 | Alipass添加对象识别类型,填写“1”表示订单信息 | +| recognitionInfo | string | 是 | 支付宝用户识别信息,参见[UID发券组件对接文档](https://docs.open.alipay.com/199/sy3hs4 ) | + +* 出参说明 + +可前往[alipay.pass.instance.add](https://docs.open.alipay.com/api_24/alipay.pass.instance.add)查看更加详细的参数说明。 + +### 卡券实例更新 +* API声明 + +updateInstance(serialNumber: string, channelId: string, tplParams: string, status: string, verifyCode: string, verifyType: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| serialNumber | string | 是 | 商户指定卡券唯一值,卡券JSON模板中fileInfo->serialNumber字段对应的值 | +| channelId | string | 是 | 代理商代替商户发放卡券后,再代替商户更新卡券时,此值为商户的PID/AppID | +| tplParams | string | 否 | Alipass添加对象识别类型,填写“1”表示订单信息 | +| status | string | 否 | 券状态,支持更新为USED、CLOSED两种状态 | +| verifyCode | string | 否 | 核销码串值(当状态变更为USED时,建议传),该值正常为模板中核销区域(Operation)对应的message值 | +| verifyType | string | 否 | 核销方式,该值正常为模板中核销区域(Operation)对应的format值,verifyCode和verifyType需同时传入 | + +* 出参说明 + +可前往[alipay.pass.instance.update](https://docs.open.alipay.com/api_24/alipay.pass.instance.update)查看更加详细的参数说明。 + +--- + + +## 小程序模板消息 TemplateMessage +### 发送模板消息 +* API声明 + +send(toUserId: string, formId: string, userTemplateId: string, page: string, data: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| toUserId | string | 是 | 发送消息的支付宝账号 | +| formId | string | 是 | 用户发生的交易行为的交易号,或者用户在小程序产生表单提交的表单号,用于信息发送的校验 | +| userTemplateId | string | 是 | 用户申请的模板id号,固定的模板id会发送固定的消息 | +| page | string | 是 | 小程序的跳转页面,用于消息中心用户点击之后详细跳转的小程序页面,例如:page/component/index | +| data | string | 是 | 开发者需要发送模板消息中的自定义部分来替换模板的占位符,例如:{"keyword1": {"value" : "12:00"},"keyword2": {"value" : "20180808"},"keyword3": {"value" : "支付宝"}} | + +* 出参说明 + +可前往[alipay.open.app.mini.templatemessage.send](https://docs.open.alipay.com/api_5/alipay.open.app.mini.templatemessage.send)查看更加详细的参数说明。 + +--- + + +# 会员能力 Member +## 支付宝身份认证 Identification +### 身份认证初始化 +* API声明 + +init(outerOrderNo: string, bizCode: string, identityParam: IdentityParam, merchantConfig: MerchantConfig) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| outerOrderNo | string | 是 | 商户请求的唯一标识,商户要保证其唯一性,值为32位长度的字母数字组合,建议前面几位字符是商户自定义的简称,中间可以使用一段时间,后段可以使用一个随机或递增序列 | +| bizCode | string | 是 | 认证场景码,入参支持的认证场景码和商户签约的认证场景相关,可选值有如下,FACE:多因子人脸认证;CERT_PHOTO:多因子证照认证;CERT_PHOTO_FACE:多因子证照和人脸认证;SMART_FACE:多因子快捷认证 | +| identityParam | IdentityParam | 是 | 需要验证的身份信息参数 | +| merchantConfig | MerchantConfig | 是 | 商户个性化配置 | + +IdentityParam对象说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| identityType | string | 是 | 身份信息参数类型,必须传入CERT_INFO | +| certType | string | 是 | 证件类型,当前支持身份证,必须传入IDENTITY_CARD | +| certName | string | 是 | 真实姓名 | +| certNo | string | 是 | 证件号码 | + +MerchantConfig对象说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| returnUrl | string | 是 | 需要回跳的目标URL地址,一般指定为商户业务页面 | + +* 出参说明 + +可前往[alipay.user.certify.open.initialize](https://docs.open.alipay.com/api_2/alipay.user.certify.open.initialize)查看更加详细的参数说明。 + +### 生成认证链接 +* API声明 + +certify(certifyId: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| certifyId | string | 是 | 本次申请操作的唯一标识,由身份认证初始化接口调用后生成,后续的操作都需要用到 | + +* 出参说明 + +可前往[alipay.user.certify.open.certify](https://docs.open.alipay.com/api_2/alipay.user.certify.open.certify)查看更加详细的参数说明。 + +### 身份认证记录查询 +* API声明 + +query(certifyId: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| certifyId | string | 是 | 身份认证操作的唯一标识,由身份认证初始化接口调用后生成 | + +* 出参说明 + +可前往[alipay.user.certify.open.query](https://docs.open.alipay.com/api_2/alipay.user.certify.open.query)查看更加详细的参数说明。 + +--- + + +# 支付能力 Payment +## 通用接口 Common +### 创建交易 +* API声明 + +create(subject: string, outTradeNo: string, totalAmount: string, buyerId: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| subject | string | 是 | 订单标题 | +| outTradeNo | string | 是 | 商户订单号,64个字符以内,可包含字母、数字、下划线,需保证在商户端不重复 | +| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] | +| buyerId | string | 是 | 买家的支付宝唯一用户号(2088开头的16位纯数字) | + +* 出参说明 + +可前往[alipay.trade.create](https://docs.open.alipay.com/api_1/alipay.trade.create)查看更加详细的参数说明。 + +### 查询交易 +* API声明 + +query(outTradeNo: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | + +* 出参说明 + +可前往[alipay.trade.query](https://docs.open.alipay.com/api_1/alipay.trade.query)查看更加详细的参数说明。 + +### 交易退款 +* API声明 + +refund(outTradeNo: string, refundAmount: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | +| refundAmount | string | 是 | 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数 | + +* 出参说明 + +可前往[alipay.trade.refund](https://docs.open.alipay.com/api_1/alipay.trade.refund)查看更加详细的参数说明。 + +### 关闭交易 +* API声明 + +close(outTradeNo: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | + +* 出参说明 + +可前往[alipay.trade.close](https://docs.open.alipay.com/api_1/alipay.trade.close)查看更加详细的参数说明。 + +### 撤销交易 +* API声明 + +cancel(outTradeNo: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | + +* 出参说明 + +可前往[alipay.trade.cancel](https://docs.open.alipay.com/api_1/alipay.trade.cancel)查看更加详细的参数说明。 + +### 交易退款查询 +* API声明 + +queryRefund(outTradeNo: string, outRequestNo: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | +| outRequestNo | string | 是 | 请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号 | + +* 出参说明 + +可前往[alipay.trade.fastpay.refund.query](https://opendocs.alipay.com/apis/api_1/alipay.trade.fastpay.refund.query)查看更加详细的参数说明。 + + +### 查询对账单下载地址 +* API声明 + +downloadBill(billType: string, billDate: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| billType | string | 是 | 账单类型,商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型:trade、signcustomer;trade指商户基于支付宝交易收单的业务账单;signcustomer是指基于商户支付宝余额收入及支出等资金变动的帐务账单 | +| billDate | string | 是 | 账单时间:日账单格式为yyyy-MM-dd,最早可下载2016年1月1日开始的日账单;月账单格式为yyyy-MM,最早可下载2016年1月开始的月账单 | + +* 出参说明 + +可前往[alipay.data.dataservice.bill.downloadurl.query](https://opendocs.alipay.com/apis/api_15/alipay.data.dataservice.bill.downloadurl.query)查看更加详细的参数说明。 + + +### 异步通知验签 +* API声明 + +verifyNotify(parameters: map[string]string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| parameters | map[string]string | 是 | 异步通知中收到的待验签的所有参数 | + +--- + +## 花呗分期 Huabei +### 创建花呗分期交易 +* API声明 + +create(subject: string, outTradeNo: string, totalAmount: string, buyerId: string, extendParams: HuabeiConfig) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| subject | string | 是 | 订单标题 | +| outTradeNo | string | 是 | 商户订单号,64个字符以内,可包含字母、数字、下划线,需保证在商户端不重复 | +| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] | +| buyerId | string | 是 | 买家的支付宝用户ID,如果为空,会从传入的码值信息中获取买家ID | +| extendParams | HuabeiConfig | 是 | 花呗交易扩展参数 | + +HuabeiConfig对象说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| hbFqNum | string | 是 | 花呗分期数,仅支持传入3、6、12 | +| hbFqSellerPercent | string | 是 | 代表卖家承担收费比例,商家承担手续费传入100,用户承担手续费传入0,仅支持传入100、0两种 | + + +* 出参说明 + +可前往[alipay.trade.create](https://docs.open.alipay.com/api_1/alipay.trade.create)查看更加详细的参数说明。 + +--- + + + +## 当面付 FaceToFace +### 当面付交易付款 +* API声明 + +pay(subject: string, outTradeNo: string, totalAmount: string, authCode: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| subject | string | 是 | 订单标题 | +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | +| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] | +| authCode | string | 是 | 支付授权码,即买家的付款码数字 | + +* 出参说明 + +可前往[alipay.trade.pay](https://docs.open.alipay.com/api_1/alipay.trade.pay)查看更加详细的参数说明。 + +* 返佣说明 + +ISV对接当面付产品需涉及返佣时,请先阅读[政策详情](https://opendocs.alipay.com/p/00fc2g)与[合作攻略](https://opendocs.alipay.com/open/300/taphxd)。 + + +**对接时必须在支付接口的extend_params参数中设置sys_service_provider_id返佣参数 ,参数值为签约返佣协议的PID**,示例代码如下(Java为例): + +```java +Map extendParams = new HashMap<>(); +extendParams.put("sys_service_provider_id", "<--请填写ISV签约协议的PID,比如:2088511833207846-->"); +AlipayTradePayResponse response = Factory.Payment.FaceToFace() + .agent("<--请填写商户应用授权后获取到的app_auth_token,比如:ca34ea491e7146cc87d25fca24c4cD11-->") + .optional("extend_params", extendParams) + .pay("iPhone6 16G", "64628156-f784-4572-9540-485b7c91b850", "0.01", "289821051157962364"); +``` + +--- +### 交易预创建,生成正扫二维码 +* API声明 + +precreate(subject: string, outTradeNo: string, totalAmount: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| subject | string | 是 | 订单标题 | +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | +| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] | + +* 出参说明 + +可前往[alipay.trade.precreate](https://docs.open.alipay.com/api_1/alipay.trade.precreate)查看更加详细的参数说明。 + +* 返佣说明 + +ISV对接当面付产品需涉及返佣时,请先阅读[政策详情](https://opendocs.alipay.com/p/00fc2g)与[合作攻略](https://opendocs.alipay.com/open/300/taphxd)。 + + +**对接时必须在支付接口的extend_params参数中设置sys_service_provider_id返佣参数 ,参数值为签约返佣协议的PID**,示例代码如下(Java为例): + +```java +Map extendParams = new HashMap<>(); +extendParams.put("sys_service_provider_id", "<--请填写ISV签约协议的PID,比如:2088511833207846-->"); +AlipayTradePrecreateResponse response = Payment.FaceToFace() + .agent("<--请填写商户应用授权后获取到的app_auth_token,比如:ca34ea491e7146cc87d25fca24c4cD11-->") + .optional("extend_params", extendParams) + .preCreate("iPhone6 16G", "64628156-f784-4572-9540-485b7c91b850", "0.01"); +``` + +--- +## 电脑网站 Page +### 电脑网站支付 +* API声明 + +pay(subject: string, outTradeNo: string, totalAmount: string, returnUrl: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| subject | string | 是 | 订单标题 | +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | +| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] | +| returnUrl | string | 否 | 支付成功后同步跳转的页面,是一个http/https开头的字符串 | + +* 出参说明 + +可前往[alipay.trade.page.pay](https://docs.open.alipay.com/api_1/alipay.trade.page.pay)查看更加详细的参数说明。 + +--- + +## 手机网站 Wap +### 手机网站支付 +* API声明 + +pay(subject: string, outTradeNo: string, totalAmount: string, quitUrl: string, returnUrl: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| subject | string | 是 | 订单标题 | +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | +| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] | +| quitUrl | string | 是 | 用户付款中途退出返回商户网站的地址 | +| returnUrl | string | 否 | 支付成功后同步跳转的页面,是一个http/https开头的字符串 | + +* 出参说明 + +可前往[alipay.trade.wap.pay](https://docs.open.alipay.com/api_1/alipay.trade.wap.pay)查看更加详细的参数说明。 + +--- + +## App支付 App +### 手机APP支付 +* API声明 + +pay(subject: string, outTradeNo: string, totalAmount: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| subject | string | 是 | 订单标题 | +| outTradeNo | string | 是 | 交易创建时传入的商户订单号 | +| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] | + +* 出参说明 + +可前往[alipay.trade.app.pay](https://docs.open.alipay.com/api_1/alipay.trade.app.pay)查看更加详细的参数说明。 + +--- + +# 安全能力 Security +## 文本风险识别 TextRisk +### 检测内容风险 +* API声明 + +detect(content: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| content | string | 是 | 待检测的文本内容 | + +* 出参说明 + +可前往[alipay.security.risk.content.detect](https://docs.open.alipay.com/api_49/alipay.security.risk.content.detect)查看更加详细的参数说明。 + +--- + +# 辅助工具 Util + + +## 加解密 AES +### AES解密(常用于会员手机号解密) +* API声明 + +decrypt(cipherText: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| cipherText | string | 是 | 密文 | + +* 出参说明 + +| 类型 | 说明 | +|------|----| +| string | 明文| + +### AES加密 +* API声明 + +encrypt(plainText: string) + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| plainText | string | 是 | 明文 | + +* 出参说明 + +| 类型 | 说明 | +|------|----| +| string | 密文| + + + + +## 通用接口 Generic +### 执行OpenAPI调用 +* API声明 + +execute(method: string, textParams: map[string]string, bizParams: map[string]any): AlipayOpenApiGenericResponse + +* 接口说明 + +对于Alipay Easy SDK尚未支持的Open API,开发者可以通过调用此方法,通过自行拼装请求参数,完成几乎所有OpenAPI的调用,且调用时可按需设置所有可选参数。本接口同样会自动为您完成请求的加签和响应的验签工作。 + +* 入参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| method | string | 是 | OpenAPI的名称,例如:alipay.trade.pay | +| textParams | map[string]string | 否 | **没有**包装在`biz_content`下的请求参数集合,例如`app_auth_token`等参数 | +| bizParams | map[string]any | 否 | 被包装在`biz_content`下的请求参数集合 | + +* 出参说明 + +| 字段名 | 类型 | 必填 | 说明 | +|------|--------|----|----| +| httpBody | string | 是 | 网关返回的HTTP响应,是一个JSON格式的字符串,开发者可按需从中解析出响应参数,响应示例:{"alipay_trade_create_response":{"code":"10000","msg":"Success","out_trade_no":"4ac9eac...","trade_no":"202003..."},"sign":"AUumfYgGSe7...02MA=="} | +| code | string | 是 | [网关返回码](https://docs.open.alipay.com/common/105806) | +| msg | string | 是 | [网关返回码描述](https://docs.open.alipay.com/common/105806) | +| subCode | string | 否 | 业务返回码,参见具体的API接口文档 | +| subMsg | string | 否 | 业务返回码描述,参见具体的API接口文档 | + +--- + + + + diff --git a/serve/vendor/alipaysdk/easysdk/CHANGELOG b/serve/vendor/alipaysdk/easysdk/CHANGELOG new file mode 100644 index 0000000..78c4092 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/CHANGELOG @@ -0,0 +1,161 @@ +最新变更 +增加通用方法中sdkExecute与fileExecute功能。增加java与php的MultipleFactory多实例调用。 +go版本sdk首次发布 + + + +Java版本 +2021-01-18 Version: 2.2.0 +1. 增加sdkExecute功能。 +2. 增加fileExecute功能。 +3. 增加MultipleFactory多实例调用。 + +2020-12-11 Version: 2.1.2 +1. 增加可设置ignoreSSL忽略SSL校验功能。 + +2020-09-23 Version: 2.1.0 +1. 升级Tea版本,降低对OkHttp的特性依赖,提升环境兼容性。 +2. 提供Factory.getClient方法,用于调用SDK扩展包中的方法。 + +2020-08-18 Version: 2.0.2 +1. 取消shade打包,便于排除冲突依赖。 + +2020-07-06 Version: 2.0.1 +1. 私钥支持阿里云KMS。 + +2020-06-09 Version: 2.0.0 +1. 支持可选业务参数的装配。 +2. 支持ISV代调用。 +3. 提供ResponseChecker辅助工具类,帮助校验响应是否成功。 + +2020-05-06 Version: 1.2.1 +1. 手机网站支付、电脑网站支付接口支持设置return_url同步跳转地址。 + +2020-04-15 Version: 1.2.0 +1. 扩展支持的支付类OpenAPI接口 +Factory.Payment.Common().queryRefund 查询退款信息 +Factory.Payment.Common().downloadBill 下载对账单 +Factory.Payment.FaceToFace().preCreate 交易预创建,生成正扫二维码 +Factory.Payment.Wap().pay 手机网站支付 +Factory.Payment.Page().pay 电脑网站支付 +Factory.Payment.App().pay 手机APP支付 +2. 支持支付的异步通知及其验签 +初始化Alipay Easy SDK的Config参数中新增notifyUrl参数,用户可以统一配置自己的回调地址。 +提供如下接口,完成支付类异步通知的验签。 +Factory.Payment.Common().verifyNotify +3. AES加解密功能 +Factory.Util.AES().decrypt 支持会员手机号AES解密 +Factory.Util.AES().encrypt AES加密 + +2020-03-31 Version: 1.1.3 +1. 去除SDK内置的logback.xml日志配置文件,以免意外覆盖开发者项目主体工程的日志配置。 + +2020-03-27 Version: 1.1.2 +1. 修复返回的响应中存在数组类型字段时,反序列化成Response对象可能抛异常的问题。 + +2020-03-16 Version: 1.1.1 +1. 修复证书路径不支持从CLASS_PATH中加载的问题。 + +2020-03-10 Version: 1.1.0 +1. 添加兜底通用接口,支持通过自行拼接请求参数完成几乎所有OpenAPI的调用。 + +2020-02-26 Version: 1.0.0 +1. 首次发布。 + + + +C#版本 +2020-12-11 Version: 2.1.2 +1. 增加可设置ignoreSSL忽略SSL校验功能。 + +2020-12-09 Version: 2.1.1 +1. 增加httpProxy功能。 + +2020-09-23 Version: 2.1.0 +1. 升级Tea版本。 +2. 提供Factory.getClient方法,用于调用SDK扩展包中的方法。 + +2020-08-18 Version: 2.0.1 +1. 修复证书模式下异步验签异常的问题。 + +2020-06-09 Version: 2.0.0 +1. 支持可选业务参数的装配。 +2. 支持ISV代调用。 +3. 提供ResponseChecker辅助工具类,帮助校验响应是否成功。 + +2020-05-06 Version: 1.2.1 +1. 手机网站支付、电脑网站支付接口支持设置return_url同步跳转地址。 + +2020-04-15 Version: 1.2.0 +1. 扩展支持的支付类OpenAPI接口 +Factory.Payment.Common().QueryRefund 查询退款信息 +Factory.Payment.Common().DownloadBill 下载对账单 +Factory.Payment.FaceToFace().PreCreate 交易预创建,生成正扫二维码 +Factory.Payment.Wap().Pay 手机网站支付 +Factory.Payment.Page().Pay 电脑网站支付 +Factory.Payment.App().Pay 手机APP支付 +2. 支持支付的异步通知及其验签 +初始化Alipay Easy SDK的Config参数中新增notifyUrl参数,用户可以统一配置自己的回调地址。 +提供如下接口,完成支付类异步通知的验签。 +Factory.Payment.Common().verifyNotify +3. AES加解密功能 +Factory.Util.AES().Decrypt 支持会员手机号AES解密 +Factory.Util.AES().Encrypt AES加密 + +2020-03-10 Version: 1.1.0 +1. 添加兜底通用接口,支持通过自行拼接请求参数完成几乎所有OpenAPI的调用。 + +2020-02-26 Version: 1.0.0 +1. 首次发布。 + + + +PHP版本 +2021-01-18 Version: 2.2.0 +1. 增加sdkExecute功能。 +2. 增加fileExecute功能。 +3. 增加MultipleFactory多实例调用。 + + +2020-12-11 Version: 2.0.3 +1. 增加可设置ignoreSSL忽略SSL校验功能。 + +2020-12-09 Version: 2.0.2 +1. 增加httpProxy功能。 +2. 修复agent不生效问题。 + +2020-07-06 Version: 2.0.0 +1. 支持可选业务参数的装配。 +2. 支持ISV代调用。 +3. 提供ResponseChecker辅助工具类,帮助校验响应是否成功。 + +2020-05-06 Version: 1.2.1 +1. 手机网站支付、电脑网站支付接口支持设置return_url同步跳转地址。 + +2020-04-15 Version: 1.2.0 +1. 扩展支持的支付类OpenAPI接口 +Factory::payment()->common()->queryRefund 查询退款信息 +Factory::payment()->common()->downloadBill 下载对账单 +Factory::payment()->faceToFace()->preCreate 交易预创建,生成正扫二维码 +Factory::payment()->wap()->pay 手机网站支付 +Factory::payment()->page()->pay 电脑网站支付 +Factory::payment()->app()->pay 手机APP支付 +2. 支持支付的异步通知及其验签 +初始化Alipay Easy SDK的Config参数中新增notifyUrl参数,用户可以统一配置自己的回调地址。 +提供如下接口,完成支付类异步通知的验签。 +Factory::payment()->common()->verifyNotify +3. AES加解密功能 +Factory::util()->aes()->decrypt 支持会员手机号AES解密 +Factory::util()->aes()->encrypt AES加密 +4. 重构api的respone模型,返回格式与Java、Net保持一致 + +2020-03-27 Version: 1.1.0 +1. 修复大小写路径敏感问题。 + +2020-03-20 Version: 1.0.0 +1. 首次发布。 + + +PHP版本 +2021-01-18 Version: 1.0.0 +1. 首次发布。 \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/LICENSE b/serve/vendor/alipaysdk/easysdk/LICENSE new file mode 100644 index 0000000..8d8fa6e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Ant Small and Micro Financial Services Group Co., Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/serve/vendor/alipaysdk/easysdk/README.md b/serve/vendor/alipaysdk/easysdk/README.md new file mode 100644 index 0000000..72cb79b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/README.md @@ -0,0 +1,206 @@ +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk?ref=badge_shield) +[![Maven Central](https://img.shields.io/maven-central/v/com.alipay.sdk/alipay-easysdk.svg)](https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk) +[![NuGet](https://badge.fury.io/nu/AlipayEasySDK.svg)](https://badge.fury.io/nu/AlipayEasySDK) +[![Packagist](https://poser.pugx.org/alipaysdk/easysdk/v/stable)](https://packagist.org/packages/alipaysdk/easysdk) + +欢迎使用 Alipay **Easy** SDK。 + +打造**最好用**的支付宝开放平台**服务端SDK**,Alipay Easy SDK让您享受**极简编程**体验,快速访问支付宝开放平台开放的各项**核心能力**。 + +## 设计理念 +不同于原有的Alipay SDK通用而全面的设计理念,Alipay Easy SDK对开放能力的API进行了更加贴近高频场景的精心设计与裁剪,简化了服务端调用方式,让调用API像使用语言内置的函数一样简便。 + +同时,您也不必担心面向高频场景提炼的API可能无法完全契合自己的个性化场景,Alipay Easy SDK支持灵活的[动态扩展](#extension)方式,同样可以满足低频参数、低频API的使用需求。 + +Alipay Easy SDK提供了与[能力地图](https://opendocs.alipay.com/mini/00am3f)相对应的代码组织结构,让开发者可以快速找到不同能力对应的API。 + +Alipay Easy SDK主要目标是提升开发者在**服务端**集成支付宝开放平台开放的各类核心能力的效率。 + +### 化繁为简 + +| Alipay Easy SDK | Alipay SDK | +|------------------|----------------------------------------------------------------| +| 极简代码风格,更贴近自然语言阅读习惯 | 传统代码风格,需要多行代码完成一个接口的调用 | +| Factory单例全局任何地方都可直接引用 | AlipayClient实例需自行创建并在上下文中传递 | +| API中只保留高频场景下的必备参数,同时提供低频可选参数的装配能力 | 没有区分高低频参数,单API最多可达数十个入参,对普通开发者的干扰较大 | + + +* Alipay Easy SDK :smiley: + +```java +Factory.Payment.Common().create("Iphone6 16G", "202003019443", "0.10", "2088002656718920"); +``` + +* Alipay SDK :confused: + +```java +AlipayTradeCreateRequest request = new AlipayTradeCreateRequest(); + +AlipayTradeCreateModel model = new AlipayTradeCreateModel(); +model.setSubject("Iphone6 16G"); +model.setOutTradeNo("202003019443"); +model.setTotalAmount("0.10"); +model.setBuyerId("2088002656718920"); +... + +request.setBizModel(model); +... + +alipayClient.execute(request); +``` + +### 如何切换 +* 无论是Alipay Easy SDK还是Alipay SDK,本质都是发送HTTP请求访问Open API网关,所以只需将原来通过Alipay SDK调用Open API的代码,替换为Alipay Easy SDK中对应API的调用即可。Alipay Easy SDK和Alipay SDK并无冲突,可以共存。 + +* 如果您所需对接的开放平台能力,Alipay Easy SDK尚未提炼出API支持([已支持的API列表](#apiList)),您可以通过[通用接口](./APIDoc.md#generic)完成调用。 + +* 我们会持续挖掘高频场景,不断丰富Alipay Easy SDK支持的API,让您在绝大多数常见场景下,都能享受Alipay Easy SDK带来的便捷。 + +## 技术特点 +### 纯语言开发 +所有Alipay Easy SDK的具体编程语言的实现,均只采用纯编程语言进行开发,不引入任何重量级框架,减少潜在的框架冲突,让SDK可以自由集成进任何代码环境中。 + +### 结构清晰 +我们按照能力类别和场景类别对API进行了归类,结构更加清晰,一目了然。 +> 更多信息请参见[API组织规范](#spec)。 + +### 参数精简 +Alipay Easy SDK对每个API都精心打磨,剔除了`Open API`中不常用的可选参数,减少普通用户的无效选择,提升开发效率。 + + + +### 灵活扩展 +开发者可以通过Fluent风格的API链式调用,在为高频场景打造的API基础上,不断扩展自己的个性化场景需求。 + +```java +// 通过调用agent方法,扩展支持ISV代调用场景 +Factory.Payment.FaceToFace().agent("ca34ea491e7146cc87d25fca24c4cD11").preCreate(...) + +// 通过调用optional方法,扩展支持个性化可选参数 +Factory.Payment.FaceToFace().optional("extend_params", extendParams).preCreate(...) + +// 多种扩展可灵活搭配,不同扩展方法功能详细说明请前往各语言主页中的“快速开始-扩展调用”栏目中查看 +Factory.Payment.FaceToFace() + .agent(...) + .optionalArgs(...) + .auth(...) + .asyncNotify(...) + .preCreate(...) +``` + +### 测试/示例完备 +每个API都有对应的单元测试进行覆盖,良好的单元测试天生就是最好的示例。 + +同时您也可以前往[API Doc](./APIDoc.md)查看每个API的详细使用说明。 + +> 注:单元测试中使用到的私钥均进行了脱敏处理,会导致单元测试无法直接执行。您可以自行更改单元测试项目中的`TestAccout类`和`privateKey.json`文件中的相关账号与私钥配置后再执行单元测试。 + +### 多语言 +Alipay Easy SDK基于阿里集团研发的[`Darabonba`](https://github.com/aliyun/darabonba)进行架构,通过DSL中间语言定义API模型,再基于DSL语言自动生成不同编程语言(Java、C#、PHP、TS等)实现的SDK,极大地提升了SDK能力的扩展效率和适用范围,同时也保证了相同的`Easy API`在不同语言生态中体验的一致性。 + +API模型的DSL描述可以进入[tea](./tea)目录查看。 + +### 快速集成 +各语言SDK均会在各自的中央仓库(Maven、NuGet、Composer、NPM etc.)中同步发布,让您使用各语言主流依赖管理工具即可一键安装集成SDK。 + +## 语言支持情况 +Alipay Easy SDK首发暂只支持`Java`、`C#`、`PHP`编程语言,更多编程语言支持正在积极新增中,敬请期待。 + +各语言具体的**使用说明**和**详细介绍**请点击如下链接进入各语言主目录查看。 + +[Java](./java) + +[C#](./csharp) + +[PHP](./php) + + + +## API组织规范 + +在Alipay Easy SDK中,API的引用路径与能力地图的组织层次一致,遵循如下规范 + +> Factory.能力类别.场景类别.接口方法名称( ... ) + +比如,如果您想要使用[能力地图](https://opendocs.alipay.com/mini/00am3f)中`营销能力`下的`模板消息`场景中的`小程序发送模板消息`,只需按如下形式编写调用代码即可(不同编程语言的连接符号可能不同)。 + +`Factory.Marketing.TemplateMessage().send( ... )` + +其中,接口方法名称通常是对其依赖的OpenAPI功能的一个最简概况,接口方法的出入参与OpenAPI中同名参数含义一致,可参照OpenAPI相关参数的使用说明。 + +Alipay Easy SDK将致力于保持良好的API命名,以符合开发者的编程直觉。 + + + +## 已支持的API列表 + +| 能力类别 | 场景类别 | 接口方法名称 | 调用的OpenAPI名称 | +|-----------|-----------------|------------------------|-----------------------------------------------------------| +| Base
基础能力 | OAuth
用户授权 | getToken
获取授权访问令牌和用户user_id | alipay\.system\.oauth\.token | +| Base
基础能力 | OAuth
用户授权 | refreshToken
刷新授权访问令牌 | alipay\.system\.oauth\.token | +| Base
基础能力 | Qrcode
小程序二维码 | create
创建小程序二维码 | alipay\.open\.app\.qrcode\.create | +| Base
基础能力 | Image
图片 | upload
上传门店照片 | alipay\.offline\.material\.image\.upload | +| Base
基础能力 | Video
视频 | upload
上传门店视频 | alipay\.offline\.material\.image\.upload | +| Member
会员能力 | Identification
支付宝身份认证 | init
身份认证初始化 | alipay\.user\.certify\.open\.initialize | +| Member
会员能力 | Identification
支付宝身份认证 | certify
生成认证链接 | alipay\.user\.certify\.open\.certify | +| Member
会员能力 | Identification
支付宝身份认证 | query
身份认证记录查询 | alipay\.user\.certify\.open\.query | +| Payment
支付能力 | Common
通用 | create
创建交易 | alipay\.trade\.create | +| Payment
支付能力 | Common
通用 | query
查询交易 | alipay\.trade\.query | +| Payment
支付能力 | Common
通用 | refund
交易退款 | alipay\.trade\.refund | +| Payment
支付能力 | Common
通用 | close
关闭交易 | alipay\.trade\.close | +| Payment
支付能力 | Common
通用 | cancel
撤销交易 | alipay\.trade\.cancel | +| Payment
支付能力 | Common
通用 | queryRefund
交易退款查询 | alipay\.trade\.fastpay\.refund\.query | +| Payment
支付能力 | Common
通用 | downloadBill
查询对账单下载地址 | alipay\.data\.dataservice\.bill\.downloadurl\.query | +| Payment
支付能力 | Common
通用 | verifyNotify
异步通知验签 | - | +| Payment
支付能力 | Huabei
花呗分期 | create
创建花呗分期交易 | alipay\.trade\.create | +| Payment
支付能力 | FaceToFace
当面付 | pay
扫用户出示的付款码,完成付款 | alipay\.trade\.pay | +| Payment
支付能力 | FaceToFace
当面付 | precreate
生成交易付款码,待用户扫码付款 | alipay\.trade\.precreate | +| Payment
支付能力 | App
手机APP | pay
生成订单串,再使用客户端 SDK 凭此串唤起支付宝收银台 | alipay\.trade\.app\.pay | +| Payment
支付能力 | Page
电脑网站 | pay
生成交易表单,渲染后自动跳转支付宝网站引导用户完成支付 | alipay\.trade\.page\.pay | +| Payment
支付能力 | Wap
手机网站 | pay
生成交易表单,渲染后自动跳转支付宝网站引导用户完成支付 | alipay\.trade\.wap\.pay | +| Security
安全能力 | TextRisk
文本内容安全 | detect
检测内容风险 | alipay\.security\.risk\.content\.detect | +| Marketing
营销能力 | Pass
支付宝卡包 | createTemplate
卡券模板创建 | alipay\.pass\.template\.add | +| Marketing
营销能力 | Pass
支付宝卡包 | updateTemplate
卡券模板更新 | alipay\.pass\.template\.update | +| Marketing
营销能力 | Pass
支付宝卡包 | addInstance
卡券实例发放 | alipay\.pass\.instance\.add | +| Marketing
营销能力 | Pass
支付宝卡包 | updateInstance
卡券实例更新 | alipay\.pass\.instance\.update | +| Marketing
营销能力 | TemplateMessage
小程序模板消息 | send
发送模板消息| alipay\.open\.app\.mini\.templatemessage\.send | +| Marketing
营销能力 | OpenLife
生活号 | createImageTextContent
创建图文消息内容 | alipay\.open\.public\.message\.content\.create | +| Marketing
营销能力 | OpenLife
生活号 | modifyImageTextContent
更新图文消息内容 | alipay\.open\.public\.message\.content\.modify | +| Marketing
营销能力 | OpenLife
生活号 | sendText
群发本文消息 | alipay\.open\.public\.message\.total\.send | +| Marketing
营销能力 | OpenLife
生活号 | sendImageText
群发图文消息 | alipay\.open\.public\.message\.total\.send | +| Marketing
营销能力 | OpenLife
生活号 | sendSingleMessage
单发模板消息 | alipay\.open\.public\.message\.single\.send | +| Marketing
营销能力 | OpenLife
生活号 | recallMessage
生活号消息撤回 | alipay\.open\.public\.life\.msg\.recall | +| Marketing
营销能力 | OpenLife
生活号 | setIndustry
模板消息行业设置 | alipay\.open\.public\.template\.message\.industry\.modify | +| Marketing
营销能力 | OpenLife
生活号 | getIndustry
生活号查询行业设置 | alipay\.open\.public\.setting\.category\.query | +| Util
辅助工具 | AES
加解密 | decrypt
解密,常用于会员手机号解密 | - | +| Util
辅助工具 | AES
加解密 | encrypt
加密 | - | +| Util
辅助工具 | Generic
通用接口 | execute
自行拼接参数,执行OpenAPI调用 | - | + +> 注:更多高频场景的API持续更新中,敬请期待。 + +您还可以前往[API Doc](./APIDoc.md)查看每个API的详细使用说明。 + +# 变更日志 +每个版本的详细更改记录在[变更日志](./CHANGELOG)中。 + +> 版本号最末一位修订号的增加(比如从`1.0.0`升级为`1.0.1`),意味着SDK的功能没有发生任何变化,仅仅是修复了部分Bug。该类升级可能不会记录在变更日志中。 + +> 版本号中间一位次版本号的增加(比如从`1.0.0`升级为`1.1.0`),意味着SDK的功能发生了可向下兼容的新增或修改。 + +> 版本号首位主版本号的增加(比如从`1.0.0`升级为`2.0.0`),意味着SDK的功能可能发生了不向下兼容的较大调整,升级主版本号后请注意做好相关的回归测试工作。 + +# 相关 +* [支付宝开放平台](https://open.alipay.com/platform/home.htm) +* [支付宝开放平台文档中心](https://docs.open.alipay.com/catalog) +* [最新源码](https://github.com/alipay/alipay-easysdk) + +# 许可证 +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk?ref=badge_large) + +# 交流与技术支持 +不管您在使用Alipay Easy SDK的过程中遇到任何问题,欢迎在当前 GitHub [提交 Issues](https://github.com/alipay/alipay-easysdk/issues/new)。 + +您也可以使用钉钉扫描下方二维码,与更多开发者和支付宝工程师共同交流。 + +![支付宝官方Alipay Easy SDK开源交流群](https://gw.alipayobjects.com/mdn/rms_0e15fa/afts/img/A*SUaHT7fpzSwAAAAAAAAAAABkARQnAQ) + diff --git a/serve/vendor/alipaysdk/easysdk/composer.json b/serve/vendor/alipaysdk/easysdk/composer.json new file mode 100644 index 0000000..c4b6225 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/composer.json @@ -0,0 +1,56 @@ +{ + "name":"alipaysdk/easysdk", + "description":"支付宝官方 Alipay Easy SDK", + "type":"library", + "version":"2.2.0", + "authors":[ + { + "name":"junying.wjy", + "email":"junying.wjy@antfin.com" + } + ], + "autoload":{ + "psr-4":{ + "Alipay\\EasySDK\\":"php/src/" + } + }, + "autoload-dev": { + "psr-4": { + "Alipay\\EasySDK\\Test\\": "php/test/" + } + }, + "license":"Apache-2.0", + "minimum-stability":"dev", + "require":{ + "php": ">=7.0", + "ext-curl":"*", + "ext-ctype":"*", + "ext-dom":"*", + "ext-fileinfo": "*", + "ext-json":"*", + "ext-libxml":"*", + "ext-simplexml":"*", + "ext-mbstring":"*", + "ext-openssl":"*", + "pimple/pimple": "^3.0", + "xin/container":"^2.0.1", + "guzzlehttp/guzzle":">=6.3", + "psr/log": "^1.1", + "ext-xmlwriter": "*", + "songshenzong/support": "^2.0", + "danielstjules/stringy": "^3.1", + "mtdowling/jmespath.php": "^2.4", + "adbario/php-dot-notation": "^2.2", + "alibabacloud/tea": "^3.1", + "alibabacloud/tea-fileform": "^0.3.2" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "repositories":{ + "packagist":{ + "type":"composer", + "url":"https://mirrors.aliyun.com/composer/" + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK.sln b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK.sln new file mode 100644 index 0000000..295623c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlipayEasySDK", "AlipayEasySDK\AlipayEasySDK.csproj", "{14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTest", "UnitTest\UnitTest.csproj", "{79DE080D-34C1-485E-996D-435A8515766D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}.Release|Any CPU.Build.0 = Release|Any CPU + {79DE080D-34C1-485E-996D-435A8515766D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79DE080D-34C1-485E-996D-435A8515766D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79DE080D-34C1-485E-996D-435A8515766D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79DE080D-34C1-485E-996D-435A8515766D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/AlipayEasySDK.csproj b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/AlipayEasySDK.csproj new file mode 100644 index 0000000..89f0a0d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/AlipayEasySDK.csproj @@ -0,0 +1,32 @@ + + + + netstandard2.0;net461 + true + 2.1.2 + antopen + zh + https://github.com/alipay/alipay-easysdk/blob/master/LICENSE + Alipay Easy SDK for .NET allows you to enjoy a minimalist programming experience and quickly access the various high-frequency capabilities of the Alipay Open Platform. + AlipayEasySDK + antopen + https://github.com/alipay/alipay-easysdk/tree/master/csharp + Alipay Easy SDK for .NET allows you to enjoy a minimalist programming experience and quickly access the various high-frequency capabilities of the Alipay Open Platform. + Alipay Easy SDK + + + + + + + + + + + + + + + + + diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Image/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Image/Client.cs new file mode 100644 index 0000000..a2ad658 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Image/Client.cs @@ -0,0 +1,324 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Base.Image.Models; + +namespace Alipay.EasySDK.Base.Image +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayOfflineMaterialImageUploadResponse Upload(string imageName, string imageFilePath) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 100000}, + {"readTimeout", 100000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.offline.material.image.upload"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary + { + {"image_type", "jpg"}, + {"image_name", imageName}, + }; + Dictionary fileParams = new Dictionary + { + {"image_content", imageFilePath}, + }; + string boundary = this._kernel.GetRandomBoundary(); + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", this._kernel.ConcatStr("multipart/form-data;charset=utf-8;boundary=", boundary)}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams + )); + request_.Body = this._kernel.ToMultipartRequestBody(textParams, fileParams, boundary); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.offline.material.image.upload"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task UploadAsync(string imageName, string imageFilePath) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 100000}, + {"readTimeout", 100000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.offline.material.image.upload"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary + { + {"image_type", "jpg"}, + {"image_name", imageName}, + }; + Dictionary fileParams = new Dictionary + { + {"image_content", imageFilePath}, + }; + string boundary = this._kernel.GetRandomBoundary(); + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", this._kernel.ConcatStr("multipart/form-data;charset=utf-8;boundary=", boundary)}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams + )); + request_.Body = this._kernel.ToMultipartRequestBody(textParams, fileParams, boundary); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.offline.material.image.upload"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Image/Models/AlipayOfflineMaterialImageUploadResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Image/Models/AlipayOfflineMaterialImageUploadResponse.cs new file mode 100644 index 0000000..c62512a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Image/Models/AlipayOfflineMaterialImageUploadResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Base.Image.Models +{ + public class AlipayOfflineMaterialImageUploadResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("image_id")] + [Validation(Required=true)] + public string ImageId { get; set; } + + [NameInMap("image_url")] + [Validation(Required=true)] + public string ImageUrl { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/OAuth/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/OAuth/Client.cs new file mode 100644 index 0000000..fc0973f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/OAuth/Client.cs @@ -0,0 +1,528 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Base.OAuth.Models; + +namespace Alipay.EasySDK.Base.OAuth +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipaySystemOauthTokenResponse GetToken(string code) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.system.oauth.token"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary + { + {"grant_type", "authorization_code"}, + {"code", code}, + }; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.system.oauth.token"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task GetTokenAsync(string code) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.system.oauth.token"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary + { + {"grant_type", "authorization_code"}, + {"code", code}, + }; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.system.oauth.token"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipaySystemOauthTokenResponse RefreshToken(string refreshToken) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.system.oauth.token"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary + { + {"grant_type", "refresh_token"}, + {"refresh_token", refreshToken}, + }; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.system.oauth.token"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task RefreshTokenAsync(string refreshToken) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.system.oauth.token"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary + { + {"grant_type", "refresh_token"}, + {"refresh_token", refreshToken}, + }; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.system.oauth.token"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/OAuth/Models/AlipaySystemOauthTokenResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/OAuth/Models/AlipaySystemOauthTokenResponse.cs new file mode 100644 index 0000000..29aa6bb --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/OAuth/Models/AlipaySystemOauthTokenResponse.cs @@ -0,0 +1,57 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Base.OAuth.Models +{ + public class AlipaySystemOauthTokenResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("user_id")] + [Validation(Required=true)] + public string UserId { get; set; } + + [NameInMap("access_token")] + [Validation(Required=true)] + public string AccessToken { get; set; } + + [NameInMap("expires_in")] + [Validation(Required=true)] + public long ExpiresIn { get; set; } + + [NameInMap("refresh_token")] + [Validation(Required=true)] + public string RefreshToken { get; set; } + + [NameInMap("re_expires_in")] + [Validation(Required=true)] + public long ReExpiresIn { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Qrcode/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Qrcode/Client.cs new file mode 100644 index 0000000..459dadd --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Qrcode/Client.cs @@ -0,0 +1,318 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Base.Qrcode.Models; + +namespace Alipay.EasySDK.Base.Qrcode +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayOpenAppQrcodeCreateResponse Create(string urlParam, string queryParam, string describe) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.app.qrcode.create"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"url_param", urlParam}, + {"query_param", queryParam}, + {"describe", describe}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.app.qrcode.create"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task CreateAsync(string urlParam, string queryParam, string describe) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.app.qrcode.create"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"url_param", urlParam}, + {"query_param", queryParam}, + {"describe", describe}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.app.qrcode.create"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Qrcode/Models/AlipayOpenAppQrcodeCreateResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Qrcode/Models/AlipayOpenAppQrcodeCreateResponse.cs new file mode 100644 index 0000000..3302d3b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Qrcode/Models/AlipayOpenAppQrcodeCreateResponse.cs @@ -0,0 +1,41 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Base.Qrcode.Models +{ + public class AlipayOpenAppQrcodeCreateResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("qr_code_url")] + [Validation(Required=true)] + public string QrCodeUrl { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Video/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Video/Client.cs new file mode 100644 index 0000000..51ec320 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Video/Client.cs @@ -0,0 +1,324 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Base.Video.Models; + +namespace Alipay.EasySDK.Base.Video +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayOfflineMaterialImageUploadResponse Upload(string videoName, string videoFilePath) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 100000}, + {"readTimeout", 100000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.offline.material.image.upload"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary + { + {"image_type", "mp4"}, + {"image_name", videoName}, + }; + Dictionary fileParams = new Dictionary + { + {"image_content", videoFilePath}, + }; + string boundary = this._kernel.GetRandomBoundary(); + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", this._kernel.ConcatStr("multipart/form-data;charset=utf-8;boundary=", boundary)}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams + )); + request_.Body = this._kernel.ToMultipartRequestBody(textParams, fileParams, boundary); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.offline.material.image.upload"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task UploadAsync(string videoName, string videoFilePath) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 100000}, + {"readTimeout", 100000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.offline.material.image.upload"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary + { + {"image_type", "mp4"}, + {"image_name", videoName}, + }; + Dictionary fileParams = new Dictionary + { + {"image_content", videoFilePath}, + }; + string boundary = this._kernel.GetRandomBoundary(); + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", this._kernel.ConcatStr("multipart/form-data;charset=utf-8;boundary=", boundary)}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams + )); + request_.Body = this._kernel.ToMultipartRequestBody(textParams, fileParams, boundary); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.offline.material.image.upload"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Video/Models/AlipayOfflineMaterialImageUploadResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Video/Models/AlipayOfflineMaterialImageUploadResponse.cs new file mode 100644 index 0000000..1ccfcac --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Base/Video/Models/AlipayOfflineMaterialImageUploadResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Base.Video.Models +{ + public class AlipayOfflineMaterialImageUploadResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("image_id")] + [Validation(Required=true)] + public string ImageId { get; set; } + + [NameInMap("image_url")] + [Validation(Required=true)] + public string ImageUrl { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Factory/Factory.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Factory/Factory.cs new file mode 100644 index 0000000..f2b25b4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Factory/Factory.cs @@ -0,0 +1,244 @@ +using System; +using Alipay.EasySDK.Kernel; +using System.Reflection; + +namespace Alipay.EasySDK.Factory +{ + /// + /// 客户端工厂,用于快速配置和访问各种场景下的API Client + /// + /// 注:该Factory获取的Client不可储存重复使用,请每次均通过Factory完成调用 + /// + public static class Factory + { + public const string SDK_VERSION = "alipay-easysdk-net-2.1.0"; + + /// + /// 将一些初始化耗时较多的信息缓存在上下文中 + /// + private static Context context; + + /// + /// 设置客户端参数,只需设置一次,即可反复使用各种场景下的API Client + /// + /// 客户端参数对象 + public static void SetOptions(Config options) + { + context = new Context(options, SDK_VERSION); + } + + /// + /// 获取调用OpenAPI所需的客户端实例 + /// 本方法用于调用SDK扩展包中的API Client下的方法 + /// + /// 注:返回的实例不可重复使用,只可用于单次调用 + /// + /// 泛型参数 + /// API Client的类型对象 + /// client实例,用于发起单次调用 + public static T GetClient() + { + Type type = typeof(T); + ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(Client) }); + context.SdkVersion = GetSdkVersion(type); + return (T)constructor.Invoke(new object[] { new Client(context) }); + } + + private static string GetSdkVersion(Type client) + { + return context.SdkVersion + "-" + client.FullName + .Replace("EasySDK.", "") + .Replace(".Client", "") + .Replace(".", "-"); + } + + /// + /// 基础能力相关 + /// + public static class Base + { + /// + /// 获取图片相关API Client + /// + /// 图片相关API Client + public static EasySDK.Base.Image.Client Image() + { + return new EasySDK.Base.Image.Client(new Client(context)); + } + + /// + /// 获取视频相关API Client + /// + /// 视频相关API Client + public static EasySDK.Base.Video.Client Video() + { + return new EasySDK.Base.Video.Client(new Client(context)); + } + + /// + /// 获取OAuth认证相关API Client + /// + /// OAuth认证相关API Client + public static EasySDK.Base.OAuth.Client OAuth() + { + return new EasySDK.Base.OAuth.Client(new Client(context)); + } + + /// + /// 获取小程序二维码相关API Client + /// + /// 小程序二维码相关API Client + public static EasySDK.Base.Qrcode.Client Qrcode() + { + return new EasySDK.Base.Qrcode.Client(new Client(context)); + } + } + + /// + /// 营销能力相关 + /// + public static class Marketing + { + /// + /// 获取生活号相关API Client + /// + /// 生活号相关API Client + public static EasySDK.Marketing.OpenLife.Client OpenLife() + { + return new EasySDK.Marketing.OpenLife.Client(new Client(context)); + } + + /// + /// 获取支付宝卡包相关API Client + /// + /// 支付宝卡包相关API Client + public static EasySDK.Marketing.Pass.Client Pass() + { + return new EasySDK.Marketing.Pass.Client(new Client(context)); + } + + /// + /// 获取小程序模板消息相关API Client + /// + /// 小程序模板消息相关API Client + public static EasySDK.Marketing.TemplateMessage.Client TemplateMessage() + { + return new EasySDK.Marketing.TemplateMessage.Client(new Client(context)); + } + } + + /// + /// 会员能力相关 + /// + public static class Member + { + /// + /// 获取支付宝身份认证相关API Client + /// + /// 支付宝身份认证相关API Client + public static EasySDK.Member.Identification.Client Identification() + { + return new EasySDK.Member.Identification.Client(new Client(context)); + } + } + + /// + /// 支付能力相关 + /// + public static class Payment + { + /// + /// 获取支付通用API Client + /// + /// 支付通用API Client + public static EasySDK.Payment.Common.Client Common() + { + return new EasySDK.Payment.Common.Client(new Client(context)); + } + + /// + /// 获取当面付API Client + /// + /// 当面付API Client + public static EasySDK.Payment.FaceToFace.Client FaceToFace() + { + return new EasySDK.Payment.FaceToFace.Client(new Client(context)); + } + + /// + /// 获取花呗API Client + /// + /// 花呗API Client + public static EasySDK.Payment.Huabei.Client Huabei() + { + return new EasySDK.Payment.Huabei.Client(new Client(context)); + } + + /// + /// 获取手机APP支付API Client + /// + /// 手机APP支付API Client + public static EasySDK.Payment.App.Client App() + { + return new EasySDK.Payment.App.Client(new Client(context)); + } + + /// + /// 获取电脑网站支付API Client + /// + /// 电脑网站支付API + public static EasySDK.Payment.Page.Client Page() + { + return new EasySDK.Payment.Page.Client(new Client(context)); + } + + /// + /// 获取手机网站支付API Client + /// + /// 手机网站支付API + public static EasySDK.Payment.Wap.Client Wap() + { + return new EasySDK.Payment.Wap.Client(new Client(context)); + } + } + + /// + /// 安全能力相关 + /// + public static class Security + { + /// + /// 获取文本风险识别相关API Client + /// + /// 文本风险识别相关API Client + public static EasySDK.Security.TextRisk.Client TextRisk() + { + return new EasySDK.Security.TextRisk.Client(new Client(context)); + } + } + + /// + /// 辅助工具 + /// + public static class Util + { + /// + /// 获取OpenAPI通用接口,可通过自行拼装参数,调用几乎所有OpenAPI + /// + /// OpenAPI通用接口 + public static EasySDK.Util.Generic.Client Generic() + { + return new EasySDK.Util.Generic.Client(new Client(context)); + } + + /// + /// 获取AES128加解密相关API Client,常用于会员手机号的解密 + /// + /// AES128加解密相关API Client + public static EasySDK.Util.AES.Client AES() + { + return new EasySDK.Util.AES.Client(new Client(context)); + } + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Client.cs new file mode 100644 index 0000000..eb8daab --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Client.cs @@ -0,0 +1,1832 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Marketing.OpenLife.Models; + +namespace Alipay.EasySDK.Marketing.OpenLife +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayOpenPublicMessageContentCreateResponse CreateImageTextContent(string title, string cover, string content, string contentComment, string ctype, string benefit, string extTags, string loginIds) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.content.create"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"title", title}, + {"cover", cover}, + {"content", content}, + {"could_comment", contentComment}, + {"ctype", ctype}, + {"benefit", benefit}, + {"ext_tags", extTags}, + {"login_ids", loginIds}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.public.message.content.create"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task CreateImageTextContentAsync(string title, string cover, string content, string contentComment, string ctype, string benefit, string extTags, string loginIds) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.content.create"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"title", title}, + {"cover", cover}, + {"content", content}, + {"could_comment", contentComment}, + {"ctype", ctype}, + {"benefit", benefit}, + {"ext_tags", extTags}, + {"login_ids", loginIds}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.public.message.content.create"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayOpenPublicMessageContentModifyResponse ModifyImageTextContent(string contentId, string title, string cover, string content, string couldComment, string ctype, string benefit, string extTags, string loginIds) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.content.modify"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"content_id", contentId}, + {"title", title}, + {"cover", cover}, + {"content", content}, + {"could_comment", couldComment}, + {"ctype", ctype}, + {"benefit", benefit}, + {"ext_tags", extTags}, + {"login_ids", loginIds}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.public.message.content.modify"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task ModifyImageTextContentAsync(string contentId, string title, string cover, string content, string couldComment, string ctype, string benefit, string extTags, string loginIds) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.content.modify"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"content_id", contentId}, + {"title", title}, + {"cover", cover}, + {"content", content}, + {"could_comment", couldComment}, + {"ctype", ctype}, + {"benefit", benefit}, + {"ext_tags", extTags}, + {"login_ids", loginIds}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.public.message.content.modify"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayOpenPublicMessageTotalSendResponse SendText(string text) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.total.send"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Text textObj = new Text + { + Title = "", + Content = text, + }; + Dictionary bizParams = new Dictionary + { + {"msg_type", "text"}, + {"text", textObj}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.public.message.total.send"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task SendTextAsync(string text) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.total.send"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Text textObj = new Text + { + Title = "", + Content = text, + }; + Dictionary bizParams = new Dictionary + { + {"msg_type", "text"}, + {"text", textObj}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.public.message.total.send"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayOpenPublicMessageTotalSendResponse SendImageText(List
articles) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.total.send"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"msg_type", "image-text"}, + {"articles", articles}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.public.message.total.send"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task SendImageTextAsync(List
articles) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.total.send"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"msg_type", "image-text"}, + {"articles", articles}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.public.message.total.send"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayOpenPublicMessageSingleSendResponse SendSingleMessage(string toUserId, Template template) + { + template.Validate(); + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.single.send"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"to_user_id", toUserId}, + {"template", template}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.public.message.single.send"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task SendSingleMessageAsync(string toUserId, Template template) + { + template.Validate(); + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.message.single.send"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"to_user_id", toUserId}, + {"template", template}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.public.message.single.send"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayOpenPublicLifeMsgRecallResponse RecallMessage(string messageId) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.life.msg.recall"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"message_id", messageId}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.public.life.msg.recall"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task RecallMessageAsync(string messageId) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.life.msg.recall"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"message_id", messageId}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.public.life.msg.recall"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayOpenPublicTemplateMessageIndustryModifyResponse SetIndustry(string primaryIndustryCode, string primaryIndustryName, string secondaryIndustryCode, string secondaryIndustryName) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.template.message.industry.modify"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"primary_industry_code", primaryIndustryCode}, + {"primary_industry_name", primaryIndustryName}, + {"secondary_industry_code", secondaryIndustryCode}, + {"secondary_industry_name", secondaryIndustryName}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.public.template.message.industry.modify"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task SetIndustryAsync(string primaryIndustryCode, string primaryIndustryName, string secondaryIndustryCode, string secondaryIndustryName) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.template.message.industry.modify"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"primary_industry_code", primaryIndustryCode}, + {"primary_industry_name", primaryIndustryName}, + {"secondary_industry_code", secondaryIndustryCode}, + {"secondary_industry_name", secondaryIndustryName}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.public.template.message.industry.modify"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayOpenPublicSettingCategoryQueryResponse GetIndustry() + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.setting.category.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.public.setting.category.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task GetIndustryAsync() + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.public.setting.category.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary(){}; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.public.setting.category.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicLifeMsgRecallResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicLifeMsgRecallResponse.cs new file mode 100644 index 0000000..ed7c829 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicLifeMsgRecallResponse.cs @@ -0,0 +1,37 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class AlipayOpenPublicLifeMsgRecallResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentCreateResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentCreateResponse.cs new file mode 100644 index 0000000..d467d46 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentCreateResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class AlipayOpenPublicMessageContentCreateResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("content_id")] + [Validation(Required=true)] + public string ContentId { get; set; } + + [NameInMap("content_url")] + [Validation(Required=true)] + public string ContentUrl { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentModifyResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentModifyResponse.cs new file mode 100644 index 0000000..db5f522 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentModifyResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class AlipayOpenPublicMessageContentModifyResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("content_id")] + [Validation(Required=true)] + public string ContentId { get; set; } + + [NameInMap("content_url")] + [Validation(Required=true)] + public string ContentUrl { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageSingleSendResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageSingleSendResponse.cs new file mode 100644 index 0000000..d4ed185 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageSingleSendResponse.cs @@ -0,0 +1,37 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class AlipayOpenPublicMessageSingleSendResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageTotalSendResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageTotalSendResponse.cs new file mode 100644 index 0000000..2bdabe3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicMessageTotalSendResponse.cs @@ -0,0 +1,41 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class AlipayOpenPublicMessageTotalSendResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("message_id")] + [Validation(Required=true)] + public string MessageId { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicSettingCategoryQueryResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicSettingCategoryQueryResponse.cs new file mode 100644 index 0000000..bc13a7c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicSettingCategoryQueryResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class AlipayOpenPublicSettingCategoryQueryResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("primary_category")] + [Validation(Required=true)] + public string PrimaryCategory { get; set; } + + [NameInMap("secondary_category")] + [Validation(Required=true)] + public string SecondaryCategory { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicTemplateMessageIndustryModifyResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicTemplateMessageIndustryModifyResponse.cs new file mode 100644 index 0000000..6196ae9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/AlipayOpenPublicTemplateMessageIndustryModifyResponse.cs @@ -0,0 +1,37 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class AlipayOpenPublicTemplateMessageIndustryModifyResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Article.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Article.cs new file mode 100644 index 0000000..f924d40 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Article.cs @@ -0,0 +1,34 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class Article : TeaModel { + [NameInMap("title")] + [Validation(Required=false)] + public string Title { get; set; } + + [NameInMap("desc")] + [Validation(Required=true)] + public string Desc { get; set; } + + [NameInMap("image_url")] + [Validation(Required=false)] + public string ImageUrl { get; set; } + + [NameInMap("url")] + [Validation(Required=true)] + public string Url { get; set; } + + [NameInMap("action_name")] + [Validation(Required=false)] + public string ActionName { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Context.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Context.cs new file mode 100644 index 0000000..c3821df --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Context.cs @@ -0,0 +1,42 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class Context : TeaModel { + [NameInMap("head_color")] + [Validation(Required=true)] + public string HeadColor { get; set; } + + [NameInMap("url")] + [Validation(Required=true)] + public string Url { get; set; } + + [NameInMap("action_name")] + [Validation(Required=true)] + public string ActionName { get; set; } + + [NameInMap("keyword1")] + [Validation(Required=false)] + public Keyword Keyword1 { get; set; } + + [NameInMap("keyword2")] + [Validation(Required=false)] + public Keyword Keyword2 { get; set; } + + [NameInMap("first")] + [Validation(Required=false)] + public Keyword First { get; set; } + + [NameInMap("remark")] + [Validation(Required=false)] + public Keyword Remark { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Keyword.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Keyword.cs new file mode 100644 index 0000000..fc9ff0d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Keyword.cs @@ -0,0 +1,22 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class Keyword : TeaModel { + [NameInMap("color")] + [Validation(Required=true)] + public string Color { get; set; } + + [NameInMap("value")] + [Validation(Required=true)] + public string Value { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Template.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Template.cs new file mode 100644 index 0000000..67c4198 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Template.cs @@ -0,0 +1,22 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class Template : TeaModel { + [NameInMap("template_id")] + [Validation(Required=true)] + public string TemplateId { get; set; } + + [NameInMap("context")] + [Validation(Required=true)] + public Context Context { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Text.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Text.cs new file mode 100644 index 0000000..df45148 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/OpenLife/Models/Text.cs @@ -0,0 +1,22 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.OpenLife.Models +{ + public class Text : TeaModel { + [NameInMap("title")] + [Validation(Required=true)] + public string Title { get; set; } + + [NameInMap("content")] + [Validation(Required=true)] + public string Content { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Client.cs new file mode 100644 index 0000000..a8d3a45 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Client.cs @@ -0,0 +1,964 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Marketing.Pass.Models; + +namespace Alipay.EasySDK.Marketing.Pass +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayPassTemplateAddResponse CreateTemplate(string uniqueId, string tplContent) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.pass.template.add"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"unique_id", uniqueId}, + {"tpl_content", tplContent}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.pass.template.add"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task CreateTemplateAsync(string uniqueId, string tplContent) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.pass.template.add"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"unique_id", uniqueId}, + {"tpl_content", tplContent}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.pass.template.add"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayPassTemplateUpdateResponse UpdateTemplate(string tplId, string tplContent) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.pass.template.update"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"tpl_id", tplId}, + {"tpl_content", tplContent}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.pass.template.update"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task UpdateTemplateAsync(string tplId, string tplContent) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.pass.template.update"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"tpl_id", tplId}, + {"tpl_content", tplContent}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.pass.template.update"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayPassInstanceAddResponse AddInstance(string tplId, string tplParams, string recognitionType, string recognitionInfo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.pass.instance.add"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"tpl_id", tplId}, + {"tpl_params", tplParams}, + {"recognition_type", recognitionType}, + {"recognition_info", recognitionInfo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.pass.instance.add"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task AddInstanceAsync(string tplId, string tplParams, string recognitionType, string recognitionInfo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.pass.instance.add"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"tpl_id", tplId}, + {"tpl_params", tplParams}, + {"recognition_type", recognitionType}, + {"recognition_info", recognitionInfo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.pass.instance.add"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayPassInstanceUpdateResponse UpdateInstance(string serialNumber, string channelId, string tplParams, string status, string verifyCode, string verifyType) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.pass.instance.update"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"serial_number", serialNumber}, + {"channel_id", channelId}, + {"tpl_params", tplParams}, + {"status", status}, + {"verify_code", verifyCode}, + {"verify_type", verifyType}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.pass.instance.update"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task UpdateInstanceAsync(string serialNumber, string channelId, string tplParams, string status, string verifyCode, string verifyType) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.pass.instance.update"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"serial_number", serialNumber}, + {"channel_id", channelId}, + {"tpl_params", tplParams}, + {"status", status}, + {"verify_code", verifyCode}, + {"verify_type", verifyType}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.pass.instance.update"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassInstanceAddResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassInstanceAddResponse.cs new file mode 100644 index 0000000..5fcfa76 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassInstanceAddResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.Pass.Models +{ + public class AlipayPassInstanceAddResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("success")] + [Validation(Required=true)] + public bool? Success { get; set; } + + [NameInMap("result")] + [Validation(Required=true)] + public string Result { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassInstanceUpdateResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassInstanceUpdateResponse.cs new file mode 100644 index 0000000..c093297 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassInstanceUpdateResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.Pass.Models +{ + public class AlipayPassInstanceUpdateResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("success")] + [Validation(Required=true)] + public bool? Success { get; set; } + + [NameInMap("result")] + [Validation(Required=true)] + public string Result { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassTemplateAddResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassTemplateAddResponse.cs new file mode 100644 index 0000000..b245df3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassTemplateAddResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.Pass.Models +{ + public class AlipayPassTemplateAddResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("success")] + [Validation(Required=true)] + public bool? Success { get; set; } + + [NameInMap("result")] + [Validation(Required=true)] + public string Result { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassTemplateUpdateResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassTemplateUpdateResponse.cs new file mode 100644 index 0000000..e02c33f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/Pass/Models/AlipayPassTemplateUpdateResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.Pass.Models +{ + public class AlipayPassTemplateUpdateResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("success")] + [Validation(Required=true)] + public bool? Success { get; set; } + + [NameInMap("result")] + [Validation(Required=true)] + public string Result { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/TemplateMessage/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/TemplateMessage/Client.cs new file mode 100644 index 0000000..fac3c57 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/TemplateMessage/Client.cs @@ -0,0 +1,322 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Marketing.TemplateMessage.Models; + +namespace Alipay.EasySDK.Marketing.TemplateMessage +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayOpenAppMiniTemplatemessageSendResponse Send(string toUserId, string formId, string userTemplateId, string page, string data) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.app.mini.templatemessage.send"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"to_user_id", toUserId}, + {"form_id", formId}, + {"user_template_id", userTemplateId}, + {"page", page}, + {"data", data}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.open.app.mini.templatemessage.send"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task SendAsync(string toUserId, string formId, string userTemplateId, string page, string data) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.open.app.mini.templatemessage.send"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"to_user_id", toUserId}, + {"form_id", formId}, + {"user_template_id", userTemplateId}, + {"page", page}, + {"data", data}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.app.mini.templatemessage.send"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/TemplateMessage/Models/AlipayOpenAppMiniTemplatemessageSendResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/TemplateMessage/Models/AlipayOpenAppMiniTemplatemessageSendResponse.cs new file mode 100644 index 0000000..8cc4b9d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Marketing/TemplateMessage/Models/AlipayOpenAppMiniTemplatemessageSendResponse.cs @@ -0,0 +1,37 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Marketing.TemplateMessage.Models +{ + public class AlipayOpenAppMiniTemplatemessageSendResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Client.cs new file mode 100644 index 0000000..7e44a5f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Client.cs @@ -0,0 +1,562 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Member.Identification.Models; + +namespace Alipay.EasySDK.Member.Identification +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayUserCertifyOpenInitializeResponse Init(string outerOrderNo, string bizCode, IdentityParam identityParam, MerchantConfig merchantConfig) + { + identityParam.Validate(); + merchantConfig.Validate(); + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.user.certify.open.initialize"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"outer_order_no", outerOrderNo}, + {"biz_code", bizCode}, + {"identity_param", identityParam}, + {"merchant_config", merchantConfig}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.user.certify.open.initialize"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task InitAsync(string outerOrderNo, string bizCode, IdentityParam identityParam, MerchantConfig merchantConfig) + { + identityParam.Validate(); + merchantConfig.Validate(); + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.user.certify.open.initialize"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"outer_order_no", outerOrderNo}, + {"biz_code", bizCode}, + {"identity_param", identityParam}, + {"merchant_config", merchantConfig}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.user.certify.open.initialize"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayUserCertifyOpenQueryResponse Query(string certifyId) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.user.certify.open.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"certify_id", certifyId}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.user.certify.open.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task QueryAsync(string certifyId) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.user.certify.open.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"certify_id", certifyId}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.user.certify.open.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayUserCertifyOpenCertifyResponse Certify(string certifyId) + { + Dictionary systemParams = new Dictionary + { + {"method", "alipay.user.certify.open.certify"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"certify_id", certifyId}, + }; + Dictionary textParams = new Dictionary(){}; + string sign = this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey")); + Dictionary response = new Dictionary + { + {"body", this._kernel.GeneratePage("GET", systemParams, bizParams, textParams, sign)}, + }; + return TeaModel.ToObject(response); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/AlipayUserCertifyOpenCertifyResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/AlipayUserCertifyOpenCertifyResponse.cs new file mode 100644 index 0000000..a0fe1f7 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/AlipayUserCertifyOpenCertifyResponse.cs @@ -0,0 +1,21 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Member.Identification.Models +{ + public class AlipayUserCertifyOpenCertifyResponse : TeaModel { + /// + /// 认证服务请求地址 + /// + [NameInMap("body")] + [Validation(Required=true)] + public string Body { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/AlipayUserCertifyOpenInitializeResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/AlipayUserCertifyOpenInitializeResponse.cs new file mode 100644 index 0000000..e9d55fb --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/AlipayUserCertifyOpenInitializeResponse.cs @@ -0,0 +1,41 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Member.Identification.Models +{ + public class AlipayUserCertifyOpenInitializeResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("certify_id")] + [Validation(Required=true)] + public string CertifyId { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/AlipayUserCertifyOpenQueryResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/AlipayUserCertifyOpenQueryResponse.cs new file mode 100644 index 0000000..92a2bab --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/AlipayUserCertifyOpenQueryResponse.cs @@ -0,0 +1,49 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Member.Identification.Models +{ + public class AlipayUserCertifyOpenQueryResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("passed")] + [Validation(Required=true)] + public string Passed { get; set; } + + [NameInMap("identity_info")] + [Validation(Required=true)] + public string IdentityInfo { get; set; } + + [NameInMap("material_info")] + [Validation(Required=true)] + public string MaterialInfo { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/IdentityParam.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/IdentityParam.cs new file mode 100644 index 0000000..a5e70db --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/IdentityParam.cs @@ -0,0 +1,30 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Member.Identification.Models +{ + public class IdentityParam : TeaModel { + [NameInMap("identity_type")] + [Validation(Required=true)] + public string IdentityType { get; set; } + + [NameInMap("cert_type")] + [Validation(Required=true)] + public string CertType { get; set; } + + [NameInMap("cert_name")] + [Validation(Required=true)] + public string CertName { get; set; } + + [NameInMap("cert_no")] + [Validation(Required=true)] + public string CertNo { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/MerchantConfig.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/MerchantConfig.cs new file mode 100644 index 0000000..6ffe99b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Member/Identification/Models/MerchantConfig.cs @@ -0,0 +1,18 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Member.Identification.Models +{ + public class MerchantConfig : TeaModel { + [NameInMap("return_url")] + [Validation(Required=true)] + public string ReturnUrl { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/App/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/App/Client.cs new file mode 100644 index 0000000..0d9fcbc --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/App/Client.cs @@ -0,0 +1,135 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Payment.App.Models; + +namespace Alipay.EasySDK.Payment.App +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + + public AlipayTradeAppPayResponse Pay(string subject, string outTradeNo, string totalAmount) + { + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.app.pay"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + }; + Dictionary textParams = new Dictionary(){}; + string sign = this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey")); + Dictionary response = new Dictionary + { + {"body", this._kernel.GenerateOrderString(systemParams, bizParams, textParams, sign)}, + }; + return TeaModel.ToObject(response); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/App/Models/AlipayTradeAppPayResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/App/Models/AlipayTradeAppPayResponse.cs new file mode 100644 index 0000000..d5a4d4d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/App/Models/AlipayTradeAppPayResponse.cs @@ -0,0 +1,21 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.App.Models +{ + public class AlipayTradeAppPayResponse : TeaModel { + /// + /// 订单信息,字符串形式 + /// + [NameInMap("body")] + [Validation(Required=true)] + public string Body { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Client.cs new file mode 100644 index 0000000..7b75c71 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Client.cs @@ -0,0 +1,1598 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Payment.Common.Models; + +namespace Alipay.EasySDK.Payment.Common +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayTradeCreateResponse Create(string subject, string outTradeNo, string totalAmount, string buyerId) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.create"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + {"buyer_id", buyerId}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.trade.create"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task CreateAsync(string subject, string outTradeNo, string totalAmount, string buyerId) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.create"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + {"buyer_id", buyerId}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.trade.create"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayTradeQueryResponse Query(string outTradeNo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.trade.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task QueryAsync(string outTradeNo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.trade.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayTradeRefundResponse Refund(string outTradeNo, string refundAmount) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.refund"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + {"refund_amount", refundAmount}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.trade.refund"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task RefundAsync(string outTradeNo, string refundAmount) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.refund"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + {"refund_amount", refundAmount}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.trade.refund"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayTradeCloseResponse Close(string outTradeNo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.close"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.trade.close"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task CloseAsync(string outTradeNo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.close"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.trade.close"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayTradeCancelResponse Cancel(string outTradeNo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.cancel"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.trade.cancel"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task CancelAsync(string outTradeNo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.cancel"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.trade.cancel"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayTradeFastpayRefundQueryResponse QueryRefund(string outTradeNo, string outRequestNo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.fastpay.refund.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + {"out_request_no", outRequestNo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.trade.fastpay.refund.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task QueryRefundAsync(string outTradeNo, string outRequestNo) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.fastpay.refund.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"out_trade_no", outTradeNo}, + {"out_request_no", outRequestNo}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.trade.fastpay.refund.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayDataDataserviceBillDownloadurlQueryResponse DownloadBill(string billType, string billDate) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.data.dataservice.bill.downloadurl.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"bill_type", billType}, + {"bill_date", billDate}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.data.dataservice.bill.downloadurl.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task DownloadBillAsync(string billType, string billDate) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.data.dataservice.bill.downloadurl.query"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"bill_type", billType}, + {"bill_date", billDate}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.data.dataservice.bill.downloadurl.query"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public bool? VerifyNotify(Dictionary parameters) + { + if (this._kernel.IsCertMode()) + { + return this._kernel.VerifyParams(parameters, this._kernel.ExtractAlipayPublicKey("")); + } + else + { + return this._kernel.VerifyParams(parameters, this._kernel.GetConfig("alipayPublicKey")); + } + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayDataDataserviceBillDownloadurlQueryResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayDataDataserviceBillDownloadurlQueryResponse.cs new file mode 100644 index 0000000..ef8b303 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayDataDataserviceBillDownloadurlQueryResponse.cs @@ -0,0 +1,41 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class AlipayDataDataserviceBillDownloadurlQueryResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("bill_download_url")] + [Validation(Required=true)] + public string BillDownloadUrl { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeCancelResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeCancelResponse.cs new file mode 100644 index 0000000..f85409a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeCancelResponse.cs @@ -0,0 +1,61 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class AlipayTradeCancelResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("trade_no")] + [Validation(Required=true)] + public string TradeNo { get; set; } + + [NameInMap("out_trade_no")] + [Validation(Required=true)] + public string OutTradeNo { get; set; } + + [NameInMap("retry_flag")] + [Validation(Required=true)] + public string RetryFlag { get; set; } + + [NameInMap("action")] + [Validation(Required=true)] + public string Action { get; set; } + + [NameInMap("gmt_refund_pay")] + [Validation(Required=true)] + public string GmtRefundPay { get; set; } + + [NameInMap("refund_settlement_id")] + [Validation(Required=true)] + public string RefundSettlementId { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeCloseResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeCloseResponse.cs new file mode 100644 index 0000000..4540726 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeCloseResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class AlipayTradeCloseResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("trade_no")] + [Validation(Required=true)] + public string TradeNo { get; set; } + + [NameInMap("out_trade_no")] + [Validation(Required=true)] + public string OutTradeNo { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeCreateResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeCreateResponse.cs new file mode 100644 index 0000000..22efe95 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeCreateResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class AlipayTradeCreateResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("out_trade_no")] + [Validation(Required=true)] + public string OutTradeNo { get; set; } + + [NameInMap("trade_no")] + [Validation(Required=true)] + public string TradeNo { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeFastpayRefundQueryResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeFastpayRefundQueryResponse.cs new file mode 100644 index 0000000..db5f643 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeFastpayRefundQueryResponse.cs @@ -0,0 +1,109 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class AlipayTradeFastpayRefundQueryResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("error_code")] + [Validation(Required=true)] + public string ErrorCode { get; set; } + + [NameInMap("gmt_refund_pay")] + [Validation(Required=true)] + public string GmtRefundPay { get; set; } + + [NameInMap("industry_sepc_detail")] + [Validation(Required=true)] + public string IndustrySepcDetail { get; set; } + + [NameInMap("out_request_no")] + [Validation(Required=true)] + public string OutRequestNo { get; set; } + + [NameInMap("out_trade_no")] + [Validation(Required=true)] + public string OutTradeNo { get; set; } + + [NameInMap("present_refund_buyer_amount")] + [Validation(Required=true)] + public string PresentRefundBuyerAmount { get; set; } + + [NameInMap("present_refund_discount_amount")] + [Validation(Required=true)] + public string PresentRefundDiscountAmount { get; set; } + + [NameInMap("present_refund_mdiscount_amount")] + [Validation(Required=true)] + public string PresentRefundMdiscountAmount { get; set; } + + [NameInMap("refund_amount")] + [Validation(Required=true)] + public string RefundAmount { get; set; } + + [NameInMap("refund_charge_amount")] + [Validation(Required=true)] + public string RefundChargeAmount { get; set; } + + [NameInMap("refund_detail_item_list")] + [Validation(Required=true)] + public List RefundDetailItemList { get; set; } + + [NameInMap("refund_reason")] + [Validation(Required=true)] + public string RefundReason { get; set; } + + [NameInMap("refund_royaltys")] + [Validation(Required=true)] + public List RefundRoyaltys { get; set; } + + [NameInMap("refund_settlement_id")] + [Validation(Required=true)] + public string RefundSettlementId { get; set; } + + [NameInMap("refund_status")] + [Validation(Required=true)] + public string RefundStatus { get; set; } + + [NameInMap("send_back_fee")] + [Validation(Required=true)] + public string SendBackFee { get; set; } + + [NameInMap("total_amount")] + [Validation(Required=true)] + public string TotalAmount { get; set; } + + [NameInMap("trade_no")] + [Validation(Required=true)] + public string TradeNo { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeQueryResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeQueryResponse.cs new file mode 100644 index 0000000..1cb27c3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeQueryResponse.cs @@ -0,0 +1,177 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class AlipayTradeQueryResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("trade_no")] + [Validation(Required=true)] + public string TradeNo { get; set; } + + [NameInMap("out_trade_no")] + [Validation(Required=true)] + public string OutTradeNo { get; set; } + + [NameInMap("buyer_logon_id")] + [Validation(Required=true)] + public string BuyerLogonId { get; set; } + + [NameInMap("trade_status")] + [Validation(Required=true)] + public string TradeStatus { get; set; } + + [NameInMap("total_amount")] + [Validation(Required=true)] + public string TotalAmount { get; set; } + + [NameInMap("trans_currency")] + [Validation(Required=true)] + public string TransCurrency { get; set; } + + [NameInMap("settle_currency")] + [Validation(Required=true)] + public string SettleCurrency { get; set; } + + [NameInMap("settle_amount")] + [Validation(Required=true)] + public string SettleAmount { get; set; } + + [NameInMap("pay_currency")] + [Validation(Required=true)] + public string PayCurrency { get; set; } + + [NameInMap("pay_amount")] + [Validation(Required=true)] + public string PayAmount { get; set; } + + [NameInMap("settle_trans_rate")] + [Validation(Required=true)] + public string SettleTransRate { get; set; } + + [NameInMap("trans_pay_rate")] + [Validation(Required=true)] + public string TransPayRate { get; set; } + + [NameInMap("buyer_pay_amount")] + [Validation(Required=true)] + public string BuyerPayAmount { get; set; } + + [NameInMap("point_amount")] + [Validation(Required=true)] + public string PointAmount { get; set; } + + [NameInMap("invoice_amount")] + [Validation(Required=true)] + public string InvoiceAmount { get; set; } + + [NameInMap("send_pay_date")] + [Validation(Required=true)] + public string SendPayDate { get; set; } + + [NameInMap("receipt_amount")] + [Validation(Required=true)] + public string ReceiptAmount { get; set; } + + [NameInMap("store_id")] + [Validation(Required=true)] + public string StoreId { get; set; } + + [NameInMap("terminal_id")] + [Validation(Required=true)] + public string TerminalId { get; set; } + + [NameInMap("fund_bill_list")] + [Validation(Required=true)] + public List FundBillList { get; set; } + + [NameInMap("store_name")] + [Validation(Required=true)] + public string StoreName { get; set; } + + [NameInMap("buyer_user_id")] + [Validation(Required=true)] + public string BuyerUserId { get; set; } + + [NameInMap("charge_amount")] + [Validation(Required=true)] + public string ChargeAmount { get; set; } + + [NameInMap("charge_flags")] + [Validation(Required=true)] + public string ChargeFlags { get; set; } + + [NameInMap("settlement_id")] + [Validation(Required=true)] + public string SettlementId { get; set; } + + [NameInMap("trade_settle_info")] + [Validation(Required=true)] + public List TradeSettleInfo { get; set; } + + [NameInMap("auth_trade_pay_mode")] + [Validation(Required=true)] + public string AuthTradePayMode { get; set; } + + [NameInMap("buyer_user_type")] + [Validation(Required=true)] + public string BuyerUserType { get; set; } + + [NameInMap("mdiscount_amount")] + [Validation(Required=true)] + public string MdiscountAmount { get; set; } + + [NameInMap("discount_amount")] + [Validation(Required=true)] + public string DiscountAmount { get; set; } + + [NameInMap("buyer_user_name")] + [Validation(Required=true)] + public string BuyerUserName { get; set; } + + [NameInMap("subject")] + [Validation(Required=true)] + public string Subject { get; set; } + + [NameInMap("body")] + [Validation(Required=true)] + public string Body { get; set; } + + [NameInMap("alipay_sub_merchant_id")] + [Validation(Required=true)] + public string AlipaySubMerchantId { get; set; } + + [NameInMap("ext_infos")] + [Validation(Required=true)] + public string ExtInfos { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeRefundResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeRefundResponse.cs new file mode 100644 index 0000000..8d850be --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/AlipayTradeRefundResponse.cs @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class AlipayTradeRefundResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("trade_no")] + [Validation(Required=true)] + public string TradeNo { get; set; } + + [NameInMap("out_trade_no")] + [Validation(Required=true)] + public string OutTradeNo { get; set; } + + [NameInMap("buyer_logon_id")] + [Validation(Required=true)] + public string BuyerLogonId { get; set; } + + [NameInMap("fund_change")] + [Validation(Required=true)] + public string FundChange { get; set; } + + [NameInMap("refund_fee")] + [Validation(Required=true)] + public string RefundFee { get; set; } + + [NameInMap("refund_currency")] + [Validation(Required=true)] + public string RefundCurrency { get; set; } + + [NameInMap("gmt_refund_pay")] + [Validation(Required=true)] + public string GmtRefundPay { get; set; } + + [NameInMap("refund_detail_item_list")] + [Validation(Required=true)] + public List RefundDetailItemList { get; set; } + + [NameInMap("store_name")] + [Validation(Required=true)] + public string StoreName { get; set; } + + [NameInMap("buyer_user_id")] + [Validation(Required=true)] + public string BuyerUserId { get; set; } + + [NameInMap("refund_preset_paytool_list")] + [Validation(Required=true)] + public List RefundPresetPaytoolList { get; set; } + + [NameInMap("refund_settlement_id")] + [Validation(Required=true)] + public string RefundSettlementId { get; set; } + + [NameInMap("present_refund_buyer_amount")] + [Validation(Required=true)] + public string PresentRefundBuyerAmount { get; set; } + + [NameInMap("present_refund_discount_amount")] + [Validation(Required=true)] + public string PresentRefundDiscountAmount { get; set; } + + [NameInMap("present_refund_mdiscount_amount")] + [Validation(Required=true)] + public string PresentRefundMdiscountAmount { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/PresetPayToolInfo.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/PresetPayToolInfo.cs new file mode 100644 index 0000000..d815680 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/PresetPayToolInfo.cs @@ -0,0 +1,22 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class PresetPayToolInfo : TeaModel { + [NameInMap("amount")] + [Validation(Required=true)] + public List Amount { get; set; } + + [NameInMap("assert_type_code")] + [Validation(Required=true)] + public string AssertTypeCode { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/RefundRoyaltyResult.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/RefundRoyaltyResult.cs new file mode 100644 index 0000000..2dd8a30 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/RefundRoyaltyResult.cs @@ -0,0 +1,42 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class RefundRoyaltyResult : TeaModel { + [NameInMap("refund_amount")] + [Validation(Required=true)] + public string RefundAmount { get; set; } + + [NameInMap("royalty_type")] + [Validation(Required=true)] + public string RoyaltyType { get; set; } + + [NameInMap("result_code")] + [Validation(Required=true)] + public string ResultCode { get; set; } + + [NameInMap("trans_out")] + [Validation(Required=true)] + public string TransOut { get; set; } + + [NameInMap("trans_out_email")] + [Validation(Required=true)] + public string TransOutEmail { get; set; } + + [NameInMap("trans_in")] + [Validation(Required=true)] + public string TransIn { get; set; } + + [NameInMap("trans_in_email")] + [Validation(Required=true)] + public string TransInEmail { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/TradeFundBill.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/TradeFundBill.cs new file mode 100644 index 0000000..08084bc --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/TradeFundBill.cs @@ -0,0 +1,34 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class TradeFundBill : TeaModel { + [NameInMap("fund_channel")] + [Validation(Required=true)] + public string FundChannel { get; set; } + + [NameInMap("bank_code")] + [Validation(Required=true)] + public string BankCode { get; set; } + + [NameInMap("amount")] + [Validation(Required=true)] + public string Amount { get; set; } + + [NameInMap("real_amount")] + [Validation(Required=true)] + public string RealAmount { get; set; } + + [NameInMap("fund_type")] + [Validation(Required=true)] + public string FundType { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/TradeSettleDetail.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/TradeSettleDetail.cs new file mode 100644 index 0000000..375e7c6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/TradeSettleDetail.cs @@ -0,0 +1,38 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class TradeSettleDetail : TeaModel { + [NameInMap("operation_type")] + [Validation(Required=true)] + public string OperationType { get; set; } + + [NameInMap("operation_serial_no")] + [Validation(Required=true)] + public string OperationSerial_no { get; set; } + + [NameInMap("operation_dt")] + [Validation(Required=true)] + public string OperationDt { get; set; } + + [NameInMap("trans_out")] + [Validation(Required=true)] + public string TransOut { get; set; } + + [NameInMap("trans_in")] + [Validation(Required=true)] + public string TransIn { get; set; } + + [NameInMap("amount")] + [Validation(Required=true)] + public string Amount { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/TradeSettleInfo.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/TradeSettleInfo.cs new file mode 100644 index 0000000..31fbef4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Common/Models/TradeSettleInfo.cs @@ -0,0 +1,18 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Common.Models +{ + public class TradeSettleInfo : TeaModel { + [NameInMap("trade_settle_detail_list")] + [Validation(Required=true)] + public List TradeSettleDetailList { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Client.cs new file mode 100644 index 0000000..3865d4b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Client.cs @@ -0,0 +1,536 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Payment.FaceToFace.Models; + +namespace Alipay.EasySDK.Payment.FaceToFace +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayTradePayResponse Pay(string subject, string outTradeNo, string totalAmount, string authCode) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.pay"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + {"auth_code", authCode}, + {"scene", "bar_code"}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.trade.pay"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task PayAsync(string subject, string outTradeNo, string totalAmount, string authCode) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.pay"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + {"auth_code", authCode}, + {"scene", "bar_code"}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.trade.pay"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public AlipayTradePrecreateResponse PreCreate(string subject, string outTradeNo, string totalAmount) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.precreate"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.trade.precreate"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task PreCreateAsync(string subject, string outTradeNo, string totalAmount) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.precreate"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.trade.precreate"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/AlipayTradePayResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/AlipayTradePayResponse.cs new file mode 100644 index 0000000..32aa8c9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/AlipayTradePayResponse.cs @@ -0,0 +1,165 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.FaceToFace.Models +{ + public class AlipayTradePayResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("trade_no")] + [Validation(Required=true)] + public string TradeNo { get; set; } + + [NameInMap("out_trade_no")] + [Validation(Required=true)] + public string OutTradeNo { get; set; } + + [NameInMap("buyer_logon_id")] + [Validation(Required=true)] + public string BuyerLogonId { get; set; } + + [NameInMap("settle_amount")] + [Validation(Required=true)] + public string SettleAmount { get; set; } + + [NameInMap("pay_currency")] + [Validation(Required=true)] + public string PayCurrency { get; set; } + + [NameInMap("pay_amount")] + [Validation(Required=true)] + public string PayAmount { get; set; } + + [NameInMap("settle_trans_rate")] + [Validation(Required=true)] + public string SettleTransRate { get; set; } + + [NameInMap("trans_pay_rate")] + [Validation(Required=true)] + public string TransPayRate { get; set; } + + [NameInMap("total_amount")] + [Validation(Required=true)] + public string TotalAmount { get; set; } + + [NameInMap("trans_currency")] + [Validation(Required=true)] + public string TransCurrency { get; set; } + + [NameInMap("settle_currency")] + [Validation(Required=true)] + public string SettleCurrency { get; set; } + + [NameInMap("receipt_amount")] + [Validation(Required=true)] + public string ReceiptAmount { get; set; } + + [NameInMap("buyer_pay_amount")] + [Validation(Required=true)] + public string BuyerPayAmount { get; set; } + + [NameInMap("point_amount")] + [Validation(Required=true)] + public string PointAmount { get; set; } + + [NameInMap("invoice_amount")] + [Validation(Required=true)] + public string InvoiceAmount { get; set; } + + [NameInMap("gmt_payment")] + [Validation(Required=true)] + public string GmtPayment { get; set; } + + [NameInMap("fund_bill_list")] + [Validation(Required=true)] + public List FundBillList { get; set; } + + [NameInMap("card_balance")] + [Validation(Required=true)] + public string CardBalance { get; set; } + + [NameInMap("store_name")] + [Validation(Required=true)] + public string StoreName { get; set; } + + [NameInMap("buyer_user_id")] + [Validation(Required=true)] + public string BuyerUserId { get; set; } + + [NameInMap("discount_goods_detail")] + [Validation(Required=true)] + public string DiscountGoodsDetail { get; set; } + + [NameInMap("voucher_detail_list")] + [Validation(Required=true)] + public List VoucherDetailList { get; set; } + + [NameInMap("advance_amount")] + [Validation(Required=true)] + public string AdvanceAmount { get; set; } + + [NameInMap("auth_trade_pay_mode")] + [Validation(Required=true)] + public string AuthTradePayMode { get; set; } + + [NameInMap("charge_amount")] + [Validation(Required=true)] + public string ChargeAmount { get; set; } + + [NameInMap("charge_flags")] + [Validation(Required=true)] + public string ChargeFlags { get; set; } + + [NameInMap("settlement_id")] + [Validation(Required=true)] + public string SettlementId { get; set; } + + [NameInMap("business_params")] + [Validation(Required=true)] + public string BusinessParams { get; set; } + + [NameInMap("buyer_user_type")] + [Validation(Required=true)] + public string BuyerUserType { get; set; } + + [NameInMap("mdiscount_amount")] + [Validation(Required=true)] + public string MdiscountAmount { get; set; } + + [NameInMap("discount_amount")] + [Validation(Required=true)] + public string DiscountAmount { get; set; } + + [NameInMap("buyer_user_name")] + [Validation(Required=true)] + public string BuyerUserName { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/AlipayTradePrecreateResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/AlipayTradePrecreateResponse.cs new file mode 100644 index 0000000..a819a28 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/AlipayTradePrecreateResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.FaceToFace.Models +{ + public class AlipayTradePrecreateResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("out_trade_no")] + [Validation(Required=true)] + public string OutTradeNo { get; set; } + + [NameInMap("qr_code")] + [Validation(Required=true)] + public string QrCode { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/TradeFundBill.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/TradeFundBill.cs new file mode 100644 index 0000000..6d0ea18 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/TradeFundBill.cs @@ -0,0 +1,30 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.FaceToFace.Models +{ + public class TradeFundBill : TeaModel { + [NameInMap("fund_channel")] + [Validation(Required=true)] + public string FundChannel { get; set; } + + [NameInMap("bank_code")] + [Validation(Required=true)] + public string BankCode { get; set; } + + [NameInMap("amount")] + [Validation(Required=true)] + public string Amount { get; set; } + + [NameInMap("real_amount")] + [Validation(Required=true)] + public string RealAmount { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/VoucherDetail.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/VoucherDetail.cs new file mode 100644 index 0000000..d2ba177 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/FaceToFace/Models/VoucherDetail.cs @@ -0,0 +1,58 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.FaceToFace.Models +{ + public class VoucherDetail : TeaModel { + [NameInMap("id")] + [Validation(Required=true)] + public string Id { get; set; } + + [NameInMap("name")] + [Validation(Required=true)] + public string Name { get; set; } + + [NameInMap("type")] + [Validation(Required=true)] + public string Type { get; set; } + + [NameInMap("amount")] + [Validation(Required=true)] + public string Amount { get; set; } + + [NameInMap("merchant_contribute")] + [Validation(Required=true)] + public string MerchantContribute { get; set; } + + [NameInMap("other_contribute")] + [Validation(Required=true)] + public string OtherContribute { get; set; } + + [NameInMap("memo")] + [Validation(Required=true)] + public string Memo { get; set; } + + [NameInMap("template_id")] + [Validation(Required=true)] + public string TemplateId { get; set; } + + [NameInMap("purchase_buyer_contribute")] + [Validation(Required=true)] + public string PurchaseBuyerContribute { get; set; } + + [NameInMap("purchase_merchant_contribute")] + [Validation(Required=true)] + public string PurchaseMerchantContribute { get; set; } + + [NameInMap("purchase_ant_contribute")] + [Validation(Required=true)] + public string PurchaseAntContribute { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Huabei/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Huabei/Client.cs new file mode 100644 index 0000000..34cbff9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Huabei/Client.cs @@ -0,0 +1,324 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Payment.Huabei.Models; + +namespace Alipay.EasySDK.Payment.Huabei +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayTradeCreateResponse Create(string subject, string outTradeNo, string totalAmount, string buyerId, HuabeiConfig extendParams) + { + extendParams.Validate(); + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.create"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + {"buyer_id", buyerId}, + {"extend_params", extendParams}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.trade.create"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task CreateAsync(string subject, string outTradeNo, string totalAmount, string buyerId, HuabeiConfig extendParams) + { + extendParams.Validate(); + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.create"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + {"buyer_id", buyerId}, + {"extend_params", extendParams}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.trade.create"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Huabei/Models/AlipayTradeCreateResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Huabei/Models/AlipayTradeCreateResponse.cs new file mode 100644 index 0000000..537bd49 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Huabei/Models/AlipayTradeCreateResponse.cs @@ -0,0 +1,45 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Huabei.Models +{ + public class AlipayTradeCreateResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("out_trade_no")] + [Validation(Required=true)] + public string OutTradeNo { get; set; } + + [NameInMap("trade_no")] + [Validation(Required=true)] + public string TradeNo { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Huabei/Models/HuabeiConfig.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Huabei/Models/HuabeiConfig.cs new file mode 100644 index 0000000..ddc73b7 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Huabei/Models/HuabeiConfig.cs @@ -0,0 +1,22 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Huabei.Models +{ + public class HuabeiConfig : TeaModel { + [NameInMap("hb_fq_num")] + [Validation(Required=true)] + public string HbFqNum { get; set; } + + [NameInMap("hb_fq_seller_percent")] + [Validation(Required=true)] + public string HbFqSellerPercent { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Page/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Page/Client.cs new file mode 100644 index 0000000..fe1470a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Page/Client.cs @@ -0,0 +1,139 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Payment.Page.Models; + +namespace Alipay.EasySDK.Payment.Page +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + + public AlipayTradePagePayResponse Pay(string subject, string outTradeNo, string totalAmount, string returnUrl) + { + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.page.pay"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + {"product_code", "FAST_INSTANT_TRADE_PAY"}, + }; + Dictionary textParams = new Dictionary + { + {"return_url", returnUrl}, + }; + string sign = this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey")); + Dictionary response = new Dictionary + { + {"body", this._kernel.GeneratePage("POST", systemParams, bizParams, textParams, sign)}, + }; + return TeaModel.ToObject(response); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Page/Models/AlipayTradePagePayResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Page/Models/AlipayTradePagePayResponse.cs new file mode 100644 index 0000000..70f4661 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Page/Models/AlipayTradePagePayResponse.cs @@ -0,0 +1,21 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Page.Models +{ + public class AlipayTradePagePayResponse : TeaModel { + /// + /// 订单信息,Form表单形式 + /// + [NameInMap("body")] + [Validation(Required=true)] + public string Body { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Wap/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Wap/Client.cs new file mode 100644 index 0000000..cbd631e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Wap/Client.cs @@ -0,0 +1,140 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Payment.Wap.Models; + +namespace Alipay.EasySDK.Payment.Wap +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + + public AlipayTradeWapPayResponse Pay(string subject, string outTradeNo, string totalAmount, string quitUrl, string returnUrl) + { + Dictionary systemParams = new Dictionary + { + {"method", "alipay.trade.wap.pay"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"subject", subject}, + {"out_trade_no", outTradeNo}, + {"total_amount", totalAmount}, + {"quit_url", quitUrl}, + {"product_code", "QUICK_WAP_WAY"}, + }; + Dictionary textParams = new Dictionary + { + {"return_url", returnUrl}, + }; + string sign = this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey")); + Dictionary response = new Dictionary + { + {"body", this._kernel.GeneratePage("POST", systemParams, bizParams, textParams, sign)}, + }; + return TeaModel.ToObject(response); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Wap/Models/AlipayTradeWapPayResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Wap/Models/AlipayTradeWapPayResponse.cs new file mode 100644 index 0000000..d1351cc --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Payment/Wap/Models/AlipayTradeWapPayResponse.cs @@ -0,0 +1,21 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Payment.Wap.Models +{ + public class AlipayTradeWapPayResponse : TeaModel { + /// + /// 订单信息,Form表单形式 + /// + [NameInMap("body")] + [Validation(Required=true)] + public string Body { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Security/TextRisk/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Security/TextRisk/Client.cs new file mode 100644 index 0000000..dae3a74 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Security/TextRisk/Client.cs @@ -0,0 +1,314 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Security.TextRisk.Models; + +namespace Alipay.EasySDK.Security.TextRisk +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipaySecurityRiskContentDetectResponse Detect(string content) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.security.risk.content.detect"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"content", content}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, "alipay.security.risk.content.detect"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task DetectAsync(string content) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", "alipay.security.risk.content.detect"}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + Dictionary bizParams = new Dictionary + { + {"content", content}, + }; + Dictionary textParams = new Dictionary(){}; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.security.risk.content.detect"); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Security/TextRisk/Models/AlipaySecurityRiskContentDetectResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Security/TextRisk/Models/AlipaySecurityRiskContentDetectResponse.cs new file mode 100644 index 0000000..9be40fd --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Security/TextRisk/Models/AlipaySecurityRiskContentDetectResponse.cs @@ -0,0 +1,49 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Security.TextRisk.Models +{ + public class AlipaySecurityRiskContentDetectResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + [NameInMap("action")] + [Validation(Required=true)] + public string Action { get; set; } + + [NameInMap("keywords")] + [Validation(Required=true)] + public List Keywords { get; set; } + + [NameInMap("unique_id")] + [Validation(Required=true)] + public string UniqueId { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Util/AES/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Util/AES/Client.cs new file mode 100644 index 0000000..883dbe2 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Util/AES/Client.cs @@ -0,0 +1,114 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + + +namespace Alipay.EasySDK.Util.AES +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + + public string Decrypt(string cipherText) + { + return this._kernel.AesDecrypt(cipherText, this._kernel.GetConfig("encryptKey")); + } + + public string Encrypt(string plainText) + { + return this._kernel.AesEncrypt(plainText, this._kernel.GetConfig("encryptKey")); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Util/Generic/Client.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Util/Generic/Client.cs new file mode 100644 index 0000000..4bed55f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Util/Generic/Client.cs @@ -0,0 +1,304 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +using Tea; +using Tea.Utils; + +using Alipay.EasySDK.Util.Generic.Models; + +namespace Alipay.EasySDK.Util.Generic +{ + public class Client + { + protected Alipay.EasySDK.Kernel.Client _kernel; + + public Client(Alipay.EasySDK.Kernel.Client kernel) + { + this._kernel = kernel; + } + + public AlipayOpenApiGenericResponse Execute(string method, Dictionary textParams, Dictionary bizParams) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", method}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = TeaCore.DoAction(request_, runtime_); + + Dictionary respMap = this._kernel.ReadAsJson(response_, method); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + public async Task ExecuteAsync(string method, Dictionary textParams, Dictionary bizParams) + { + Dictionary runtime_ = new Dictionary + { + {"ignoreSSL", this._kernel.GetConfig("ignoreSSL")}, + {"httpProxy", this._kernel.GetConfig("httpProxy")}, + {"connectTimeout", 15000}, + {"readTimeout", 15000}, + {"retry", new Dictionary + { + {"maxAttempts", 0}, + }}, + }; + + TeaRequest _lastRequest = null; + Exception _lastException = null; + long _now = System.DateTime.Now.Millisecond; + int _retryTimes = 0; + while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now)) + { + if (_retryTimes > 0) + { + int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes); + if (backoffTime > 0) + { + TeaCore.Sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try + { + TeaRequest request_ = new TeaRequest(); + Dictionary systemParams = new Dictionary + { + {"method", method}, + {"app_id", this._kernel.GetConfig("appId")}, + {"timestamp", this._kernel.GetTimestamp()}, + {"format", "json"}, + {"version", "1.0"}, + {"alipay_sdk", this._kernel.GetSdkVersion()}, + {"charset", "UTF-8"}, + {"sign_type", this._kernel.GetConfig("signType")}, + {"app_cert_sn", this._kernel.GetMerchantCertSN()}, + {"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()}, + }; + request_.Protocol = this._kernel.GetConfig("protocol"); + request_.Method = "POST"; + request_.Pathname = "/gateway.do"; + request_.Headers = new Dictionary + { + {"host", this._kernel.GetConfig("gatewayHost")}, + {"content-type", "application/x-www-form-urlencoded;charset=utf-8"}, + }; + request_.Query = this._kernel.SortMap(TeaConverter.merge + ( + new Dictionary() + { + {"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))}, + }, + systemParams, + textParams + )); + request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_); + + Dictionary respMap = await this._kernel.ReadAsJsonAsync(response_, method); + if (this._kernel.IsCertMode()) + { + if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap)))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + else + { + if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey"))) + { + return TeaModel.ToObject(this._kernel.ToRespModel(respMap)); + } + } + throw new TeaException(new Dictionary + { + {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, + }); + } + catch (Exception e) + { + if (TeaCore.IsRetryable(e)) + { + _lastException = e; + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest, _lastException); + } + + + /// + /// ISV代商户代用,指定appAuthToken + /// + /// 代调用token + /// 本客户端,便于链式调用 + public Client Agent(string appAuthToken) + { + _kernel.InjectTextParam("app_auth_token", appAuthToken); + return this; + } + + /// + /// 用户授权调用,指定authToken + /// + /// 用户授权token + /// 本客户端,便于链式调用 + public Client Auth(string authToken) + { + _kernel.InjectTextParam("auth_token", authToken); + return this; + } + + /// + /// 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + /// + /// 异步通知回调地址,例如:https://www.test.com/callback + /// 本客户端,便于链式调用 + public Client AsyncNotify(string url) + { + _kernel.InjectTextParam("notify_url", url); + return this; + } + + /// + /// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + /// + /// 后端系统测试地址 + /// 本客户端,便于链式调用 + public Client Route(string testUrl) + { + _kernel.InjectTextParam("ws_service_url", testUrl); + return this; + } + + /// + /// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// + /// 业务请求参数名称(biz_content下的字段名,比如timeout_express) + /// + /// 业务请求参数的值,一个可以序列化成JSON的对象 + /// 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用string储存 + /// 如果该字段是一个数值型类型(比如:Number),请使用long储存 + /// 如果该字段是一个复杂类型,请使用嵌套的Dictionary指定各下级字段的值 + /// 如果该字段是一个数组,请使用List储存各个值 + /// 对于更复杂的情况,也支持Dictionary和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + /// + /// 本客户端,便于链式调用 + public Client Optional(string key, object value) + { + _kernel.InjectBizParam(key, value); + return this; + } + + /// + /// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + /// optional方法的批量版本 + /// + /// 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + /// 本客户端,便于链式调用 + public Client BatchOptional(Dictionary optionalArgs) + { + foreach (var pair in optionalArgs) + { + _kernel.InjectBizParam(pair.Key, pair.Value); + } + return this; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Util/Generic/Models/AlipayOpenApiGenericResponse.cs b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Util/Generic/Models/AlipayOpenApiGenericResponse.cs new file mode 100644 index 0000000..73b0c1d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/AlipayEasySDK/Util/Generic/Models/AlipayOpenApiGenericResponse.cs @@ -0,0 +1,37 @@ +// This file is auto-generated, don't edit it. Thanks. + +using System; +using System.Collections.Generic; +using System.IO; + +using Tea; + +namespace Alipay.EasySDK.Util.Generic.Models +{ + public class AlipayOpenApiGenericResponse : TeaModel { + /// + /// 响应原始字符串 + /// + [NameInMap("http_body")] + [Validation(Required=true)] + public string HttpBody { get; set; } + + [NameInMap("code")] + [Validation(Required=true)] + public string Code { get; set; } + + [NameInMap("msg")] + [Validation(Required=true)] + public string Msg { get; set; } + + [NameInMap("sub_code")] + [Validation(Required=true)] + public string SubCode { get; set; } + + [NameInMap("sub_msg")] + [Validation(Required=true)] + public string SubMsg { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/README.md b/serve/vendor/alipaysdk/easysdk/csharp/README.md new file mode 100644 index 0000000..2851f96 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/README.md @@ -0,0 +1,248 @@ +[![NuGet](https://badge.fury.io/nu/AlipayEasySDK.svg)](https://badge.fury.io/nu/AlipayEasySDK) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk?ref=badge_shield) + +欢迎使用 Alipay **Easy** SDK for .NET 。 + +Alipay Esay SDK for .NET让您不用复杂编程即可访支付宝开放平台开放的各项常用能力,SDK可以自动帮您满足能力调用过程中所需的证书校验、加签、验签、发送HTTP请求等非功能性要求。 + +下面向您介绍Alipay Easy SDK for .NET 的基本设计理念和使用方法。 + +## 设计理念 +不同于原有的[Alipay SDK](https://github.com/alipay/alipay-sdk-net-all)通用而全面的设计理念,Alipay Easy SDK对开放能力的API进行了更加贴近高频场景的精心设计与裁剪,简化了服务端调用方式,让调用API像使用语言内置的函数一样简便。 + +同时,您也不必担心面向高频场景提炼的API可能无法完全契合自己的个性化场景,Alipay Easy SDK支持灵活的动态扩展方式,同样可以满足低频参数、低频API的使用需求。 + +Alipay Easy SDK提供了与[能力地图](https://opendocs.alipay.com/mini/00am3f)相对应的代码组织结构,让开发者可以快速找到不同能力对应的API。 + +Alipay Easy SDK主要目标是提升开发者在**服务端**集成支付宝开放平台开放的各类核心能力的效率。 + +## 环境要求 +1. Alipay Easy SDK for .NET基于`.Net Standard 2.0`开发,支持`.Net Framework 4.6.1`、.`Net Core 2.0`及其以上版本 + +2. 使用 Alipay Easy SDK for .NET 之前 ,您需要先前往[支付宝开发平台-开发者中心](https://openhome.alipay.com/platform/developerIndex.htm)完成开发者接入的一些准备工作,包括创建应用、为应用添加功能包、设置应用的接口加签方式等。 + +3. 准备工作完成后,注意保存如下信息,后续将作为使用SDK的输入。 + +* 加签模式为公钥证书模式时(推荐) + +`AppId`、`应用的私钥`、`应用公钥证书文件`、`支付宝公钥证书文件`、`支付宝根证书文件` + +* 加签模式为公钥模式时 + +`AppId`、`应用的私钥`、`支付宝公钥` + +## 安装依赖 +### 通过[NuGet](https://www.nuget.org/packages/AlipayEasySDK/)程序包管理器在线安装依赖(推荐) +* 在 `解决方案资源管理器面板` 中右击您的项目选择 `管理 NuGet 程序包` 菜单,在打开的 `NuGet 管理面板` 中点击 `浏览` 选项卡输入 `AlipayEasySDK`,在下方列表中选择 `Authors` 为 `antopen` 由官方发布的**最新稳定版**NuGet包,点击 **安装** 即可。 + +* 或者通过 .NET CLI 工具来安装 + > dotnet add package AlipayEasySDK + +### 离线安装NuGet包(适用于自己修改源码后的本地重新打包安装) +1. 使用`Visual Studio`打开本`README.md`所在文件夹下的`AlipayEasySDK.sln`解决方案,在`生成`菜单栏下,执行`全部重新生成`。 +2. 在`AlipayEasySDK/bin/Debug`或`AlipayEasySDK/bin/Release`目录下,找到`AlipayEasySDK.[version].nupkg`文件,该文件即为本SDK的NuGet离线包。 +3. 参照[NuGet离线安装程序包使用指南](https://yq.aliyun.com/articles/689227),在您的.NET应用项目工程中引入本SDK的NuGet离线包,即可完成SDK的依赖安装。 + +## 快速开始 +### 普通调用 +以下这段代码示例向您展示了使用Alipay Easy SDK for .NET调用一个API的3个主要步骤: + +1. 设置参数(全局只需设置一次)。 +2. 发起API调用。 +3. 处理响应或异常。 + +```charp +using System; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Kernel; +using Alipay.EasySDK.Kernel.Util; +using Alipay.EasySDK.Payment.FaceToFace.Models; + +namespace SDKDemo +{ + class Program + { + static void Main(string[] args) + { + // 1. 设置参数(全局只需设置一次) + Factory.SetOptions(GetConfig()); + try + { + // 2. 发起API调用(以创建当面付收款二维码为例) + AlipayTradePrecreateResponse response = Factory.Payment.FaceToFace() + .PreCreate("Apple iPhone11 128G", "2234567234890", "5799.00"); + // 3. 处理响应或异常 + if (ResponseChecker.Success(response)) + { + Console.WriteLine("调用成功"); + } + else + { + Console.WriteLine("调用失败,原因:" + response.Msg + "," + response.SubMsg); + } + } + catch (Exception ex) + { + Console.WriteLine("调用遭遇异常,原因:" + ex.Message); + throw ex; + } + } + + static private Config GetConfig() + { + return new Config() + { + Protocol = "https", + GatewayHost = "openapi.alipay.com", + SignType = "RSA2", + + AppId = "<-- 请填写您的AppId,例如:2019091767145019 -->", + + // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中 + MerchantPrivateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->", + + MerchantCertPath = "<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->", + AlipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->", + AlipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt -->", + + // 如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可 + // AlipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->" + + //可设置异步通知接收服务地址(可选) + NotifyUrl = "<-- 请填写您的支付类接口异步通知接收服务地址,例如:https://www.test.com/callback -->", + + //可设置AES密钥,调用AES加解密相关接口时需要(可选) + EncryptKey = "<-- 请填写您的AES密钥,例如:aa4BtZ4tspm2wnXLb1ThQA== -->" + }; + } + } +} +``` + +### 扩展调用 +#### ISV代调用 + +```csharp +Factory.Payment.FaceToFace() + //调用Agent扩展方法,设置app_auth_token,完成ISV代调用 + .Agent("ca34ea491e7146cc87d25fca24c4cD11") + .PreCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +#### 设置独立的异步通知地址 + +```csharp +Factory.Payment.FaceToFace() + // 调用AsyncNotify扩展方法,可以为每此API调用,设置独立的异步通知地址 + // 此处设置的异步通知地址的优先级高于全局Config中配置的异步通知地址 + .AsyncNotify("https://www.test.com/callback") + .PreCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +#### 设置可选业务参数 + +```csharp +List goodsDetailList = new List(); +Dictionary goodsDetail = new Dictionary +{ + { "goods_id", "apple-01" }, + { "goods_name", "Apple iPhone11 128G" }, + { "quantity", 1 }, + { "price", "5799.00" } +}; +goodsDetailList.Add(goodsDetail); + +Factory.Payment.FaceToFace() + // 调用Optional扩展方法,完成可选业务参数(biz_content下的可选字段)的设置 + .Optional("seller_id", "2088102146225135") + .Optional("discountable_amount", "8.88") + .Optional("goods_detail", goodsDetailList) + .PreCreate("Apple iPhone11 128G", "2234567890", "5799.00"); + +Dictionary optionalArgs = new Dictionary +{ + { "seller_id", "2088102146225135" }, + { "discountable_amount", "8.88" }, + { "goods_detail", goodsDetailList } +}; + +Factory.Payment.FaceToFace() + // 也可以调用BatchOptional扩展方法,批量设置可选业务参数(biz_content下的可选字段) + .BatchOptional(optionalArgs) + .PreCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +#### 多种扩展灵活组合 + +```csharp +// 多种扩展方式可灵活组装(对扩展方法的调用顺序没有要求) +Factory.Payment.FaceToFace() + .Agent("ca34ea491e7146cc87d25fca24c4cD11") + .AsyncNotify("https://www.test.com/callback") + .Optional("seller_id", "2088102146225135") + .PreCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +## API组织规范 +在Alipay Easy SDK中,API的引用路径与能力地图的组织层次一致,遵循如下规则 + +> Factory.能力名称.场景名称().接口方法名称( ... ) + +比如,如果您想要使用[能力地图](https://opendocs.alipay.com/mini/00am3f)中`营销能力`下的`模板消息`场景中的`小程序发送模板消息`,只需按如下形式编写调用代码即可(不同编程语言的连接符号可能不同)。 + +`Factory.Marketing.TemplateMessage().send( ... )` + +其中,接口方法名称通常是对其依赖的OpenAPI功能的一个最简概况,接口方法的出入参与OpenAPI中同名参数含义一致,可参照OpenAPI相关参数的使用说明。 + +Alipay Easy SDK将致力于保持良好的API命名,以符合开发者的编程直觉。 + +## 已支持的API列表 + +| 能力类别 | 场景类别 | 接口方法名称 | 调用的OpenAPI名称 | +|-----------|-----------------|------------------------|-----------------------------------------------------------| +| Base | OAuth | getToken | alipay\.system\.oauth\.token | +| Base | OAuth | refreshToken | alipay\.system\.oauth\.token | +| Base | Qrcode | create | alipay\.open\.app\.qrcode\.create | +| Base | Image | upload | alipay\.offline\.material\.image\.upload | +| Base | Video | upload | alipay\.offline\.material\.image\.upload | +| Member | Identification | init | alipay\.user\.certify\.open\.initialize | +| Member | Identification | certify | alipay\.user\.certify\.open\.certify | +| Member | Identification | query | alipay\.user\.certify\.open\.query | +| Payment | Common | create | alipay\.trade\.create | +| Payment | Common | query | alipay\.trade\.query | +| Payment | Common | refund | alipay\.trade\.refund | +| Payment | Common | close | alipay\.trade\.close | +| Payment | Common | cancel | alipay\.trade\.cancel | +| Payment | Common | queryRefund | alipay\.trade\.fastpay\.refund\.query | +| Payment | Common | downloadBill | alipay\.data\.dataservice\.bill\.downloadurl\.query | +| Payment | Common | verifyNotify | - | +| Payment | Huabei | create | alipay\.trade\.create | +| Payment | FaceToFace | pay | alipay\.trade\.pay | +| Payment | FaceToFace | precreate | alipay\.trade\.precreate | +| Payment | App | pay | alipay\.trade\.app\.pay | +| Payment | Page | pay | alipay\.trade\.page\.pay | +| Payment | Wap | pay | alipay\.trade\.wap\.pay | +| Security | TextRisk | detect | alipay\.security\.risk\.content\.detect | +| Marketing | Pass | createTemplate | alipay\.pass\.template\.add | +| Marketing | Pass | updateTemplate | alipay\.pass\.template\.update | +| Marketing | Pass | addInstance | alipay\.pass\.instance\.add | +| Marketing | Pass | updateInstance | alipay\.pass\.instance\.update | +| Marketing | TemplateMessage | send | alipay\.open\.app\.mini\.templatemessage\.send | +| Marketing | OpenLife | createImageTextContent | alipay\.open\.public\.message\.content\.create | +| Marketing | OpenLife | modifyImageTextContent | alipay\.open\.public\.message\.content\.modify | +| Marketing | OpenLife | sendText | alipay\.open\.public\.message\.total\.send | +| Marketing | OpenLife | sendImageText | alipay\.open\.public\.message\.total\.send | +| Marketing | OpenLife | sendSingleMessage | alipay\.open\.public\.message\.single\.send | +| Marketing | OpenLife | recallMessage | alipay\.open\.public\.life\.msg\.recall | +| Marketing | OpenLife | setIndustry | alipay\.open\.public\.template\.message\.industry\.modify | +| Marketing | OpenLife | getIndustry | alipay\.open\.public\.setting\.category\.query | +| Util | AES | decrypt | - | +| Util | AES | encrypt | - | +| Util | Generic | execute | - | + +> 注:更多高频场景的API持续更新中,敬请期待。 + +## 文档 +[API Doc](./../APIDoc.md) + +[Alipay Easy SDK](./../README.md) diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/Image/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/Image/ClientTest.cs new file mode 100644 index 0000000..88a5b81 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/Image/ClientTest.cs @@ -0,0 +1,32 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Base.Image.Models; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Base.Image +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestUpload() + { + AlipayOfflineMaterialImageUploadResponse response = Factory.Base.Image().Upload( + "测试图片", TestAccount.GetSolutionBasePath() + "/UnitTest/Fixture/sample.png"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.NotNull(response.ImageId); + Assert.IsTrue(response.ImageUrl.StartsWith("https://")); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/OAuth/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/OAuth/ClientTest.cs new file mode 100644 index 0000000..6bd7a87 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/OAuth/ClientTest.cs @@ -0,0 +1,42 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Base.OAuth.Models; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Base.OAuth +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestGetToken() + { + AlipaySystemOauthTokenResponse response = Factory.Base.OAuth().GetToken("1234567890"); + + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40002"); + Assert.AreEqual(response.Msg, "Invalid Arguments"); + Assert.AreEqual(response.SubCode, "isv.code-invalid"); + Assert.AreEqual(response.SubMsg, "授权码code无效"); + Assert.NotNull(response.HttpBody); + } + + [Test] + public void TestRefreshToken() + { + AlipaySystemOauthTokenResponse response = Factory.Base.OAuth().RefreshToken("1234567890"); + + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40002"); + Assert.AreEqual(response.Msg, "Invalid Arguments"); + Assert.AreEqual(response.SubCode, "isv.refresh-token-invalid"); + Assert.AreEqual(response.SubMsg, "刷新令牌refresh_token无效"); + Assert.NotNull(response.HttpBody); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/Qrcode/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/Qrcode/ClientTest.cs new file mode 100644 index 0000000..4f01d96 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/Qrcode/ClientTest.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Base.Qrcode.Models; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Base.Qrcode +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestCreate() + { + AlipayOpenAppQrcodeCreateResponse response = Factory.Base.Qrcode().Create( + "https://opendocs.alipay.com", "ageIndex=1", "文档站点"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.NotNull(response.QrCodeUrl); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/Video/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/Video/ClientTest.cs new file mode 100644 index 0000000..37d6e05 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Base/Video/ClientTest.cs @@ -0,0 +1,32 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Base.Video.Models; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Base.Video +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestUpload() + { + AlipayOfflineMaterialImageUploadResponse response = Factory.Base.Video().Upload( + "测试视频", TestAccount.GetSolutionBasePath() + "/UnitTest/Fixture/sample.mp4"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.NotNull(response.ImageId); + Assert.IsTrue(response.ImageUrl.StartsWith("https://")); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Factory/FactoryTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Factory/FactoryTest.cs new file mode 100644 index 0000000..81373ca --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Factory/FactoryTest.cs @@ -0,0 +1,33 @@ +using System; +using NUnit.Framework; +using Alipay.EasySDK.Payment.Common.Models; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.FactoryTest +{ + public class FactoryTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestGetClient() + { + AlipayTradeFastpayRefundQueryResponse response = Factory.GetClient() + .QueryRefund("64628156-f784-4572-9540-485b7c91b850", "64628156-f784-4572-9540-485b7c91b850"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.RefundAmount, "0.01"); + Assert.AreEqual(response.TotalAmount, "0.01"); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/alipayCertPublicKey_RSA2.crt b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/alipayCertPublicKey_RSA2.crt new file mode 100644 index 0000000..fd7c0a0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/alipayCertPublicKey_RSA2.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIQIBkJAnXy/rwX3BTZaKNEzjANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MTkwNwYDVQQDDDBBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IENs +YXNzIDIgUjEwHhcNMTkwOTAyMTI0NDIyWhcNMjEwOTAxMTI0NDIyWjB0MQswCQYDVQQGEwJDTjEP +MA0GA1UECgwG6ZKf6ZuoMQ8wDQYDVQQLDAZBbGlwYXkxQzBBBgNVBAMMOuaUr+S7mOWunSjkuK3l +m70p572R57uc5oqA5pyv5pyJ6ZmQ5YWs5Y+4LTIwODgwMDI2NTY3MTg5MjAwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDQxh7MsF7bsPyQlToJWOPlmGfqUerZI2o2725LUqrabGYOaAgx +a8OAm6sFXoq6TykRltIBEmAjYjMYudQelwxSv8NhQ1eLEFrY7o2Z3TQ+y8lvlLmvqWnEMzOqq4Fc +UN6gzd1nissGVtzUkmx9ErB+89g6WAKV1bFCZBQHIjzfMIqcZkddUZ4SiksMKB/ncKFOJPJf2CUI +i31URny3WlIoC44jG1SiX2sPKdbkbsSGQcDfGIpNRQBNJxlXX/8Y8D7RrFCWHtjh4ONSMT29+xjS +8HNM0gSR2y4QKXyRupXrNY9yTTtkPhQIEjfSjsQPnuM+3b7VFd3GSDcDbvskNRNLAgMBAAGjEjAQ +MA4GA1UdDwEB/wQEAwID+DANBgkqhkiG9w0BAQsFAAOCAQEAf8Qx2UsLFqPDTxKk9eT0np75NqJ8 +MexTuPJ/gC+Lp20YzEUyYW2rPlDFhDmFztlqk9RdynLRqyjB5dOAdWlxhgDlEqB9E6DvkVKtpIaL +7h7zqJei9gb/STAyf5vTVWR/WTmOhp3vQhaj7+lt14JwK/ELYMdBLD2IdmFis7YdzhCsGo7Y4FPb +BuHCV8Ngfaf2PvDlKaFOVzDg8tGnMBbAOgpe+mhxKUdhNG3eXcO0Z813rNIC15YAvWm68tNAwuZJ +rIVgK+049WUojwUJxOwVyzewob/8Gx7o8ipIV5E/bMrduSvigsj7OmNzwQ5/iSm31dfcXi3fOXXz +BLMb888PlA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE4jCCAsqgAwIBAgIIYsSr5bKAMl8wDQYJKoZIhvcNAQELBQAwejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMjE0MzQxNVoXDTM3MTEyNjE0MzQxNVowgYIxCzAJBgNVBAYTAkNOMRYwFAYDVQQKDA1BbnQgRmluYW5jaWFsMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE5MDcGA1UEAwwwQW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDbGFzcyAyIFIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsLMfYaoRoPRbmDcAfXPCmKf43pWRN5yTXa/KJWO0l+mrgQvs89bANEvbDUxlkGwycwtwi5DgBuBgVhLliXu+R9CYgr2dXs8D8Hx/gsggDcyGPLmVrDOnL+dyeauheARZfA3du60fwEwwbGcVIpIxPa/4n3IS/ElxQa6DNgqxh8J9Xwh7qMGl0JK9+bALuxf7B541Gr4p0WENG8fhgjBV4w4ut9eQLOoa1eddOUSZcy46Z7allwowwgt7b5VFfx/P1iKJ3LzBMgkCK7GZ2kiLrL7RiqV+h482J7hkJD+ardoc6LnrHO/hIZymDxok+VH9fVeUdQa29IZKrIDVj65THQIDAQABo2MwYTAfBgNVHSMEGDAWgBRfdLQEwE8HWurlsdsio4dBspzhATAdBgNVHQ4EFgQUSqHkYINtUSAtDPnS8XoyoP9p7qEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAIQ8TzFy4bVIVb8+WhHKCkKNPcJe2EZuIcqvRoi727lZTJOfYy/JzLtckyZYfEI8J0lasZ29wkTta1IjSo+a6XdhudU4ONVBrL70U8Kzntplw/6TBNbLFpp7taRALjUgbCOk4EoBMbeCL0GiYYsTS0mw7xdySzmGQku4GTyqutIGPQwKxSj9iSFw1FCZqr4VP4tyXzMUgc52SzagA6i7AyLedd3tbS6lnR5BL+W9Kx9hwT8L7WANAxQzv/jGldeuSLN8bsTxlOYlsdjmIGu/C9OWblPYGpjQQIRyvs4Cc/mNhrh+14EQgwuemIIFDLOgcD+iISoN8CqegelNcJndFw1PDN6LkVoiHz9p7jzsge8RKay/QW6C03KNDpWZEUCgCUdfHfo8xKeR+LL1cfn24HKJmZt8L/aeRZwZ1jwePXFRVtiXELvgJuM/tJDIFj2KD337iV64fWcKQ/ydDVGqfDZAdcU4hQdsrPWENwPTQPfVPq2NNLMyIH9+WKx9Ed6/WzeZmIy5ZWpX1TtTolo6OJXQFeItMAjHxW/ZSZTok5IS3FuRhExturaInnzjYpx50a6kS34c5+c8hYq7sAtZ/CNLZmBnBCFDaMQqT8xFZJ5uolUaSeXxg7JFY1QsYp5RKvj4SjFwCGKJ2+hPPe9UyyltxOidNtxjaknOCeBHytOr +-----END CERTIFICATE----- diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/alipayRootCert.crt b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/alipayRootCert.crt new file mode 100644 index 0000000..76417c5 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/alipayRootCert.crt @@ -0,0 +1,88 @@ +-----BEGIN CERTIFICATE----- +MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG +EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw +MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO +UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE +MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT +V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti +W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ +MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b +53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI +pDoiVhsLwg== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIF0zCCA7ugAwIBAgIIH8+hjWpIDREwDQYJKoZIhvcNAQELBQAwejELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMTEzNDg0MFoXDTM4MDIyODEzNDg0 +MFowejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNV +BAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAtytTRcBNuur5h8xuxnlKJetT65cHGemGi8oD+beHFPTk +rUTlFt9Xn7fAVGo6QSsPb9uGLpUFGEdGmbsQ2q9cV4P89qkH04VzIPwT7AywJdt2 +xAvMs+MgHFJzOYfL1QkdOOVO7NwKxH8IvlQgFabWomWk2Ei9WfUyxFjVO1LVh0Bp +dRBeWLMkdudx0tl3+21t1apnReFNQ5nfX29xeSxIhesaMHDZFViO/DXDNW2BcTs6 +vSWKyJ4YIIIzStumD8K1xMsoaZBMDxg4itjWFaKRgNuPiIn4kjDY3kC66Sl/6yTl +YUz8AybbEsICZzssdZh7jcNb1VRfk79lgAprm/Ktl+mgrU1gaMGP1OE25JCbqli1 +Pbw/BpPynyP9+XulE+2mxFwTYhKAwpDIDKuYsFUXuo8t261pCovI1CXFzAQM2w7H +DtA2nOXSW6q0jGDJ5+WauH+K8ZSvA6x4sFo4u0KNCx0ROTBpLif6GTngqo3sj+98 +SZiMNLFMQoQkjkdN5Q5g9N6CFZPVZ6QpO0JcIc7S1le/g9z5iBKnifrKxy0TQjtG +PsDwc8ubPnRm/F82RReCoyNyx63indpgFfhN7+KxUIQ9cOwwTvemmor0A+ZQamRe +9LMuiEfEaWUDK+6O0Gl8lO571uI5onYdN1VIgOmwFbe+D8TcuzVjIZ/zvHrAGUcC +AwEAAaNdMFswCwYDVR0PBAQDAgEGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFF90 +tATATwda6uWx2yKjh0GynOEBMB8GA1UdIwQYMBaAFF90tATATwda6uWx2yKjh0Gy +nOEBMA0GCSqGSIb3DQEBCwUAA4ICAQCVYaOtqOLIpsrEikE5lb+UARNSFJg6tpkf +tJ2U8QF/DejemEHx5IClQu6ajxjtu0Aie4/3UnIXop8nH/Q57l+Wyt9T7N2WPiNq +JSlYKYbJpPF8LXbuKYG3BTFTdOVFIeRe2NUyYh/xs6bXGr4WKTXb3qBmzR02FSy3 +IODQw5Q6zpXj8prYqFHYsOvGCEc1CwJaSaYwRhTkFedJUxiyhyB5GQwoFfExCVHW +05ZFCAVYFldCJvUzfzrWubN6wX0DD2dwultgmldOn/W/n8at52mpPNvIdbZb2F41 +T0YZeoWnCJrYXjq/32oc1cmifIHqySnyMnavi75DxPCdZsCOpSAT4j4lAQRGsfgI +kkLPGQieMfNNkMCKh7qjwdXAVtdqhf0RVtFILH3OyEodlk1HYXqX5iE5wlaKzDop +PKwf2Q3BErq1xChYGGVS+dEvyXc/2nIBlt7uLWKp4XFjqekKbaGaLJdjYP5b2s7N +1dM0MXQ/f8XoXKBkJNzEiM3hfsU6DOREgMc1DIsFKxfuMwX3EkVQM1If8ghb6x5Y +jXayv+NLbidOSzk4vl5QwngO/JYFMkoc6i9LNwEaEtR9PhnrdubxmrtM+RjfBm02 +77q3dSWFESFQ4QxYWew4pHE0DpWbWy/iMIKQ6UZ5RLvB8GEcgt8ON7BBJeMc+Dyi +kT9qhqn+lw== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIICiDCCAgygAwIBAgIIQX76UsB/30owDAYIKoZIzj0EAwMFADB6MQswCQYDVQQG +EwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UECwwXQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNpYWwgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgRTEwHhcNMTkwNDI4MTYyMDQ0WhcNNDkwNDIwMTYyMDQ0 +WjB6MQswCQYDVQQGEwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UE +CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNp +YWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRTEwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAASCCRa94QI0vR5Up9Yr9HEupz6hSoyjySYqo7v837KnmjveUIUNiuC9pWAU +WP3jwLX3HkzeiNdeg22a0IZPoSUCpasufiLAnfXh6NInLiWBrjLJXDSGaY7vaokt +rpZvAdmjXTBbMAsGA1UdDwQEAwIBBjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRZ +4ZTgDpksHL2qcpkFkxD2zVd16TAfBgNVHSMEGDAWgBRZ4ZTgDpksHL2qcpkFkxD2 +zVd16TAMBggqhkjOPQQDAwUAA2gAMGUCMQD4IoqT2hTUn0jt7oXLdMJ8q4vLp6sg +wHfPiOr9gxreb+e6Oidwd2LDnC4OUqCWiF8CMAzwKs4SnDJYcMLf2vpkbuVE4dTH +Rglz+HGcTLWsFs4KxLsq7MuU+vJTBUeDJeDjdA== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIUEMdk6dVgOEIS2cCP0Q43P90Ps5YwDQYJKoZIhvcNAQEF +BQAwajELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM +E0NoaW5hIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMMH2lUcnVzQ2hpbmEgQ2xhc3Mg +MiBSb290IENBIC0gRzMwHhcNMTMwNDE4MDkzNjU2WhcNMzMwNDE4MDkzNjU2WjBq +MQswCQYDVQQGEwJDTjETMBEGA1UECgwKaVRydXNDaGluYTEcMBoGA1UECwwTQ2hp +bmEgVHJ1c3QgTmV0d29yazEoMCYGA1UEAwwfaVRydXNDaGluYSBDbGFzcyAyIFJv +b3QgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPPShpV +nJbMqqCw6Bz1kehnoPst9pkr0V9idOwU2oyS47/HjJXk9Rd5a9xfwkPO88trUpz5 +4GmmwspDXjVFu9L0eFaRuH3KMha1Ak01citbF7cQLJlS7XI+tpkTGHEY5pt3EsQg +wykfZl/A1jrnSkspMS997r2Gim54cwz+mTMgDRhZsKK/lbOeBPpWtcFizjXYCqhw +WktvQfZBYi6o4sHCshnOswi4yV1p+LuFcQ2ciYdWvULh1eZhLxHbGXyznYHi0dGN +z+I9H8aXxqAQfHVhbdHNzi77hCxFjOy+hHrGsyzjrd2swVQ2iUWP8BfEQqGLqM1g +KgWKYfcTGdbPB1MCAwEAAaNjMGEwHQYDVR0OBBYEFG/oAMxTVe7y0+408CTAK8hA +uTyRMB8GA1UdIwQYMBaAFG/oAMxTVe7y0+408CTAK8hAuTyRMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBLnUTfW7hp +emMbuUGCk7RBswzOT83bDM6824EkUnf+X0iKS95SUNGeeSWK2o/3ALJo5hi7GZr3 +U8eLaWAcYizfO99UXMRBPw5PRR+gXGEronGUugLpxsjuynoLQu8GQAeysSXKbN1I +UugDo9u8igJORYA+5ms0s5sCUySqbQ2R5z/GoceyI9LdxIVa1RjVX8pYOj8JFwtn +DJN3ftSFvNMYwRuILKuqUYSHc2GPYiHVflDh5nDymCMOQFcFG3WsEuB+EYQPFgIU +1DHmdZcz7Llx8UOZXX2JupWCYzK1XhJb+r4hK5ncf/w8qGtYlmyJpxk3hr1TfUJX +Yf4Zr0fJsGuv +-----END CERTIFICATE----- \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/appCertPublicKey_2019051064521003.crt b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/appCertPublicKey_2019051064521003.crt new file mode 100644 index 0000000..ad22ab9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/appCertPublicKey_2019051064521003.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIEkzCCA3ugAwIBAgIQICABI1M0G1IN1Hv7M5NTmjANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MTkwNwYDVQQDDDBBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IENs +YXNzIDEgUjEwHhcNMjAwMTIzMDc0NTQ3WhcNMjIwMTIyMDc0NTQ3WjBbMQswCQYDVQQGEwJDTjEP +MA0GA1UECgwG6ZKf6ZuoMQ8wDQYDVQQLDAZBbGlwYXkxKjAoBgNVBAMMITIwODgwMDI2NTY3MTg5 +MjAtMjAxOTA1MTA2NDUyMTAwMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIRaW3zN +ZGJY3oOUL41KMZqcoyI9JyDWG/fyb8qShWgH9NGinO6JeGWWX2pU2b5GKCd1CB6imnbD5U3zvErR +Z6h9Kc9pD4M22MNqnpuFontWuFXhq01MIbuolV5zTw94nrMR4aMPgTt7wX6svcQ8cKyg+v7Xz4DH +QCQOPhtFM3aL1UHsEZhLp+F2xNENTGpphmlV7D50ahnAo3A8Jdkt9ZBIzkWk4CoMdeoYk6BlOETG +XZ93Mc1TKR6cLNPj7LIUKb7xUh4ekaRoky2RP7k9NgBLsZLDjMkqZmzvHHhnstddmq5Er49Ger9b +VHnKsWNMWtN0Oi+ZyWTDcwvACdCgLbcCAwEAAaOCASkwggElMB8GA1UdIwQYMBaAFHEH4gRhFuTl +8mXrMQ/J4PQ8mtWRMB0GA1UdDgQWBBSNSXcCsxvjAa3v5QcTyVZ183CMjzBABgNVHSAEOTA3MDUG +B2CBHAFuAQEwKjAoBggrBgEFBQcCARYcaHR0cDovL2NhLmFsaXBheS5jb20vY3BzLnBkZjAOBgNV +HQ8BAf8EBAMCBsAwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2NhLmFsaXBheS5jb20vY3JsMzcu +Y3JsMGAGCCsGAQUFBwEBBFQwUjAoBggrBgEFBQcwAoYcaHR0cDovL2NhLmFsaXBheS5jb20vY2E2 +LmNlcjAmBggrBgEFBQcwAYYaaHR0cDovL2NhLmFsaXBheS5jb206ODM0MC8wDQYJKoZIhvcNAQEL +BQADggEBAA0l9rTtjEl4uqE4RP4Nd+A0KgM8NmWQHLxsubDRMSeYVFMzrpSm8V9zhlxLmKdFxWP/ +OuY4SHRe8eOSA++5yJc3ihg9B7/ddK2kNTsnaB7Xtvex685kvDDR8DMZmQYeirDThGVPhUeBgPdk +wY0R5KU6mEh2FzT3QIxDzP6t4ssSyYHhFPssZ4PXHFQ5eHzmdpJ81/85crfques67JxAm4CCfldb +bX0DH1BUrPxcnvz4Kj5lKv1qIvBR71yUnrGFOKAVCx04VYK4dTNDI70W9lLgX1aTfLGUBTYiJe/J +Zq/XlYhQP/T7t8HOAaCQFf2hM9tRq62EaL1UbExV2hcAP/E= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/privateKey.json b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/privateKey.json new file mode 100644 index 0000000..39daf4d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/privateKey.json @@ -0,0 +1,4 @@ +{ + "2019022663440152": "<- 已脱敏,如想要执行单元测试,请开发者自行替换TestAccount中的相关账号并在此重新配置新的APPID与私钥的关联 ->", + "2019051064521003": "<- 已脱敏,如想要执行单元测试,请开发者自行替换TestAccount中的相关账号并在此重新配置新的APPID与私钥的关联 ->" +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/sample.mp4 b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/sample.mp4 new file mode 100644 index 0000000..26fb8b2 Binary files /dev/null and b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/sample.mp4 differ diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/sample.png b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/sample.png new file mode 100644 index 0000000..066ec3b Binary files /dev/null and b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Fixture/sample.png differ diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Marketing/OpenLife/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Marketing/OpenLife/ClientTest.cs new file mode 100644 index 0000000..872e4f1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Marketing/OpenLife/ClientTest.cs @@ -0,0 +1,205 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Marketing.OpenLife.Models; +using System.Collections.Generic; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Marketing.OpenLife +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.OpenLife.CONFIG); + } + + [Test] + public void TestCreateImageTextContent() + { + AlipayOpenPublicMessageContentCreateResponse response = Factory.Marketing.OpenLife().CreateImageTextContent("标题", + "http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED", + "示例", "T", "activity", "满100减10", + "关键,热度", "13434343432,xxx@163.com"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.NotNull(response.ContentId); + Assert.NotNull(response.ContentUrl); + } + + [Test] + public void TestModifyImageTextContent() + { + AlipayOpenPublicMessageContentModifyResponse response = Factory.Marketing.OpenLife().ModifyImageTextContent( + "20190510645210035577f788-d6cd-4020-9dba-1a195edb7342", "新标题", + "http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED", + "新示例", "T", "activity", "满100减20", + "关键,热度", "13434343432,xxx@163.com"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.ContentId, "20190510645210035577f788-d6cd-4020-9dba-1a195edb7342"); + Assert.NotNull(response.ContentUrl); + } + + [Test] + public void TestSendText() + { + AlipayOpenPublicMessageTotalSendResponse response = Factory.Marketing.OpenLife().SendText("测试"); + + if (response.Code.Equals("10000")) + { + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.NotNull(response.MessageId); + } + else + { + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40004"); + Assert.AreEqual(response.Msg, "Business Failed"); + Assert.AreEqual(response.SubCode, "PUB.MSG_BATCH_SD_OVER"); + Assert.AreEqual(response.SubMsg, "批量发送消息频率超限"); + Assert.NotNull(response.HttpBody); + Assert.Null(response.MessageId); + } + } + + [Test] + public void TestSendImageText() + { + Article article = new Article + { + ActionName = "测试", + Desc = "测试", + Title = "测试", + ImageUrl = "http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED", + Url = "https://docs.open.alipay.com/api_6/alipay.open.public.message.total.send" + }; + AlipayOpenPublicMessageTotalSendResponse response = Factory.Marketing.OpenLife().SendImageText(new List
{ article }); + + if (response.Code.Equals("10000")) + { + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.NotNull(response.MessageId); + } + else + { + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40004"); + Assert.AreEqual(response.Msg, "Business Failed"); + Assert.AreEqual(response.SubCode, "PUB.MSG_BATCH_SD_OVER"); + Assert.AreEqual(response.SubMsg, "批量发送消息频率超限"); + Assert.NotNull(response.HttpBody); + Assert.Null(response.MessageId); + } + } + + [Test] + public void TestSendSingleMessage() + { + Keyword keyword = new Keyword + { + Color = "#85be53", + Value = "HU7142" + }; + Context context = new Context + { + HeadColor = "#85be53", + Url = "https://docs.open.alipay.com/api_6/alipay.open.public.message.single.send", + ActionName = "查看详情", + Keyword1 = keyword, + Keyword2 = keyword, + First = keyword, + Remark = keyword + }; + Alipay.EasySDK.Marketing.OpenLife.Models.Template template = new Alipay.EasySDK.Marketing.OpenLife.Models.Template + { + TemplateId = "e44cd3e52ffa46b1a50afc145f55d1ea", + Context = context + }; + AlipayOpenPublicMessageSingleSendResponse response = Factory.Marketing.OpenLife().SendSingleMessage( + "2088002656718920", template); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + } + + [Test] + public void TestRecallMessage() + { + AlipayOpenPublicLifeMsgRecallResponse response = Factory.Marketing.OpenLife().RecallMessage("201905106452100327f456f6-8dd2-4a06-8b0e-ec8a3a85c46a"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + } + + [Test] + public void TestSetIndustry() + { + AlipayOpenPublicTemplateMessageIndustryModifyResponse response = Factory.Marketing.OpenLife().SetIndustry( + "10001/20102", "IT科技/IT软件与服务", + "10001/20102", "IT科技/IT软件与服务"); + + if (response.Code.Equals("10000")) + { + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + } + else + { + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40004"); + Assert.AreEqual(response.Msg, "Business Failed"); + Assert.AreEqual(response.SubCode, "3002"); + Assert.AreEqual(response.SubMsg, ("模板消息行业一月只能修改一次")); + Assert.NotNull(response.HttpBody); + } + } + + [Test] + public void TestGetIndustry() + { + AlipayOpenPublicSettingCategoryQueryResponse response = Factory.Marketing.OpenLife().GetIndustry(); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.PrimaryCategory, "IT科技/IT软件与服务"); + Assert.AreEqual(response.SecondaryCategory, "IT科技/IT软件与服务"); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Marketing/Pass/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Marketing/Pass/ClientTest.cs new file mode 100644 index 0000000..2ed33a1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Marketing/Pass/ClientTest.cs @@ -0,0 +1,100 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Marketing.Pass.Models; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Marketing.Pass +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestCreateTemplate() + { + AlipayPassTemplateAddResponse response = Factory.Marketing.Pass().CreateTemplate("123456789", GetTplContent()); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.True(response.Success); + Assert.True(response.Result.Contains("tpl_id")); + } + + [Test] + public void TestUpdateTemplate() + { + AlipayPassTemplateUpdateResponse response = Factory.Marketing.Pass().UpdateTemplate("2020012014534017917956080", GetTplContent()); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.True(response.Success); + Assert.True(response.Result.Contains("tpl_id")); + } + + [Test] + public void TestAddInstance() + { + AlipayPassInstanceAddResponse response = Factory.Marketing.Pass().AddInstance("2020012014534017917956080", "{}", + "1", "{\"partner_id\":\"2088102114633762\",\"out_trade_no\":\"1234567\"}"); + + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40004"); + Assert.AreEqual(response.Msg, "Business Failed"); + Assert.AreEqual(response.SubCode, "KP.AE_ALIPASS_APPID_NOSUPPORT"); + Assert.AreEqual(response.SubMsg, "该AppId不支持"); + Assert.NotNull(response.HttpBody); + Assert.False(response.Success); + Assert.True(response.Result.Contains("该AppId不支持")); + } + + [Test] + public void TestUpdateInstance() + { + AlipayPassInstanceUpdateResponse response = Factory.Marketing.Pass().UpdateInstance("209919213", + "2088918273", "{}", "USED", "8612231273", "wave"); + + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40004"); + Assert.AreEqual(response.Msg, "Business Failed"); + Assert.AreEqual(response.SubCode, "KP.AE_ALIPASS_NOTEXIST"); + Assert.AreEqual(response.SubMsg, "卡券不存在"); + Assert.NotNull(response.HttpBody); + Assert.False(response.Success); + Assert.True(response.Result.Contains("{\"operate\":\"UPDATE\"}")); + } + + private string GetTplContent() + { + return "{\"logo\":\"http://img01.taobaocdn.com/top/i1/LB1NDJuQpXXXXbYXFXXXXXXXXXX\",\"strip\":null,\"icon\":null," + + "\"content\":{\"evoucherInfo\":{\"goodsId\":\"\",\"title\":\"test\",\"type\":\"boardingPass\"," + + "\"product\":\"air\",\"startDate\":\"2020-01-20 13:45:56\",\"endDate\":\"2020-01-25 13:45:56\"," + + "\"operation\":[{\"message\":{\"img\":\"http://img01.taobaocdn.com/top/i1/LB1NDJuQpXXXXbYXFXXXXXXXXXX\"," + + "\"target\":\"\"},\"format\":\"img\",\"messageEncoding\":\"utf-8\",\"altText\":\"\"}]," + + "\"einfo\":{\"logoText\":\"test\",\"headFields\":[{\"key\":\"test\",\"label\":\"测试\",\"value\":\"\"," + + "\"type\":\"text\"}],\"primaryFields\":[{\"key\":\"from\",\"label\":\"测试\",\"value\":\"\",\"type\":\"text\"}," + + "{\"key\":\"to\",\"label\":\"测试\",\"value\":\"\",\"type\":\"text\"}],\"secondaryFields\":[{\"key\":\"fltNo\"," + + "\"label\":\"航班号\",\"value\":\"CA123\",\"type\":\"text\"}],\"auxiliaryFields\":[{\"key\":\"test\"," + + "\"label\":\"测试\",\"value\":\"\",\"type\":\"text\"}],\"backFields\":[]},\"locations\":[]}," + + "\"merchant\":{\"mname\":\"钟雨\",\"mtel\":\"\",\"minfo\":\"\"},\"platform\":{\"channelID\":\"2088201564809153\"," + + "\"webServiceUrl\":\"https://alipass.alipay.com/builder/syncRecord.htm?tempId=2020012013442621326446216\"}," + + "\"style\":{\"backgroundColor\":\"RGB(26,150,219)\"},\"fileInfo\":{\"formatVersion\":\"2\",\"canShare\":true," + + "\"canBuy\":false,\"canPresent\":true,\"serialNumber\":\"2020012013520759738677158\",\"supportTaxi\":\"true\"," + + "\"taxiSchemaUrl\":\"alipays://platformapi/startapp?appId=20000778&bizid=260&channel=71322\"}," + + "\"appInfo\":{\"app\":{\"android_appid\":\"\",\"ios_appid\":\"\",\"android_launch\":\"\",\"ios_launch\":\"\"," + + "\"android_download\":\"\",\"ios_download\":\"\"},\"label\":\"测试\",\"message\":\"\"}," + + "\"source\":\"alipassprod\",\"alipayVerify\":[\"qrcode\"]}}"; + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Marketing/TemplateMessage/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Marketing/TemplateMessage/ClientTest.cs new file mode 100644 index 0000000..0c7b11a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Marketing/TemplateMessage/ClientTest.cs @@ -0,0 +1,34 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Marketing.TemplateMessage.Models; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Marketing.TemplateMessage +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestSend() + { + AlipayOpenAppMiniTemplatemessageSendResponse response = Factory.Marketing.TemplateMessage().Send( + "2088102122458832", + "2017010100000000580012345678", + "MDI4YzIxMDE2M2I5YTQzYjUxNWE4MjA4NmU1MTIyYmM=", + "page/component/index", + "{\"keyword1\": {\"value\" : \"12:00\"},\"keyword2\": {\"value\" : \"20180808\"},\"keyword3\": {\"value\" : \"支付宝\"}}"); + + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40004"); + Assert.AreEqual(response.Msg, "Business Failed"); + Assert.AreEqual(response.SubCode, "USER_TEMPLATE_ILLEGAL"); + Assert.AreEqual(response.SubMsg, "模板非法"); + Assert.NotNull(response.HttpBody); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Member/Identification/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Member/Identification/ClientTest.cs new file mode 100644 index 0000000..c09d5e1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Member/Identification/ClientTest.cs @@ -0,0 +1,72 @@ +using System; +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Member.Identification.Models; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Member.Identification +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestInit() + { + IdentityParam identityParam = new IdentityParam() + { + IdentityType = "CERT_INFO", + CertType = "IDENTITY_CARD", + CertName = "张三", + CertNo = "513901198008089876" + }; + + MerchantConfig merchantConfig = new MerchantConfig() + { + ReturnUrl = "www.taobao.com" + }; + + + AlipayUserCertifyOpenInitializeResponse response = Factory.Member.Identification().Init( + Guid.NewGuid().ToString(), "FACE", identityParam, merchantConfig); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.NotNull(response.CertifyId); + } + + [Test] + public void TestCertify() + { + AlipayUserCertifyOpenCertifyResponse response = Factory.Member.Identification().Certify("bbdb57e87211279e2c22de5846d85161"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.IsTrue(response.Body.Contains("https://openapi.alipay.com/gateway.do?alipay_sdk=alipay-easysdk-net")); + Assert.IsTrue(response.Body.Contains("sign")); + } + + [Test] + public void TestQuery() + { + AlipayUserCertifyOpenQueryResponse response = Factory.Member.Identification().Query("89ad1f1b8171d9741c3e5620fd77f9de"); + + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40004"); + Assert.AreEqual(response.Msg, "Business Failed"); + Assert.AreEqual(response.SubCode, "CERTIFY_ID_EXPIRED"); + Assert.AreEqual(response.SubMsg, "认证已失效"); + Assert.NotNull(response.HttpBody); + Assert.IsNull(response.Passed); + Assert.IsNull(response.IdentityInfo); + Assert.IsNull(response.MaterialInfo); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/App/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/App/ClientTest.cs new file mode 100644 index 0000000..a61d12b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/App/ClientTest.cs @@ -0,0 +1,54 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Payment.App.Models; +using System.Collections.Generic; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Payment.App +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestPay() + { + AlipayTradeAppPayResponse response = Factory.Payment.App().Pay("iPhone6 16G", + "f4833085-0c46-4bb0-8e5f-622a02a4cffc", "0.10"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.IsTrue(response.Body.Contains("app_id=2019022663440152&biz_content=%7b%22subject%22%3a%22iPhone6+16G%22%2c%22" + + "out_trade_no%22%3a%22f4833085-0c46-4bb0-8e5f-622a02a4cffc%22%2c%22total_amount%22%3a%220.10%22%7d&charset=UTF-8&" + + "format=json&method=alipay.trade.app.pay¬ify_url=https%3a%2f%2fwww.test.com%2fcallback&sign=")); + } + + [Test] + public void TestPayWithOptional() + { + AlipayTradeAppPayResponse response = Factory.Payment.App() + .Agent("ca34ea491e7146cc87d25fca24c4cD11") + .Optional("extend_params", GetHuabeiConfig()) + .Pay("iPhone6 16G", "f4833085-0c46-4bb0-8e5f-622a02a4cffc", "0.10"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.IsTrue(response.Body.Contains("app_auth_token=ca34ea491e7146cc87d25fca24c4cD11&app_id=2019022663440152&biz_content=%7b%22subject%22%3a%22iPhone6+16G%22%2c" + + "%22out_trade_no%22%3a%22f4833085-0c46-4bb0-8e5f-622a02a4cffc%22%2c%22total_amount%22%3a%220" + + ".10%22%2c%22extend_params%22%3a%7b%22hb_fq_num%22%3a%223%22%2c%22hb_fq_seller_percent%22%3a%22100%22%7d%7d&charset=UTF" + + "-8&format=json&method=alipay.trade.app.pay¬ify_url=https%3a%2f%2fwww.test.com%2fcallback&sign=")); + } + + private Dictionary GetHuabeiConfig() + { + Dictionary extendParams = new Dictionary + { + { "hb_fq_num", "3" }, + { "hb_fq_seller_percent", "100" } + }; + return extendParams; + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Common/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Common/ClientTest.cs new file mode 100644 index 0000000..2087f22 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Common/ClientTest.cs @@ -0,0 +1,154 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Payment.Common.Models; +using System; +using System.Collections.Generic; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Payment.Common +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestCreate() + { + string outTradeNo = Guid.NewGuid().ToString(); + AlipayTradeCreateResponse response = Factory.Payment.Common().Create("iPhone6 16G", + outTradeNo, "88.88", "2088002656718920"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.OutTradeNo, outTradeNo); + Assert.True(response.TradeNo.StartsWith("202")); + } + + [Test] + public void TestCreateWithOptional() + { + string outTradeNo = Guid.NewGuid().ToString(); + AlipayTradeCreateResponse response = Factory.Payment.Common().Optional("goods_detail", GetGoodsDetail()) + .Create("iPhone6 16G", outTradeNo, "0.01", "2088002656718920"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.OutTradeNo, outTradeNo); + Assert.True(response.TradeNo.StartsWith("202")); + } + + private List GetGoodsDetail() + { + List goodsDetail = new List(); + Dictionary goodDetail = new Dictionary(); + goodDetail.Add("goods_id", "apple-01"); + goodDetail.Add("goods_name", "iPhone6 16G"); + goodDetail.Add("quantity", 1); + goodDetail.Add("price", "0.01"); + goodsDetail.Add(goodDetail); + return goodsDetail; + } + + [Test] + public void TestQuery() + { + AlipayTradeQueryResponse response = Factory.Payment.Common().Query("6f149ddb-ab8c-4546-81fb-5880b4aaa318"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.OutTradeNo, "6f149ddb-ab8c-4546-81fb-5880b4aaa318"); + } + + [Test] + public void TestCancel() + { + AlipayTradeCancelResponse response = Factory.Payment.Common().Cancel(CreateNewAndReturnOutTradeNo()); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.Action, "close"); + } + + [Test] + public void TestClose() + { + AlipayTradeCloseResponse response = Factory.Payment.Common().Close(CreateNewAndReturnOutTradeNo()); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + } + + [Test] + public void TestRefund() + { + AlipayTradeRefundResponse response = Factory.Payment.Common().Refund(CreateNewAndReturnOutTradeNo(), "0.01"); + + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40004"); + Assert.AreEqual(response.Msg, "Business Failed"); + Assert.AreEqual(response.SubCode, "ACQ.TRADE_STATUS_ERROR"); + Assert.AreEqual(response.SubMsg, "交易状态不合法"); + Assert.NotNull(response.HttpBody); + } + + [Test] + public void TestQueryRefund() + { + AlipayTradeFastpayRefundQueryResponse response = Factory.Payment.Common().QueryRefund( + "64628156-f784-4572-9540-485b7c91b850", "64628156-f784-4572-9540-485b7c91b850"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.RefundAmount, "0.01"); + Assert.AreEqual(response.TotalAmount, "0.01"); + } + + [Test] + public void TestDownloadBill() + { + AlipayDataDataserviceBillDownloadurlQueryResponse response = Factory.Payment.Common().DownloadBill("trade", "2020-01"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.IsTrue(response.BillDownloadUrl.StartsWith("http://dwbillcenter.alipay.com/")); + } + + private string CreateNewAndReturnOutTradeNo() + { + return Factory.Payment.Common().Create("iPhone6 16G", Guid.NewGuid().ToString(), + "88.88", "2088002656718920").OutTradeNo; + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/FaceToFace/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/FaceToFace/ClientTest.cs new file mode 100644 index 0000000..b5a2c2c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/FaceToFace/ClientTest.cs @@ -0,0 +1,51 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Payment.FaceToFace.Models; +using System; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Payment.FaceToFace +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestPay() + { + AlipayTradePayResponse response = Factory.Payment.FaceToFace().Pay("Iphone6 16G", CreateNewAndReturnOutTradeNo(), "0.01", "1234567890"); + + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "40004"); + Assert.AreEqual(response.Msg, "Business Failed"); + Assert.AreEqual(response.SubCode, "ACQ.PAYMENT_AUTH_CODE_INVALID"); + Assert.AreEqual(response.SubMsg, "支付失败,获取顾客账户信息失败,请顾客刷新付款码后重新收款,如再次收款失败,请联系管理员处理。[SOUNDWAVE_PARSER_FAIL]"); + Assert.NotNull(response.HttpBody); + } + + [Test] + public void TestPreCreate() + { + AlipayTradePrecreateResponse response = Factory.Payment.FaceToFace().PreCreate("iPhone6 16G", + CreateNewAndReturnOutTradeNo(), "0.10"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.IsTrue(response.QrCode.StartsWith("https://qr.alipay.com/")); + } + + private string CreateNewAndReturnOutTradeNo() + { + return Factory.Payment.Common().Create("Iphone6 16G", Guid.NewGuid().ToString(), + "88.88", "2088002656718920").OutTradeNo; + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Huabei/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Huabei/ClientTest.cs new file mode 100644 index 0000000..137f685 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Huabei/ClientTest.cs @@ -0,0 +1,39 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Payment.Huabei.Models; +using System; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Payment.HuaBei +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestCrate() + { + string outTradeNo = Guid.NewGuid().ToString(); + HuabeiConfig config = new HuabeiConfig() + { + HbFqNum = "3", + HbFqSellerPercent = "0" + }; + AlipayTradeCreateResponse response = Factory.Payment.Huabei().Create("Iphone6 16G", + outTradeNo, "88.88", "2088002656718920", config); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.OutTradeNo, outTradeNo); + Assert.True(response.TradeNo.StartsWith("202")); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Page/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Page/ClientTest.cs new file mode 100644 index 0000000..05398e9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Page/ClientTest.cs @@ -0,0 +1,50 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Payment.Page.Models; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Payment.Page +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestPay() + { + AlipayTradePagePayResponse response = Factory.Payment.Page().Pay("iPhone6 16G", + "e5b5bd79-8310-447d-b63b-0fe3a393324d", "0.10", "https://www.taobao.com"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.IsTrue(response.Body.Contains("
")); + Assert.IsTrue(response.Body.Contains("")); + Assert.IsTrue(response.Body.Contains("")); + } + + [Test] + public void TestPayWithOptionalNotify() + { + AlipayTradePagePayResponse response = Factory.Payment.Page().AsyncNotify("https://www.test2.com/newCallback") + .Pay("iPhone6 16G", "e5b5bd79-8310-447d-b63b-0fe3a393324d", "0.10", "https://www.taobao.com"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.IsTrue(response.Body.Contains("")); + Assert.IsTrue(response.Body.Contains("")); + Assert.IsTrue(response.Body.Contains("")); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Wap/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Wap/ClientTest.cs new file mode 100644 index 0000000..7b8b512 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Payment/Wap/ClientTest.cs @@ -0,0 +1,65 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Payment.Wap.Models; +using Alipay.EasySDK.Kernel.Util; +using System.Collections.Generic; + +namespace UnitTest.Payment.Wap +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestPay() + { + AlipayTradeWapPayResponse response = Factory.Payment.Wap().Pay("iPhone6 16G", + "b7f4bc7d-ea4b-4efd-9072-d8ea913c8946", "0.10", + "https://www.taobao.com", "https://www.taobao.com"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.IsTrue(response.Body.Contains("")); + Assert.IsTrue(response.Body.Contains("")); + Assert.IsTrue(response.Body.Contains("")); + } + + [Test] + public void TestPayWithOptional() + { + Dictionary optionalArgs = new Dictionary + { + { "timeout_express", "10m" }, + { "body", "iPhone6 16G"} + }; + AlipayTradeWapPayResponse response = Factory.Payment.Wap() + .Agent("ca34ea491e7146cc87d25fca24c4cD11").BatchOptional(optionalArgs) + .Pay("iPhone6 16G", "b7f4bc7d-ea4b-4efd-9072-d8ea913c8946", "0.10", + "https://www.taobao.com", "https://www.taobao.com"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.IsTrue(response.Body.Contains("")); + Assert.IsTrue(response.Body.Contains("")); + Assert.IsTrue(response.Body.Contains("")); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Security/TextRisk/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Security/TextRisk/ClientTest.cs new file mode 100644 index 0000000..54f2d71 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Security/TextRisk/ClientTest.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Security.TextRisk.Models; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Security.TextRisk +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestDetect() + { + AlipaySecurityRiskContentDetectResponse response = Factory.Security.TextRisk().Detect("test"); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.Null(response.SubCode); + Assert.Null(response.SubMsg); + Assert.NotNull(response.HttpBody); + Assert.AreEqual(response.Action, "PASSED"); + Assert.NotNull(response.UniqueId); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/TestAccount.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/TestAccount.cs new file mode 100644 index 0000000..5ce4299 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/TestAccount.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.IO; +using System; +using Alipay.EasySDK.Kernel; +using Newtonsoft.Json; + +namespace UnitTest +{ + public static class TestAccount + { + /// + /// 从文件中读取私钥 + /// + /// 注意:实际开发过程中,请务必注意不要将私钥信息配置在源码中(比如配置为常量或储存在配置文件的某个字段中等),因为私钥的保密等级往往比源码高得多,将会增加私钥泄露的风险。 + /// 推荐将私钥信息储存在专用的私钥文件中,将私钥文件通过安全的流程分发到服务器的安全储存区域上,仅供自己的应用运行时读取。 + /// + /// 私钥对应的APP_ID + /// 私钥字符串 + private static string GetPrivateKey(string appId) + { + IDictionary json = JsonConvert.DeserializeObject>( + File.ReadAllText(GetSolutionBasePath() + "/UnitTest/Fixture/privateKey.json")); + return json[appId]; + } + + /// + /// 获取解决方案所在路径 + /// + /// 解决方案所在绝对路径 + public static string GetSolutionBasePath() + { + string current = Directory.GetCurrentDirectory(); + do + { + current = Directory.GetParent(current).ToString(); + } + while (!current.EndsWith("bin", StringComparison.Ordinal)); + return current + "/../.."; + } + + /// + /// 线上小程序测试账号 + /// + public static class Mini + { + public static Config CONFIG = GetConfig(); + + public static Config GetConfig() + { + return new Config + { + Protocol = "https", + GatewayHost = "openapi.alipay.com", + AppId = "<-- 请填写您的AppId,例如:2019022663440152 -->", + SignType = "RSA2", + + AlipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumX1EaLM4ddn1Pia4SxTRb62aVYxU8I2mHMqrc" + + "pQU6F01mIO/DjY7R4xUWcLi0I2oH/BK/WhckEDCFsGrT7mO+JX8K4sfaWZx1aDGs0m25wOCNjp+DCVBXotXSCurqgGI/9UrY+" + + "QydYDnsl4jB65M3p8VilF93MfS01omEDjUW+1MM4o3FP0khmcKsoHnYGs21btEeh0LK1gnnTDlou6Jwv3Ew36CbCNY2cYkuyP" + + "AW0j47XqzhWJ7awAx60fwgNBq6ZOEPJnODqH20TAdTLNxPSl4qGxamjBO+RuInBy+Bc2hFHq3pNv6hTAfktggRKkKzDlDEUwg" + + "SLE7d2eL7P6rwIDAQAB -->", + MerchantPrivateKey = GetPrivateKey("<-- 请填写您的AppId,例如:2019022663440152 -->"), + NotifyUrl = "<-- 请填写您的异步通知接收服务器地址,例如:https://www.test.com/callback" + }; + } + } + + /// + /// 线上生活号测试账号 + /// + public static class OpenLife + { + public static Config CONFIG = new Config + { + Protocol = "https", + GatewayHost = "openapi.alipay.com", + AppId = "<-- 请填写您的AppId,例如:2019051064521003 -->", + SignType = "RSA2", + + AlipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径,例如:GetSolutionBasePath() + \"/UnitTest/Fixture/alipayCertPublicKey_RSA2.crt\" -->", + AlipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径,例如:GetSolutionBasePath() + \"/UnitTest/Fixture/alipayRootCert.crt\" -->", + MerchantCertPath = "<-- 请填写您的应用公钥证书文件路径,例如:GetSolutionBasePath() + \"/UnitTest/Fixture/appCertPublicKey_2019051064521003.crt\" -->", + MerchantPrivateKey = GetPrivateKey("<-- 请填写您的AppId,例如:2019051064521003 -->") + }; + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/UnitTest.csproj b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/UnitTest.csproj new file mode 100644 index 0000000..0a75581 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/UnitTest.csproj @@ -0,0 +1,50 @@ + + + + netcoreapp2.1 + + false + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Util/AES/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Util/AES/ClientTest.cs new file mode 100644 index 0000000..77370fb --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Util/AES/ClientTest.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Kernel; + +namespace UnitTest.Util.AES +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Config config = TestAccount.Mini.GetConfig(); + config.EncryptKey = "aa4BtZ4tspm2wnXLb1ThQA=="; + Factory.SetOptions(config); + } + + [Test] + public void TestDecrypt() + { + string plainText = Factory.Util.AES().Decrypt("ILpoMowjIQjfYMR847rnFQ=="); + Assert.AreEqual(plainText, "test1234567"); + } + + [Test] + public void TestEncrypt() + { + string cipherText = Factory.Util.AES().Encrypt("test1234567"); + Assert.AreEqual(cipherText, "ILpoMowjIQjfYMR847rnFQ=="); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Util/Generic/ClientTest.cs b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Util/Generic/ClientTest.cs new file mode 100644 index 0000000..003ef76 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/csharp/UnitTest/Util/Generic/ClientTest.cs @@ -0,0 +1,79 @@ +using NUnit.Framework; +using Alipay.EasySDK.Factory; +using Alipay.EasySDK.Util.Generic.Models; +using System; +using System.Collections.Generic; +using Alipay.EasySDK.Kernel.Util; + +namespace UnitTest.Util.Generic +{ + public class ClientTest + { + [SetUp] + public void SetUp() + { + Factory.SetOptions(TestAccount.Mini.CONFIG); + } + + [Test] + public void TestExecuteWithoutAppAuthToken() + { + string outTradeNo = Guid.NewGuid().ToString(); + AlipayOpenApiGenericResponse response = Factory.Util.Generic().Execute( + "alipay.trade.create", null, GetBizParams(outTradeNo)); + + Assert.IsTrue(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "10000"); + Assert.AreEqual(response.Msg, "Success"); + Assert.IsNull(response.SubCode); + Assert.IsNull(response.SubMsg); + Assert.NotNull(response.HttpBody); + } + + [Test] + public void TestExecuteWithAppAuthToken() + { + string outTradeNo = Guid.NewGuid().ToString(); + AlipayOpenApiGenericResponse response = Factory.Util.Generic().Execute( + "alipay.trade.create", GetTextParams(), GetBizParams(outTradeNo)); + + Assert.IsFalse(ResponseChecker.Success(response)); + Assert.AreEqual(response.Code, "20001"); + Assert.AreEqual(response.Msg, "Insufficient Token Permissions"); + Assert.AreEqual(response.SubCode, "aop.invalid-app-auth-token"); + Assert.AreEqual(response.SubMsg, "无效的应用授权令牌"); + Assert.NotNull(response.HttpBody); + } + + private Dictionary GetTextParams() + { + return new Dictionary + { + { "app_auth_token", "201712BB_D0804adb2e743078d1822d536956X34" } + }; + + } + + private Dictionary GetBizParams(string outTradeNo) + { + return new Dictionary + { + { "subject", "Iphone6 16G" }, + { "out_trade_no", outTradeNo }, + { "total_amount", "0.10" }, + { "buyer_id", "2088002656718920" }, + { "extend_params", GetHuabeiParams() } + }; + + } + + private Dictionary GetHuabeiParams() + { + return new Dictionary + { + { "hb_fq_num", "3"}, + { "hb_fq_seller_percent", "3"} + }; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/go/README.md b/serve/vendor/alipaysdk/easysdk/go/README.md new file mode 100644 index 0000000..8e19125 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/README.md @@ -0,0 +1,90 @@ +[![Latest Stable Version](https://poser.pugx.org/alipaysdk/easysdk/v/stable)](https://packagist.org/packages/alipaysdk/easysdk) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk?ref=badge_shield) + +欢迎使用 Alipay **Easy** SDK for Go 。 + +Alipay Esay SDK for Go让您不用复杂编程即可访支付宝开放平台开放的各项常用能力,SDK可以自动帮您满足能力调用过程中所需的证书校验、加签、验签、发送HTTP请求等非功能性要求。 + +下面向您介绍Alipay Easy SDK for Go 的基本设计理念和使用方法。 + +## 设计理念 + +Alipay Easy SDK主要目标是提升开发者在**服务端**集成支付宝开放平台开放的各类核心能力的效率。 + +## 环境要求 +1. Alipay Easy SDK for Go 需要配合`Go 1.12`或其以上版本。 + +2. 使用 Alipay Easy SDK for Go 之前 ,您需要先前往[支付宝开发平台-开发者中心](https://openhome.alipay.com/platform/developerIndex.htm)完成开发者接入的一些准备工作,包括创建应用、为应用添加功能包、设置应用的接口加签方式等。 + +3. 准备工作完成后,注意保存如下信息,后续将作为使用SDK的输入。 + +* 加签模式为公钥证书模式时(推荐) + +`AppId`、`应用的私钥`、`应用公钥证书文件`、`支付宝公钥证书文件`、`支付宝根证书文件` + +* 加签模式为公钥模式时 + +`AppId`、`应用的私钥`、`支付宝公钥` + +## 安装 +手动下载go目录下源码集成即可 + +## 快速使用 +以下这段代码示例向您展示了使用Alipay Easy SDK for Go调用一个API的3个主要步骤: + +1. 设置参数(全局只需设置一次)。 +2. 发起API调用。 +3. 处理响应或异常。 + +```go +package main + +import ( + "encoding/json" + "fmt" + "kernel" + "time" +) + +func init() { + account:= kernel.Client{} + account.Protocol = "https" + account.GatewayHost = "openapi.alipay.com" + account.AppId = "<-- 请填写您的AppId,例如:2019022663440152 -->" + account.SignType = "RSA2" + account.AlipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->" + account.MerchantPrivateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->" + + kernel.InitClient(account) +} + + +func main() { + result, _ := kernel.Execute("alipay.trade.create", nil, getBizParams(time.Now().Format("2006-01-02 15:04:05"))) + fmt.Println(result) +} + +func getBizParams(outTradeNo string) map[string]string { + bizParams := map[string]string{ + "subject": "phone6 16G", + "out_trade_no": outTradeNo, + "total_amount": "0.10", + "buyer_id": "2088002656718920", + "extend_params": getHuabeiParams(), + } + return bizParams +} + +func getHuabeiParams() string { + extendParams := map[string]string{ + "hb_fq_num": "3", + "hb_fq_seller_percent": "3", + } + byt, _ := json.Marshal(extendParams) + return string(byt) +} +``` + +## 文档 + +[Alipay Easy SDK](./../README.md) diff --git a/serve/vendor/alipaysdk/easysdk/go/src/kernel/AlipayConstants.go b/serve/vendor/alipaysdk/easysdk/go/src/kernel/AlipayConstants.go new file mode 100644 index 0000000..aedfaec --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/kernel/AlipayConstants.go @@ -0,0 +1,14 @@ +package kernel + +/** + * 与网关HTTP交互中涉及到的字段值 + */ +const bizContent = "biz_content" +const alipayCertSN = "alipay_cert_sn" +const signField = "sign" +const bodyField = "http_body" +const notifyUrl = "notify_url" +const methodField = "method" +const response = "_response" +const errorResponse = "error_response" +const sdkVersion = "alipay-easysdk-go-1.0.0" \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/go/src/kernel/BaseClient.go b/serve/vendor/alipaysdk/easysdk/go/src/kernel/BaseClient.go new file mode 100644 index 0000000..921a268 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/kernel/BaseClient.go @@ -0,0 +1,246 @@ +package kernel + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "io" + "io/ioutil" + Sort "sort" + "strings" + "tea" + "time" +) + +var this Client + +func GetConfig(key string) string { + if key == "protocol" { + return this.Protocol + } else if key == "gatewayHost" { + return this.GatewayHost + } else if key == "appId" { + return this.AppId + } else if key == "signType" { + return this.SignType + } else if key == "alipayPublicKey" { + return this.AlipayPublicKey + } else if key == "merchantPrivateKey" { + return this.MerchantPrivateKey + } else if key == "merchantCertPath" { + return this.MerchantCertPath + } else if key == "alipayCertPath" { + return this.AlipayCertPath + } else if key == "alipayRootCertPath" { + return this.AlipayRootCertPath + } else if key == "notifyUrl" { + return this.NotifyUrl + } else if key == "encryptKey" { + return this.EncryptKey + } else { + panic(key + " is illegal") + } +} + +func InitClient(config Client) { + this = config +} + +/** +获取时间戳,格式yyyy-MM-dd HH:mm:ss +*/ +func GetTimestamp() string { + return time.Now().Format("2006-01-02 15:04:05") +} + +func GetSdkVersion() string { + return sdkVersion +} + +func GetMerchantCertSN() string { + return this.MerchantCertSN +} + +func GetAlipayCertSN(alipayCertSN map[string]string) string { + return this.AlipayCertSN +} + +func GetAlipayRootCertSN() string { + return this.AlipayRootCertSN +} + +func ExtractAlipayPublicKey(alipayPublicKey string) string { + return this.AlipayCertSN +} + +func IsCertMode() bool { + if len(this.AlipayCertSN) != 0 { + return true + } else { + return false + } +} + +/** +将业务参数和其他额外文本参数按www-form-urlencoded格式转换成HTTP Body中的字节数组,注意要做URL Encode +*/ +func ToUrlEncodedRequestBody(bizParams map[string]string) string { + sortedMap := getSortedMap(nil, bizParams, nil) + if sortedMap == nil { + return "" + } + return buildQueryString(bizParams) +} + +func buildQueryString(sortedMap map[string]string) string { + requestUrl := "" + keys := make([]string, 0) + for k, _ := range sortedMap { + keys = append(keys, k) + } + Sort.Strings(keys) + var pList = make([]string, 0, 0) + for _, key := range keys { + pList = append(pList, key+"="+sortedMap[key]) + } + requestUrl = strings.Join(pList, "&") + return requestUrl +} + +func getSortedMap(systemParams map[string]string, bizParams map[string]string, textParams map[string]string) map[string]string { + sortedMap := tea.Merge(systemParams, bizParams, textParams) + sortedMap = SortMap(sortedMap) + return sortedMap +} + +func SortMap(romanNumeralDict map[string]string) map[string]string { + keys := make([]string, 0) + for k, _ := range romanNumeralDict { + keys = append(keys, k) + } + Sort.Strings(keys) + return romanNumeralDict +} + +/** +计算签名 +*/ +func Sign(systemParams map[string]string, bizParams map[string]string, textParams map[string]string, privateKey string) string { + if bizParams != nil { + byt, _ := json.Marshal(bizParams) + bizParams[bizContent] = string(byt) + } + sortedMap := getSortedMap(systemParams, bizParams, textParams) + data := buildQueryString(sortedMap) + var prvKey = formatKey(privateKey, `-----BEGIN RSA PRIVATE KEY-----`, `-----END RSA PRIVATE KEY-----`, 64) + signData := RsaSignWithSha256([]byte(data), prvKey) + return base64.StdEncoding.EncodeToString(signData) +} + +func Verify(respMap map[string]string, alipayPublicKey string) bool { + resp := respMap[bodyField] + method := respMap[methodField] + content, sign := getSignSourceData(resp, method) + signBytes, err := base64.StdEncoding.DecodeString(sign) + if err != nil { + return false + } + pubKey := formatKey(alipayPublicKey, `-----BEGIN PUBLIC KEY-----`, `-----END PUBLIC KEY-----`, 64) + result := RsaVerySignWithSha256([]byte(content), signBytes, pubKey) + return result +} + +func getSignSourceData(body string, method string) (content string, sign string) { + var rootNodeName = strings.Replace(method, ".", "_", -1) + response + var rootIndex = strings.LastIndex(body, rootNodeName) + var errorIndex = strings.LastIndex(body, errorResponse) + if rootIndex > 0 { + return parserJSONSource(body, rootNodeName, rootIndex) + } else if errorIndex > 0 { + return parserJSONSource(body, errorResponse, errorIndex) + } else { + return "", "" + } +} + +func parserJSONSource(responseContent string, nodeName string, nodeIndex int) (content string, sign string) { + signDataStartIndex := nodeIndex + len(nodeName) + 2 + signIndex := 0 + if strings.LastIndex(responseContent, alipayCertSN) > 0 { + signIndex = strings.LastIndex(responseContent, "\""+alipayCertSN+"\"") + } else { + signIndex = strings.LastIndex(responseContent, "\""+signField+"\"") + } + signDataEndIndex := signIndex - 1 + indexLen := signDataEndIndex - signDataStartIndex + if indexLen < 0 { + return "", "" + } + content = responseContent[signDataStartIndex:signDataEndIndex] + sign = responseContent[signIndex+8 : len(responseContent)-2] + return content, sign +} + +func ToRespModel(resp map[string]string) map[string]interface{} { + body := resp[bodyField] + method := resp[methodField] + content, _ := getSignSourceData(body, method) + result := map[string]interface{}{ + bodyField: body, + } + arg := make(map[string]interface{}) + err := json.Unmarshal([]byte(content), &arg) + tmp := make(map[string]string) + err = json.Unmarshal([]byte(content), &tmp) + if err == nil { + for key, value := range arg { + if value != "" { + result[key] = value + } + } + } + return result +} + +/** +解析网关响应内容,同时将API的接口名称和响应原文插入到响应数组的method和body字段中 +*/ +func ReadAsJson(response io.Reader, method string) (map[string]string, error) { + byt, err := ioutil.ReadAll(response) + if err != nil { + return nil, err + } + err = json.Unmarshal(byt, response) + result := map[string]string{ + bodyField: string(byt), + methodField: method, + } + return result, err +} + +func AesDecrypt(cipherText string, encryptKey string) { + de:=AESDecrypt([]byte(cipherText), []byte(encryptKey)) + fmt.Println(de) +} + +func AesEncrypt(plainText string, encryptKey string) { + en := AESEncrypt([]byte(plainText), []byte(encryptKey)) + fmt.Println(en) +} + +type Client struct { + Protocol string + GatewayHost string + AppId string + SignType string + AlipayPublicKey string + MerchantPrivateKey string + MerchantCertPath string + AlipayCertPath string + AlipayRootCertPath string + NotifyUrl string + EncryptKey string + MerchantCertSN string + AlipayCertSN string + AlipayRootCertSN string +} diff --git a/serve/vendor/alipaysdk/easysdk/go/src/kernel/client.go b/serve/vendor/alipaysdk/easysdk/go/src/kernel/client.go new file mode 100644 index 0000000..1c57492 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/kernel/client.go @@ -0,0 +1,142 @@ +package kernel + + +import ( + "tea" +) + +type AlipayOpenApiGenericResponse struct { + HttpBody *string `json:"http_body" xml:"http_body" require:"true"` + Code *string `json:"code" xml:"code" require:"true"` + Msg *string `json:"msg" xml:"msg" require:"true"` + SubCode *string `json:"sub_code" xml:"sub_code" require:"true"` + SubMsg *string `json:"sub_msg" xml:"sub_msg" require:"true"` +} + +func (s AlipayOpenApiGenericResponse) String() string { + return tea.Prettify(s) +} + +func (s AlipayOpenApiGenericResponse) GoString() string { + return s.String() +} + +func (s *AlipayOpenApiGenericResponse) SetHttpBody(v string) *AlipayOpenApiGenericResponse { + s.HttpBody = &v + return s +} + +func (s *AlipayOpenApiGenericResponse) SetCode(v string) *AlipayOpenApiGenericResponse { + s.Code = &v + return s +} + +func (s *AlipayOpenApiGenericResponse) SetMsg(v string) *AlipayOpenApiGenericResponse { + s.Msg = &v + return s +} + +func (s *AlipayOpenApiGenericResponse) SetSubCode(v string) *AlipayOpenApiGenericResponse { + s.SubCode = &v + return s +} + +func (s *AlipayOpenApiGenericResponse) SetSubMsg(v string) *AlipayOpenApiGenericResponse { + s.SubMsg = &v + return s +} + +func NewClient()(*Client, error) { + client := new(Client) + err := client.Init() + return client, err +} + +func (client *Client)Init()(_err error) { + return nil +} + + +func Execute(method string, textParams map[string]string, bizParams map[string]string) (_result *AlipayOpenApiGenericResponse, _err error) { + _runtime := map[string]interface{}{ + "connectTimeout": 15000, + "readTimeout": 15000, + "retry": map[string]int{ + "maxAttempts": 0, + }, + } + + _resp := &AlipayOpenApiGenericResponse{} + for _retryTimes := 0; tea.AllowRetry(_runtime["retry"], _retryTimes); _retryTimes++ { + if _retryTimes > 0 { + _backoffTime := tea.GetBackoffTime(_runtime["backoff"], _retryTimes) + if _backoffTime > 0 { + tea.Sleep(_backoffTime) + } + } + + _resp, _err = func()(*AlipayOpenApiGenericResponse, error){ + request_ := tea.NewRequest() + systemParams := map[string]string{ + "method": method, + "app_id": GetConfig("appId"), + "timestamp": GetTimestamp(), + "format": "json", + "version": "1.0", + "alipay_sdk": GetSdkVersion(), + "charset": "UTF-8", + "sign_type": GetConfig("signType"), + "app_cert_sn": GetMerchantCertSN(), + "alipay_root_cert_sn": GetAlipayRootCertSN(), + } + request_.Protocol = GetConfig("protocol") + request_.Method = "POST" + request_.Pathname = "/gateway.do" + request_.Headers = map[string]string{ + "host": GetConfig("gatewayHost"), + "content-type": "application/x-www-form-urlencoded;charset=utf-8", + } + request_.Query = SortMap(tea.Merge(map[string]string{ + "sign": Sign(systemParams, bizParams, textParams, GetConfig("merchantPrivateKey")), + },systemParams, + textParams)) + request_.Body = tea.ToReader(ToUrlEncodedRequestBody(bizParams)) + response_, _err := tea.DoRequest(request_, _runtime) + if _err != nil { + return nil, _err + } + respMap, _err := ReadAsJson(response_.Body, method) + if _err != nil { + return nil, _err + } + + if IsCertMode() { + if Verify(respMap, ExtractAlipayPublicKey(GetAlipayCertSN(respMap))) { + _result = &AlipayOpenApiGenericResponse{} + _body := ToRespModel(respMap) + _err = tea.Convert(_body, &_result) + return _result, _err + } + + } else { + if Verify(respMap, GetConfig("alipayPublicKey")) { + _result = &AlipayOpenApiGenericResponse{} + _body := ToRespModel(respMap) + _err = tea.Convert(_body, &_result) + return _result, _err + } + + } + + _err = tea.NewSDKError(map[string]interface{}{ + "message": "验签失败,请检查支付宝公钥设置是否正确。", + }) + return nil, _err + }() + if !tea.Retryable(_err) { + break + } + } + + return _resp, _err +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/go/src/kernel/signer.go b/serve/vendor/alipaysdk/easysdk/go/src/kernel/signer.go new file mode 100644 index 0000000..490848f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/kernel/signer.go @@ -0,0 +1,133 @@ +package kernel + +import ( + "bytes" + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "strings" +) + +//签名 +func RsaSignWithSha256(data []byte, keyBytes []byte) []byte { + h := sha256.New() + h.Write(data) + hashed := h.Sum(nil) + block, _ := pem.Decode(keyBytes) + if block == nil { + panic(errors.New("private key error")) + } + privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + fmt.Println("ParsePKCS8PrivateKey err", err) + panic(err) + } + + signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed) + if err != nil { + fmt.Printf("Error from signing: %s\n", err) + panic(err) + } + + return signature +} + +//验证 +func RsaVerySignWithSha256(data, signData, keyBytes []byte) bool { + block, _ := pem.Decode(keyBytes) + if block == nil { + panic(errors.New("public key error")) + } + pubKey, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + panic(err) + } + + hashed := sha256.Sum256(data) + err = rsa.VerifyPKCS1v15(pubKey.(*rsa.PublicKey), crypto.SHA256, hashed[:], signData) + if err != nil { + panic(err) + } + return true +} + +func formatKey(raw, prefix, suffix string, lineCount int) []byte { + if raw == "" { + return nil + } + raw = strings.Replace(raw, prefix, "", 1) + raw = strings.Replace(raw, suffix, "", 1) + raw = strings.Replace(raw, " ", "", -1) + raw = strings.Replace(raw, "\n", "", -1) + raw = strings.Replace(raw, "\r", "", -1) + raw = strings.Replace(raw, "\t", "", -1) + var sl = len(raw) + var c = sl / lineCount + if sl%lineCount > 0 { + c = c + 1 + } + + var buf bytes.Buffer + buf.WriteString(prefix + "\n") + for i := 0; i < c; i++ { + var b = i * lineCount + var e = b + lineCount + if e > sl { + buf.WriteString(raw[b:]) + } else { + buf.WriteString(raw[b:e]) + } + buf.WriteString("\n") + } + buf.WriteString(suffix) + return buf.Bytes() +} + +//解密 +func AESDecrypt(crypted, key []byte) []byte { + block, _ := aes.NewCipher(key) + blockSize := block.BlockSize() + blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) + origData := make([]byte, len(crypted)) + blockMode.CryptBlocks(origData, crypted) + origData = PKCS7UnPadding(origData) + return origData +} + +//去补码 +func PKCS7UnPadding(origData []byte) []byte { + length := len(origData) + unpadding := int(origData[length-1]) + return origData[:length-unpadding] +} + +//加密 +func AESEncrypt(origData, key []byte) []byte { + //获取block块 + block, _ := aes.NewCipher(key) + //补码 + origData = PKCS7Padding(origData, block.BlockSize()) + //加密模式, + blockMode := cipher.NewCBCEncrypter(block, key[:block.BlockSize()]) + //创建明文长度的数组 + crypted := make([]byte, len(origData)) + //加密明文 + blockMode.CryptBlocks(crypted, origData) + return crypted +} + +//补码 +func PKCS7Padding(origData []byte, blockSize int) []byte { + //计算需要补几位数 + padding := blockSize - len(origData)%blockSize + //在切片后面追加char数量的byte(char) + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(origData, padtext...) +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/go/src/tea/debug.go b/serve/vendor/alipaysdk/easysdk/go/src/tea/debug.go new file mode 100644 index 0000000..39608cf --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/tea/debug.go @@ -0,0 +1,37 @@ +package tea + + +import ( + "fmt" + "os" + "strings" +) + +type Debug func(format string, v ...interface{}) + +var hookGetEnv = func() string { + return os.Getenv("DEBUG") +} + +var hookPrint = func(input string) { + fmt.Println(input) +} + +func Init(flag string) Debug { + enable := false + + env := hookGetEnv() + parts := strings.Split(env, ",") + for _, part := range parts { + if part == flag { + enable = true + break + } + } + + return func(format string, v ...interface{}) { + if enable { + hookPrint(fmt.Sprintf(format, v...)) + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/go/src/tea/logger.go b/serve/vendor/alipaysdk/easysdk/go/src/tea/logger.go new file mode 100644 index 0000000..ff9ff85 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/tea/logger.go @@ -0,0 +1,110 @@ +package tea + + +import ( + "io" + "log" + "strings" + "time" +) + +type Logger struct { + *log.Logger + formatTemplate string + isOpen bool + lastLogMsg string +} + +var defaultLoggerTemplate = `{time} {channel}: "{method} {uri} HTTP/{version}" {code} {cost} {hostname}` +var loggerParam = []string{"{time}", "{start_time}", "{ts}", "{channel}", "{pid}", "{host}", "{method}", "{uri}", "{version}", "{target}", "{hostname}", "{code}", "{error}", "{req_headers}", "{res_body}", "{res_headers}", "{cost}"} +var logChannel string + +func InitLogMsg(fieldMap map[string]string) { + for _, value := range loggerParam { + fieldMap[value] = "" + } +} + +func (logger *Logger) SetFormatTemplate(template string) { + logger.formatTemplate = template + +} + +func (logger *Logger) GetFormatTemplate() string { + return logger.formatTemplate + +} + +func NewLogger(level string, channel string, out io.Writer, template string) *Logger { + if level == "" { + level = "info" + } + + logChannel = "AlibabaCloud" + if channel != "" { + logChannel = channel + } + log := log.New(out, "["+strings.ToUpper(level)+"]", log.Lshortfile) + if template == "" { + template = defaultLoggerTemplate + } + + return &Logger{ + Logger: log, + formatTemplate: template, + isOpen: true, + } +} + +func (logger *Logger) OpenLogger() { + logger.isOpen = true +} + +func (logger *Logger) CloseLogger() { + logger.isOpen = false +} + +func (logger *Logger) SetIsopen(isopen bool) { + logger.isOpen = isopen +} + +func (logger *Logger) GetIsopen() bool { + return logger.isOpen +} + +func (logger *Logger) SetLastLogMsg(lastLogMsg string) { + logger.lastLogMsg = lastLogMsg +} + +func (logger *Logger) GetLastLogMsg() string { + return logger.lastLogMsg +} + +func SetLogChannel(channel string) { + logChannel = channel +} + +func (logger *Logger) PrintLog(fieldMap map[string]string, err error) { + if err != nil { + fieldMap["{error}"] = err.Error() + } + fieldMap["{time}"] = time.Now().Format("2006-01-02 15:04:05") + fieldMap["{ts}"] = getTimeInFormatISO8601() + fieldMap["{channel}"] = logChannel + if logger != nil { + logMsg := logger.formatTemplate + for key, value := range fieldMap { + logMsg = strings.Replace(logMsg, key, value, -1) + } + logger.lastLogMsg = logMsg + if logger.isOpen == true { + logger.Output(2, logMsg) + } + } +} + +func getTimeInFormatISO8601() (timeStr string) { + gmt := time.FixedZone("GMT", 0) + + return time.Now().In(gmt).Format("2006-01-02T15:04:05Z") +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/go/src/tea/progress.go b/serve/vendor/alipaysdk/easysdk/go/src/tea/progress.go new file mode 100644 index 0000000..8991d6a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/tea/progress.go @@ -0,0 +1,60 @@ +package tea + +// ProgressEventType defines transfer progress event type +type ProgressEventType int + +const ( + // TransferStartedEvent transfer started, set TotalBytes + TransferStartedEvent ProgressEventType = 1 + iota + // TransferDataEvent transfer data, set ConsumedBytes anmd TotalBytes + TransferDataEvent + // TransferCompletedEvent transfer completed + TransferCompletedEvent + // TransferFailedEvent transfer encounters an error + TransferFailedEvent +) + +// ProgressEvent defines progress event +type ProgressEvent struct { + ConsumedBytes int64 + TotalBytes int64 + RwBytes int64 + EventType ProgressEventType +} + +// ProgressListener listens progress change +type ProgressListener interface { + ProgressChanged(event *ProgressEvent) +} + +// -------------------- Private -------------------- + +func NewProgressEvent(eventType ProgressEventType, consumed, total int64, rwBytes int64) *ProgressEvent { + return &ProgressEvent{ + ConsumedBytes: consumed, + TotalBytes: total, + RwBytes: rwBytes, + EventType: eventType} +} + +// publishProgress +func PublishProgress(listener ProgressListener, event *ProgressEvent) { + if listener != nil && event != nil { + listener.ProgressChanged(event) + } +} + +func GetProgressListener(obj interface{}) ProgressListener { + if obj == nil { + return nil + } + listener, ok := obj.(ProgressListener) + if !ok { + return nil + } + return listener +} + +type ReaderTracker struct { + CompletedBytes int64 +} diff --git a/serve/vendor/alipaysdk/easysdk/go/src/tea/tea.go b/serve/vendor/alipaysdk/easysdk/go/src/tea/tea.go new file mode 100644 index 0000000..a0e70e0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/tea/tea.go @@ -0,0 +1,919 @@ +package tea + + +import ( + "bytes" + "context" + "crypto/tls" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "math" + "math/rand" + "net" + "net/http" + "net/url" + "os" + "reflect" + "regexp" + "strconv" + "strings" + "sync" + "time" + + "golang.org/x/net/proxy" +) + +var debugLog = Init("tea") + +var hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) { + return fn +} + +var basicTypes = []string{ + "int", "int64", "float32", "float64", "string", "bool", "uint64", +} + +// Verify whether the parameters meet the requirements +var validateParams = []string{"require", "pattern", "maxLength"} + +// CastError is used for cast type fails +type CastError struct { + Message string +} + +// Request is used wrap http request +type Request struct { + Protocol string + Port int + Method string + Pathname string + Domain string + Headers map[string]string + Query map[string]string + Body io.Reader +} + +// Response is use d wrap http response +type Response struct { + Body io.ReadCloser + StatusCode int + StatusMessage string + Headers map[string]string +} + +// SDKError struct is used save error code and message +type SDKError struct { + Code string + Message string + Data string +} + +// RuntimeObject is used for converting http configuration +type RuntimeObject struct { + IgnoreSSL bool `json:"ignoreSSL" xml:"ignoreSSL"` + ReadTimeout int `json:"readTimeout" xml:"readTimeout"` + ConnectTimeout int `json:"connectTimeout" xml:"connectTimeout"` + LocalAddr string `json:"localAddr" xml:"localAddr"` + HttpProxy string `json:"httpProxy" xml:"httpProxy"` + HttpsProxy string `json:"httpsProxy" xml:"httpsProxy"` + NoProxy string `json:"noProxy" xml:"noProxy"` + MaxIdleConns int `json:"maxIdleConns" xml:"maxIdleConns"` + Socks5Proxy string `json:"socks5Proxy" xml:"socks5Proxy"` + Socks5NetWork string `json:"socks5NetWork" xml:"socks5NetWork"` + Listener ProgressListener `json:"listener" xml:"listener"` + Tracker *ReaderTracker `json:"tracker" xml:"tracker"` + Logger *Logger `json:"logger" xml:"logger"` +} + +type teaClient struct { + sync.Mutex + httpClient *http.Client + ifInit bool +} + +var clientPool = &sync.Map{} + +func (r *RuntimeObject) getClientTag(domain string) string { + return strconv.FormatBool(r.IgnoreSSL) + strconv.Itoa(r.ReadTimeout) + + strconv.Itoa(r.ConnectTimeout) + r.LocalAddr + r.HttpProxy + + r.HttpsProxy + r.NoProxy + r.Socks5Proxy + r.Socks5NetWork + domain +} + +// NewRuntimeObject is used for shortly create runtime object +func NewRuntimeObject(runtime map[string]interface{}) *RuntimeObject { + if runtime == nil { + return &RuntimeObject{} + } + + runtimeObject := &RuntimeObject{ + IgnoreSSL: TransInterfaceToBool(runtime["ignoreSSL"]), + ReadTimeout: TransInterfaceToInt(runtime["readTimeout"]), + ConnectTimeout: TransInterfaceToInt(runtime["connectTimeout"]), + LocalAddr: TransInterfaceToString(runtime["localAddr"]), + HttpProxy: TransInterfaceToString(runtime["httpProxy"]), + HttpsProxy: TransInterfaceToString(runtime["httpsProxy"]), + NoProxy: TransInterfaceToString(runtime["noProxy"]), + MaxIdleConns: TransInterfaceToInt(runtime["maxIdleConns"]), + Socks5Proxy: TransInterfaceToString(runtime["socks5Proxy"]), + Socks5NetWork: TransInterfaceToString(runtime["socks5NetWork"]), + } + if runtime["listener"] != nil { + runtimeObject.Listener = runtime["listener"].(ProgressListener) + } + if runtime["tracker"] != nil { + runtimeObject.Tracker = runtime["tracker"].(*ReaderTracker) + } + if runtime["logger"] != nil { + runtimeObject.Logger = runtime["logger"].(*Logger) + } + return runtimeObject +} + +// NewCastError is used for cast type fails +func NewCastError(message string) (err error) { + return &CastError{ + Message: message, + } +} + +// NewRequest is used shortly create Request +func NewRequest() (req *Request) { + return &Request{ + Headers: map[string]string{}, + Query: map[string]string{}, + } +} + +// NewResponse is create response with http response +func NewResponse(httpResponse *http.Response) (res *Response) { + res = &Response{} + res.Body = httpResponse.Body + res.Headers = make(map[string]string) + res.StatusCode = httpResponse.StatusCode + res.StatusMessage = httpResponse.Status + return +} + +// NewSDKError is used for shortly create SDKError object +func NewSDKError(obj map[string]interface{}) *SDKError { + err := &SDKError{} + if val, ok := obj["code"].(int); ok { + err.Code = strconv.Itoa(val) + } else if val, ok := obj["code"].(string); ok { + err.Code = val + } + + if obj["message"] != nil { + err.Message = obj["message"].(string) + } + if data := obj["data"]; data != nil { + byt, _ := json.Marshal(data) + err.Data = string(byt) + } + return err +} + +// Return message of CastError +func (err *CastError) Error() string { + return err.Message +} + +// Convert is use convert map[string]interface object to struct +func Convert(in interface{}, out interface{}) error { + byt, _ := json.Marshal(in) + err := json.Unmarshal(byt, out) + return err +} + +// ReadBody is used read response body +func (response *Response) ReadBody() (body []byte, err error) { + defer response.Body.Close() + var buffer [512]byte + result := bytes.NewBuffer(nil) + + for { + n, err := response.Body.Read(buffer[0:]) + result.Write(buffer[0:n]) + if err != nil && err == io.EOF { + break + } else if err != nil { + return nil, err + } + } + return result.Bytes(), nil +} + +func getTeaClient(tag string) *teaClient { + client, ok := clientPool.Load(tag) + if client == nil && !ok { + client = &teaClient{ + httpClient: &http.Client{}, + ifInit: false, + } + clientPool.Store(tag, client) + } + return client.(*teaClient) +} + +// DoRequest is used send request to server +func DoRequest(request *Request, requestRuntime map[string]interface{}) (response *Response, err error) { + runtimeObject := NewRuntimeObject(requestRuntime) + fieldMap := make(map[string]string) + InitLogMsg(fieldMap) + defer func() { + if runtimeObject.Logger != nil { + runtimeObject.Logger.PrintLog(fieldMap, err) + } + }() + if request.Method == "" { + request.Method = "GET" + } + + if request.Protocol == "" { + request.Protocol = "http" + } else { + request.Protocol = strings.ToLower(request.Protocol) + } + + if request.Protocol == "http" { + request.Port = 80 + } else if request.Protocol == "https" { + request.Port = 443 + } + + requestURL := "" + request.Domain = request.Headers["host"] + matched, _ := regexp.MatchString(":", request.Domain) + if matched { + requestURL = fmt.Sprintf("%s://%s%s", request.Protocol, request.Domain, request.Pathname) + } else { + requestURL = fmt.Sprintf("%s://%s:%d%s", request.Protocol, request.Domain, request.Port, request.Pathname) + } + queryParams := request.Query + // sort QueryParams by key + q := url.Values{} + for key, value := range queryParams { + q.Add(key, value) + } + querystring := q.Encode() + if len(querystring) > 0 { + if strings.Contains(requestURL, "?") { + requestURL = fmt.Sprintf("%s&%s", requestURL, querystring) + } else { + requestURL = fmt.Sprintf("%s?%s", requestURL, querystring) + } + } + debugLog("> %s %s", request.Method, requestURL) + + httpRequest, err := http.NewRequest(request.Method, requestURL, request.Body) + if err != nil { + return + } + httpRequest.Host = request.Domain + + client := getTeaClient(runtimeObject.getClientTag(request.Domain)) + client.Lock() + if !client.ifInit { + trans, err := getHttpTransport(request, runtimeObject) + if err != nil { + return nil, err + } + client.httpClient.Timeout = time.Duration(runtimeObject.ConnectTimeout) * time.Second + client.httpClient.Transport = trans + client.ifInit = true + } + client.Unlock() + for key, value := range request.Headers { + if value == "" || key == "content-length" { + continue + } else if key == "host" { + httpRequest.Header["Host"] = []string{value} + } else { + httpRequest.Header[key] = []string{value} + } + debugLog("> %s: %s", key, value) + } + contentlength, _ := strconv.Atoi(request.Headers["content-length"]) + event := NewProgressEvent(TransferStartedEvent, 0, int64(contentlength), 0) + PublishProgress(runtimeObject.Listener, event) + + putMsgToMap(fieldMap, httpRequest) + startTime := time.Now() + fieldMap["{start_time}"] = startTime.Format("2006-01-02 15:04:05") + res, err := hookDo(client.httpClient.Do)(httpRequest) + fieldMap["{cost}"] = time.Since(startTime).String() + completedBytes := int64(0) + if runtimeObject.Tracker != nil { + completedBytes = runtimeObject.Tracker.CompletedBytes + } + if err != nil { + event = NewProgressEvent(TransferFailedEvent, completedBytes, int64(contentlength), 0) + PublishProgress(runtimeObject.Listener, event) + return + } + + event = NewProgressEvent(TransferCompletedEvent, completedBytes, int64(contentlength), 0) + PublishProgress(runtimeObject.Listener, event) + + response = NewResponse(res) + fieldMap["{code}"] = strconv.Itoa(res.StatusCode) + fieldMap["{res_headers}"] = TransToString(res.Header) + debugLog("< HTTP/1.1 %s", res.Status) + for key, value := range res.Header { + debugLog("< %s: %s", key, strings.Join(value, "")) + if len(value) != 0 { + response.Headers[strings.ToLower(key)] = value[0] + } + } + return +} + +func getHttpTransport(req *Request, runtime *RuntimeObject) (*http.Transport, error) { + trans := new(http.Transport) + httpProxy, err := getHttpProxy(req.Protocol, req.Domain, runtime) + if err != nil { + return nil, err + } + trans.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: runtime.IgnoreSSL, + } + if httpProxy != nil { + trans.Proxy = http.ProxyURL(httpProxy) + if httpProxy.User != nil { + password, _ := httpProxy.User.Password() + auth := httpProxy.User.Username() + ":" + password + basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) + req.Headers["Proxy-Authorization"] = basic + } + } + if runtime.Socks5Proxy != "" { + socks5Proxy, err := getSocks5Proxy(runtime) + if err != nil { + return nil, err + } + if socks5Proxy != nil { + var auth *proxy.Auth + if socks5Proxy.User != nil { + password, _ := socks5Proxy.User.Password() + auth = &proxy.Auth{ + User: socks5Proxy.User.Username(), + Password: password, + } + } + dialer, err := proxy.SOCKS5(strings.ToLower(runtime.Socks5NetWork), socks5Proxy.String(), auth, + &net.Dialer{ + Timeout: time.Duration(runtime.ConnectTimeout) * time.Second, + DualStack: true, + LocalAddr: getLocalAddr(runtime.LocalAddr, req.Port), + }) + if err != nil { + return nil, err + } + trans.Dial = dialer.Dial + } + } else { + trans.DialContext = setDialContext(runtime, req.Port) + } + return trans, nil +} + +func TransToString(object interface{}) string { + byt, _ := json.Marshal(object) + return string(byt) +} + +func putMsgToMap(fieldMap map[string]string, request *http.Request) { + fieldMap["{host}"] = request.Host + fieldMap["{method}"] = request.Method + fieldMap["{uri}"] = request.URL.RequestURI() + fieldMap["{pid}"] = strconv.Itoa(os.Getpid()) + fieldMap["{version}"] = strings.Split(request.Proto, "/")[1] + hostname, _ := os.Hostname() + fieldMap["{hostname}"] = hostname + fieldMap["{req_headers}"] = TransToString(request.Header) + fieldMap["{target}"] = request.URL.Path + request.URL.RawQuery +} + +func getNoProxy(protocol string, runtime *RuntimeObject) []string { + var urls []string + if runtime.NoProxy != "" { + urls = strings.Split(runtime.NoProxy, ",") + } else if rawurl := os.Getenv("NO_PROXY"); rawurl != "" { + urls = strings.Split(rawurl, ",") + } else if rawurl := os.Getenv("no_proxy"); rawurl != "" { + urls = strings.Split(rawurl, ",") + } + + return urls +} + +func ToReader(obj interface{}) io.Reader { + switch obj.(type) { + case string: + return strings.NewReader(obj.(string)) + case []byte: + return strings.NewReader(string(obj.([]byte))) + case io.Reader: + return obj.(io.Reader) + default: + panic("Invalid Body. Please set a valid Body.") + } +} + +func ToString(val interface{}) string { + return fmt.Sprintf("%v", val) +} + +func getHttpProxy(protocol, host string, runtime *RuntimeObject) (proxy *url.URL, err error) { + urls := getNoProxy(protocol, runtime) + for _, url := range urls { + if url == host { + return nil, nil + } + } + if protocol == "https" { + if runtime.HttpsProxy != "" { + proxy, err = url.Parse(runtime.HttpsProxy) + } else if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" { + proxy, err = url.Parse(rawurl) + } else if rawurl := os.Getenv("https_proxy"); rawurl != "" { + proxy, err = url.Parse(rawurl) + } + } else { + if runtime.HttpProxy != "" { + proxy, err = url.Parse(runtime.HttpProxy) + } else if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" { + proxy, err = url.Parse(rawurl) + } else if rawurl := os.Getenv("http_proxy"); rawurl != "" { + proxy, err = url.Parse(rawurl) + } + } + + return proxy, err +} + +func getSocks5Proxy(runtime *RuntimeObject) (proxy *url.URL, err error) { + if runtime.Socks5Proxy != "" { + proxy, err = url.Parse(runtime.Socks5Proxy) + } + return proxy, err +} + +func getLocalAddr(localAddr string, port int) (addr *net.TCPAddr) { + if localAddr != "" { + addr = &net.TCPAddr{ + Port: port, + IP: []byte(localAddr), + } + } + return addr +} + +func setDialContext(runtime *RuntimeObject, port int) func(cxt context.Context, net, addr string) (c net.Conn, err error) { + return func(ctx context.Context, network, address string) (net.Conn, error) { + if runtime.LocalAddr != "" { + netAddr := &net.TCPAddr{ + Port: port, + IP: []byte(runtime.LocalAddr), + } + return (&net.Dialer{ + Timeout: time.Duration(runtime.ConnectTimeout) * time.Second, + DualStack: true, + LocalAddr: netAddr, + }).DialContext(ctx, network, address) + } + return (&net.Dialer{ + Timeout: time.Duration(runtime.ConnectTimeout) * time.Second, + DualStack: true, + }).DialContext(ctx, network, address) + } +} + +func (err *SDKError) Error() string { + return fmt.Sprintf("SDKError: %s %s %s", err.Code, err.Message, err.Data) +} + +func ToObject(obj interface{}) map[string]interface{} { + result := make(map[string]interface{}) + byt, _ := json.Marshal(obj) + err := json.Unmarshal(byt, &result) + if err != nil { + return nil + } + return result +} + +func AllowRetry(retry interface{}, retryTimes int) bool { + if retryTimes == 0 { + return true + } + retryMap, ok := retry.(map[string]interface{}) + if !ok { + return false + } + retryable, ok := retryMap["retryable"].(bool) + if !ok || !retryable { + return false + } + + maxAttempts, ok := retryMap["maxAttempts"].(int) + if !ok || maxAttempts < retryTimes { + return false + } + return true +} + +func Merge(args ...interface{}) map[string]string { + finalArg := make(map[string]string) + for _, obj := range args { + switch obj.(type) { + case map[string]string: + arg := obj.(map[string]string) + for key, value := range arg { + if value != "" { + finalArg[key] = value + } + } + default: + byt, _ := json.Marshal(obj) + arg := make(map[string]string) + err := json.Unmarshal(byt, &arg) + if err != nil { + return finalArg + } + for key, value := range arg { + if value != "" { + finalArg[key] = value + } + } + } + } + + return finalArg +} + +func isNil(a interface{}) bool { + defer func() { + recover() + }() + vi := reflect.ValueOf(a) + return vi.IsNil() +} + +func ToMap(args ...interface{}) map[string]interface{} { + isNotNil := false + finalArg := make(map[string]interface{}) + for _, obj := range args { + if obj == nil { + continue + } + + if isNil(obj) { + continue + } + isNotNil = true + + switch obj.(type) { + case map[string]string: + arg := obj.(map[string]string) + for key, value := range arg { + if value != "" { + finalArg[key] = value + } + } + case map[string]interface{}: + arg := obj.(map[string]interface{}) + for key, value := range arg { + if value != nil { + finalArg[key] = value + } + } + case string: + str := obj.(string) + arg := make(map[string]interface{}) + err := json.Unmarshal([]byte(str), &arg) + if err == nil { + for key, value := range arg { + if value != nil { + finalArg[key] = value + } + } + } + tmp := make(map[string]string) + err = json.Unmarshal([]byte(str), &tmp) + if err == nil { + for key, value := range arg { + if value != "" { + finalArg[key] = value + } + } + } + case []byte: + byt := obj.([]byte) + arg := make(map[string]interface{}) + err := json.Unmarshal(byt, &arg) + if err == nil { + for key, value := range arg { + if value != nil { + finalArg[key] = value + } + } + break + } + default: + val := reflect.ValueOf(obj) + res := structToMap(val) + for key, value := range res { + if value != nil { + finalArg[key] = value + } + } + } + } + + if !isNotNil { + return nil + } + return finalArg +} + +func structToMap(dataValue reflect.Value) map[string]interface{} { + out := make(map[string]interface{}) + if !dataValue.IsValid() { + return out + } + if dataValue.Kind().String() == "ptr" { + dataValue = dataValue.Elem() + } + if !dataValue.IsValid() { + return out + } + dataType := dataValue.Type() + if dataType.Kind().String() != "struct" { + return out + } + for i := 0; i < dataType.NumField(); i++ { + field := dataType.Field(i) + name, containsNameTag := field.Tag.Lookup("json") + if !containsNameTag { + name = field.Name + } + fieldValue := dataValue.FieldByName(field.Name) + if !fieldValue.IsValid() { + continue + } + if field.Type.Kind().String() == "struct" { + out[name] = structToMap(fieldValue) + } else if field.Type.Kind().String() == "ptr" && + field.Type.Elem().Kind().String() == "struct" { + if fieldValue.Elem().IsValid() { + out[name] = structToMap(fieldValue) + } + } else if field.Type.Kind().String() == "ptr" { + if fieldValue.IsValid() && !fieldValue.IsNil() { + out[name] = fieldValue.Elem().Interface() + } + } else if field.Type.Kind().String() == "slice" { + tmp := make([]interface{}, 0) + num := fieldValue.Len() + for i := 0; i < num; i++ { + value := fieldValue.Index(i) + if !value.IsValid() { + continue + } + if value.Type().Kind().String() == "ptr" && + value.Type().Elem().Kind().String() == "struct" { + if value.IsValid() && !value.IsNil() { + tmp = append(tmp, structToMap(value)) + } + } else if value.Type().Kind().String() == "struct" { + tmp = append(tmp, structToMap(value)) + } else if value.Type().Kind().String() == "ptr" { + if value.IsValid() && !value.IsNil() { + tmp = append(tmp, value.Elem().Interface()) + } + } else { + tmp = append(tmp, value.Interface()) + } + } + if len(tmp) > 0 { + out[name] = tmp + } + } else { + out[name] = fieldValue.Interface() + } + + } + return out +} + +func Retryable(err error) bool { + if err == nil { + return false + } + if realErr, ok := err.(*SDKError); ok { + code, err := strconv.Atoi(realErr.Code) + if err != nil { + return true + } + return code >= http.StatusInternalServerError + } + return true +} + +func GetBackoffTime(backoff interface{}, retrytimes int) int { + backoffMap, ok := backoff.(map[string]interface{}) + if !ok { + return 0 + } + policy, ok := backoffMap["policy"].(string) + if !ok || policy == "no" { + return 0 + } + + period, ok := backoffMap["period"].(int) + if !ok || period == 0 { + return 0 + } + + maxTime := math.Pow(2.0, float64(retrytimes)) + return rand.Intn(int(maxTime-1)) * period +} + +func Sleep(backoffTime int) { + sleeptime := time.Duration(backoffTime) * time.Second + time.Sleep(sleeptime) +} + +func Validate(params interface{}) error { + requestValue := reflect.ValueOf(params).Elem() + err := validate(requestValue) + return err +} + +// Verify whether the parameters meet the requirements +func validate(dataValue reflect.Value) error { + if strings.HasPrefix(dataValue.Type().String(), "*") { // Determines whether the input is a structure object or a pointer object + if dataValue.IsNil() { + return nil + } + dataValue = dataValue.Elem() + } + dataType := dataValue.Type() + for i := 0; i < dataType.NumField(); i++ { + field := dataType.Field(i) + valueField := dataValue.Field(i) + for _, value := range validateParams { + err := validateParam(field, valueField, value) + if err != nil { + return err + } + } + } + return nil +} + +func validateParam(field reflect.StructField, valueField reflect.Value, tagName string) error { + tag, containsTag := field.Tag.Lookup(tagName) // Take out the checked regular expression + if containsTag && tagName == "require" { + err := checkRequire(field, valueField) + if err != nil { + return err + } + } + if strings.HasPrefix(field.Type.String(), "[]") { // Verify the parameters of the array type + err := validateSlice(valueField, containsTag, tag, tagName) + if err != nil { + return err + } + } else if valueField.Kind() == reflect.Ptr { // Determines whether it is a pointer object + err := validatePtr(valueField, containsTag, tag, tagName) + if err != nil { + return err + } + } + return nil +} + +func validateSlice(valueField reflect.Value, containsregexpTag bool, tag, tagName string) error { + if valueField.IsValid() && !valueField.IsNil() { // Determines whether the parameter has a value + for m := 0; m < valueField.Len(); m++ { + elementValue := valueField.Index(m) + if elementValue.Type().Kind() == reflect.Ptr { // Determines whether the child elements of an array are of a basic type + err := validatePtr(elementValue, containsregexpTag, tag, tagName) + if err != nil { + return err + } + } + } + } + return nil +} + +func validatePtr(elementValue reflect.Value, containsregexpTag bool, tag, tagName string) error { + if elementValue.IsNil() { + return nil + } + + if isFilterType(elementValue.Elem().Type().String(), basicTypes) { + if containsregexpTag { + if tagName == "pattern" { + err := checkPattern(elementValue.Elem(), tag) + if err != nil { + return err + } + } + + if tagName == "maxLength" { + err := checkMaxLength(elementValue.Elem(), tag) + if err != nil { + return err + } + } + } + } else { + err := validate(elementValue) + if err != nil { + return err + } + } + return nil +} + +func checkRequire(field reflect.StructField, valueField reflect.Value) error { + name, _ := field.Tag.Lookup("json") + if !valueField.IsNil() && valueField.IsValid() { + return nil + } + return errors.New(name + " should be setted") +} + +func checkPattern(valueField reflect.Value, tag string) error { + if valueField.IsValid() && valueField.String() != "" { + value := valueField.String() + if match, _ := regexp.MatchString(tag, value); !match { // Determines whether the parameter value satisfies the regular expression or not, and throws an error + return errors.New(value + " is not matched " + tag) + } + } + return nil +} + +func checkMaxLength(valueField reflect.Value, tag string) error { + if valueField.IsValid() && valueField.String() != "" { + maxLength, err := strconv.Atoi(tag) + if err != nil { + return err + } + length := valueField.Len() + if valueField.Kind().String() == "string" { + length = strings.Count(valueField.String(), "") - 1 + } + if maxLength < length { + errMsg := fmt.Sprintf("Length of %s is more than %d", valueField.String(), maxLength) + return errors.New(errMsg) + } + } + return nil +} + +// Determines whether realType is in filterTypes +func isFilterType(realType string, filterTypes []string) bool { + for _, value := range filterTypes { + if value == realType { + return true + } + } + return false +} + +func TransInterfaceToBool(val interface{}) bool { + if val == nil { + return false + } + + return val.(bool) +} + +func TransInterfaceToInt(val interface{}) int { + if val == nil { + return 0 + } + + return val.(int) +} + +func TransInterfaceToString(val interface{}) string { + if val == nil { + return "" + } + + return val.(string) +} + +func Prettify(i interface{}) string { + resp, _ := json.MarshalIndent(i, "", " ") + return string(resp) +} diff --git a/serve/vendor/alipaysdk/easysdk/go/src/tea/utils.go b/serve/vendor/alipaysdk/easysdk/go/src/tea/utils.go new file mode 100644 index 0000000..c02590d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/tea/utils.go @@ -0,0 +1,44 @@ +package tea + + +import ( + "reflect" + "strings" + "testing" +) + +func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool { + for i := 0; i < len(kinds); i++ { + if kind == kinds[i] { + return true + } + } + + return false +} + +func AssertEqual(t *testing.T, a, b interface{}) { + if !reflect.DeepEqual(a, b) { + t.Errorf("%v != %v", a, b) + } +} + +func AssertNil(t *testing.T, object interface{}) { + if !isNil(object) { + t.Errorf("%v is not nil", object) + } +} + +func AssertNotNil(t *testing.T, object interface{}) { + if isNil(object) { + t.Errorf("%v is nil", object) + } +} + +func AssertContains(t *testing.T, contains string, msgAndArgs ...string) { + for _, value := range msgAndArgs { + if ok := strings.Contains(contains, value); !ok { + t.Errorf("%s does not contain %s", contains, value) + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/go/src/test/main.go b/serve/vendor/alipaysdk/easysdk/go/src/test/main.go new file mode 100644 index 0000000..0734d0b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/go/src/test/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "encoding/json" + "fmt" + "kernel" + "time" +) + +func init() { + account:= kernel.Client{} + account.Protocol = "https" + account.GatewayHost = "openapi.alipay.com" + account.AppId = "<-- 请填写您的AppId,例如:2019022663440152 -->" + account.SignType = "RSA2" + account.AlipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->" + account.MerchantPrivateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->" + + kernel.InitClient(account) +} + + +func main() { + result, _ := kernel.Execute("alipay.trade.create", nil, getBizParams(time.Now().Format("2006-01-02 15:04:05"))) + fmt.Println(result) +} + +func getBizParams(outTradeNo string) map[string]string { + bizParams := map[string]string{ + "subject": "phone6 16G", + "out_trade_no": outTradeNo, + "total_amount": "0.10", + "buyer_id": "2088002656718920", + "extend_params": getHuabeiParams(), + } + return bizParams +} + +func getHuabeiParams() string { + extendParams := map[string]string{ + "hb_fq_num": "3", + "hb_fq_seller_percent": "3", + } + byt, _ := json.Marshal(extendParams) + return string(byt) +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/README.md b/serve/vendor/alipaysdk/easysdk/java/README.md new file mode 100644 index 0000000..f9463b6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/README.md @@ -0,0 +1,235 @@ +[![Maven Central](https://img.shields.io/maven-central/v/com.alipay.sdk/alipay-easysdk.svg)](https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk?ref=badge_shield) + +欢迎使用 Alipay **Easy** SDK for Java 。 + +Alipay Esay SDK for Java让您不用复杂编程即可访支付宝开放平台开放的各项常用能力,SDK可以自动帮您满足能力调用过程中所需的证书校验、加签、验签、发送HTTP请求等非功能性要求。 + +下面向您介绍Alipay Easy SDK for Java 的基本设计理念和使用方法。 + +## 设计理念 +不同于原有的[Alipay SDK](https://github.com/alipay/alipay-sdk-java-all)通用而全面的设计理念,Alipay Easy SDK对开放能力的API进行了更加贴近高频场景的精心设计与裁剪,简化了服务端调用方式,让调用API像使用语言内置的函数一样简便。 + +同时,您也不必担心面向高频场景提炼的API可能无法完全契合自己的个性化场景,Alipay Easy SDK支持灵活的动态扩展方式,同样可以满足低频参数、低频API的使用需求。 + +Alipay Easy SDK提供了与[能力地图](https://opendocs.alipay.com/mini/00am3f)相对应的代码组织结构,让开发者可以快速找到不同能力对应的API。 + +Alipay Easy SDK主要目标是提升开发者在**服务端**集成支付宝开放平台开放的各类核心能力的效率。 + +## 环境要求 +1. Alipay Easy SDK for Java 需要配合`JDK 1.8`或其以上版本。 + +2. 使用 Alipay Easy SDK for Java 之前 ,您需要先前往[支付宝开发平台-开发者中心](https://openhome.alipay.com/platform/developerIndex.htm)完成开发者接入的一些准备工作,包括创建应用、为应用添加功能包、设置应用的接口加签方式等。 + +3. 准备工作完成后,注意保存如下信息,后续将作为使用SDK的输入。 + +* 加签模式为公钥证书模式时(推荐) + +`AppId`、`应用的私钥`、`应用公钥证书文件`、`支付宝公钥证书文件`、`支付宝根证书文件` + +* 加签模式为公钥模式时 + +`AppId`、`应用的私钥`、`支付宝公钥` + +## 安装依赖 +### 通过[Maven](https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk)来管理项目依赖 +推荐通过Maven来管理项目依赖,您只需在项目的`pom.xml`文件中声明如下依赖 + +```xml + + com.alipay.sdk + alipay-easysdk + Use the version shown in the maven badge + +``` + +## 快速开始 +### 普通调用 +以下这段代码示例向您展示了使用Alipay Easy SDK for Java调用一个API的3个主要步骤: + +1. 设置参数(全局只需设置一次)。 +2. 发起API调用。 +3. 处理响应或异常。 + +```java +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.factory.Factory.Payment; +import com.alipay.easysdk.kernel.Config; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse; + +public class Main { + public static void main(String[] args) throws Exception { + // 1. 设置参数(全局只需设置一次) + Factory.setOptions(getOptions()); + try { + // 2. 发起API调用(以创建当面付收款二维码为例) + AlipayTradePrecreateResponse response = Payment.FaceToFace() + .preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); + // 3. 处理响应或异常 + if (ResponseChecker.success(response)) { + System.out.println("调用成功"); + } else { + System.err.println("调用失败,原因:" + response.msg + "," + response.subMsg); + } + } catch (Exception e) { + System.err.println("调用遭遇异常,原因:" + e.getMessage()); + throw new RuntimeException(e.getMessage(), e); + } + } + + private static Config getOptions() { + Config config = new Config(); + config.protocol = "https"; + config.gatewayHost = "openapi.alipay.com"; + config.signType = "RSA2"; + + config.appId = "<-- 请填写您的AppId,例如:2019091767145019 -->"; + + // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中 + config.merchantPrivateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->"; + + //注:证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径,优先从文件系统中加载,加载失败后会继续尝试从CLASS_PATH中加载 + config.merchantCertPath = "<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->"; + config.alipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->"; + config.alipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt -->"; + + //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可 + // config.alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->"; + + //可设置异步通知接收服务地址(可选) + config.notifyUrl = "<-- 请填写您的支付类接口异步通知接收服务地址,例如:https://www.test.com/callback -->"; + + //可设置AES密钥,调用AES加解密相关接口时需要(可选) + config.encryptKey = "<-- 请填写您的AES密钥,例如:aa4BtZ4tspm2wnXLb1ThQA== -->"; + + return config; + } +} +``` + +### 扩展调用 +#### ISV代调用 + +```java +Factory.Payment.FaceToFace() + // 调用agent扩展方法,设置app_auth_token,完成ISV代调用 + .agent("ca34ea491e7146cc87d25fca24c4cD11") + .preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +#### 设置独立的异步通知地址 + +```java +Factory.Payment.FaceToFace() + // 调用asyncNotify扩展方法,可以为每此API调用,设置独立的异步通知地址 + // 此处设置的异步通知地址的优先级高于全局Config中配置的异步通知地址 + .asyncNotify("https://www.test.com/callback") + .preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +#### 设置可选业务参数 + +```java +List goodsDetailList = new ArrayList<>(); +Map goodsDetail = new HashMap<>(); +goodsDetail.put("goods_id", "apple-01"); +goodsDetail.put("goods_name", "Apple iPhone11 128G"); +goodsDetail.put("quantity", 1); +goodsDetail.put("price", "5799.00"); +goodsDetailList.add(goodsDetail); + +Factory.Payment.FaceToFace() + // 调用optional扩展方法,完成可选业务参数(biz_content下的可选字段)的设置 + .optional("seller_id", "2088102146225135") + .optional("discountable_amount", "8.88") + .optional("goods_detail", goodsDetailList) + .preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); + + +Map optionalArgs = new HashMap<>(); +optionalArgs.put("seller_id", "2088102146225135"); +optionalArgs.put("discountable_amount", "8.88"); +optionalArgs.put("goods_detail", goodsDetailList); + +Factory.Payment.FaceToFace() + // 也可以调用batchOptional扩展方法,批量设置可选业务参数(biz_content下的可选字段) + .batchOptional(optionalArgs) + .preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` +#### 多种扩展灵活组合 + +```java +// 多种扩展方式可灵活组装(对扩展方法的调用顺序没有要求) +Factory.Payment.FaceToFace() + .agent("ca34ea491e7146cc87d25fca24c4cD11") + .asyncNotify("https://www.test.com/callback") + .optional("seller_id", "2088102146225135") + .preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +## API组织规范 +在Alipay Easy SDK中,API的引用路径与能力地图的组织层次一致,遵循如下规范 + +> Factory.能力名称.场景名称().接口方法名称( ... ) + +比如,如果您想要使用[能力地图](https://opendocs.alipay.com/mini/00am3f)中`营销能力`下的`模板消息`场景中的`小程序发送模板消息`,只需按如下形式编写调用代码即可。 + +`Factory.Marketing.TemplateMessage().send( ... )` + +其中,接口方法名称通常是对其依赖的OpenAPI功能的一个最简概况,接口方法的出入参与OpenAPI中同名参数含义一致,可参照OpenAPI相关参数的使用说明。 + +Alipay Easy SDK将致力于保持良好的API命名,以符合开发者的编程直觉。 + +## 已支持的API列表 + +| 能力类别 | 场景类别 | 接口方法名称 | 调用的OpenAPI名称 | +|-----------|-----------------|------------------------|-----------------------------------------------------------| +| Base | OAuth | getToken | alipay\.system\.oauth\.token | +| Base | OAuth | refreshToken | alipay\.system\.oauth\.token | +| Base | Qrcode | create | alipay\.open\.app\.qrcode\.create | +| Base | Image | upload | alipay\.offline\.material\.image\.upload | +| Base | Video | upload | alipay\.offline\.material\.image\.upload | +| Member | Identification | init | alipay\.user\.certify\.open\.initialize | +| Member | Identification | certify | alipay\.user\.certify\.open\.certify | +| Member | Identification | query | alipay\.user\.certify\.open\.query | +| Payment | Common | create | alipay\.trade\.create | +| Payment | Common | query | alipay\.trade\.query | +| Payment | Common | refund | alipay\.trade\.refund | +| Payment | Common | close | alipay\.trade\.close | +| Payment | Common | cancel | alipay\.trade\.cancel | +| Payment | Common | queryRefund | alipay\.trade\.fastpay\.refund\.query | +| Payment | Common | downloadBill | alipay\.data\.dataservice\.bill\.downloadurl\.query | +| Payment | Common | verifyNotify | - | +| Payment | Huabei | create | alipay\.trade\.create | +| Payment | FaceToFace | pay | alipay\.trade\.pay | +| Payment | FaceToFace | precreate | alipay\.trade\.precreate | +| Payment | App | pay | alipay\.trade\.app\.pay | +| Payment | Page | pay | alipay\.trade\.page\.pay | +| Payment | Wap | pay | alipay\.trade\.wap\.pay | +| Security | TextRisk | detect | alipay\.security\.risk\.content\.detect | +| Marketing | Pass | createTemplate | alipay\.pass\.template\.add | +| Marketing | Pass | updateTemplate | alipay\.pass\.template\.update | +| Marketing | Pass | addInstance | alipay\.pass\.instance\.add | +| Marketing | Pass | updateInstance | alipay\.pass\.instance\.update | +| Marketing | TemplateMessage | send | alipay\.open\.app\.mini\.templatemessage\.send | +| Marketing | OpenLife | createImageTextContent | alipay\.open\.public\.message\.content\.create | +| Marketing | OpenLife | modifyImageTextContent | alipay\.open\.public\.message\.content\.modify | +| Marketing | OpenLife | sendText | alipay\.open\.public\.message\.total\.send | +| Marketing | OpenLife | sendImageText | alipay\.open\.public\.message\.total\.send | +| Marketing | OpenLife | sendSingleMessage | alipay\.open\.public\.message\.single\.send | +| Marketing | OpenLife | recallMessage | alipay\.open\.public\.life\.msg\.recall | +| Marketing | OpenLife | setIndustry | alipay\.open\.public\.template\.message\.industry\.modify | +| Marketing | OpenLife | getIndustry | alipay\.open\.public\.setting\.category\.query | +| Util | AES | decrypt | - | +| Util | AES | encrypt | - | +| Util | Generic | execute | - | +| Util | Generic | sdkExecute | - | +| Util | Generic | fileExecute | - | + +> 注:更多高频场景的API持续更新中,敬请期待。 + +## 文档 +[API Doc](./../APIDoc.md) + +[Alipay Easy SDK](./../README.md) diff --git a/serve/vendor/alipaysdk/easysdk/java/pom.xml b/serve/vendor/alipaysdk/easysdk/java/pom.xml new file mode 100644 index 0000000..3aa5a0e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/pom.xml @@ -0,0 +1,195 @@ + + + 4.0.0 + com.alipay.sdk + alipay-easysdk + 2.2.0 + Alipay Easy SDK + https://open.alipay.com + Alipay Easy SDK for Java + allows you to enjoy a minimalist programming experience + and quickly access the various high-frequency capabilities of the Alipay Open Platform. + + + + mvnrepository + mvnrepository + http://www.mvnrepository.com/ + default + + true + + + false + + + + + UTF-8 + 1.7 + 1.7 + + + + junit + junit + 4.11 + test + + + ch.qos.logback + logback-core + 1.2.3 + test + + + ch.qos.logback + logback-classic + 1.2.3 + test + + + ch.qos.logback + logback-access + 1.2.3 + test + + + org.mockito + mockito-core + 3.2.0 + test + + + com.alipay.sdk + easysdk-kernel + 1.0.8 + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + sonatype-nexus-staging + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + MIT License + http://www.opensource.org/licenses/mit-license.php + + + + scm:git:git@github.com:alipay/alipay-easysdk.git + scm:git:ssh://github.com:alipay/alipay-easysdk.git + http://github.com/alipay/alipay-easysdk/tree/master/java + + + + antopen + antopen + antopen@aliyun.com + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + UTF-8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.3.2 + + + + + maven-deploy-plugin + 2.8.2 + + + default-deploy + deploy + + deploy + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + + + org.apache.maven.plugins + maven-scm-plugin + 1.8.1 + + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + attach-sources + verify + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + true + UTF-8 + UTF-8 + UTF-8 + -Xdoclint:none + + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/image/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/image/Client.java new file mode 100644 index 0000000..d951cb5 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/image/Client.java @@ -0,0 +1,178 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.base.image; + +import com.aliyun.tea.*; +import com.alipay.easysdk.base.image.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayOfflineMaterialImageUploadResponse upload(String imageName, String imageFilePath) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 100000), + new TeaPair("readTimeout", 100000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.offline.material.image.upload"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = new java.util.HashMap<>(); + java.util.Map textParams = TeaConverter.buildMap( + new TeaPair("image_type", "jpg"), + new TeaPair("image_name", imageName) + ); + java.util.Map fileParams = TeaConverter.buildMap( + new TeaPair("image_content", imageFilePath) + ); + String boundary = _kernel.getRandomBoundary(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", _kernel.concatStr("multipart/form-data;charset=utf-8;boundary=", boundary)) + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams + )); + request_.body = _kernel.toMultipartRequestBody(textParams, fileParams, boundary); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.offline.material.image.upload"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOfflineMaterialImageUploadResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOfflineMaterialImageUploadResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/image/models/AlipayOfflineMaterialImageUploadResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/image/models/AlipayOfflineMaterialImageUploadResponse.java new file mode 100644 index 0000000..d0b1f45 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/image/models/AlipayOfflineMaterialImageUploadResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.base.image.models; + +import com.aliyun.tea.*; + +public class AlipayOfflineMaterialImageUploadResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("image_id") + @Validation(required = true) + public String imageId; + + @NameInMap("image_url") + @Validation(required = true) + public String imageUrl; + + public static AlipayOfflineMaterialImageUploadResponse build(java.util.Map map) throws Exception { + AlipayOfflineMaterialImageUploadResponse self = new AlipayOfflineMaterialImageUploadResponse(); + return TeaModel.build(map, self); + } + + public AlipayOfflineMaterialImageUploadResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOfflineMaterialImageUploadResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOfflineMaterialImageUploadResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOfflineMaterialImageUploadResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOfflineMaterialImageUploadResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayOfflineMaterialImageUploadResponse setImageId(String imageId) { + this.imageId = imageId; + return this; + } + public String getImageId() { + return this.imageId; + } + + public AlipayOfflineMaterialImageUploadResponse setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + return this; + } + public String getImageUrl() { + return this.imageUrl; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/oauth/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/oauth/Client.java new file mode 100644 index 0000000..0a457ab --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/oauth/Client.java @@ -0,0 +1,261 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.base.oauth; + +import com.aliyun.tea.*; +import com.alipay.easysdk.base.oauth.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipaySystemOauthTokenResponse getToken(String code) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.system.oauth.token"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = new java.util.HashMap<>(); + java.util.Map textParams = TeaConverter.buildMap( + new TeaPair("grant_type", "authorization_code"), + new TeaPair("code", code) + ); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.system.oauth.token"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipaySystemOauthTokenResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipaySystemOauthTokenResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipaySystemOauthTokenResponse refreshToken(String refreshToken) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.system.oauth.token"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = new java.util.HashMap<>(); + java.util.Map textParams = TeaConverter.buildMap( + new TeaPair("grant_type", "refresh_token"), + new TeaPair("refresh_token", refreshToken) + ); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.system.oauth.token"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipaySystemOauthTokenResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipaySystemOauthTokenResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/oauth/models/AlipaySystemOauthTokenResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/oauth/models/AlipaySystemOauthTokenResponse.java new file mode 100644 index 0000000..9920331 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/oauth/models/AlipaySystemOauthTokenResponse.java @@ -0,0 +1,133 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.base.oauth.models; + +import com.aliyun.tea.*; + +public class AlipaySystemOauthTokenResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("user_id") + @Validation(required = true) + public String userId; + + @NameInMap("access_token") + @Validation(required = true) + public String accessToken; + + @NameInMap("expires_in") + @Validation(required = true) + public Long expiresIn; + + @NameInMap("refresh_token") + @Validation(required = true) + public String refreshToken; + + @NameInMap("re_expires_in") + @Validation(required = true) + public Long reExpiresIn; + + public static AlipaySystemOauthTokenResponse build(java.util.Map map) throws Exception { + AlipaySystemOauthTokenResponse self = new AlipaySystemOauthTokenResponse(); + return TeaModel.build(map, self); + } + + public AlipaySystemOauthTokenResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipaySystemOauthTokenResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipaySystemOauthTokenResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipaySystemOauthTokenResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipaySystemOauthTokenResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipaySystemOauthTokenResponse setUserId(String userId) { + this.userId = userId; + return this; + } + public String getUserId() { + return this.userId; + } + + public AlipaySystemOauthTokenResponse setAccessToken(String accessToken) { + this.accessToken = accessToken; + return this; + } + public String getAccessToken() { + return this.accessToken; + } + + public AlipaySystemOauthTokenResponse setExpiresIn(Long expiresIn) { + this.expiresIn = expiresIn; + return this; + } + public Long getExpiresIn() { + return this.expiresIn; + } + + public AlipaySystemOauthTokenResponse setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + return this; + } + public String getRefreshToken() { + return this.refreshToken; + } + + public AlipaySystemOauthTokenResponse setReExpiresIn(Long reExpiresIn) { + this.reExpiresIn = reExpiresIn; + return this; + } + public Long getReExpiresIn() { + return this.reExpiresIn; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/qrcode/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/qrcode/Client.java new file mode 100644 index 0000000..9a66b6a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/qrcode/Client.java @@ -0,0 +1,176 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.base.qrcode; + +import com.aliyun.tea.*; +import com.alipay.easysdk.base.qrcode.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayOpenAppQrcodeCreateResponse create(String urlParam, String queryParam, String describe) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.app.qrcode.create"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("url_param", urlParam), + new TeaPair("query_param", queryParam), + new TeaPair("describe", describe) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.app.qrcode.create"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenAppQrcodeCreateResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenAppQrcodeCreateResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/qrcode/models/AlipayOpenAppQrcodeCreateResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/qrcode/models/AlipayOpenAppQrcodeCreateResponse.java new file mode 100644 index 0000000..a1a6daa --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/qrcode/models/AlipayOpenAppQrcodeCreateResponse.java @@ -0,0 +1,85 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.base.qrcode.models; + +import com.aliyun.tea.*; + +public class AlipayOpenAppQrcodeCreateResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("qr_code_url") + @Validation(required = true) + public String qrCodeUrl; + + public static AlipayOpenAppQrcodeCreateResponse build(java.util.Map map) throws Exception { + AlipayOpenAppQrcodeCreateResponse self = new AlipayOpenAppQrcodeCreateResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenAppQrcodeCreateResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenAppQrcodeCreateResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenAppQrcodeCreateResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenAppQrcodeCreateResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenAppQrcodeCreateResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayOpenAppQrcodeCreateResponse setQrCodeUrl(String qrCodeUrl) { + this.qrCodeUrl = qrCodeUrl; + return this; + } + public String getQrCodeUrl() { + return this.qrCodeUrl; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/video/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/video/Client.java new file mode 100644 index 0000000..fcb1989 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/video/Client.java @@ -0,0 +1,178 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.base.video; + +import com.aliyun.tea.*; +import com.alipay.easysdk.base.video.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayOfflineMaterialImageUploadResponse upload(String videoName, String videoFilePath) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 100000), + new TeaPair("readTimeout", 100000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.offline.material.image.upload"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = new java.util.HashMap<>(); + java.util.Map textParams = TeaConverter.buildMap( + new TeaPair("image_type", "mp4"), + new TeaPair("image_name", videoName) + ); + java.util.Map fileParams = TeaConverter.buildMap( + new TeaPair("image_content", videoFilePath) + ); + String boundary = _kernel.getRandomBoundary(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", _kernel.concatStr("multipart/form-data;charset=utf-8;boundary=", boundary)) + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams + )); + request_.body = _kernel.toMultipartRequestBody(textParams, fileParams, boundary); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.offline.material.image.upload"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOfflineMaterialImageUploadResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOfflineMaterialImageUploadResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/video/models/AlipayOfflineMaterialImageUploadResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/video/models/AlipayOfflineMaterialImageUploadResponse.java new file mode 100644 index 0000000..cbe2687 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/base/video/models/AlipayOfflineMaterialImageUploadResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.base.video.models; + +import com.aliyun.tea.*; + +public class AlipayOfflineMaterialImageUploadResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("image_id") + @Validation(required = true) + public String imageId; + + @NameInMap("image_url") + @Validation(required = true) + public String imageUrl; + + public static AlipayOfflineMaterialImageUploadResponse build(java.util.Map map) throws Exception { + AlipayOfflineMaterialImageUploadResponse self = new AlipayOfflineMaterialImageUploadResponse(); + return TeaModel.build(map, self); + } + + public AlipayOfflineMaterialImageUploadResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOfflineMaterialImageUploadResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOfflineMaterialImageUploadResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOfflineMaterialImageUploadResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOfflineMaterialImageUploadResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayOfflineMaterialImageUploadResponse setImageId(String imageId) { + this.imageId = imageId; + return this; + } + public String getImageId() { + return this.imageId; + } + + public AlipayOfflineMaterialImageUploadResponse setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + return this; + } + public String getImageUrl() { + return this.imageUrl; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/factory/Factory.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/factory/Factory.java new file mode 100644 index 0000000..0190e6f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/factory/Factory.java @@ -0,0 +1,259 @@ +/** + * Alipay.com Inc. Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.factory; + +import com.alipay.easysdk.kernel.AlipayConstants; +import com.alipay.easysdk.kernel.Client; +import com.alipay.easysdk.kernel.Config; +import com.alipay.easysdk.kernel.Context; +import com.alipay.easysdk.kms.aliyun.AliyunKMSClient; +import com.alipay.easysdk.kms.aliyun.AliyunKMSSigner; +import com.aliyun.tea.TeaModel; + +import java.lang.reflect.Constructor; + +/** + * 客户端工厂,用于快速配置和访问各种场景下的API Client + * + * 注:该Factory获取的Client不可储存重复使用,请每次均通过Factory完成调用 + * + * @author zhongyu + * @version $Id: Factory.java, v 0.1 2020年01月18日 11:26 AM zhongyu Exp $ + */ +public class Factory { + + public static final String SDK_VERSION = "alipay-easysdk-java-2.1.2"; + + /** + * 将一些初始化耗时较多的信息缓存在上下文中 + */ + private static Context context; + + /** + * 设置客户端参数,只需设置一次,即可反复使用各种场景下的API Client + * + * @param options 客户端参数对象 + */ + public static void setOptions(Config options) { + try { + context = new Context(options, SDK_VERSION); + + if (AlipayConstants.AliyunKMS.equals(context.getConfig(AlipayConstants.SIGN_PROVIDER_CONFIG_KEY))) { + context.setSigner(new AliyunKMSSigner(new AliyunKMSClient(TeaModel.buildMap(options)))); + } + + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + /** + * 获取调用OpenAPI所需的客户端实例 + * 本方法用于调用SDK扩展包中的API Client下的方法 + * + * 注:返回的实例不可重复使用,只可用于单次调用 + * + * @param client API Client的类型对象 + * @return client实例,用于发起单次调用 + */ + public static T getClient(Class client) { + try { + Constructor constructor = client.getConstructor(Client.class); + context.setSdkVersion(getSdkVersion(client)); + return constructor.newInstance(new Client(context)); + } catch (Exception e) { + throw new RuntimeException("" + e.getMessage(), e); + } + } + + private static String getSdkVersion(Class client) { + return context.getSdkVersion() + "-" + client.getCanonicalName() + .replace("com.alipay.easysdk.", "") + .replace(".Client", "") + .replace(".", "-"); + } + + /** + * 支付能力相关 + */ + public static class Payment { + /** + * 获取支付通用API Client + * + * @return 支付通用API Client + */ + public static com.alipay.easysdk.payment.common.Client Common() throws Exception { + return new com.alipay.easysdk.payment.common.Client(new Client(context)); + } + + /** + * 获取花呗相关API Client + * + * @return 花呗相关API Client + */ + public static com.alipay.easysdk.payment.huabei.Client Huabei() throws Exception { + return new com.alipay.easysdk.payment.huabei.Client(new Client(context)); + } + + /** + * 获取当面付相关API Client + * + * @return 当面付相关API Client + */ + public static com.alipay.easysdk.payment.facetoface.Client FaceToFace() throws Exception { + return new com.alipay.easysdk.payment.facetoface.Client(new Client(context)); + } + + /** + * 获取电脑网站支付相关API Client + * + * @return 电脑网站支付相关API Client + */ + public static com.alipay.easysdk.payment.page.Client Page() throws Exception { + return new com.alipay.easysdk.payment.page.Client(new Client(context)); + } + + /** + * 获取手机网站支付相关API Client + * + * @return 手机网站支付相关API Client + */ + public static com.alipay.easysdk.payment.wap.Client Wap() throws Exception { + return new com.alipay.easysdk.payment.wap.Client(new Client(context)); + } + + /** + * 获取手机APP支付相关API Client + * + * @return 手机APP支付相关API Client + */ + public static com.alipay.easysdk.payment.app.Client App() throws Exception { + return new com.alipay.easysdk.payment.app.Client(new Client(context)); + } + } + + /** + * 基础能力相关 + */ + public static class Base { + /** + * 获取图片相关API Client + * + * @return 图片相关API Client + */ + public static com.alipay.easysdk.base.image.Client Image() throws Exception { + return new com.alipay.easysdk.base.image.Client(new Client(context)); + } + + /** + * 获取视频相关API Client + * + * @return 视频相关API Client + */ + public static com.alipay.easysdk.base.video.Client Video() throws Exception { + return new com.alipay.easysdk.base.video.Client(new Client(context)); + } + + /** + * 获取OAuth认证相关API Client + * + * @return OAuth认证相关API Client + */ + public static com.alipay.easysdk.base.oauth.Client OAuth() throws Exception { + return new com.alipay.easysdk.base.oauth.Client(new Client(context)); + } + + /** + * 获取小程序二维码相关API Client + * + * @return 小程序二维码相关API Client + */ + public static com.alipay.easysdk.base.qrcode.Client Qrcode() throws Exception { + return new com.alipay.easysdk.base.qrcode.Client(new Client(context)); + } + } + + /** + * 营销能力相关 + */ + public static class Marketing { + /** + * 获取生活号相关API Client + * + * @return 生活号相关API Client + */ + public static com.alipay.easysdk.marketing.openlife.Client OpenLife() throws Exception { + return new com.alipay.easysdk.marketing.openlife.Client(new Client(context)); + } + + /** + * 获取支付宝卡包相关API Client + * + * @return 支付宝卡包相关API Client + */ + public static com.alipay.easysdk.marketing.pass.Client Pass() throws Exception { + return new com.alipay.easysdk.marketing.pass.Client(new Client(context)); + } + + /** + * 获取小程序模板消息相关API Client + * + * @return 小程序模板消息相关API Client + */ + public static com.alipay.easysdk.marketing.templatemessage.Client TemplateMessage() throws Exception { + return new com.alipay.easysdk.marketing.templatemessage.Client(new Client(context)); + } + } + + /** + * 会员能力相关 + */ + public static class Member { + /** + * 获取支付宝身份认证相关API Client + * + * @return 支付宝身份认证相关API Client + */ + public static com.alipay.easysdk.member.identification.Client Identification() throws Exception { + return new com.alipay.easysdk.member.identification.Client(new Client(context)); + } + } + + /** + * 安全能力相关 + */ + public static class Security { + /** + * 获取文本风险识别相关API Client + * + * @return 文本风险识别相关API Client + */ + public static com.alipay.easysdk.security.textrisk.Client TextRisk() throws Exception { + return new com.alipay.easysdk.security.textrisk.Client(new Client(context)); + } + } + + /** + * 辅助工具 + */ + public static class Util { + /** + * 获取OpenAPI通用接口,可通过自行拼装参数,调用几乎所有OpenAPI + * + * @return OpenAPI通用接口 + */ + public static com.alipay.easysdk.util.generic.Client Generic() throws Exception { + return new com.alipay.easysdk.util.generic.Client(new Client(context)); + } + + /** + * 获取AES128加解密相关API Client,常用于会员手机号的解密 + * + * @return AES128加解密相关API Client + */ + public static com.alipay.easysdk.util.aes.Client AES() throws Exception { + return new com.alipay.easysdk.util.aes.Client(new Client(context)); + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/factory/MultipleFactory.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/factory/MultipleFactory.java new file mode 100644 index 0000000..b8a0fc8 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/factory/MultipleFactory.java @@ -0,0 +1,229 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.factory; + +import com.alipay.easysdk.kernel.AlipayConstants; +import com.alipay.easysdk.kernel.Client; +import com.alipay.easysdk.kernel.Config; +import com.alipay.easysdk.kernel.Context; +import com.alipay.easysdk.kms.aliyun.AliyunKMSClient; +import com.alipay.easysdk.kms.aliyun.AliyunKMSSigner; +import com.aliyun.tea.TeaModel; + +import java.lang.reflect.Constructor; + +/** + * @author junying + * @version : MultipleFactory.java, v 0.1 2020年12月23日 2:14 下午 junying Exp $ + */ +public class MultipleFactory { + + public final String SDK_VERSION = "alipay-easysdk-java-2.1.2"; + + /** + * 将一些初始化耗时较多的信息缓存在上下文中 + */ + public Context context; + + /** + * 设置客户端参数,只需设置一次,即可反复使用各种场景下的API Client + * + * @param options 客户端参数对象 + */ + public void setOptions(Config options) { + try { + context = new Context(options, SDK_VERSION); + + if (AlipayConstants.AliyunKMS.equals(context.getConfig(AlipayConstants.SIGN_PROVIDER_CONFIG_KEY))) { + context.setSigner(new AliyunKMSSigner(new AliyunKMSClient(TeaModel.buildMap(options)))); + } + + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + /** + * 获取调用OpenAPI所需的客户端实例 + * 本方法用于调用SDK扩展包中的API Client下的方法 + *

+ * 注:返回的实例不可重复使用,只可用于单次调用 + * + * @param client API Client的类型对象 + * @return client实例,用于发起单次调用 + */ + public T getClient(Class client) { + try { + Constructor constructor = client.getConstructor(Client.class); + context.setSdkVersion(getSdkVersion(client)); + return constructor.newInstance(new Client(context)); + } catch (Exception e) { + throw new RuntimeException("" + e.getMessage(), e); + } + } + + private String getSdkVersion(Class client) { + return context.getSdkVersion() + "-" + client.getCanonicalName() + .replace("com.alipay.easysdk.", "") + .replace(".Client", "") + .replace(".", "-"); + } + + /** + * 获取支付通用API Client + * + * @return 支付通用API Client + */ + public com.alipay.easysdk.payment.common.Client Common() throws Exception { + return new com.alipay.easysdk.payment.common.Client(new Client(context)); + } + + /** + * 获取花呗相关API Client + * + * @return 花呗相关API Client + */ + public com.alipay.easysdk.payment.huabei.Client Huabei() throws Exception { + return new com.alipay.easysdk.payment.huabei.Client(new Client(context)); + } + + /** + * 获取当面付相关API Client + * + * @return 当面付相关API Client + */ + public com.alipay.easysdk.payment.facetoface.Client FaceToFace() throws Exception { + return new com.alipay.easysdk.payment.facetoface.Client(new Client(context)); + } + + /** + * 获取电脑网站支付相关API Client + * + * @return 电脑网站支付相关API Client + */ + public com.alipay.easysdk.payment.page.Client Page() throws Exception { + return new com.alipay.easysdk.payment.page.Client(new Client(context)); + } + + /** + * 获取手机网站支付相关API Client + * + * @return 手机网站支付相关API Client + */ + public com.alipay.easysdk.payment.wap.Client Wap() throws Exception { + return new com.alipay.easysdk.payment.wap.Client(new Client(context)); + } + + /** + * 获取手机APP支付相关API Client + * + * @return 手机APP支付相关API Client + */ + public com.alipay.easysdk.payment.app.Client App() throws Exception { + return new com.alipay.easysdk.payment.app.Client(new Client(context)); + } + + + /** + * 获取图片相关API Client + * + * @return 图片相关API Client + */ + public com.alipay.easysdk.base.image.Client Image() throws Exception { + return new com.alipay.easysdk.base.image.Client(new Client(context)); + } + + /** + * 获取视频相关API Client + * + * @return 视频相关API Client + */ + public com.alipay.easysdk.base.video.Client Video() throws Exception { + return new com.alipay.easysdk.base.video.Client(new Client(context)); + } + + /** + * 获取OAuth认证相关API Client + * + * @return OAuth认证相关API Client + */ + public com.alipay.easysdk.base.oauth.Client OAuth() throws Exception { + return new com.alipay.easysdk.base.oauth.Client(new Client(context)); + } + + /** + * 获取小程序二维码相关API Client + * + * @return 小程序二维码相关API Client + */ + public com.alipay.easysdk.base.qrcode.Client Qrcode() throws Exception { + return new com.alipay.easysdk.base.qrcode.Client(new Client(context)); + } + + + /** + * 获取生活号相关API Client + * + * @return 生活号相关API Client + */ + public com.alipay.easysdk.marketing.openlife.Client OpenLife() throws Exception { + return new com.alipay.easysdk.marketing.openlife.Client(new Client(context)); + } + + /** + * 获取支付宝卡包相关API Client + * + * @return 支付宝卡包相关API Client + */ + public com.alipay.easysdk.marketing.pass.Client Pass() throws Exception { + return new com.alipay.easysdk.marketing.pass.Client(new Client(context)); + } + + /** + * 获取小程序模板消息相关API Client + * + * @return 小程序模板消息相关API Client + */ + public com.alipay.easysdk.marketing.templatemessage.Client TemplateMessage() throws Exception { + return new com.alipay.easysdk.marketing.templatemessage.Client(new Client(context)); + } + + + /** + * 获取支付宝身份认证相关API Client + * + * @return 支付宝身份认证相关API Client + */ + public com.alipay.easysdk.member.identification.Client Identification() throws Exception { + return new com.alipay.easysdk.member.identification.Client(new Client(context)); + } + + /** + * 获取文本风险识别相关API Client + * + * @return 文本风险识别相关API Client + */ + public com.alipay.easysdk.security.textrisk.Client TextRisk() throws Exception { + return new com.alipay.easysdk.security.textrisk.Client(new Client(context)); + } + + /** + * 获取OpenAPI通用接口,可通过自行拼装参数,调用几乎所有OpenAPI + * + * @return OpenAPI通用接口 + */ + public com.alipay.easysdk.util.generic.Client Generic() throws Exception { + return new com.alipay.easysdk.util.generic.Client(new Client(context)); + } + + /** + * 获取AES128加解密相关API Client,常用于会员手机号的解密 + * + * @return AES128加解密相关API Client + */ + public com.alipay.easysdk.util.aes.Client AES() throws Exception { + return new com.alipay.easysdk.util.aes.Client(new Client(context)); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunKMSClient.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunKMSClient.java new file mode 100644 index 0000000..04645db --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunKMSClient.java @@ -0,0 +1,286 @@ +package com.alipay.easysdk.kms.aliyun; + +import com.alipay.easysdk.kernel.AlipayConstants; +import com.alipay.easysdk.kms.aliyun.models.AsymmetricSignRequest; +import com.alipay.easysdk.kms.aliyun.models.AsymmetricSignResponse; +import com.alipay.easysdk.kms.aliyun.models.GetPublicKeyRequest; +import com.alipay.easysdk.kms.aliyun.models.GetPublicKeyResponse; +import com.alipay.easysdk.kms.aliyun.models.RuntimeOptions; +import com.aliyun.tea.TeaConverter; +import com.aliyun.tea.TeaModel; +import com.aliyun.tea.TeaPair; +import org.bouncycastle.asn1.gm.GMNamedCurves; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SM3Digest; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.util.encoders.Base64; + +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.PublicKey; +import java.security.Security; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; + +/** + * 实现KMS的Client + * + * @author aliyunkms + * @version $Id: AliyunKMSClient.java, v 0.1 2020年05月08日 10:53 PM aliyunkms Exp $ + */ +public class AliyunKMSClient extends AliyunRpcClient { + //支付宝signType与KMS签名算法映射表 + private static final Map signAlgs = new HashMap<>(); + private static final Map digestAlgs = new HashMap<>(); + private static final Map namedCurves = new HashMap<>(); + + static { + digestAlgs.put("RSA_PKCS1_SHA_256", "SHA-256"); + digestAlgs.put("RSA_PSS_SHA_256", "SHA-256"); + digestAlgs.put("ECDSA_SHA_256", "SHA-256"); + + namedCurves.put("SM2DSA", "sm2p256v1"); + + signAlgs.put("RSA2", "RSA_PKCS1_SHA_256"); + } + + private String keyId; + private String keyVersionId; + private String algorithm; + private PublicKey publicKey; + private String protocol; + private String method; + private String version; + private Integer connectTimeout; + private Integer readTimeout; + private Integer maxAttempts; + private boolean ignoreSSL; + + public AliyunKMSClient(Map config) throws Exception { + super(config); + this.keyId = (String) config.get("kmsKeyId"); + this.keyVersionId = (String) config.get("kmsKeyVersionId"); + this.algorithm = signAlgs.get((String) config.get(AlipayConstants.SIGN_TYPE_CONFIG_KEY)); + this.publicKey = null; + this.protocol = "HTTPS"; + this.method = "POST"; + this.version = "2016-01-20"; + this.connectTimeout = 15000; + this.readTimeout = 15000; + this.maxAttempts = 3; + this.ignoreSSL = false; + } + + private GetPublicKeyResponse _getPublicKey(GetPublicKeyRequest request) throws Exception { + validateModel(request); + RuntimeOptions runtime = RuntimeOptions.build(TeaConverter.buildMap( + new TeaPair("connectTimeout", this.connectTimeout), + new TeaPair("readTimeout", this.readTimeout), + new TeaPair("maxAttempts", this.maxAttempts), + new TeaPair("ignoreSSL", this.ignoreSSL) + )); + return TeaModel.toModel( + this.doRequest("GetPublicKey", this.protocol, this.method, this.version, TeaModel.buildMap(request), null, runtime), + new GetPublicKeyResponse()); + } + + private PublicKey getPublicKey(String keyId, String keyVersionId) throws Exception { + GetPublicKeyRequest request = GetPublicKeyRequest.build(TeaConverter.buildMap( + new TeaPair("KeyId", keyId), + new TeaPair("KeyVersionId", keyVersionId) + )); + GetPublicKeyResponse response = _getPublicKey(request); + String pemKey = response.publicKey; + pemKey = pemKey.replaceFirst("-----BEGIN PUBLIC KEY-----", ""); + pemKey = pemKey.replaceFirst("-----END PUBLIC KEY-----", ""); + pemKey = pemKey.replaceAll("\\s", ""); + byte[] derKey = Base64.decode(pemKey); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(derKey); + Security.addProvider(new BouncyCastleProvider()); + return KeyFactory.getInstance("EC", "BC").generatePublic(keySpec); + } + + private byte[] getZ(ECPublicKeyParameters ecPublicKeyParameters, ECDomainParameters ecDomainParameters) { + Digest digest = new SM3Digest(); + digest.reset(); + + String userID = "1234567812345678"; + addUserID(digest, userID.getBytes()); + + addFieldElement(digest, ecDomainParameters.getCurve().getA()); + addFieldElement(digest, ecDomainParameters.getCurve().getB()); + addFieldElement(digest, ecDomainParameters.getG().getAffineXCoord()); + addFieldElement(digest, ecDomainParameters.getG().getAffineYCoord()); + addFieldElement(digest, ecPublicKeyParameters.getQ().getAffineXCoord()); + addFieldElement(digest, ecPublicKeyParameters.getQ().getAffineYCoord()); + + byte[] result = new byte[digest.getDigestSize()]; + digest.doFinal(result, 0); + return result; + } + + private void addUserID(Digest digest, byte[] userID) { + int len = userID.length * 8; + digest.update((byte) (len >> 8 & 0xFF)); + digest.update((byte) (len & 0xFF)); + digest.update(userID, 0, userID.length); + } + + private void addFieldElement(Digest digest, ECFieldElement v) { + byte[] p = v.getEncoded(); + digest.update(p, 0, p.length); + } + + private byte[] calcSM3Digest(PublicKey pubKey, byte[] message) { + X9ECParameters x9ECParameters = GMNamedCurves.getByName(namedCurves.get(this.algorithm)); + ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), + x9ECParameters.getN()); + BCECPublicKey localECPublicKey = (BCECPublicKey) pubKey; + ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(), ecDomainParameters); + byte[] z = getZ(ecPublicKeyParameters, ecDomainParameters); + Digest digest = new SM3Digest(); + digest.update(z, 0, z.length); + digest.update(message, 0, message.length); + byte[] result = new byte[digest.getDigestSize()]; + digest.doFinal(result, 0); + return result; + } + + private AsymmetricSignResponse _asymmetricSign(AsymmetricSignRequest request) throws Exception { + validateModel(request); + RuntimeOptions runtime = RuntimeOptions.build(TeaConverter.buildMap( + new TeaPair("connectTimeout", this.connectTimeout), + new TeaPair("readTimeout", this.readTimeout), + new TeaPair("maxAttempts", this.maxAttempts), + new TeaPair("ignoreSSL", this.ignoreSSL) + )); + return TeaModel.toModel( + this.doRequest("AsymmetricSign", this.protocol, this.method, this.version, TeaModel.buildMap(request), null, runtime), + new AsymmetricSignResponse()); + } + + private String asymmetricSign(String keyId, String keyVersionId, String algorithm, byte[] message) throws Exception { + byte[] digest; + if (algorithm.equals("SM2DSA")) { + if (this.publicKey == null) { + this.publicKey = getPublicKey(keyId, keyVersionId); + } + digest = calcSM3Digest(this.publicKey, message); + } else { + digest = MessageDigest.getInstance(digestAlgs.get(algorithm)).digest(message); + } + + AsymmetricSignRequest request = AsymmetricSignRequest.build(TeaConverter.buildMap( + new TeaPair("keyId", keyId), + new TeaPair("keyVersionId", keyVersionId), + new TeaPair("algorithm", algorithm), + new TeaPair("digest", Base64.toBase64String(digest)) + )); + AsymmetricSignResponse response = _asymmetricSign(request); + return response.value; + } + + /** + * 计算签名 + * + * @param content 待签名的内容 + * @return 签名值的Base64串 + */ + public String sign(String content) throws Exception { + return asymmetricSign(this.keyId, this.keyVersionId, this.algorithm, content.getBytes(AlipayConstants.DEFAULT_CHARSET)); + } + + public String getAlgorithm() { + return this.algorithm; + } + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public String getKeyId() { + return this.keyId; + } + + public void setKeyId(String keyId) { + this.keyId = keyId; + } + + public String getKeyVersionId() { + return this.keyVersionId; + } + + public void setKeyVersionId(String keyVersionId) { + this.keyVersionId = keyVersionId; + } + + public PublicKey getPublicKey() { + return this.publicKey; + } + + public void setPublicKey(PublicKey publicKey) { + this.publicKey = publicKey; + } + + public String getProtocol() { + return this.protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getMethod() { + return this.method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getVersion() { + return this.version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Integer getConnectTimeout() { + return this.connectTimeout; + } + + public void setConnectTimeout(Integer connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public Integer getReadTimeout() { + return this.readTimeout; + } + + public void setReadTimeout(Integer readTimeout) { + this.readTimeout = readTimeout; + } + + public Integer getMaxAttempts() { + return this.maxAttempts; + } + + public void setMaxAttempts(Integer maxAttempts) { + this.maxAttempts = maxAttempts; + } + + public boolean getIgnoreSSL() { + return this.ignoreSSL; + } + + public void setIgnoreSSL(boolean ignoreSSL) { + this.ignoreSSL = ignoreSSL; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunKMSConfig.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunKMSConfig.java new file mode 100644 index 0000000..f5979c6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunKMSConfig.java @@ -0,0 +1,72 @@ +package com.alipay.easysdk.kms.aliyun; + + +import com.alipay.easysdk.kernel.Config; +import com.aliyun.tea.*; + +/** + * KMS配置参数模型 + */ +public class AliyunKMSConfig extends Config { + /** + * 阿里云官方申请的AccessKey Id + */ + @NameInMap("aliyunAccessKeyId") + public String aliyunAccessKeyId; + + /** + * 阿里云官方申请的AccessKey Secret + */ + @NameInMap("aliyunAccessKeySecret") + public String aliyunAccessKeySecret; + + /** + * 从阿里云官方获取的临时安全令牌Security Token + */ + @NameInMap("aliyunSecurityToken") + public String aliyunSecurityToken; + + /** + * 阿里云RAM角色全局资源描述符 + */ + @NameInMap("aliyunRoleArn") + public String aliyunRoleArn; + + /** + * 阿里云RAM角色自定义策略 + */ + @NameInMap("aliyunRolePolicy") + public String aliyunRolePolicy; + + /** + * 阿里云ECS实例RAM角色名称 + */ + @NameInMap("aliyunRoleName") + public String aliyunRoleName; + + /** + * KMS主密钥ID + */ + @NameInMap("kmsKeyId") + public String kmsKeyId; + + /** + * KMS主密钥版本ID + */ + @NameInMap("kmsKeyVersionId") + public String kmsKeyVersionId; + + /** + * KMS服务地址 + * KMS服务地址列表详情,请参考: + * https://help.aliyun.com/document_detail/69006.html?spm=a2c4g.11186623.2.9.783f77cfAoNhY6#concept-69006-zh + */ + @NameInMap("kmsEndpoint") + public String kmsEndpoint; + + /** + * 凭据类型,支持的类型有"access_key","sts","ecs_ram_role","ram_role_arn" + */ + @NameInMap("credentialType") + public String credentialType; +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunKMSSigner.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunKMSSigner.java new file mode 100644 index 0000000..4888f4f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunKMSSigner.java @@ -0,0 +1,45 @@ +package com.alipay.easysdk.kms.aliyun; + +import com.alipay.easysdk.kernel.util.Signer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * KMS签名器 + * + * @author aliyunkms + * @version $Id: AliyunKMSSigner.java, v 0.1 2020年05月08日 9:10 PM aliyunkms Exp $ + */ +public class AliyunKMSSigner extends Signer { + private AliyunKMSClient client; + private static final Logger LOGGER = LoggerFactory.getLogger(Signer.class); + + public AliyunKMSSigner(AliyunKMSClient aliyunKmsClient) { + this.client = aliyunKmsClient; + } + + /** + * 计算签名 + * + * @param content 待签名的内容 + * @param privateKeyPem 私钥,使用KMS签名不使用此参数 + * @return 签名值的Base64串 + */ + public String sign(String content, String privateKeyPem) { + try { + return this.client.sign(content); + } catch (Exception e) { + String errorMessage = "签名遭遇异常,content=" + content + " reason=" + e.getMessage(); + LOGGER.error(errorMessage, e); + throw new RuntimeException(errorMessage, e); + } + } + + public AliyunKMSClient getClient() { + return this.client; + } + + public void setClient(AliyunKMSClient client) { + this.client = client; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunRpcClient.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunRpcClient.java new file mode 100644 index 0000000..43424ed --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/AliyunRpcClient.java @@ -0,0 +1,353 @@ +package com.alipay.easysdk.kms.aliyun; + +import com.alipay.easysdk.kms.aliyun.credentials.AccessKeyCredentials; +import com.alipay.easysdk.kms.aliyun.credentials.BasicSessionCredentials; +import com.alipay.easysdk.kms.aliyun.credentials.ICredentials; +import com.alipay.easysdk.kms.aliyun.credentials.provider.CredentialsProviderFactory; +import com.alipay.easysdk.kms.aliyun.credentials.provider.EcsRamRoleCredentialsProvider; +import com.alipay.easysdk.kms.aliyun.credentials.provider.ICredentialsProvider; +import com.alipay.easysdk.kms.aliyun.credentials.provider.RamRoleArnCredentialsProvider; +import com.alipay.easysdk.kms.aliyun.credentials.provider.StaticCredentialsProvider; +import com.alipay.easysdk.kms.aliyun.credentials.utils.CredentialType; +import com.alipay.easysdk.kms.aliyun.models.RuntimeOptions; +import com.aliyun.tea.Tea; +import com.aliyun.tea.TeaConverter; +import com.aliyun.tea.TeaException; +import com.aliyun.tea.TeaModel; +import com.aliyun.tea.TeaPair; +import com.aliyun.tea.TeaRequest; +import com.aliyun.tea.TeaResponse; +import com.aliyun.tea.TeaRetryableException; +import com.aliyun.tea.TeaUnretryableException; +import com.aliyun.tea.ValidateException; +import com.aliyun.tea.utils.StringUtils; +import com.google.gson.Gson; +import org.bouncycastle.util.encoders.Base64; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.SimpleTimeZone; +import java.util.UUID; + +public class AliyunRpcClient { + private final String accessKeyId; + private final String accessKeySecret; + private final String securityToken; + private final String roleArn; + private final String roleName; + private final String credentialType; + private final String policy; + private final String endpoint; + private final String format; + private final String signatureMethod; + private final String signatureVersion; + private final ICredentialsProvider credentialsProvider; + + public AliyunRpcClient(Map config) { + this.accessKeyId = (String) config.get("aliyunAccessKeyId"); + this.accessKeySecret = (String) config.get("aliyunAccessKeySecret"); + this.securityToken = (String) config.get("aliyunSecurityToken"); + this.roleArn = (String) config.get("aliyunRoleArn"); + this.roleName = (String) config.get("aliyunRoleName"); + this.credentialType = (String) config.get("credentialType"); + this.policy = (String) config.get("aliyunRolePolicy"); + this.endpoint = (String) config.get("kmsEndpoint"); + this.format = "json"; + this.signatureMethod = "HMAC-SHA1"; + this.signatureVersion = "1.0"; + this.credentialsProvider = getCredentialsProvider(); + } + + public static String percentEncode(String value) throws UnsupportedEncodingException { + return value != null ? URLEncoder.encode(value, "UTF-8").replace("+", "%20") + .replace("*", "%2A").replace("%7E", "~") : null; + } + + private static String getSignature(Map signedParams, String method, String secret) throws Exception { + String[] sortedKeys = signedParams.keySet().toArray(new String[0]); + Arrays.sort(sortedKeys); + StringBuilder canonicalizedQueryString = new StringBuilder(); + + for (String key : sortedKeys) { + if (!StringUtils.isEmpty(signedParams.get(key))) { + canonicalizedQueryString.append("&").append(percentEncode(key)).append("=").append( + percentEncode((String) signedParams.get(key))); + } + } + + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(new SecretKeySpec((secret + "&").getBytes(StandardCharsets.UTF_8), "HmacSHA1")); + String stringToSign = method + + "&" + + percentEncode("/") + + "&" + + percentEncode(canonicalizedQueryString.toString().substring(1)); + byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); + return Base64.toBase64String(signData); + } + + public static Object parseJSON(String json) { + return (new Gson()).fromJson(json, Map.class); + } + + public static Map assertAsMap(Object object) { + if (null != object && Map.class.isAssignableFrom(object.getClass())) { + return (Map) object; + } else { + throw new RuntimeException("The value is not a object"); + } + } + + public static byte[] readAsBytes(InputStream stream) throws IOException { + if (null == stream) { + return new byte[0]; + } else { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + byte[] buff = new byte[1024]; + + while (true) { + int read = stream.read(buff); + if (read == -1) { + return os.toByteArray(); + } + + os.write(buff, 0, read); + } + } + } + + public static String readAsString(InputStream stream) throws IOException { + return new String(readAsBytes(stream), StandardCharsets.UTF_8); + } + + public static Object readAsJSON(InputStream stream) throws IOException { + String body = readAsString(stream); + return parseJSON(body); + } + + public static String getTimestamp() { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + df.setTimeZone(new SimpleTimeZone(0, "UTC")); + return df.format(new Date()); + } + + public static String getNonce() { + StringBuilder uniqueNonce = new StringBuilder(); + UUID uuid = UUID.randomUUID(); + uniqueNonce.append(uuid.toString()); + uniqueNonce.append(System.currentTimeMillis()); + uniqueNonce.append(Thread.currentThread().getId()); + return uniqueNonce.toString(); + } + + public static String toFormString(Map map) throws UnsupportedEncodingException { + if (null == map) { + return ""; + } + StringBuilder result = new StringBuilder(); + boolean first = true; + for (Map.Entry entry : map.entrySet()) { + if (StringUtils.isEmpty(entry.getValue())) { + continue; + } + if (first) { + first = false; + } else { + result.append("&"); + } + result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); + result.append("="); + result.append(URLEncoder.encode(String.valueOf(entry.getValue()), "UTF-8")); + } + return result.toString(); + } + + public static void validateModel(TeaModel m) throws Exception { + if (null == m) { + throw new ValidateException("parameter is not allowed as null"); + } else { + m.validate(); + } + } + + public static Map anyifyMapValue(Map map) { + Map result = new HashMap<>(); + if (null == map) { + return null; + } + for (Map.Entry entry : map.entrySet()) { + result.put(entry.getKey(), entry.getValue()); + } + return result; + } + + public static boolean is4xx(Number code) { + if (null == code) { + return false; + } else { + return code.intValue() >= 400 && code.intValue() < 500; + } + } + + public static boolean is5xx(Number code) { + if (null == code) { + return false; + } else { + return code.intValue() >= 500 && code.intValue() < 600; + } + } + + public static boolean isUnset(Object object) { + return null == object; + } + + private ICredentialsProvider getCredentialsProvider() { + CredentialsProviderFactory factory = new CredentialsProviderFactory(); + if (StringUtils.isEmpty(this.credentialType)) { + return getAccessKeyCredentialsProvider(this.accessKeyId, this.accessKeySecret, factory); + } + switch (this.credentialType) { + case CredentialType.ACCESS_KEY: + return getAccessKeyCredentialsProvider(this.accessKeyId, this.accessKeySecret, factory); + case CredentialType.STS: + return getStsTokenCredentialsProvider(this.accessKeyId, this.accessKeySecret, this.securityToken, factory); + case CredentialType.ECS_RAM_ROLE: + return getEcsRamRoleCredentialsProvider(this.roleName, factory); + case CredentialType.RAM_ROLE_ARN: + return getRamRoleArnCredentialsProvider(this.accessKeyId, this.accessKeySecret, this.roleArn, this.policy, factory); + } + throw new IllegalArgumentException("The credentialType is not supported"); + } + + private ICredentialsProvider getAccessKeyCredentialsProvider(String accessKeyId, String accessKeySecret, + CredentialsProviderFactory factory) { + return factory.createCredentialsProvider(new StaticCredentialsProvider(new AccessKeyCredentials(accessKeyId, accessKeySecret))); + } + + private ICredentialsProvider getStsTokenCredentialsProvider(String accessKeyId, String accessKeySecret, String securityToken, + CredentialsProviderFactory factory) { + return factory.createCredentialsProvider(new StaticCredentialsProvider(new BasicSessionCredentials(accessKeyId, + accessKeySecret, securityToken))); + } + + private ICredentialsProvider getEcsRamRoleCredentialsProvider(String roleName, CredentialsProviderFactory factory) { + if (StringUtils.isEmpty(roleName)) { + throw new IllegalArgumentException("The roleName is empty"); + } + return factory.createCredentialsProvider(new EcsRamRoleCredentialsProvider(roleName)); + } + + private ICredentialsProvider getRamRoleArnCredentialsProvider(String accessKeyId, String accessKeySecret, String roleArn, + String policy, CredentialsProviderFactory factory) { + if (StringUtils.isEmpty(accessKeyId) || StringUtils.isEmpty(accessKeySecret)) { + throw new IllegalArgumentException("The accessKeyId or accessKeySecret is empty"); + } + if (StringUtils.isEmpty(roleArn)) { + throw new IllegalArgumentException("The roleArn is empty"); + } + return factory.createCredentialsProvider(new RamRoleArnCredentialsProvider(accessKeyId, accessKeySecret, roleArn, policy)); + } + + public Map doRequest(String action, String protocol, String method, String version, Map query, + Map body, RuntimeOptions runtime) throws Exception { + Map runtime_ = TeaConverter.buildMap( + new TeaPair("readTimeout", runtime.readTimeout), + new TeaPair("connectTimeout", runtime.connectTimeout), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", runtime.maxAttempts) + )), + new TeaPair("backoff", TeaConverter.buildMap( + new TeaPair("policy", runtime.backoffPolicy), + new TeaPair("period", runtime.backoffPeriod) + )), + new TeaPair("ignoreSSL", runtime.ignoreSSL) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + request_.protocol = protocol; + request_.method = method; + request_.pathname = "/"; + request_.query = TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("Action", action), + new TeaPair("Format", this.format), + new TeaPair("Timestamp", getTimestamp()), + new TeaPair("Version", version), + new TeaPair("SignatureNonce", getNonce()) + ), + query + ); + request_.headers = TeaConverter.buildMap( + new TeaPair("host", this.endpoint) + ); + if (!isUnset(body)) { + java.util.Map tmp = anyifyMapValue(body); + request_.body = Tea.toReadable(toFormString(tmp)); + request_.headers.put("content-type", "application/x-www-form-urlencoded"); + } + + ICredentials credentials = this.credentialsProvider.getCredentials(); + if (credentials == null) { + throw new TeaRetryableException(); + } + + request_.query.put("SignatureMethod", this.signatureMethod); + request_.query.put("SignatureVersion", this.signatureVersion); + request_.query.put("AccessKeyId", credentials.getAccessKeyId()); + if (!StringUtils.isEmpty(credentials.getSecurityToken())) { + request_.query.put("SecurityToken", credentials.getSecurityToken()); + } + java.util.Map signedParam = TeaConverter.merge(String.class, + request_.query, + body + ); + request_.query.put("Signature", getSignature(signedParam, request_.method, credentials.getAccessKeySecret())); + + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + Object obj = readAsJSON(response_.body); + java.util.Map res = assertAsMap(obj); + if (is4xx(response_.statusCode) || is5xx(response_.statusCode)) { + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", res.get("Message")), + new TeaPair("data", res), + new TeaPair("code", res.get("Code")) + )); + } + + return res; + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw e; + } + } + + throw new TeaUnretryableException(_lastRequest); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/AccessKeyCredentials.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/AccessKeyCredentials.java new file mode 100644 index 0000000..f3a33b3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/AccessKeyCredentials.java @@ -0,0 +1,42 @@ +package com.alipay.easysdk.kms.aliyun.credentials; + +import com.alipay.easysdk.kms.aliyun.credentials.utils.StringUtils; + +public class AccessKeyCredentials implements ICredentials { + private String accessKeyId; + private String accessKeySecret; + + public AccessKeyCredentials(String accessKeyId, String accessKeySecret) { + if (StringUtils.isEmpty(accessKeyId)) { + throw new IllegalArgumentException("Access key ID cannot be empty"); + } + if (StringUtils.isEmpty(accessKeySecret)) { + throw new IllegalArgumentException("Access key secret cannot be empty"); + } + this.accessKeyId = accessKeyId; + this.accessKeySecret = accessKeySecret; + } + + public void setAccessKeyId(String accessKeyId) { + this.accessKeyId = accessKeyId; + } + + public void setAccessKeySecret(String accessKeySecret) { + this.accessKeySecret = accessKeySecret; + } + + @Override + public String getAccessKeyId() { + return accessKeyId; + } + + @Override + public String getAccessKeySecret() { + return accessKeySecret; + } + + @Override + public String getSecurityToken() { + return null; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/BasicSessionCredentials.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/BasicSessionCredentials.java new file mode 100644 index 0000000..d7e6279 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/BasicSessionCredentials.java @@ -0,0 +1,51 @@ +package com.alipay.easysdk.kms.aliyun.credentials; + +public class BasicSessionCredentials implements ICredentials { + protected final Long roleSessionDurationSeconds; + private final String accessKeyId; + private final String accessKeySecret; + private final String securityToken; + private Long sessionStartedTimeInMilliSeconds = 0L; + + public BasicSessionCredentials(String accessKeyId, String accessKeySecret, String securityToken) { + this(accessKeyId, accessKeySecret, securityToken, 0L); + } + + public BasicSessionCredentials(String accessKeyId, String accessKeySecret, String securityToken, Long roleSessionDurationSeconds) { + if (accessKeyId == null) { + throw new IllegalArgumentException("Access key ID cannot be null."); + } + if (accessKeySecret == null) { + throw new IllegalArgumentException("Access key secret cannot be null."); + } + this.accessKeyId = accessKeyId; + this.accessKeySecret = accessKeySecret; + this.securityToken = securityToken; + this.roleSessionDurationSeconds = roleSessionDurationSeconds; + this.sessionStartedTimeInMilliSeconds = System.currentTimeMillis(); + } + + @Override + public String getAccessKeyId() { + return accessKeyId; + } + + @Override + public String getAccessKeySecret() { + return accessKeySecret; + } + + @Override + public String getSecurityToken() { + return securityToken; + } + + public boolean willSoonExpire() { + if (roleSessionDurationSeconds == 0) { + return false; + } + long now = System.currentTimeMillis(); + double expireFact = 0.95; + return roleSessionDurationSeconds * expireFact < (now - sessionStartedTimeInMilliSeconds) / 1000.0; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/EcsRamRoleCredentials.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/EcsRamRoleCredentials.java new file mode 100644 index 0000000..89e40ba --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/EcsRamRoleCredentials.java @@ -0,0 +1,47 @@ +package com.alipay.easysdk.kms.aliyun.credentials; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +public class EcsRamRoleCredentials extends BasicSessionCredentials { + private final Long expiration; + private final Double expireFact = 0.95; + private final Long refreshIntervalInMillSeconds = 180000L; + private long lastFailedRefreshTime = 0; + + public EcsRamRoleCredentials(String accessKeyId, String accessKeySecret, String sessionToken, + String expiration, long roleSessionDurationSeconds) { + super(accessKeyId, accessKeySecret, sessionToken, roleSessionDurationSeconds); + + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + parser.setTimeZone(TimeZone.getTimeZone("GMT")); + try { + Date date = parser.parse(expiration.replace('T', ' ').replace('Z', ' ')); + this.expiration = date.getTime(); + } catch (ParseException e) { + throw new IllegalArgumentException("Failed to get valid expiration time from ECS Metadata service."); + } + } + + @Override + public boolean willSoonExpire() { + long now = System.currentTimeMillis(); + return this.roleSessionDurationSeconds * (1 - expireFact) > (expiration - now) / 1000; + } + + public boolean isExpired() { + long now = System.currentTimeMillis(); + return now >= expiration - refreshIntervalInMillSeconds; + } + + public boolean shouldRefresh() { + long now = System.currentTimeMillis(); + return now - lastFailedRefreshTime > refreshIntervalInMillSeconds; + } + + public void setLastFailedRefreshTime() { + lastFailedRefreshTime = System.currentTimeMillis(); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/ICredentials.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/ICredentials.java new file mode 100644 index 0000000..13990d0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/ICredentials.java @@ -0,0 +1,7 @@ +package com.alipay.easysdk.kms.aliyun.credentials; + +public interface ICredentials { + public String getAccessKeyId(); + public String getAccessKeySecret(); + public String getSecurityToken(); +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/exceptions/CredentialException.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/exceptions/CredentialException.java new file mode 100644 index 0000000..ca60619 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/exceptions/CredentialException.java @@ -0,0 +1,11 @@ +package com.alipay.easysdk.kms.aliyun.credentials.exceptions; + +public class CredentialException extends Exception { + public CredentialException(String message) { + super(message); + } + @Override + public String getMessage() { + return super.getMessage(); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/CompatibleUrlConnClient.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/CompatibleUrlConnClient.java new file mode 100644 index 0000000..caf4630 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/CompatibleUrlConnClient.java @@ -0,0 +1,155 @@ +package com.alipay.easysdk.kms.aliyun.credentials.http; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map; + +public class CompatibleUrlConnClient implements Closeable { + protected static final String ACCEPT_ENCODING = "Accept-Encoding"; + + public static HttpResponse compatibleGetResponse(HttpRequest request) + throws IOException, NoSuchAlgorithmException, KeyManagementException { + CompatibleUrlConnClient client = new CompatibleUrlConnClient(); + HttpResponse response = client.syncInvoke(request); + client.close(); + return response; + } + + public HttpResponse syncInvoke(HttpRequest request) throws IOException, NoSuchAlgorithmException, KeyManagementException { + InputStream content = null; + HttpResponse response = null; + HttpURLConnection httpConn = buildHttpConnection(request); + + try { + httpConn.connect(); + content = httpConn.getInputStream(); + response = new HttpResponse(httpConn.getURL().toString()); + parseHttpConn(response, httpConn, content); + return response; + } catch (IOException e) { + content = httpConn.getErrorStream(); + response = new HttpResponse(httpConn.getURL().toString()); + parseHttpConn(response, httpConn, content); + return response; + } finally { + if (content != null) { + content.close(); + } + httpConn.disconnect(); + } + } + + public SSLSocketFactory createSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException { + X509TrustManager compositeX509TrustManager = new CompositeX509TrustManager(); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[] {compositeX509TrustManager}, new java.security.SecureRandom()); + return sslContext.getSocketFactory(); + } + + public void checkHttpRequest(HttpRequest request) { + String strUrl = request.getUrl(); + if (null == strUrl) { + throw new IllegalArgumentException("URL is null for HttpRequest."); + } + if (null == request.getMethod()) { + throw new IllegalArgumentException("Method is not set for HttpRequest."); + } + } + + public HttpURLConnection initHttpConnection(URL url, HttpRequest request) + throws IOException, KeyManagementException, NoSuchAlgorithmException { + HttpURLConnection httpConn; + if ("https".equalsIgnoreCase(url.getProtocol())) { + HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection(); + SSLSocketFactory sslSocketFactory = createSSLSocketFactory(); + httpsConn.setSSLSocketFactory(sslSocketFactory); + httpsConn.setHostnameVerifier(new TrueHostnameVerifier()); + httpConn = httpsConn; + } else { + httpConn = (HttpURLConnection) url.openConnection(); + } + httpConn.setRequestMethod(request.getMethod().toString()); + httpConn.setInstanceFollowRedirects(false); + httpConn.setDoOutput(true); + httpConn.setDoInput(true); + httpConn.setUseCaches(false); + httpConn.setConnectTimeout(request.getConnectTimeout()); + httpConn.setReadTimeout(request.getReadTimeout()); + httpConn.setRequestProperty(ACCEPT_ENCODING, "identity"); + return httpConn; + } + + public HttpURLConnection buildHttpConnection(HttpRequest request) throws IOException, NoSuchAlgorithmException, KeyManagementException { + checkHttpRequest(request); + String strUrl = request.getUrl(); + URL url = new URL(strUrl); + System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); + HttpURLConnection httpConn = initHttpConnection(url, request); + return httpConn; + } + + public void parseHttpConn(HttpResponse response, HttpURLConnection httpConn, InputStream content) + throws IOException, NoSuchAlgorithmException { + byte[] buff = readContent(content); + response.setStatus(httpConn.getResponseCode()); + response.setResponseMessage(httpConn.getResponseMessage()); + Map> headers = httpConn.getHeaderFields(); + for (Map.Entry> entry : headers.entrySet()) { + String key = entry.getKey(); + if (null == key) { + continue; + } + List values = entry.getValue(); + StringBuilder builder = new StringBuilder(values.get(0)); + for (int i = 1; i < values.size(); i++) { + builder.append(","); + builder.append(values.get(i)); + } + response.putHeaderParameter(key, builder.toString()); + } + String type = response.getHeaderValue("Content-Type"); + if (buff != null && type != null) { + response.setEncoding("UTF-8"); + String[] split = type.split(";"); + response.setHttpContentType(FormatType.mapAcceptToFormat(split[0].trim())); + if (split.length > 1 && split[1].contains("=")) { + String[] codings = split[1].split("="); + response.setEncoding(codings[1].trim().toUpperCase()); + } + } + response.setHttpContent(buff, response.getEncoding(), response.getHttpContentType()); + } + + private byte[] readContent(InputStream content) throws IOException { + if (content == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buff = new byte[1024]; + while (true) { + final int read = content.read(buff); + if (read == -1) { + break; + } + outputStream.write(buff, 0, read); + } + return outputStream.toByteArray(); + } + + @Override + public void close() throws IOException { + + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/CompositeX509TrustManager.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/CompositeX509TrustManager.java new file mode 100644 index 0000000..ee04cf2 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/CompositeX509TrustManager.java @@ -0,0 +1,22 @@ +package com.alipay.easysdk.kms.aliyun.credentials.http; + +import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +public class CompositeX509TrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/FormatType.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/FormatType.java new file mode 100644 index 0000000..b63af19 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/FormatType.java @@ -0,0 +1,29 @@ +package com.alipay.easysdk.kms.aliyun.credentials.http; + +import java.util.Arrays; + +public enum FormatType { + XML("application/xml", "text/xml"), + JSON("application/json", "text/json"), + RAW("application/octet-stream"), + FORM("application/x-www-form-urlencoded"); + + private final String[] formats; + + FormatType(String... formats) { + this.formats = formats; + } + + public static String mapFormatToAccept(FormatType format) { + return format.formats[0]; + } + + public static FormatType mapAcceptToFormat(String accept) { + for (FormatType value : values()) { + if (Arrays.asList(value.formats).contains(accept)) { + return value; + } + } + return FormatType.RAW; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/HttpMessage.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/HttpMessage.java new file mode 100644 index 0000000..7e6379f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/HttpMessage.java @@ -0,0 +1,182 @@ +package com.alipay.easysdk.kms.aliyun.credentials.http; + +import com.alipay.easysdk.kms.aliyun.credentials.exceptions.CredentialException; +import com.alipay.easysdk.kms.aliyun.credentials.utils.Base64Utils; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.X509TrustManager; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class HttpMessage { + protected static final String CONTENT_TYPE = "Content-Type"; + protected static final String CONTENT_MD5 = "Content-MD5"; + protected static final String CONTENT_LENGTH = "Content-Length"; + protected FormatType httpContentType = null; + protected byte[] httpContent = null; + protected String encoding = null; + protected Map headers = new HashMap(); + protected Integer connectTimeout = null; + protected Integer readTimeout = null; + private String url = null; + private MethodType method = null; + protected boolean ignoreSSLCerts = false; + private KeyManager[] keyManagers = null; + private X509TrustManager[] x509TrustManagers = null; + + public HttpMessage(String strUrl) { + this.url = strUrl; + } + + public HttpMessage() { + } + + public FormatType getHttpContentType() { + return httpContentType; + } + + public void setHttpContentType(FormatType httpContentType) { + this.httpContentType = httpContentType; + } + + public byte[] getHttpContent() { + return httpContent; + } + + public String getHttpContentString() throws CredentialException { + String stringContent = ""; + if (this.httpContent != null) { + try { + if (this.encoding == null) { + stringContent = new String(this.httpContent); + } else { + stringContent = new String(this.httpContent, this.encoding); + } + } catch (UnsupportedEncodingException e) { + throw new CredentialException("UnsupportedEncoding: Can not parse response due to unsupported encoding."); + } + } + return stringContent; + } + + public void setHttpContent(byte[] httpContent, String encoding, FormatType format) throws NoSuchAlgorithmException { + this.httpContent = httpContent; + if (null == httpContent) { + this.headers.remove(CONTENT_MD5); + this.headers.put(CONTENT_LENGTH, "0"); + this.headers.remove(CONTENT_TYPE); + this.httpContentType = null; + this.httpContent = null; + this.encoding = null; + return; + } + + // for GET HEADER DELETE OPTION method, sdk should ignore the content + if (getMethod() != null && !getMethod().hasContent()) { + httpContent = new byte[0]; + } + + this.httpContent = httpContent; + this.encoding = encoding; + String contentLen = String.valueOf(httpContent.length); + String strMd5 = md5Sum(httpContent); + this.headers.put(CONTENT_MD5, strMd5); + this.headers.put(CONTENT_LENGTH, contentLen); + if (null != format) { + this.headers.put(CONTENT_TYPE, FormatType.mapFormatToAccept(format)); + } + } + + public static String md5Sum(byte[] buff) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] messageDigest = md.digest(buff); + return Base64Utils.encode(messageDigest); + + } + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public Map getHeaders() { + return Collections.unmodifiableMap(headers); + } + + public String getHeaderValue(String name) { + return this.headers.get(name); + } + + public void putHeaderParameter(String name, String value) { + if (null != name && null != value) { + this.headers.put(name, value); + } + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public Integer getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(Integer connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public Integer getReadTimeout() { + return readTimeout; + } + + public void setReadTimeout(Integer readTimeout) { + this.readTimeout = readTimeout; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public MethodType getMethod() { + return method; + } + + public void setMethod(MethodType method) { + this.method = method; + } + + public boolean isIgnoreSSLCerts() { + return ignoreSSLCerts; + } + + public void setIgnoreSSLCerts(boolean ignoreSSLCerts) { + this.ignoreSSLCerts = ignoreSSLCerts; + } + + public KeyManager[] getKeyManagers() { + return keyManagers; + } + + public void setKeyManagers(KeyManager[] keyManagers) { + this.keyManagers = keyManagers; + } + + public X509TrustManager[] getX509TrustManagers() { + return x509TrustManagers; + } + + public void setX509TrustManagers(X509TrustManager[] x509TrustManagers) { + this.x509TrustManagers = x509TrustManagers; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/HttpRequest.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/HttpRequest.java new file mode 100644 index 0000000..a8fc38e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/HttpRequest.java @@ -0,0 +1,40 @@ +package com.alipay.easysdk.kms.aliyun.credentials.http; + +import com.alipay.easysdk.kms.aliyun.credentials.utils.ParameterUtils; + +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +public class HttpRequest extends HttpMessage { + private final Map immutableMap = new HashMap(); + + public HttpRequest() { + setCommonParameter(); + } + + public HttpRequest(String url) { + super(url); + setCommonParameter(); + } + + private void setCommonParameter() { + this.immutableMap.put("Timestamp", ParameterUtils.getISO8601Time(new Date())); + this.immutableMap.put("SignatureNonce", ParameterUtils.getUniqueNonce()); + this.immutableMap.put("SignatureMethod", "HMAC-SHA1"); + this.immutableMap.put("SignatureVersion", "1.0"); + } + + public void setUrlParameter(String key, String value) { + this.immutableMap.put(key, value); + } + + public String getUrlParameter(String key) { + return this.immutableMap.get(key); + } + + public Map getUrlParameters() { + return Collections.unmodifiableMap(immutableMap); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/HttpResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/HttpResponse.java new file mode 100644 index 0000000..6335060 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/HttpResponse.java @@ -0,0 +1,33 @@ +package com.alipay.easysdk.kms.aliyun.credentials.http; + +public class HttpResponse extends HttpMessage { + private int status; + private String responseMessage; + + public HttpResponse(String strUrl) { + super(strUrl); + } + + public HttpResponse() { + } + + public boolean isSuccess() { + return 200 <= this.status && this.status < 300; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getResponseMessage() { + return responseMessage; + } + + public void setResponseMessage(String responseMessage) { + this.responseMessage = responseMessage; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/MethodType.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/MethodType.java new file mode 100644 index 0000000..b42718c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/MethodType.java @@ -0,0 +1,17 @@ +package com.alipay.easysdk.kms.aliyun.credentials.http; + +public enum MethodType { + GET(false), + PUT(true), + POST(true); + + private final boolean hasContent; + + MethodType(boolean hasContent) { + this.hasContent = hasContent; + } + + public boolean hasContent() { + return hasContent; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/TrueHostnameVerifier.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/TrueHostnameVerifier.java new file mode 100644 index 0000000..865600e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/http/TrueHostnameVerifier.java @@ -0,0 +1,11 @@ +package com.alipay.easysdk.kms.aliyun.credentials.http; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; + +public class TrueHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(String s, SSLSession sslSession) { + return true; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/CredentialsProviderFactory.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/CredentialsProviderFactory.java new file mode 100644 index 0000000..393d8df --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/CredentialsProviderFactory.java @@ -0,0 +1,7 @@ +package com.alipay.easysdk.kms.aliyun.credentials.provider; + +public class CredentialsProviderFactory { + public T createCredentialsProvider(T classInstance) { + return classInstance; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/ECSMetadataServiceCredentialsFetcher.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/ECSMetadataServiceCredentialsFetcher.java new file mode 100644 index 0000000..f9ec70a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/ECSMetadataServiceCredentialsFetcher.java @@ -0,0 +1,110 @@ +package com.alipay.easysdk.kms.aliyun.credentials.provider; + +import com.alipay.easysdk.kms.aliyun.credentials.EcsRamRoleCredentials; +import com.alipay.easysdk.kms.aliyun.credentials.exceptions.CredentialException; +import com.alipay.easysdk.kms.aliyun.credentials.http.CompatibleUrlConnClient; +import com.alipay.easysdk.kms.aliyun.credentials.http.HttpRequest; +import com.alipay.easysdk.kms.aliyun.credentials.http.HttpResponse; +import com.alipay.easysdk.kms.aliyun.credentials.http.MethodType; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + +public class ECSMetadataServiceCredentialsFetcher { + private static final String URL_IN_ECS_METADATA = "/latest/meta-data/ram/security-credentials/"; + private static final int DEFAULT_TIMEOUT_IN_MILLISECONDS = 1000; + private static final String ECS_METADAT_FETCH_ERROR_MSG = "Failed to get RAM session credentials from ECS metadata service."; + private static final int DEFAULT_ECS_SESSION_TOKEN_DURATION_SECONDS = 3600 * 6; + private URL credentialUrl; + private String roleName; + private String metadataServiceHost = "100.100.100.200"; + private int connectionTimeoutInMilliseconds; + + public ECSMetadataServiceCredentialsFetcher() { + this.connectionTimeoutInMilliseconds = DEFAULT_TIMEOUT_IN_MILLISECONDS; + } + + public void setRoleName(String roleName) { + if (null == roleName) { + throw new NullPointerException("You must specifiy a valid role name."); + } + this.roleName = roleName; + setCredentialUrl(); + } + + private void setCredentialUrl() { + try { + this.credentialUrl = new URL("http://" + metadataServiceHost + URL_IN_ECS_METADATA + roleName); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e.toString()); + } + } + + public ECSMetadataServiceCredentialsFetcher withECSMetadataServiceHost(String host) { + System.err.println("withECSMetadataServiceHost() method is only for testing, please don't use it"); + this.metadataServiceHost = host; + setCredentialUrl(); + return this; + } + + public ECSMetadataServiceCredentialsFetcher withConnectionTimeout(int milliseconds) { + this.connectionTimeoutInMilliseconds = milliseconds; + return this; + } + + public String getMetadata() throws CredentialException { + HttpRequest request = new HttpRequest(credentialUrl.toString()); + request.setMethod(MethodType.GET); + request.setConnectTimeout(connectionTimeoutInMilliseconds); + request.setReadTimeout(connectionTimeoutInMilliseconds); + HttpResponse response; + + try { + response = CompatibleUrlConnClient.compatibleGetResponse(request); + } catch (Exception e) { + throw new CredentialException("Failed to connect ECS Metadata Service: " + e.toString()); + } + + if (response.getStatus() != HttpURLConnection.HTTP_OK) { + throw new CredentialException(ECS_METADAT_FETCH_ERROR_MSG + " HttpCode=" + response.getStatus()); + } + + return new String(response.getHttpContent()); + } + + public EcsRamRoleCredentials fetch() throws CredentialException { + String jsonContent = getMetadata(); + JsonObject jsonObject = null; + jsonObject = new JsonParser().parse(jsonContent).getAsJsonObject(); + + if (jsonObject.has("Code") && jsonObject.has("AccessKeyId") && jsonObject.has("AccessKeySecret") && jsonObject + .has("SecurityToken") && jsonObject.has("Expiration")) { + + } else { + throw new CredentialException("Invalid json got from ECS Metadata service."); + } + + if (!"Success".equals(jsonObject.get("Code").getAsString())) { + throw new CredentialException(ECS_METADAT_FETCH_ERROR_MSG); + } + return new EcsRamRoleCredentials(jsonObject.get("AccessKeyId").getAsString(), jsonObject.get( + "AccessKeySecret").getAsString(), jsonObject.get("SecurityToken").getAsString(), jsonObject.get( + "Expiration").getAsString(), DEFAULT_ECS_SESSION_TOKEN_DURATION_SECONDS); + } + + public EcsRamRoleCredentials fetch(int retryTimes) throws CredentialException { + for (int i = 0; i <= retryTimes; i++) { + try { + return fetch(); + } catch (CredentialException e) { + if (i == retryTimes) { + throw e; + } + } + } + throw new CredentialException("Failed to connect ECS Metadata Service: Max retry times exceeded."); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/EcsRamRoleCredentialsProvider.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/EcsRamRoleCredentialsProvider.java new file mode 100644 index 0000000..dd1be21 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/EcsRamRoleCredentialsProvider.java @@ -0,0 +1,42 @@ +package com.alipay.easysdk.kms.aliyun.credentials.provider; + +import com.alipay.easysdk.kms.aliyun.credentials.EcsRamRoleCredentials; +import com.alipay.easysdk.kms.aliyun.credentials.ICredentials; +import com.alipay.easysdk.kms.aliyun.credentials.exceptions.CredentialException; + +public class EcsRamRoleCredentialsProvider implements ICredentialsProvider { + private static final int MAX_ECS_METADATA_FETCH_RETRY_TIMES = 3; + private final String roleName; + private EcsRamRoleCredentials credentials = null; + private ECSMetadataServiceCredentialsFetcher fetcher; + + public EcsRamRoleCredentialsProvider(String roleName) { + if (null == roleName) { + throw new NullPointerException("You must specifiy a valid role name."); + } + this.roleName = roleName; + this.fetcher = new ECSMetadataServiceCredentialsFetcher(); + this.fetcher.setRoleName(this.roleName); + } + + public EcsRamRoleCredentialsProvider withFetcher(ECSMetadataServiceCredentialsFetcher fetcher) { + this.fetcher = fetcher; + this.fetcher.setRoleName(roleName); + return this; + } + + @Override + public ICredentials getCredentials() throws CredentialException { + if (credentials == null || credentials.isExpired()) { + credentials = fetcher.fetch(MAX_ECS_METADATA_FETCH_RETRY_TIMES); + } else if (credentials.willSoonExpire() && credentials.shouldRefresh()) { + try { + credentials = fetcher.fetch(); + } catch (CredentialException e) { + // Use the current expiring session token and wait for next round + credentials.setLastFailedRefreshTime(); + } + } + return credentials; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/ICredentialsProvider.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/ICredentialsProvider.java new file mode 100644 index 0000000..e27ae01 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/ICredentialsProvider.java @@ -0,0 +1,7 @@ +package com.alipay.easysdk.kms.aliyun.credentials.provider; + +import com.alipay.easysdk.kms.aliyun.credentials.ICredentials; + +public interface ICredentialsProvider { + public ICredentials getCredentials() throws Exception; +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/RamRoleArnCredentialsProvider.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/RamRoleArnCredentialsProvider.java new file mode 100644 index 0000000..cf5e6f1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/RamRoleArnCredentialsProvider.java @@ -0,0 +1,97 @@ +package com.alipay.easysdk.kms.aliyun.credentials.provider; + +import com.alipay.easysdk.kms.aliyun.credentials.BasicSessionCredentials; +import com.alipay.easysdk.kms.aliyun.credentials.ICredentials; +import com.alipay.easysdk.kms.aliyun.credentials.exceptions.CredentialException; +import com.alipay.easysdk.kms.aliyun.credentials.http.CompatibleUrlConnClient; +import com.alipay.easysdk.kms.aliyun.credentials.http.HttpRequest; +import com.alipay.easysdk.kms.aliyun.credentials.http.HttpResponse; +import com.alipay.easysdk.kms.aliyun.credentials.http.MethodType; +import com.alipay.easysdk.kms.aliyun.credentials.utils.HmacSHA1Signer; +import com.alipay.easysdk.kms.aliyun.credentials.utils.ParameterUtils; +import com.google.gson.Gson; + +import java.util.Map; + +public class RamRoleArnCredentialsProvider implements ICredentialsProvider { + public static final int DEFAULT_DURATION_SECONDS = 3600; + private static final int DEFAULT_TIMEOUT_IN_MILLISECONDS = 5000; + private static final String DEFAULT_STS_ENDPOINT = "sts.aliyuncs.com"; + private final String roleArn; + private final String roleSessionName; + private final String accessKeyId; + private final String accessKeySecret; + private final String stsEndpoint; + private String policy; + private Integer connectTimeout; + private Integer readTimeout; + private BasicSessionCredentials credential = null; + + public RamRoleArnCredentialsProvider(String accessKeyId, String accessKeySecret, String roleArn) { + this.roleArn = roleArn; + this.accessKeyId = accessKeyId; + this.accessKeySecret = accessKeySecret; + this.roleSessionName = getNewRoleSessionName(); + this.stsEndpoint = DEFAULT_STS_ENDPOINT; + this.connectTimeout = DEFAULT_TIMEOUT_IN_MILLISECONDS; + this.readTimeout = DEFAULT_TIMEOUT_IN_MILLISECONDS * 2; + } + + public RamRoleArnCredentialsProvider(String accessKeyId, String accessKeySecret, String roleArn, String policy) { + this(accessKeyId, accessKeySecret, roleArn); + this.policy = policy; + } + + public RamRoleArnCredentialsProvider withConnectionTimeout(int milliseconds) { + this.connectTimeout = milliseconds; + this.readTimeout = milliseconds * 2; + return this; + } + + public static String getNewRoleSessionName() { + return "kms-credentials-" + System.currentTimeMillis(); + } + + @Override + public ICredentials getCredentials() throws Exception { + if (credential == null || credential.willSoonExpire()) { + CompatibleUrlConnClient client = new CompatibleUrlConnClient(); + credential = getNewSessionCredential(client); + } + return credential; + } + + public BasicSessionCredentials getNewSessionCredential(CompatibleUrlConnClient client) throws Exception { + ParameterUtils parameterUtils = new ParameterUtils(); + HttpRequest httpRequest = new HttpRequest(); + httpRequest.setUrlParameter("Action", "AssumeRole"); + httpRequest.setUrlParameter("Format", "JSON"); + httpRequest.setUrlParameter("Version", "2015-04-01"); + httpRequest.setUrlParameter("DurationSeconds", String.valueOf(DEFAULT_DURATION_SECONDS)); + httpRequest.setUrlParameter("RoleArn", this.roleArn); + httpRequest.setUrlParameter("AccessKeyId", this.accessKeyId); + httpRequest.setUrlParameter("RoleSessionName", this.roleSessionName); + if (this.policy != null) { + httpRequest.setUrlParameter("Policy", this.policy); + } + httpRequest.setMethod(MethodType.GET); + httpRequest.setConnectTimeout(this.connectTimeout); + httpRequest.setReadTimeout(this.readTimeout); + String strToSign = parameterUtils.composeStringToSign(MethodType.GET, httpRequest.getUrlParameters()); + String signature = HmacSHA1Signer.signString(strToSign, this.accessKeySecret + "&"); + httpRequest.setUrlParameter("Signature", signature); + httpRequest.setUrl(parameterUtils.composeUrl(this.stsEndpoint, httpRequest.getUrlParameters(), "https")); + HttpResponse httpResponse = client.syncInvoke(httpRequest); + Gson gson = new Gson(); + Map map = gson.fromJson(httpResponse.getHttpContentString(), Map.class); + if (map.containsKey("Credentials")) { + Map credential = (Map) map.get("Credentials"); + Long expiration = ParameterUtils.getUTCDate(credential.get("Expiration")).getTime(); + return new BasicSessionCredentials(credential.get("AccessKeyId"), credential.get("AccessKeySecret"), + credential.get("SecurityToken"), expiration); + } else { + throw new CredentialException(gson.toJson(map)); + } + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/StaticCredentialsProvider.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/StaticCredentialsProvider.java new file mode 100644 index 0000000..cadd103 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/provider/StaticCredentialsProvider.java @@ -0,0 +1,16 @@ +package com.alipay.easysdk.kms.aliyun.credentials.provider; + +import com.alipay.easysdk.kms.aliyun.credentials.ICredentials; + +public class StaticCredentialsProvider implements ICredentialsProvider{ + private final ICredentials credentials; + + public StaticCredentialsProvider(ICredentials credentials) { + this.credentials = credentials; + } + + @Override + public ICredentials getCredentials() throws Exception { + return this.credentials; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/AcsURLEncoder.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/AcsURLEncoder.java new file mode 100644 index 0000000..1dc9de7 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/AcsURLEncoder.java @@ -0,0 +1,17 @@ +package com.alipay.easysdk.kms.aliyun.credentials.utils; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +public class AcsURLEncoder { + public final static String URL_ENCODING = "UTF-8"; + + public static String encode(String value) throws UnsupportedEncodingException { + return URLEncoder.encode(value, URL_ENCODING); + } + + public static String percentEncode(String value) throws UnsupportedEncodingException { + return value != null ? URLEncoder.encode(value, URL_ENCODING).replace("+", "%20") + .replace("*", "%2A").replace("%7E", "~") : null; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/Base64Utils.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/Base64Utils.java new file mode 100644 index 0000000..1f4baa2 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/Base64Utils.java @@ -0,0 +1,33 @@ +package com.alipay.easysdk.kms.aliyun.credentials.utils; + +public class Base64Utils { + private static final String BASE64_CODE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/"; + + private static byte[] zeroPad(int length, byte[] bytes) { + byte[] padded = new byte[length]; + System.arraycopy(bytes, 0, padded, 0, bytes.length); + return padded; + } + + public synchronized static String encode(byte[] buff) { + StringBuilder strBuilder = new StringBuilder(""); + int paddingCount = (3 - (buff.length % 3)) % 3; + byte[] stringArray = zeroPad(buff.length + paddingCount, buff); + for (int i = 0; i < stringArray.length; i += 3) { + int j = ((stringArray[i] & 0xff) << 16) + + ((stringArray[i + 1] & 0xff) << 8) + + (stringArray[i + 2] & 0xff); + strBuilder.append(BASE64_CODE.charAt((j >> 18) & 0x3f)); + strBuilder.append(BASE64_CODE.charAt((j >> 12) & 0x3f)); + strBuilder.append(BASE64_CODE.charAt((j >> 6) & 0x3f)); + strBuilder.append(BASE64_CODE.charAt(j & 0x3f)); + } + int intPos = strBuilder.length(); + for (int i = paddingCount; i > 0; i--) { + strBuilder.setCharAt(intPos - i, '='); + } + + return strBuilder.toString(); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/CredentialType.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/CredentialType.java new file mode 100644 index 0000000..6351c96 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/CredentialType.java @@ -0,0 +1,8 @@ +package com.alipay.easysdk.kms.aliyun.credentials.utils; + +public class CredentialType { + public static final String ACCESS_KEY = "access_key"; + public static final String STS = "sts"; + public static final String ECS_RAM_ROLE = "ecs_ram_role"; + public static final String RAM_ROLE_ARN = "ram_role_arn"; +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/HmacSHA1Signer.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/HmacSHA1Signer.java new file mode 100644 index 0000000..ff76325 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/HmacSHA1Signer.java @@ -0,0 +1,41 @@ +package com.alipay.easysdk.kms.aliyun.credentials.utils; + +import com.alipay.easysdk.kms.aliyun.credentials.ICredentials; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +public class HmacSHA1Signer { + public static final String ENCODING = "UTF-8"; + private static final String ALGORITHM_NAME = "HmacSHA1"; + + public static String signString(String stringToSign, ICredentials credential) { + return signString(stringToSign, credential.getAccessKeySecret()); + } + + public static String signString(String stringToSign, String accessKeySecret) { + try { + Mac mac = Mac.getInstance(ALGORITHM_NAME); + mac.init(new SecretKeySpec(accessKeySecret.getBytes(ENCODING), ALGORITHM_NAME)); + byte[] signData = mac.doFinal(stringToSign.getBytes(ENCODING)); + return Base64Utils.encode(signData); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException(e.toString()); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e.toString()); + } catch (InvalidKeyException e) { + throw new IllegalArgumentException(e.toString()); + } + } + + public static String getSignerName() { + return "HMAC-SHA1"; + } + + public static String getSignerVersion() { + return "1.0"; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/ParameterUtils.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/ParameterUtils.java new file mode 100644 index 0000000..ce9d64f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/ParameterUtils.java @@ -0,0 +1,81 @@ +package com.alipay.easysdk.kms.aliyun.credentials.utils; + +import com.alipay.easysdk.kms.aliyun.credentials.http.MethodType; + +import java.io.UnsupportedEncodingException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +public class ParameterUtils { + private final static String TIME_ZONE = "UTC"; + private final static String FORMAT_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + private final static String SEPARATOR = "&"; + public static final String ENCODING = "UTF-8"; + private static final String ALGORITHM_NAME = "HmacSHA1"; + + public static String getUniqueNonce() { + StringBuilder uniqueNonce = new StringBuilder(); + UUID uuid = UUID.randomUUID(); + uniqueNonce.append(uuid.toString()); + uniqueNonce.append(System.currentTimeMillis()); + uniqueNonce.append(Thread.currentThread().getId()); + return uniqueNonce.toString(); + } + + public static String getISO8601Time(Date date) { + SimpleDateFormat df = new SimpleDateFormat(FORMAT_ISO8601); + df.setTimeZone(new SimpleTimeZone(0, TIME_ZONE)); + return df.format(date); + } + + public static Date getUTCDate(String date) throws ParseException { + SimpleDateFormat df = new SimpleDateFormat(FORMAT_ISO8601); + df.setTimeZone(new SimpleTimeZone(0, TIME_ZONE)); + return df.parse(date); + } + + public String composeStringToSign(MethodType method, Map queries) throws UnsupportedEncodingException { + String[] sortedKeys = queries.keySet().toArray(new String[]{}); + Arrays.sort(sortedKeys); + StringBuilder canonicalizedQueryString = new StringBuilder(); + + for (String key : sortedKeys) { + if (!StringUtils.isEmpty(queries.get(key))) { + canonicalizedQueryString.append("&") + .append(AcsURLEncoder.percentEncode(key)).append("=") + .append(AcsURLEncoder.percentEncode(queries.get(key))); + } + } + + return method.toString() + + SEPARATOR + + AcsURLEncoder.percentEncode("/") + + SEPARATOR + + AcsURLEncoder.percentEncode(canonicalizedQueryString.toString().substring(1)); + } + + public String composeUrl(String endpoint, Map queries, String protocol) throws UnsupportedEncodingException { + StringBuilder urlBuilder = new StringBuilder(""); + urlBuilder.append(protocol); + urlBuilder.append("://").append(endpoint); + urlBuilder.append("/?"); + StringBuilder builder = new StringBuilder(""); + + for (Map.Entry entry : queries.entrySet()) { + String key = entry.getKey(); + String val = entry.getValue(); + if (val == null) { + continue; + } + builder.append(AcsURLEncoder.encode(key)); + builder.append("=").append(AcsURLEncoder.encode(val)); + builder.append("&"); + } + + int strIndex = builder.length(); + builder.deleteCharAt(strIndex - 1); + String query = builder.toString(); + return urlBuilder.append(query).toString(); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/StringUtils.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/StringUtils.java new file mode 100644 index 0000000..635be53 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/credentials/utils/StringUtils.java @@ -0,0 +1,7 @@ +package com.alipay.easysdk.kms.aliyun.credentials.utils; + +public class StringUtils { + public static boolean isEmpty(final CharSequence cs) { + return cs == null || cs.length() == 0; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/AsymmetricSignRequest.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/AsymmetricSignRequest.java new file mode 100644 index 0000000..7c5b412 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/AsymmetricSignRequest.java @@ -0,0 +1,26 @@ +package com.alipay.easysdk.kms.aliyun.models; + +import com.aliyun.tea.*; + +public class AsymmetricSignRequest extends TeaModel { + @NameInMap("KeyId") + @Validation(required = true) + public String keyId; + + @NameInMap("KeyVersionId") + @Validation(required = true) + public String keyVersionId; + + @NameInMap("Algorithm") + @Validation(required = true) + public String algorithm; + + @NameInMap("Digest") + @Validation(required = true) + public String digest; + + public static AsymmetricSignRequest build(java.util.Map map) throws Exception { + AsymmetricSignRequest self = new AsymmetricSignRequest(); + return TeaModel.build(map, self); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/AsymmetricSignResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/AsymmetricSignResponse.java new file mode 100644 index 0000000..2e47bce --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/AsymmetricSignResponse.java @@ -0,0 +1,26 @@ +package com.alipay.easysdk.kms.aliyun.models; + +import com.aliyun.tea.*; + +public class AsymmetricSignResponse extends TeaModel { + @NameInMap("Value") + @Validation(required = true) + public String value; + + @NameInMap("KeyId") + @Validation(required = true) + public String keyId; + + @NameInMap("RequestId") + @Validation(required = true) + public String requestId; + + @NameInMap("KeyVersionId") + @Validation(required = true) + public String keyVersionId; + + public static AsymmetricSignResponse build(java.util.Map map) throws Exception { + AsymmetricSignResponse self = new AsymmetricSignResponse(); + return TeaModel.build(map, self); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/GetPublicKeyRequest.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/GetPublicKeyRequest.java new file mode 100644 index 0000000..e4d592e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/GetPublicKeyRequest.java @@ -0,0 +1,18 @@ +package com.alipay.easysdk.kms.aliyun.models; + +import com.aliyun.tea.*; + +public class GetPublicKeyRequest extends TeaModel { + @NameInMap("KeyId") + @Validation(required = true) + public String keyId; + + @NameInMap("KeyVersionId") + @Validation(required = true) + public String keyVersionId; + + public static GetPublicKeyRequest build(java.util.Map map) throws Exception { + GetPublicKeyRequest self = new GetPublicKeyRequest(); + return TeaModel.build(map, self); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/GetPublicKeyResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/GetPublicKeyResponse.java new file mode 100644 index 0000000..d6148e8 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/GetPublicKeyResponse.java @@ -0,0 +1,26 @@ +package com.alipay.easysdk.kms.aliyun.models; + +import com.aliyun.tea.*; + +public class GetPublicKeyResponse extends TeaModel { + @NameInMap("PublicKey") + @Validation(required = true) + public String publicKey; + + @NameInMap("KeyId") + @Validation(required = true) + public String keyId; + + @NameInMap("RequestId") + @Validation(required = true) + public String requestId; + + @NameInMap("KeyVersionId") + @Validation(required = true) + public String keyVersionId; + + public static GetPublicKeyResponse build(java.util.Map map) throws Exception { + GetPublicKeyResponse self = new GetPublicKeyResponse(); + return TeaModel.build(map, self); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/RuntimeOptions.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/RuntimeOptions.java new file mode 100644 index 0000000..9345d1c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/kms/aliyun/models/RuntimeOptions.java @@ -0,0 +1,26 @@ +package com.alipay.easysdk.kms.aliyun.models; + +import com.aliyun.tea.NameInMap; +import com.aliyun.tea.TeaModel; + +import java.util.Map; + +public class RuntimeOptions extends TeaModel { + @NameInMap("ignoreSSL") + public Boolean ignoreSSL; + @NameInMap("maxAttempts") + public Integer maxAttempts; + @NameInMap("backoffPolicy") + public String backoffPolicy; + @NameInMap("backoffPeriod") + public Integer backoffPeriod; + @NameInMap("readTimeout") + public Integer readTimeout; + @NameInMap("connectTimeout") + public Integer connectTimeout; + + public static RuntimeOptions build(Map map) throws Exception { + RuntimeOptions self = new RuntimeOptions(); + return TeaModel.build(map, self); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/Client.java new file mode 100644 index 0000000..628d52d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/Client.java @@ -0,0 +1,793 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife; + +import com.aliyun.tea.*; +import com.alipay.easysdk.marketing.openlife.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayOpenPublicMessageContentCreateResponse createImageTextContent(String title, String cover, String content, String contentComment, String ctype, String benefit, String extTags, String loginIds) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.public.message.content.create"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("title", title), + new TeaPair("cover", cover), + new TeaPair("content", content), + new TeaPair("could_comment", contentComment), + new TeaPair("ctype", ctype), + new TeaPair("benefit", benefit), + new TeaPair("ext_tags", extTags), + new TeaPair("login_ids", loginIds) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.public.message.content.create"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageContentCreateResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageContentCreateResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayOpenPublicMessageContentModifyResponse modifyImageTextContent(String contentId, String title, String cover, String content, String couldComment, String ctype, String benefit, String extTags, String loginIds) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.public.message.content.modify"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("content_id", contentId), + new TeaPair("title", title), + new TeaPair("cover", cover), + new TeaPair("content", content), + new TeaPair("could_comment", couldComment), + new TeaPair("ctype", ctype), + new TeaPair("benefit", benefit), + new TeaPair("ext_tags", extTags), + new TeaPair("login_ids", loginIds) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.public.message.content.modify"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageContentModifyResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageContentModifyResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayOpenPublicMessageTotalSendResponse sendText(String text) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.public.message.total.send"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + Text textObj = Text.build(TeaConverter.buildMap( + new TeaPair("title", ""), + new TeaPair("content", text) + )); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("msg_type", "text"), + new TeaPair("text", textObj) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.public.message.total.send"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageTotalSendResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageTotalSendResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayOpenPublicMessageTotalSendResponse sendImageText(java.util.List

articles) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.public.message.total.send"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("msg_type", "image-text"), + new TeaPair("articles", articles) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.public.message.total.send"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageTotalSendResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageTotalSendResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayOpenPublicMessageSingleSendResponse sendSingleMessage(String toUserId, Template template) throws Exception { + TeaModel.validateParams(template, "template"); + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.public.message.single.send"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("to_user_id", toUserId), + new TeaPair("template", template) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.public.message.single.send"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageSingleSendResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicMessageSingleSendResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayOpenPublicLifeMsgRecallResponse recallMessage(String messageId) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.public.life.msg.recall"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("message_id", messageId) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.public.life.msg.recall"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicLifeMsgRecallResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicLifeMsgRecallResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayOpenPublicTemplateMessageIndustryModifyResponse setIndustry(String primaryIndustryCode, String primaryIndustryName, String secondaryIndustryCode, String secondaryIndustryName) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.public.template.message.industry.modify"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("primary_industry_code", primaryIndustryCode), + new TeaPair("primary_industry_name", primaryIndustryName), + new TeaPair("secondary_industry_code", secondaryIndustryCode), + new TeaPair("secondary_industry_name", secondaryIndustryName) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.public.template.message.industry.modify"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicTemplateMessageIndustryModifyResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicTemplateMessageIndustryModifyResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayOpenPublicSettingCategoryQueryResponse getIndustry() throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.public.setting.category.query"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = new java.util.HashMap<>(); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.public.setting.category.query"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicSettingCategoryQueryResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenPublicSettingCategoryQueryResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicLifeMsgRecallResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicLifeMsgRecallResponse.java new file mode 100644 index 0000000..2655c93 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicLifeMsgRecallResponse.java @@ -0,0 +1,73 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class AlipayOpenPublicLifeMsgRecallResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + public static AlipayOpenPublicLifeMsgRecallResponse build(java.util.Map map) throws Exception { + AlipayOpenPublicLifeMsgRecallResponse self = new AlipayOpenPublicLifeMsgRecallResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenPublicLifeMsgRecallResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenPublicLifeMsgRecallResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenPublicLifeMsgRecallResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenPublicLifeMsgRecallResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenPublicLifeMsgRecallResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageContentCreateResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageContentCreateResponse.java new file mode 100644 index 0000000..120d4ec --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageContentCreateResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class AlipayOpenPublicMessageContentCreateResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("content_id") + @Validation(required = true) + public String contentId; + + @NameInMap("content_url") + @Validation(required = true) + public String contentUrl; + + public static AlipayOpenPublicMessageContentCreateResponse build(java.util.Map map) throws Exception { + AlipayOpenPublicMessageContentCreateResponse self = new AlipayOpenPublicMessageContentCreateResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenPublicMessageContentCreateResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenPublicMessageContentCreateResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenPublicMessageContentCreateResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenPublicMessageContentCreateResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenPublicMessageContentCreateResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayOpenPublicMessageContentCreateResponse setContentId(String contentId) { + this.contentId = contentId; + return this; + } + public String getContentId() { + return this.contentId; + } + + public AlipayOpenPublicMessageContentCreateResponse setContentUrl(String contentUrl) { + this.contentUrl = contentUrl; + return this; + } + public String getContentUrl() { + return this.contentUrl; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageContentModifyResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageContentModifyResponse.java new file mode 100644 index 0000000..8b93b46 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageContentModifyResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class AlipayOpenPublicMessageContentModifyResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("content_id") + @Validation(required = true) + public String contentId; + + @NameInMap("content_url") + @Validation(required = true) + public String contentUrl; + + public static AlipayOpenPublicMessageContentModifyResponse build(java.util.Map map) throws Exception { + AlipayOpenPublicMessageContentModifyResponse self = new AlipayOpenPublicMessageContentModifyResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenPublicMessageContentModifyResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenPublicMessageContentModifyResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenPublicMessageContentModifyResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenPublicMessageContentModifyResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenPublicMessageContentModifyResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayOpenPublicMessageContentModifyResponse setContentId(String contentId) { + this.contentId = contentId; + return this; + } + public String getContentId() { + return this.contentId; + } + + public AlipayOpenPublicMessageContentModifyResponse setContentUrl(String contentUrl) { + this.contentUrl = contentUrl; + return this; + } + public String getContentUrl() { + return this.contentUrl; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageSingleSendResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageSingleSendResponse.java new file mode 100644 index 0000000..fee42ff --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageSingleSendResponse.java @@ -0,0 +1,73 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class AlipayOpenPublicMessageSingleSendResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + public static AlipayOpenPublicMessageSingleSendResponse build(java.util.Map map) throws Exception { + AlipayOpenPublicMessageSingleSendResponse self = new AlipayOpenPublicMessageSingleSendResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenPublicMessageSingleSendResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenPublicMessageSingleSendResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenPublicMessageSingleSendResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenPublicMessageSingleSendResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenPublicMessageSingleSendResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageTotalSendResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageTotalSendResponse.java new file mode 100644 index 0000000..44f600c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicMessageTotalSendResponse.java @@ -0,0 +1,85 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class AlipayOpenPublicMessageTotalSendResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("message_id") + @Validation(required = true) + public String messageId; + + public static AlipayOpenPublicMessageTotalSendResponse build(java.util.Map map) throws Exception { + AlipayOpenPublicMessageTotalSendResponse self = new AlipayOpenPublicMessageTotalSendResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenPublicMessageTotalSendResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenPublicMessageTotalSendResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenPublicMessageTotalSendResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenPublicMessageTotalSendResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenPublicMessageTotalSendResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayOpenPublicMessageTotalSendResponse setMessageId(String messageId) { + this.messageId = messageId; + return this; + } + public String getMessageId() { + return this.messageId; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicSettingCategoryQueryResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicSettingCategoryQueryResponse.java new file mode 100644 index 0000000..d9d1d30 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicSettingCategoryQueryResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class AlipayOpenPublicSettingCategoryQueryResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("primary_category") + @Validation(required = true) + public String primaryCategory; + + @NameInMap("secondary_category") + @Validation(required = true) + public String secondaryCategory; + + public static AlipayOpenPublicSettingCategoryQueryResponse build(java.util.Map map) throws Exception { + AlipayOpenPublicSettingCategoryQueryResponse self = new AlipayOpenPublicSettingCategoryQueryResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenPublicSettingCategoryQueryResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenPublicSettingCategoryQueryResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenPublicSettingCategoryQueryResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenPublicSettingCategoryQueryResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenPublicSettingCategoryQueryResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayOpenPublicSettingCategoryQueryResponse setPrimaryCategory(String primaryCategory) { + this.primaryCategory = primaryCategory; + return this; + } + public String getPrimaryCategory() { + return this.primaryCategory; + } + + public AlipayOpenPublicSettingCategoryQueryResponse setSecondaryCategory(String secondaryCategory) { + this.secondaryCategory = secondaryCategory; + return this; + } + public String getSecondaryCategory() { + return this.secondaryCategory; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicTemplateMessageIndustryModifyResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicTemplateMessageIndustryModifyResponse.java new file mode 100644 index 0000000..cacafee --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/AlipayOpenPublicTemplateMessageIndustryModifyResponse.java @@ -0,0 +1,73 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class AlipayOpenPublicTemplateMessageIndustryModifyResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + public static AlipayOpenPublicTemplateMessageIndustryModifyResponse build(java.util.Map map) throws Exception { + AlipayOpenPublicTemplateMessageIndustryModifyResponse self = new AlipayOpenPublicTemplateMessageIndustryModifyResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenPublicTemplateMessageIndustryModifyResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenPublicTemplateMessageIndustryModifyResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenPublicTemplateMessageIndustryModifyResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenPublicTemplateMessageIndustryModifyResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenPublicTemplateMessageIndustryModifyResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Article.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Article.java new file mode 100644 index 0000000..ad0510d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Article.java @@ -0,0 +1,69 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class Article extends TeaModel { + @NameInMap("title") + public String title; + + @NameInMap("desc") + @Validation(required = true) + public String desc; + + @NameInMap("image_url") + public String imageUrl; + + @NameInMap("url") + @Validation(required = true) + public String url; + + @NameInMap("action_name") + public String actionName; + + public static Article build(java.util.Map map) throws Exception { + Article self = new Article(); + return TeaModel.build(map, self); + } + + public Article setTitle(String title) { + this.title = title; + return this; + } + public String getTitle() { + return this.title; + } + + public Article setDesc(String desc) { + this.desc = desc; + return this; + } + public String getDesc() { + return this.desc; + } + + public Article setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + return this; + } + public String getImageUrl() { + return this.imageUrl; + } + + public Article setUrl(String url) { + this.url = url; + return this; + } + public String getUrl() { + return this.url; + } + + public Article setActionName(String actionName) { + this.actionName = actionName; + return this; + } + public String getActionName() { + return this.actionName; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Context.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Context.java new file mode 100644 index 0000000..4fce800 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Context.java @@ -0,0 +1,92 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class Context extends TeaModel { + @NameInMap("head_color") + @Validation(required = true) + public String headColor; + + @NameInMap("url") + @Validation(required = true) + public String url; + + @NameInMap("action_name") + @Validation(required = true) + public String actionName; + + @NameInMap("keyword1") + public Keyword keyword1; + + @NameInMap("keyword2") + public Keyword keyword2; + + @NameInMap("first") + public Keyword first; + + @NameInMap("remark") + public Keyword remark; + + public static Context build(java.util.Map map) throws Exception { + Context self = new Context(); + return TeaModel.build(map, self); + } + + public Context setHeadColor(String headColor) { + this.headColor = headColor; + return this; + } + public String getHeadColor() { + return this.headColor; + } + + public Context setUrl(String url) { + this.url = url; + return this; + } + public String getUrl() { + return this.url; + } + + public Context setActionName(String actionName) { + this.actionName = actionName; + return this; + } + public String getActionName() { + return this.actionName; + } + + public Context setKeyword1(Keyword keyword1) { + this.keyword1 = keyword1; + return this; + } + public Keyword getKeyword1() { + return this.keyword1; + } + + public Context setKeyword2(Keyword keyword2) { + this.keyword2 = keyword2; + return this; + } + public Keyword getKeyword2() { + return this.keyword2; + } + + public Context setFirst(Keyword first) { + this.first = first; + return this; + } + public Keyword getFirst() { + return this.first; + } + + public Context setRemark(Keyword remark) { + this.remark = remark; + return this; + } + public Keyword getRemark() { + return this.remark; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Keyword.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Keyword.java new file mode 100644 index 0000000..fa0f38d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Keyword.java @@ -0,0 +1,36 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class Keyword extends TeaModel { + @NameInMap("color") + @Validation(required = true) + public String color; + + @NameInMap("value") + @Validation(required = true) + public String value; + + public static Keyword build(java.util.Map map) throws Exception { + Keyword self = new Keyword(); + return TeaModel.build(map, self); + } + + public Keyword setColor(String color) { + this.color = color; + return this; + } + public String getColor() { + return this.color; + } + + public Keyword setValue(String value) { + this.value = value; + return this; + } + public String getValue() { + return this.value; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Template.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Template.java new file mode 100644 index 0000000..4008cca --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Template.java @@ -0,0 +1,36 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class Template extends TeaModel { + @NameInMap("template_id") + @Validation(required = true) + public String templateId; + + @NameInMap("context") + @Validation(required = true) + public Context context; + + public static Template build(java.util.Map map) throws Exception { + Template self = new Template(); + return TeaModel.build(map, self); + } + + public Template setTemplateId(String templateId) { + this.templateId = templateId; + return this; + } + public String getTemplateId() { + return this.templateId; + } + + public Template setContext(Context context) { + this.context = context; + return this; + } + public Context getContext() { + return this.context; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Text.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Text.java new file mode 100644 index 0000000..fd0fbb4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/openlife/models/Text.java @@ -0,0 +1,36 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.openlife.models; + +import com.aliyun.tea.*; + +public class Text extends TeaModel { + @NameInMap("title") + @Validation(required = true) + public String title; + + @NameInMap("content") + @Validation(required = true) + public String content; + + public static Text build(java.util.Map map) throws Exception { + Text self = new Text(); + return TeaModel.build(map, self); + } + + public Text setTitle(String title) { + this.title = title; + return this; + } + public String getTitle() { + return this.title; + } + + public Text setContent(String content) { + this.content = content; + return this; + } + public String getContent() { + return this.content; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/Client.java new file mode 100644 index 0000000..e907dc6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/Client.java @@ -0,0 +1,439 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.pass; + +import com.aliyun.tea.*; +import com.alipay.easysdk.marketing.pass.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayPassTemplateAddResponse createTemplate(String uniqueId, String tplContent) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.pass.template.add"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("unique_id", uniqueId), + new TeaPair("tpl_content", tplContent) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.pass.template.add"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayPassTemplateAddResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayPassTemplateAddResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayPassTemplateUpdateResponse updateTemplate(String tplId, String tplContent) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.pass.template.update"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("tpl_id", tplId), + new TeaPair("tpl_content", tplContent) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.pass.template.update"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayPassTemplateUpdateResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayPassTemplateUpdateResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayPassInstanceAddResponse addInstance(String tplId, String tplParams, String recognitionType, String recognitionInfo) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.pass.instance.add"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("tpl_id", tplId), + new TeaPair("tpl_params", tplParams), + new TeaPair("recognition_type", recognitionType), + new TeaPair("recognition_info", recognitionInfo) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.pass.instance.add"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayPassInstanceAddResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayPassInstanceAddResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayPassInstanceUpdateResponse updateInstance(String serialNumber, String channelId, String tplParams, String status, String verifyCode, String verifyType) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.pass.instance.update"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("serial_number", serialNumber), + new TeaPair("channel_id", channelId), + new TeaPair("tpl_params", tplParams), + new TeaPair("status", status), + new TeaPair("verify_code", verifyCode), + new TeaPair("verify_type", verifyType) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.pass.instance.update"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayPassInstanceUpdateResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayPassInstanceUpdateResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassInstanceAddResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassInstanceAddResponse.java new file mode 100644 index 0000000..e2eac33 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassInstanceAddResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.pass.models; + +import com.aliyun.tea.*; + +public class AlipayPassInstanceAddResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("success") + @Validation(required = true) + public Boolean success; + + @NameInMap("result") + @Validation(required = true) + public String result; + + public static AlipayPassInstanceAddResponse build(java.util.Map map) throws Exception { + AlipayPassInstanceAddResponse self = new AlipayPassInstanceAddResponse(); + return TeaModel.build(map, self); + } + + public AlipayPassInstanceAddResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayPassInstanceAddResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayPassInstanceAddResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayPassInstanceAddResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayPassInstanceAddResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayPassInstanceAddResponse setSuccess(Boolean success) { + this.success = success; + return this; + } + public Boolean getSuccess() { + return this.success; + } + + public AlipayPassInstanceAddResponse setResult(String result) { + this.result = result; + return this; + } + public String getResult() { + return this.result; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassInstanceUpdateResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassInstanceUpdateResponse.java new file mode 100644 index 0000000..03ecaa1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassInstanceUpdateResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.pass.models; + +import com.aliyun.tea.*; + +public class AlipayPassInstanceUpdateResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("success") + @Validation(required = true) + public Boolean success; + + @NameInMap("result") + @Validation(required = true) + public String result; + + public static AlipayPassInstanceUpdateResponse build(java.util.Map map) throws Exception { + AlipayPassInstanceUpdateResponse self = new AlipayPassInstanceUpdateResponse(); + return TeaModel.build(map, self); + } + + public AlipayPassInstanceUpdateResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayPassInstanceUpdateResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayPassInstanceUpdateResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayPassInstanceUpdateResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayPassInstanceUpdateResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayPassInstanceUpdateResponse setSuccess(Boolean success) { + this.success = success; + return this; + } + public Boolean getSuccess() { + return this.success; + } + + public AlipayPassInstanceUpdateResponse setResult(String result) { + this.result = result; + return this; + } + public String getResult() { + return this.result; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassTemplateAddResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassTemplateAddResponse.java new file mode 100644 index 0000000..6b7f8f5 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassTemplateAddResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.pass.models; + +import com.aliyun.tea.*; + +public class AlipayPassTemplateAddResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("success") + @Validation(required = true) + public Boolean success; + + @NameInMap("result") + @Validation(required = true) + public String result; + + public static AlipayPassTemplateAddResponse build(java.util.Map map) throws Exception { + AlipayPassTemplateAddResponse self = new AlipayPassTemplateAddResponse(); + return TeaModel.build(map, self); + } + + public AlipayPassTemplateAddResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayPassTemplateAddResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayPassTemplateAddResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayPassTemplateAddResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayPassTemplateAddResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayPassTemplateAddResponse setSuccess(Boolean success) { + this.success = success; + return this; + } + public Boolean getSuccess() { + return this.success; + } + + public AlipayPassTemplateAddResponse setResult(String result) { + this.result = result; + return this; + } + public String getResult() { + return this.result; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassTemplateUpdateResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassTemplateUpdateResponse.java new file mode 100644 index 0000000..4a49185 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/pass/models/AlipayPassTemplateUpdateResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.pass.models; + +import com.aliyun.tea.*; + +public class AlipayPassTemplateUpdateResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("success") + @Validation(required = true) + public Boolean success; + + @NameInMap("result") + @Validation(required = true) + public String result; + + public static AlipayPassTemplateUpdateResponse build(java.util.Map map) throws Exception { + AlipayPassTemplateUpdateResponse self = new AlipayPassTemplateUpdateResponse(); + return TeaModel.build(map, self); + } + + public AlipayPassTemplateUpdateResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayPassTemplateUpdateResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayPassTemplateUpdateResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayPassTemplateUpdateResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayPassTemplateUpdateResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayPassTemplateUpdateResponse setSuccess(Boolean success) { + this.success = success; + return this; + } + public Boolean getSuccess() { + return this.success; + } + + public AlipayPassTemplateUpdateResponse setResult(String result) { + this.result = result; + return this; + } + public String getResult() { + return this.result; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/templatemessage/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/templatemessage/Client.java new file mode 100644 index 0000000..eb801f1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/templatemessage/Client.java @@ -0,0 +1,178 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.templatemessage; + +import com.aliyun.tea.*; +import com.alipay.easysdk.marketing.templatemessage.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayOpenAppMiniTemplatemessageSendResponse send(String toUserId, String formId, String userTemplateId, String page, String data) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.open.app.mini.templatemessage.send"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("to_user_id", toUserId), + new TeaPair("form_id", formId), + new TeaPair("user_template_id", userTemplateId), + new TeaPair("page", page), + new TeaPair("data", data) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.open.app.mini.templatemessage.send"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenAppMiniTemplatemessageSendResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenAppMiniTemplatemessageSendResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/templatemessage/models/AlipayOpenAppMiniTemplatemessageSendResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/templatemessage/models/AlipayOpenAppMiniTemplatemessageSendResponse.java new file mode 100644 index 0000000..13073d0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/marketing/templatemessage/models/AlipayOpenAppMiniTemplatemessageSendResponse.java @@ -0,0 +1,73 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.marketing.templatemessage.models; + +import com.aliyun.tea.*; + +public class AlipayOpenAppMiniTemplatemessageSendResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + public static AlipayOpenAppMiniTemplatemessageSendResponse build(java.util.Map map) throws Exception { + AlipayOpenAppMiniTemplatemessageSendResponse self = new AlipayOpenAppMiniTemplatemessageSendResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenAppMiniTemplatemessageSendResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenAppMiniTemplatemessageSendResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenAppMiniTemplatemessageSendResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenAppMiniTemplatemessageSendResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenAppMiniTemplatemessageSendResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/Client.java new file mode 100644 index 0000000..dad0427 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/Client.java @@ -0,0 +1,287 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.member.identification; + +import com.aliyun.tea.*; +import com.alipay.easysdk.member.identification.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayUserCertifyOpenInitializeResponse init(String outerOrderNo, String bizCode, IdentityParam identityParam, MerchantConfig merchantConfig) throws Exception { + TeaModel.validateParams(identityParam, "identityParam"); + TeaModel.validateParams(merchantConfig, "merchantConfig"); + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.user.certify.open.initialize"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("outer_order_no", outerOrderNo), + new TeaPair("biz_code", bizCode), + new TeaPair("identity_param", identityParam), + new TeaPair("merchant_config", merchantConfig) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.user.certify.open.initialize"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayUserCertifyOpenInitializeResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayUserCertifyOpenInitializeResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayUserCertifyOpenQueryResponse query(String certifyId) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.user.certify.open.query"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("certify_id", certifyId) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.user.certify.open.query"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayUserCertifyOpenQueryResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayUserCertifyOpenQueryResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayUserCertifyOpenCertifyResponse certify(String certifyId) throws Exception { + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.user.certify.open.certify"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("certify_id", certifyId) + ); + java.util.Map textParams = new java.util.HashMap<>(); + String sign = _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey")); + java.util.Map response = TeaConverter.buildMap( + new TeaPair("body", _kernel.generatePage("GET", systemParams, bizParams, textParams, sign)) + ); + return TeaModel.toModel(response, new AlipayUserCertifyOpenCertifyResponse()); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/AlipayUserCertifyOpenCertifyResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/AlipayUserCertifyOpenCertifyResponse.java new file mode 100644 index 0000000..4590186 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/AlipayUserCertifyOpenCertifyResponse.java @@ -0,0 +1,25 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.member.identification.models; + +import com.aliyun.tea.*; + +public class AlipayUserCertifyOpenCertifyResponse extends TeaModel { + // 认证服务请求地址 + @NameInMap("body") + @Validation(required = true) + public String body; + + public static AlipayUserCertifyOpenCertifyResponse build(java.util.Map map) throws Exception { + AlipayUserCertifyOpenCertifyResponse self = new AlipayUserCertifyOpenCertifyResponse(); + return TeaModel.build(map, self); + } + + public AlipayUserCertifyOpenCertifyResponse setBody(String body) { + this.body = body; + return this; + } + public String getBody() { + return this.body; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/AlipayUserCertifyOpenInitializeResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/AlipayUserCertifyOpenInitializeResponse.java new file mode 100644 index 0000000..ccf2c06 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/AlipayUserCertifyOpenInitializeResponse.java @@ -0,0 +1,85 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.member.identification.models; + +import com.aliyun.tea.*; + +public class AlipayUserCertifyOpenInitializeResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("certify_id") + @Validation(required = true) + public String certifyId; + + public static AlipayUserCertifyOpenInitializeResponse build(java.util.Map map) throws Exception { + AlipayUserCertifyOpenInitializeResponse self = new AlipayUserCertifyOpenInitializeResponse(); + return TeaModel.build(map, self); + } + + public AlipayUserCertifyOpenInitializeResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayUserCertifyOpenInitializeResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayUserCertifyOpenInitializeResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayUserCertifyOpenInitializeResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayUserCertifyOpenInitializeResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayUserCertifyOpenInitializeResponse setCertifyId(String certifyId) { + this.certifyId = certifyId; + return this; + } + public String getCertifyId() { + return this.certifyId; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/AlipayUserCertifyOpenQueryResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/AlipayUserCertifyOpenQueryResponse.java new file mode 100644 index 0000000..4bc2bea --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/AlipayUserCertifyOpenQueryResponse.java @@ -0,0 +1,109 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.member.identification.models; + +import com.aliyun.tea.*; + +public class AlipayUserCertifyOpenQueryResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("passed") + @Validation(required = true) + public String passed; + + @NameInMap("identity_info") + @Validation(required = true) + public String identityInfo; + + @NameInMap("material_info") + @Validation(required = true) + public String materialInfo; + + public static AlipayUserCertifyOpenQueryResponse build(java.util.Map map) throws Exception { + AlipayUserCertifyOpenQueryResponse self = new AlipayUserCertifyOpenQueryResponse(); + return TeaModel.build(map, self); + } + + public AlipayUserCertifyOpenQueryResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayUserCertifyOpenQueryResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayUserCertifyOpenQueryResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayUserCertifyOpenQueryResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayUserCertifyOpenQueryResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayUserCertifyOpenQueryResponse setPassed(String passed) { + this.passed = passed; + return this; + } + public String getPassed() { + return this.passed; + } + + public AlipayUserCertifyOpenQueryResponse setIdentityInfo(String identityInfo) { + this.identityInfo = identityInfo; + return this; + } + public String getIdentityInfo() { + return this.identityInfo; + } + + public AlipayUserCertifyOpenQueryResponse setMaterialInfo(String materialInfo) { + this.materialInfo = materialInfo; + return this; + } + public String getMaterialInfo() { + return this.materialInfo; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/IdentityParam.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/IdentityParam.java new file mode 100644 index 0000000..b806df2 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/IdentityParam.java @@ -0,0 +1,60 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.member.identification.models; + +import com.aliyun.tea.*; + +public class IdentityParam extends TeaModel { + @NameInMap("identity_type") + @Validation(required = true) + public String identityType; + + @NameInMap("cert_type") + @Validation(required = true) + public String certType; + + @NameInMap("cert_name") + @Validation(required = true) + public String certName; + + @NameInMap("cert_no") + @Validation(required = true) + public String certNo; + + public static IdentityParam build(java.util.Map map) throws Exception { + IdentityParam self = new IdentityParam(); + return TeaModel.build(map, self); + } + + public IdentityParam setIdentityType(String identityType) { + this.identityType = identityType; + return this; + } + public String getIdentityType() { + return this.identityType; + } + + public IdentityParam setCertType(String certType) { + this.certType = certType; + return this; + } + public String getCertType() { + return this.certType; + } + + public IdentityParam setCertName(String certName) { + this.certName = certName; + return this; + } + public String getCertName() { + return this.certName; + } + + public IdentityParam setCertNo(String certNo) { + this.certNo = certNo; + return this; + } + public String getCertNo() { + return this.certNo; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/MerchantConfig.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/MerchantConfig.java new file mode 100644 index 0000000..e643008 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/member/identification/models/MerchantConfig.java @@ -0,0 +1,24 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.member.identification.models; + +import com.aliyun.tea.*; + +public class MerchantConfig extends TeaModel { + @NameInMap("return_url") + @Validation(required = true) + public String returnUrl; + + public static MerchantConfig build(java.util.Map map) throws Exception { + MerchantConfig self = new MerchantConfig(); + return TeaModel.build(map, self); + } + + public MerchantConfig setReturnUrl(String returnUrl) { + this.returnUrl = returnUrl; + return this; + } + public String getReturnUrl() { + return this.returnUrl; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/app/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/app/Client.java new file mode 100644 index 0000000..a4c8b29 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/app/Client.java @@ -0,0 +1,115 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.app; + +import com.aliyun.tea.*; +import com.alipay.easysdk.payment.app.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + + public AlipayTradeAppPayResponse pay(String subject, String outTradeNo, String totalAmount) throws Exception { + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.app.pay"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("subject", subject), + new TeaPair("out_trade_no", outTradeNo), + new TeaPair("total_amount", totalAmount) + ); + java.util.Map textParams = new java.util.HashMap<>(); + String sign = _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey")); + java.util.Map response = TeaConverter.buildMap( + new TeaPair("body", _kernel.generateOrderString(systemParams, bizParams, textParams, sign)) + ); + return TeaModel.toModel(response, new AlipayTradeAppPayResponse()); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/app/models/AlipayTradeAppPayResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/app/models/AlipayTradeAppPayResponse.java new file mode 100644 index 0000000..55334ff --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/app/models/AlipayTradeAppPayResponse.java @@ -0,0 +1,25 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.app.models; + +import com.aliyun.tea.*; + +public class AlipayTradeAppPayResponse extends TeaModel { + // 订单信息,字符串形式 + @NameInMap("body") + @Validation(required = true) + public String body; + + public static AlipayTradeAppPayResponse build(java.util.Map map) throws Exception { + AlipayTradeAppPayResponse self = new AlipayTradeAppPayResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradeAppPayResponse setBody(String body) { + this.body = body; + return this; + } + public String getBody() { + return this.body; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/Client.java new file mode 100644 index 0000000..7923f80 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/Client.java @@ -0,0 +1,698 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common; + +import com.aliyun.tea.*; +import com.alipay.easysdk.payment.common.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayTradeCreateResponse create(String subject, String outTradeNo, String totalAmount, String buyerId) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.create"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("subject", subject), + new TeaPair("out_trade_no", outTradeNo), + new TeaPair("total_amount", totalAmount), + new TeaPair("buyer_id", buyerId) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.trade.create"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeCreateResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeCreateResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayTradeQueryResponse query(String outTradeNo) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.query"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("out_trade_no", outTradeNo) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.trade.query"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeQueryResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeQueryResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayTradeRefundResponse refund(String outTradeNo, String refundAmount) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.refund"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("out_trade_no", outTradeNo), + new TeaPair("refund_amount", refundAmount) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.trade.refund"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeRefundResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeRefundResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayTradeCloseResponse close(String outTradeNo) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.close"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("out_trade_no", outTradeNo) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.trade.close"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeCloseResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeCloseResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayTradeCancelResponse cancel(String outTradeNo) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.cancel"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("out_trade_no", outTradeNo) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.trade.cancel"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeCancelResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeCancelResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayTradeFastpayRefundQueryResponse queryRefund(String outTradeNo, String outRequestNo) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.fastpay.refund.query"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("out_trade_no", outTradeNo), + new TeaPair("out_request_no", outRequestNo) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.trade.fastpay.refund.query"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeFastpayRefundQueryResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeFastpayRefundQueryResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayDataDataserviceBillDownloadurlQueryResponse downloadBill(String billType, String billDate) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.data.dataservice.bill.downloadurl.query"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("bill_type", billType), + new TeaPair("bill_date", billDate) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.data.dataservice.bill.downloadurl.query"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayDataDataserviceBillDownloadurlQueryResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayDataDataserviceBillDownloadurlQueryResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public Boolean verifyNotify(java.util.Map parameters) throws Exception { + if (_kernel.isCertMode()) { + return _kernel.verifyParams(parameters, _kernel.extractAlipayPublicKey("")); + } else { + return _kernel.verifyParams(parameters, _kernel.getConfig("alipayPublicKey")); + } + + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayDataDataserviceBillDownloadurlQueryResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayDataDataserviceBillDownloadurlQueryResponse.java new file mode 100644 index 0000000..df377d8 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayDataDataserviceBillDownloadurlQueryResponse.java @@ -0,0 +1,85 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class AlipayDataDataserviceBillDownloadurlQueryResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("bill_download_url") + @Validation(required = true) + public String billDownloadUrl; + + public static AlipayDataDataserviceBillDownloadurlQueryResponse build(java.util.Map map) throws Exception { + AlipayDataDataserviceBillDownloadurlQueryResponse self = new AlipayDataDataserviceBillDownloadurlQueryResponse(); + return TeaModel.build(map, self); + } + + public AlipayDataDataserviceBillDownloadurlQueryResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayDataDataserviceBillDownloadurlQueryResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayDataDataserviceBillDownloadurlQueryResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayDataDataserviceBillDownloadurlQueryResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayDataDataserviceBillDownloadurlQueryResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayDataDataserviceBillDownloadurlQueryResponse setBillDownloadUrl(String billDownloadUrl) { + this.billDownloadUrl = billDownloadUrl; + return this; + } + public String getBillDownloadUrl() { + return this.billDownloadUrl; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeCancelResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeCancelResponse.java new file mode 100644 index 0000000..4787efe --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeCancelResponse.java @@ -0,0 +1,145 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class AlipayTradeCancelResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("trade_no") + @Validation(required = true) + public String tradeNo; + + @NameInMap("out_trade_no") + @Validation(required = true) + public String outTradeNo; + + @NameInMap("retry_flag") + @Validation(required = true) + public String retryFlag; + + @NameInMap("action") + @Validation(required = true) + public String action; + + @NameInMap("gmt_refund_pay") + @Validation(required = true) + public String gmtRefundPay; + + @NameInMap("refund_settlement_id") + @Validation(required = true) + public String refundSettlementId; + + public static AlipayTradeCancelResponse build(java.util.Map map) throws Exception { + AlipayTradeCancelResponse self = new AlipayTradeCancelResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradeCancelResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayTradeCancelResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayTradeCancelResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayTradeCancelResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayTradeCancelResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayTradeCancelResponse setTradeNo(String tradeNo) { + this.tradeNo = tradeNo; + return this; + } + public String getTradeNo() { + return this.tradeNo; + } + + public AlipayTradeCancelResponse setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + return this; + } + public String getOutTradeNo() { + return this.outTradeNo; + } + + public AlipayTradeCancelResponse setRetryFlag(String retryFlag) { + this.retryFlag = retryFlag; + return this; + } + public String getRetryFlag() { + return this.retryFlag; + } + + public AlipayTradeCancelResponse setAction(String action) { + this.action = action; + return this; + } + public String getAction() { + return this.action; + } + + public AlipayTradeCancelResponse setGmtRefundPay(String gmtRefundPay) { + this.gmtRefundPay = gmtRefundPay; + return this; + } + public String getGmtRefundPay() { + return this.gmtRefundPay; + } + + public AlipayTradeCancelResponse setRefundSettlementId(String refundSettlementId) { + this.refundSettlementId = refundSettlementId; + return this; + } + public String getRefundSettlementId() { + return this.refundSettlementId; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeCloseResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeCloseResponse.java new file mode 100644 index 0000000..bcceee1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeCloseResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class AlipayTradeCloseResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("trade_no") + @Validation(required = true) + public String tradeNo; + + @NameInMap("out_trade_no") + @Validation(required = true) + public String outTradeNo; + + public static AlipayTradeCloseResponse build(java.util.Map map) throws Exception { + AlipayTradeCloseResponse self = new AlipayTradeCloseResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradeCloseResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayTradeCloseResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayTradeCloseResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayTradeCloseResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayTradeCloseResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayTradeCloseResponse setTradeNo(String tradeNo) { + this.tradeNo = tradeNo; + return this; + } + public String getTradeNo() { + return this.tradeNo; + } + + public AlipayTradeCloseResponse setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + return this; + } + public String getOutTradeNo() { + return this.outTradeNo; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeCreateResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeCreateResponse.java new file mode 100644 index 0000000..1a0f91d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeCreateResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class AlipayTradeCreateResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("out_trade_no") + @Validation(required = true) + public String outTradeNo; + + @NameInMap("trade_no") + @Validation(required = true) + public String tradeNo; + + public static AlipayTradeCreateResponse build(java.util.Map map) throws Exception { + AlipayTradeCreateResponse self = new AlipayTradeCreateResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradeCreateResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayTradeCreateResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayTradeCreateResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayTradeCreateResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayTradeCreateResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayTradeCreateResponse setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + return this; + } + public String getOutTradeNo() { + return this.outTradeNo; + } + + public AlipayTradeCreateResponse setTradeNo(String tradeNo) { + this.tradeNo = tradeNo; + return this; + } + public String getTradeNo() { + return this.tradeNo; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeFastpayRefundQueryResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeFastpayRefundQueryResponse.java new file mode 100644 index 0000000..3c13251 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeFastpayRefundQueryResponse.java @@ -0,0 +1,289 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class AlipayTradeFastpayRefundQueryResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("error_code") + @Validation(required = true) + public String errorCode; + + @NameInMap("gmt_refund_pay") + @Validation(required = true) + public String gmtRefundPay; + + @NameInMap("industry_sepc_detail") + @Validation(required = true) + public String industrySepcDetail; + + @NameInMap("out_request_no") + @Validation(required = true) + public String outRequestNo; + + @NameInMap("out_trade_no") + @Validation(required = true) + public String outTradeNo; + + @NameInMap("present_refund_buyer_amount") + @Validation(required = true) + public String presentRefundBuyerAmount; + + @NameInMap("present_refund_discount_amount") + @Validation(required = true) + public String presentRefundDiscountAmount; + + @NameInMap("present_refund_mdiscount_amount") + @Validation(required = true) + public String presentRefundMdiscountAmount; + + @NameInMap("refund_amount") + @Validation(required = true) + public String refundAmount; + + @NameInMap("refund_charge_amount") + @Validation(required = true) + public String refundChargeAmount; + + @NameInMap("refund_detail_item_list") + @Validation(required = true) + public java.util.List refundDetailItemList; + + @NameInMap("refund_reason") + @Validation(required = true) + public String refundReason; + + @NameInMap("refund_royaltys") + @Validation(required = true) + public java.util.List refundRoyaltys; + + @NameInMap("refund_settlement_id") + @Validation(required = true) + public String refundSettlementId; + + @NameInMap("refund_status") + @Validation(required = true) + public String refundStatus; + + @NameInMap("send_back_fee") + @Validation(required = true) + public String sendBackFee; + + @NameInMap("total_amount") + @Validation(required = true) + public String totalAmount; + + @NameInMap("trade_no") + @Validation(required = true) + public String tradeNo; + + public static AlipayTradeFastpayRefundQueryResponse build(java.util.Map map) throws Exception { + AlipayTradeFastpayRefundQueryResponse self = new AlipayTradeFastpayRefundQueryResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradeFastpayRefundQueryResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayTradeFastpayRefundQueryResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayTradeFastpayRefundQueryResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayTradeFastpayRefundQueryResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayTradeFastpayRefundQueryResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayTradeFastpayRefundQueryResponse setErrorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } + public String getErrorCode() { + return this.errorCode; + } + + public AlipayTradeFastpayRefundQueryResponse setGmtRefundPay(String gmtRefundPay) { + this.gmtRefundPay = gmtRefundPay; + return this; + } + public String getGmtRefundPay() { + return this.gmtRefundPay; + } + + public AlipayTradeFastpayRefundQueryResponse setIndustrySepcDetail(String industrySepcDetail) { + this.industrySepcDetail = industrySepcDetail; + return this; + } + public String getIndustrySepcDetail() { + return this.industrySepcDetail; + } + + public AlipayTradeFastpayRefundQueryResponse setOutRequestNo(String outRequestNo) { + this.outRequestNo = outRequestNo; + return this; + } + public String getOutRequestNo() { + return this.outRequestNo; + } + + public AlipayTradeFastpayRefundQueryResponse setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + return this; + } + public String getOutTradeNo() { + return this.outTradeNo; + } + + public AlipayTradeFastpayRefundQueryResponse setPresentRefundBuyerAmount(String presentRefundBuyerAmount) { + this.presentRefundBuyerAmount = presentRefundBuyerAmount; + return this; + } + public String getPresentRefundBuyerAmount() { + return this.presentRefundBuyerAmount; + } + + public AlipayTradeFastpayRefundQueryResponse setPresentRefundDiscountAmount(String presentRefundDiscountAmount) { + this.presentRefundDiscountAmount = presentRefundDiscountAmount; + return this; + } + public String getPresentRefundDiscountAmount() { + return this.presentRefundDiscountAmount; + } + + public AlipayTradeFastpayRefundQueryResponse setPresentRefundMdiscountAmount(String presentRefundMdiscountAmount) { + this.presentRefundMdiscountAmount = presentRefundMdiscountAmount; + return this; + } + public String getPresentRefundMdiscountAmount() { + return this.presentRefundMdiscountAmount; + } + + public AlipayTradeFastpayRefundQueryResponse setRefundAmount(String refundAmount) { + this.refundAmount = refundAmount; + return this; + } + public String getRefundAmount() { + return this.refundAmount; + } + + public AlipayTradeFastpayRefundQueryResponse setRefundChargeAmount(String refundChargeAmount) { + this.refundChargeAmount = refundChargeAmount; + return this; + } + public String getRefundChargeAmount() { + return this.refundChargeAmount; + } + + public AlipayTradeFastpayRefundQueryResponse setRefundDetailItemList(java.util.List refundDetailItemList) { + this.refundDetailItemList = refundDetailItemList; + return this; + } + public java.util.List getRefundDetailItemList() { + return this.refundDetailItemList; + } + + public AlipayTradeFastpayRefundQueryResponse setRefundReason(String refundReason) { + this.refundReason = refundReason; + return this; + } + public String getRefundReason() { + return this.refundReason; + } + + public AlipayTradeFastpayRefundQueryResponse setRefundRoyaltys(java.util.List refundRoyaltys) { + this.refundRoyaltys = refundRoyaltys; + return this; + } + public java.util.List getRefundRoyaltys() { + return this.refundRoyaltys; + } + + public AlipayTradeFastpayRefundQueryResponse setRefundSettlementId(String refundSettlementId) { + this.refundSettlementId = refundSettlementId; + return this; + } + public String getRefundSettlementId() { + return this.refundSettlementId; + } + + public AlipayTradeFastpayRefundQueryResponse setRefundStatus(String refundStatus) { + this.refundStatus = refundStatus; + return this; + } + public String getRefundStatus() { + return this.refundStatus; + } + + public AlipayTradeFastpayRefundQueryResponse setSendBackFee(String sendBackFee) { + this.sendBackFee = sendBackFee; + return this; + } + public String getSendBackFee() { + return this.sendBackFee; + } + + public AlipayTradeFastpayRefundQueryResponse setTotalAmount(String totalAmount) { + this.totalAmount = totalAmount; + return this; + } + public String getTotalAmount() { + return this.totalAmount; + } + + public AlipayTradeFastpayRefundQueryResponse setTradeNo(String tradeNo) { + this.tradeNo = tradeNo; + return this; + } + public String getTradeNo() { + return this.tradeNo; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeQueryResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeQueryResponse.java new file mode 100644 index 0000000..e6cd500 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeQueryResponse.java @@ -0,0 +1,493 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class AlipayTradeQueryResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("trade_no") + @Validation(required = true) + public String tradeNo; + + @NameInMap("out_trade_no") + @Validation(required = true) + public String outTradeNo; + + @NameInMap("buyer_logon_id") + @Validation(required = true) + public String buyerLogonId; + + @NameInMap("trade_status") + @Validation(required = true) + public String tradeStatus; + + @NameInMap("total_amount") + @Validation(required = true) + public String totalAmount; + + @NameInMap("trans_currency") + @Validation(required = true) + public String transCurrency; + + @NameInMap("settle_currency") + @Validation(required = true) + public String settleCurrency; + + @NameInMap("settle_amount") + @Validation(required = true) + public String settleAmount; + + @NameInMap("pay_currency") + @Validation(required = true) + public String payCurrency; + + @NameInMap("pay_amount") + @Validation(required = true) + public String payAmount; + + @NameInMap("settle_trans_rate") + @Validation(required = true) + public String settleTransRate; + + @NameInMap("trans_pay_rate") + @Validation(required = true) + public String transPayRate; + + @NameInMap("buyer_pay_amount") + @Validation(required = true) + public String buyerPayAmount; + + @NameInMap("point_amount") + @Validation(required = true) + public String pointAmount; + + @NameInMap("invoice_amount") + @Validation(required = true) + public String invoiceAmount; + + @NameInMap("send_pay_date") + @Validation(required = true) + public String sendPayDate; + + @NameInMap("receipt_amount") + @Validation(required = true) + public String receiptAmount; + + @NameInMap("store_id") + @Validation(required = true) + public String storeId; + + @NameInMap("terminal_id") + @Validation(required = true) + public String terminalId; + + @NameInMap("fund_bill_list") + @Validation(required = true) + public java.util.List fundBillList; + + @NameInMap("store_name") + @Validation(required = true) + public String storeName; + + @NameInMap("buyer_user_id") + @Validation(required = true) + public String buyerUserId; + + @NameInMap("charge_amount") + @Validation(required = true) + public String chargeAmount; + + @NameInMap("charge_flags") + @Validation(required = true) + public String chargeFlags; + + @NameInMap("settlement_id") + @Validation(required = true) + public String settlementId; + + @NameInMap("trade_settle_info") + @Validation(required = true) + public java.util.List tradeSettleInfo; + + @NameInMap("auth_trade_pay_mode") + @Validation(required = true) + public String authTradePayMode; + + @NameInMap("buyer_user_type") + @Validation(required = true) + public String buyerUserType; + + @NameInMap("mdiscount_amount") + @Validation(required = true) + public String mdiscountAmount; + + @NameInMap("discount_amount") + @Validation(required = true) + public String discountAmount; + + @NameInMap("buyer_user_name") + @Validation(required = true) + public String buyerUserName; + + @NameInMap("subject") + @Validation(required = true) + public String subject; + + @NameInMap("body") + @Validation(required = true) + public String body; + + @NameInMap("alipay_sub_merchant_id") + @Validation(required = true) + public String alipaySubMerchantId; + + @NameInMap("ext_infos") + @Validation(required = true) + public String extInfos; + + public static AlipayTradeQueryResponse build(java.util.Map map) throws Exception { + AlipayTradeQueryResponse self = new AlipayTradeQueryResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradeQueryResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayTradeQueryResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayTradeQueryResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayTradeQueryResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayTradeQueryResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayTradeQueryResponse setTradeNo(String tradeNo) { + this.tradeNo = tradeNo; + return this; + } + public String getTradeNo() { + return this.tradeNo; + } + + public AlipayTradeQueryResponse setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + return this; + } + public String getOutTradeNo() { + return this.outTradeNo; + } + + public AlipayTradeQueryResponse setBuyerLogonId(String buyerLogonId) { + this.buyerLogonId = buyerLogonId; + return this; + } + public String getBuyerLogonId() { + return this.buyerLogonId; + } + + public AlipayTradeQueryResponse setTradeStatus(String tradeStatus) { + this.tradeStatus = tradeStatus; + return this; + } + public String getTradeStatus() { + return this.tradeStatus; + } + + public AlipayTradeQueryResponse setTotalAmount(String totalAmount) { + this.totalAmount = totalAmount; + return this; + } + public String getTotalAmount() { + return this.totalAmount; + } + + public AlipayTradeQueryResponse setTransCurrency(String transCurrency) { + this.transCurrency = transCurrency; + return this; + } + public String getTransCurrency() { + return this.transCurrency; + } + + public AlipayTradeQueryResponse setSettleCurrency(String settleCurrency) { + this.settleCurrency = settleCurrency; + return this; + } + public String getSettleCurrency() { + return this.settleCurrency; + } + + public AlipayTradeQueryResponse setSettleAmount(String settleAmount) { + this.settleAmount = settleAmount; + return this; + } + public String getSettleAmount() { + return this.settleAmount; + } + + public AlipayTradeQueryResponse setPayCurrency(String payCurrency) { + this.payCurrency = payCurrency; + return this; + } + public String getPayCurrency() { + return this.payCurrency; + } + + public AlipayTradeQueryResponse setPayAmount(String payAmount) { + this.payAmount = payAmount; + return this; + } + public String getPayAmount() { + return this.payAmount; + } + + public AlipayTradeQueryResponse setSettleTransRate(String settleTransRate) { + this.settleTransRate = settleTransRate; + return this; + } + public String getSettleTransRate() { + return this.settleTransRate; + } + + public AlipayTradeQueryResponse setTransPayRate(String transPayRate) { + this.transPayRate = transPayRate; + return this; + } + public String getTransPayRate() { + return this.transPayRate; + } + + public AlipayTradeQueryResponse setBuyerPayAmount(String buyerPayAmount) { + this.buyerPayAmount = buyerPayAmount; + return this; + } + public String getBuyerPayAmount() { + return this.buyerPayAmount; + } + + public AlipayTradeQueryResponse setPointAmount(String pointAmount) { + this.pointAmount = pointAmount; + return this; + } + public String getPointAmount() { + return this.pointAmount; + } + + public AlipayTradeQueryResponse setInvoiceAmount(String invoiceAmount) { + this.invoiceAmount = invoiceAmount; + return this; + } + public String getInvoiceAmount() { + return this.invoiceAmount; + } + + public AlipayTradeQueryResponse setSendPayDate(String sendPayDate) { + this.sendPayDate = sendPayDate; + return this; + } + public String getSendPayDate() { + return this.sendPayDate; + } + + public AlipayTradeQueryResponse setReceiptAmount(String receiptAmount) { + this.receiptAmount = receiptAmount; + return this; + } + public String getReceiptAmount() { + return this.receiptAmount; + } + + public AlipayTradeQueryResponse setStoreId(String storeId) { + this.storeId = storeId; + return this; + } + public String getStoreId() { + return this.storeId; + } + + public AlipayTradeQueryResponse setTerminalId(String terminalId) { + this.terminalId = terminalId; + return this; + } + public String getTerminalId() { + return this.terminalId; + } + + public AlipayTradeQueryResponse setFundBillList(java.util.List fundBillList) { + this.fundBillList = fundBillList; + return this; + } + public java.util.List getFundBillList() { + return this.fundBillList; + } + + public AlipayTradeQueryResponse setStoreName(String storeName) { + this.storeName = storeName; + return this; + } + public String getStoreName() { + return this.storeName; + } + + public AlipayTradeQueryResponse setBuyerUserId(String buyerUserId) { + this.buyerUserId = buyerUserId; + return this; + } + public String getBuyerUserId() { + return this.buyerUserId; + } + + public AlipayTradeQueryResponse setChargeAmount(String chargeAmount) { + this.chargeAmount = chargeAmount; + return this; + } + public String getChargeAmount() { + return this.chargeAmount; + } + + public AlipayTradeQueryResponse setChargeFlags(String chargeFlags) { + this.chargeFlags = chargeFlags; + return this; + } + public String getChargeFlags() { + return this.chargeFlags; + } + + public AlipayTradeQueryResponse setSettlementId(String settlementId) { + this.settlementId = settlementId; + return this; + } + public String getSettlementId() { + return this.settlementId; + } + + public AlipayTradeQueryResponse setTradeSettleInfo(java.util.List tradeSettleInfo) { + this.tradeSettleInfo = tradeSettleInfo; + return this; + } + public java.util.List getTradeSettleInfo() { + return this.tradeSettleInfo; + } + + public AlipayTradeQueryResponse setAuthTradePayMode(String authTradePayMode) { + this.authTradePayMode = authTradePayMode; + return this; + } + public String getAuthTradePayMode() { + return this.authTradePayMode; + } + + public AlipayTradeQueryResponse setBuyerUserType(String buyerUserType) { + this.buyerUserType = buyerUserType; + return this; + } + public String getBuyerUserType() { + return this.buyerUserType; + } + + public AlipayTradeQueryResponse setMdiscountAmount(String mdiscountAmount) { + this.mdiscountAmount = mdiscountAmount; + return this; + } + public String getMdiscountAmount() { + return this.mdiscountAmount; + } + + public AlipayTradeQueryResponse setDiscountAmount(String discountAmount) { + this.discountAmount = discountAmount; + return this; + } + public String getDiscountAmount() { + return this.discountAmount; + } + + public AlipayTradeQueryResponse setBuyerUserName(String buyerUserName) { + this.buyerUserName = buyerUserName; + return this; + } + public String getBuyerUserName() { + return this.buyerUserName; + } + + public AlipayTradeQueryResponse setSubject(String subject) { + this.subject = subject; + return this; + } + public String getSubject() { + return this.subject; + } + + public AlipayTradeQueryResponse setBody(String body) { + this.body = body; + return this; + } + public String getBody() { + return this.body; + } + + public AlipayTradeQueryResponse setAlipaySubMerchantId(String alipaySubMerchantId) { + this.alipaySubMerchantId = alipaySubMerchantId; + return this; + } + public String getAlipaySubMerchantId() { + return this.alipaySubMerchantId; + } + + public AlipayTradeQueryResponse setExtInfos(String extInfos) { + this.extInfos = extInfos; + return this; + } + public String getExtInfos() { + return this.extInfos; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeRefundResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeRefundResponse.java new file mode 100644 index 0000000..170fdc9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/AlipayTradeRefundResponse.java @@ -0,0 +1,253 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class AlipayTradeRefundResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("trade_no") + @Validation(required = true) + public String tradeNo; + + @NameInMap("out_trade_no") + @Validation(required = true) + public String outTradeNo; + + @NameInMap("buyer_logon_id") + @Validation(required = true) + public String buyerLogonId; + + @NameInMap("fund_change") + @Validation(required = true) + public String fundChange; + + @NameInMap("refund_fee") + @Validation(required = true) + public String refundFee; + + @NameInMap("refund_currency") + @Validation(required = true) + public String refundCurrency; + + @NameInMap("gmt_refund_pay") + @Validation(required = true) + public String gmtRefundPay; + + @NameInMap("refund_detail_item_list") + @Validation(required = true) + public java.util.List refundDetailItemList; + + @NameInMap("store_name") + @Validation(required = true) + public String storeName; + + @NameInMap("buyer_user_id") + @Validation(required = true) + public String buyerUserId; + + @NameInMap("refund_preset_paytool_list") + @Validation(required = true) + public java.util.List refundPresetPaytoolList; + + @NameInMap("refund_settlement_id") + @Validation(required = true) + public String refundSettlementId; + + @NameInMap("present_refund_buyer_amount") + @Validation(required = true) + public String presentRefundBuyerAmount; + + @NameInMap("present_refund_discount_amount") + @Validation(required = true) + public String presentRefundDiscountAmount; + + @NameInMap("present_refund_mdiscount_amount") + @Validation(required = true) + public String presentRefundMdiscountAmount; + + public static AlipayTradeRefundResponse build(java.util.Map map) throws Exception { + AlipayTradeRefundResponse self = new AlipayTradeRefundResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradeRefundResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayTradeRefundResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayTradeRefundResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayTradeRefundResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayTradeRefundResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayTradeRefundResponse setTradeNo(String tradeNo) { + this.tradeNo = tradeNo; + return this; + } + public String getTradeNo() { + return this.tradeNo; + } + + public AlipayTradeRefundResponse setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + return this; + } + public String getOutTradeNo() { + return this.outTradeNo; + } + + public AlipayTradeRefundResponse setBuyerLogonId(String buyerLogonId) { + this.buyerLogonId = buyerLogonId; + return this; + } + public String getBuyerLogonId() { + return this.buyerLogonId; + } + + public AlipayTradeRefundResponse setFundChange(String fundChange) { + this.fundChange = fundChange; + return this; + } + public String getFundChange() { + return this.fundChange; + } + + public AlipayTradeRefundResponse setRefundFee(String refundFee) { + this.refundFee = refundFee; + return this; + } + public String getRefundFee() { + return this.refundFee; + } + + public AlipayTradeRefundResponse setRefundCurrency(String refundCurrency) { + this.refundCurrency = refundCurrency; + return this; + } + public String getRefundCurrency() { + return this.refundCurrency; + } + + public AlipayTradeRefundResponse setGmtRefundPay(String gmtRefundPay) { + this.gmtRefundPay = gmtRefundPay; + return this; + } + public String getGmtRefundPay() { + return this.gmtRefundPay; + } + + public AlipayTradeRefundResponse setRefundDetailItemList(java.util.List refundDetailItemList) { + this.refundDetailItemList = refundDetailItemList; + return this; + } + public java.util.List getRefundDetailItemList() { + return this.refundDetailItemList; + } + + public AlipayTradeRefundResponse setStoreName(String storeName) { + this.storeName = storeName; + return this; + } + public String getStoreName() { + return this.storeName; + } + + public AlipayTradeRefundResponse setBuyerUserId(String buyerUserId) { + this.buyerUserId = buyerUserId; + return this; + } + public String getBuyerUserId() { + return this.buyerUserId; + } + + public AlipayTradeRefundResponse setRefundPresetPaytoolList(java.util.List refundPresetPaytoolList) { + this.refundPresetPaytoolList = refundPresetPaytoolList; + return this; + } + public java.util.List getRefundPresetPaytoolList() { + return this.refundPresetPaytoolList; + } + + public AlipayTradeRefundResponse setRefundSettlementId(String refundSettlementId) { + this.refundSettlementId = refundSettlementId; + return this; + } + public String getRefundSettlementId() { + return this.refundSettlementId; + } + + public AlipayTradeRefundResponse setPresentRefundBuyerAmount(String presentRefundBuyerAmount) { + this.presentRefundBuyerAmount = presentRefundBuyerAmount; + return this; + } + public String getPresentRefundBuyerAmount() { + return this.presentRefundBuyerAmount; + } + + public AlipayTradeRefundResponse setPresentRefundDiscountAmount(String presentRefundDiscountAmount) { + this.presentRefundDiscountAmount = presentRefundDiscountAmount; + return this; + } + public String getPresentRefundDiscountAmount() { + return this.presentRefundDiscountAmount; + } + + public AlipayTradeRefundResponse setPresentRefundMdiscountAmount(String presentRefundMdiscountAmount) { + this.presentRefundMdiscountAmount = presentRefundMdiscountAmount; + return this; + } + public String getPresentRefundMdiscountAmount() { + return this.presentRefundMdiscountAmount; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/PresetPayToolInfo.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/PresetPayToolInfo.java new file mode 100644 index 0000000..39a8b30 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/PresetPayToolInfo.java @@ -0,0 +1,36 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class PresetPayToolInfo extends TeaModel { + @NameInMap("amount") + @Validation(required = true) + public java.util.List amount; + + @NameInMap("assert_type_code") + @Validation(required = true) + public String assertTypeCode; + + public static PresetPayToolInfo build(java.util.Map map) throws Exception { + PresetPayToolInfo self = new PresetPayToolInfo(); + return TeaModel.build(map, self); + } + + public PresetPayToolInfo setAmount(java.util.List amount) { + this.amount = amount; + return this; + } + public java.util.List getAmount() { + return this.amount; + } + + public PresetPayToolInfo setAssertTypeCode(String assertTypeCode) { + this.assertTypeCode = assertTypeCode; + return this; + } + public String getAssertTypeCode() { + return this.assertTypeCode; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/RefundRoyaltyResult.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/RefundRoyaltyResult.java new file mode 100644 index 0000000..06602d9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/RefundRoyaltyResult.java @@ -0,0 +1,96 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class RefundRoyaltyResult extends TeaModel { + @NameInMap("refund_amount") + @Validation(required = true) + public String refundAmount; + + @NameInMap("royalty_type") + @Validation(required = true) + public String royaltyType; + + @NameInMap("result_code") + @Validation(required = true) + public String resultCode; + + @NameInMap("trans_out") + @Validation(required = true) + public String transOut; + + @NameInMap("trans_out_email") + @Validation(required = true) + public String transOutEmail; + + @NameInMap("trans_in") + @Validation(required = true) + public String transIn; + + @NameInMap("trans_in_email") + @Validation(required = true) + public String transInEmail; + + public static RefundRoyaltyResult build(java.util.Map map) throws Exception { + RefundRoyaltyResult self = new RefundRoyaltyResult(); + return TeaModel.build(map, self); + } + + public RefundRoyaltyResult setRefundAmount(String refundAmount) { + this.refundAmount = refundAmount; + return this; + } + public String getRefundAmount() { + return this.refundAmount; + } + + public RefundRoyaltyResult setRoyaltyType(String royaltyType) { + this.royaltyType = royaltyType; + return this; + } + public String getRoyaltyType() { + return this.royaltyType; + } + + public RefundRoyaltyResult setResultCode(String resultCode) { + this.resultCode = resultCode; + return this; + } + public String getResultCode() { + return this.resultCode; + } + + public RefundRoyaltyResult setTransOut(String transOut) { + this.transOut = transOut; + return this; + } + public String getTransOut() { + return this.transOut; + } + + public RefundRoyaltyResult setTransOutEmail(String transOutEmail) { + this.transOutEmail = transOutEmail; + return this; + } + public String getTransOutEmail() { + return this.transOutEmail; + } + + public RefundRoyaltyResult setTransIn(String transIn) { + this.transIn = transIn; + return this; + } + public String getTransIn() { + return this.transIn; + } + + public RefundRoyaltyResult setTransInEmail(String transInEmail) { + this.transInEmail = transInEmail; + return this; + } + public String getTransInEmail() { + return this.transInEmail; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/TradeFundBill.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/TradeFundBill.java new file mode 100644 index 0000000..7bed9d6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/TradeFundBill.java @@ -0,0 +1,72 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class TradeFundBill extends TeaModel { + @NameInMap("fund_channel") + @Validation(required = true) + public String fundChannel; + + @NameInMap("bank_code") + @Validation(required = true) + public String bankCode; + + @NameInMap("amount") + @Validation(required = true) + public String amount; + + @NameInMap("real_amount") + @Validation(required = true) + public String realAmount; + + @NameInMap("fund_type") + @Validation(required = true) + public String fundType; + + public static TradeFundBill build(java.util.Map map) throws Exception { + TradeFundBill self = new TradeFundBill(); + return TeaModel.build(map, self); + } + + public TradeFundBill setFundChannel(String fundChannel) { + this.fundChannel = fundChannel; + return this; + } + public String getFundChannel() { + return this.fundChannel; + } + + public TradeFundBill setBankCode(String bankCode) { + this.bankCode = bankCode; + return this; + } + public String getBankCode() { + return this.bankCode; + } + + public TradeFundBill setAmount(String amount) { + this.amount = amount; + return this; + } + public String getAmount() { + return this.amount; + } + + public TradeFundBill setRealAmount(String realAmount) { + this.realAmount = realAmount; + return this; + } + public String getRealAmount() { + return this.realAmount; + } + + public TradeFundBill setFundType(String fundType) { + this.fundType = fundType; + return this; + } + public String getFundType() { + return this.fundType; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/TradeSettleDetail.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/TradeSettleDetail.java new file mode 100644 index 0000000..ac475e3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/TradeSettleDetail.java @@ -0,0 +1,84 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class TradeSettleDetail extends TeaModel { + @NameInMap("operation_type") + @Validation(required = true) + public String operationType; + + @NameInMap("operation_serial_no") + @Validation(required = true) + public String operationSerial_no; + + @NameInMap("operation_dt") + @Validation(required = true) + public String operationDt; + + @NameInMap("trans_out") + @Validation(required = true) + public String transOut; + + @NameInMap("trans_in") + @Validation(required = true) + public String transIn; + + @NameInMap("amount") + @Validation(required = true) + public String amount; + + public static TradeSettleDetail build(java.util.Map map) throws Exception { + TradeSettleDetail self = new TradeSettleDetail(); + return TeaModel.build(map, self); + } + + public TradeSettleDetail setOperationType(String operationType) { + this.operationType = operationType; + return this; + } + public String getOperationType() { + return this.operationType; + } + + public TradeSettleDetail setOperationSerial_no(String operationSerial_no) { + this.operationSerial_no = operationSerial_no; + return this; + } + public String getOperationSerial_no() { + return this.operationSerial_no; + } + + public TradeSettleDetail setOperationDt(String operationDt) { + this.operationDt = operationDt; + return this; + } + public String getOperationDt() { + return this.operationDt; + } + + public TradeSettleDetail setTransOut(String transOut) { + this.transOut = transOut; + return this; + } + public String getTransOut() { + return this.transOut; + } + + public TradeSettleDetail setTransIn(String transIn) { + this.transIn = transIn; + return this; + } + public String getTransIn() { + return this.transIn; + } + + public TradeSettleDetail setAmount(String amount) { + this.amount = amount; + return this; + } + public String getAmount() { + return this.amount; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/TradeSettleInfo.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/TradeSettleInfo.java new file mode 100644 index 0000000..35b1c04 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/common/models/TradeSettleInfo.java @@ -0,0 +1,24 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.common.models; + +import com.aliyun.tea.*; + +public class TradeSettleInfo extends TeaModel { + @NameInMap("trade_settle_detail_list") + @Validation(required = true) + public java.util.List tradeSettleDetailList; + + public static TradeSettleInfo build(java.util.Map map) throws Exception { + TradeSettleInfo self = new TradeSettleInfo(); + return TeaModel.build(map, self); + } + + public TradeSettleInfo setTradeSettleDetailList(java.util.List tradeSettleDetailList) { + this.tradeSettleDetailList = tradeSettleDetailList; + return this; + } + public java.util.List getTradeSettleDetailList() { + return this.tradeSettleDetailList; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/Client.java new file mode 100644 index 0000000..94f340b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/Client.java @@ -0,0 +1,265 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.facetoface; + +import com.aliyun.tea.*; +import com.alipay.easysdk.payment.facetoface.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayTradePayResponse pay(String subject, String outTradeNo, String totalAmount, String authCode) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.pay"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("subject", subject), + new TeaPair("out_trade_no", outTradeNo), + new TeaPair("total_amount", totalAmount), + new TeaPair("auth_code", authCode), + new TeaPair("scene", "bar_code") + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.trade.pay"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradePayResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradePayResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayTradePrecreateResponse preCreate(String subject, String outTradeNo, String totalAmount) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.precreate"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("subject", subject), + new TeaPair("out_trade_no", outTradeNo), + new TeaPair("total_amount", totalAmount) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.trade.precreate"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradePrecreateResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradePrecreateResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/AlipayTradePayResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/AlipayTradePayResponse.java new file mode 100644 index 0000000..06ecc95 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/AlipayTradePayResponse.java @@ -0,0 +1,457 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.facetoface.models; + +import com.aliyun.tea.*; + +public class AlipayTradePayResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("trade_no") + @Validation(required = true) + public String tradeNo; + + @NameInMap("out_trade_no") + @Validation(required = true) + public String outTradeNo; + + @NameInMap("buyer_logon_id") + @Validation(required = true) + public String buyerLogonId; + + @NameInMap("settle_amount") + @Validation(required = true) + public String settleAmount; + + @NameInMap("pay_currency") + @Validation(required = true) + public String payCurrency; + + @NameInMap("pay_amount") + @Validation(required = true) + public String payAmount; + + @NameInMap("settle_trans_rate") + @Validation(required = true) + public String settleTransRate; + + @NameInMap("trans_pay_rate") + @Validation(required = true) + public String transPayRate; + + @NameInMap("total_amount") + @Validation(required = true) + public String totalAmount; + + @NameInMap("trans_currency") + @Validation(required = true) + public String transCurrency; + + @NameInMap("settle_currency") + @Validation(required = true) + public String settleCurrency; + + @NameInMap("receipt_amount") + @Validation(required = true) + public String receiptAmount; + + @NameInMap("buyer_pay_amount") + @Validation(required = true) + public String buyerPayAmount; + + @NameInMap("point_amount") + @Validation(required = true) + public String pointAmount; + + @NameInMap("invoice_amount") + @Validation(required = true) + public String invoiceAmount; + + @NameInMap("gmt_payment") + @Validation(required = true) + public String gmtPayment; + + @NameInMap("fund_bill_list") + @Validation(required = true) + public java.util.List fundBillList; + + @NameInMap("card_balance") + @Validation(required = true) + public String cardBalance; + + @NameInMap("store_name") + @Validation(required = true) + public String storeName; + + @NameInMap("buyer_user_id") + @Validation(required = true) + public String buyerUserId; + + @NameInMap("discount_goods_detail") + @Validation(required = true) + public String discountGoodsDetail; + + @NameInMap("voucher_detail_list") + @Validation(required = true) + public java.util.List voucherDetailList; + + @NameInMap("advance_amount") + @Validation(required = true) + public String advanceAmount; + + @NameInMap("auth_trade_pay_mode") + @Validation(required = true) + public String authTradePayMode; + + @NameInMap("charge_amount") + @Validation(required = true) + public String chargeAmount; + + @NameInMap("charge_flags") + @Validation(required = true) + public String chargeFlags; + + @NameInMap("settlement_id") + @Validation(required = true) + public String settlementId; + + @NameInMap("business_params") + @Validation(required = true) + public String businessParams; + + @NameInMap("buyer_user_type") + @Validation(required = true) + public String buyerUserType; + + @NameInMap("mdiscount_amount") + @Validation(required = true) + public String mdiscountAmount; + + @NameInMap("discount_amount") + @Validation(required = true) + public String discountAmount; + + @NameInMap("buyer_user_name") + @Validation(required = true) + public String buyerUserName; + + public static AlipayTradePayResponse build(java.util.Map map) throws Exception { + AlipayTradePayResponse self = new AlipayTradePayResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradePayResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayTradePayResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayTradePayResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayTradePayResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayTradePayResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayTradePayResponse setTradeNo(String tradeNo) { + this.tradeNo = tradeNo; + return this; + } + public String getTradeNo() { + return this.tradeNo; + } + + public AlipayTradePayResponse setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + return this; + } + public String getOutTradeNo() { + return this.outTradeNo; + } + + public AlipayTradePayResponse setBuyerLogonId(String buyerLogonId) { + this.buyerLogonId = buyerLogonId; + return this; + } + public String getBuyerLogonId() { + return this.buyerLogonId; + } + + public AlipayTradePayResponse setSettleAmount(String settleAmount) { + this.settleAmount = settleAmount; + return this; + } + public String getSettleAmount() { + return this.settleAmount; + } + + public AlipayTradePayResponse setPayCurrency(String payCurrency) { + this.payCurrency = payCurrency; + return this; + } + public String getPayCurrency() { + return this.payCurrency; + } + + public AlipayTradePayResponse setPayAmount(String payAmount) { + this.payAmount = payAmount; + return this; + } + public String getPayAmount() { + return this.payAmount; + } + + public AlipayTradePayResponse setSettleTransRate(String settleTransRate) { + this.settleTransRate = settleTransRate; + return this; + } + public String getSettleTransRate() { + return this.settleTransRate; + } + + public AlipayTradePayResponse setTransPayRate(String transPayRate) { + this.transPayRate = transPayRate; + return this; + } + public String getTransPayRate() { + return this.transPayRate; + } + + public AlipayTradePayResponse setTotalAmount(String totalAmount) { + this.totalAmount = totalAmount; + return this; + } + public String getTotalAmount() { + return this.totalAmount; + } + + public AlipayTradePayResponse setTransCurrency(String transCurrency) { + this.transCurrency = transCurrency; + return this; + } + public String getTransCurrency() { + return this.transCurrency; + } + + public AlipayTradePayResponse setSettleCurrency(String settleCurrency) { + this.settleCurrency = settleCurrency; + return this; + } + public String getSettleCurrency() { + return this.settleCurrency; + } + + public AlipayTradePayResponse setReceiptAmount(String receiptAmount) { + this.receiptAmount = receiptAmount; + return this; + } + public String getReceiptAmount() { + return this.receiptAmount; + } + + public AlipayTradePayResponse setBuyerPayAmount(String buyerPayAmount) { + this.buyerPayAmount = buyerPayAmount; + return this; + } + public String getBuyerPayAmount() { + return this.buyerPayAmount; + } + + public AlipayTradePayResponse setPointAmount(String pointAmount) { + this.pointAmount = pointAmount; + return this; + } + public String getPointAmount() { + return this.pointAmount; + } + + public AlipayTradePayResponse setInvoiceAmount(String invoiceAmount) { + this.invoiceAmount = invoiceAmount; + return this; + } + public String getInvoiceAmount() { + return this.invoiceAmount; + } + + public AlipayTradePayResponse setGmtPayment(String gmtPayment) { + this.gmtPayment = gmtPayment; + return this; + } + public String getGmtPayment() { + return this.gmtPayment; + } + + public AlipayTradePayResponse setFundBillList(java.util.List fundBillList) { + this.fundBillList = fundBillList; + return this; + } + public java.util.List getFundBillList() { + return this.fundBillList; + } + + public AlipayTradePayResponse setCardBalance(String cardBalance) { + this.cardBalance = cardBalance; + return this; + } + public String getCardBalance() { + return this.cardBalance; + } + + public AlipayTradePayResponse setStoreName(String storeName) { + this.storeName = storeName; + return this; + } + public String getStoreName() { + return this.storeName; + } + + public AlipayTradePayResponse setBuyerUserId(String buyerUserId) { + this.buyerUserId = buyerUserId; + return this; + } + public String getBuyerUserId() { + return this.buyerUserId; + } + + public AlipayTradePayResponse setDiscountGoodsDetail(String discountGoodsDetail) { + this.discountGoodsDetail = discountGoodsDetail; + return this; + } + public String getDiscountGoodsDetail() { + return this.discountGoodsDetail; + } + + public AlipayTradePayResponse setVoucherDetailList(java.util.List voucherDetailList) { + this.voucherDetailList = voucherDetailList; + return this; + } + public java.util.List getVoucherDetailList() { + return this.voucherDetailList; + } + + public AlipayTradePayResponse setAdvanceAmount(String advanceAmount) { + this.advanceAmount = advanceAmount; + return this; + } + public String getAdvanceAmount() { + return this.advanceAmount; + } + + public AlipayTradePayResponse setAuthTradePayMode(String authTradePayMode) { + this.authTradePayMode = authTradePayMode; + return this; + } + public String getAuthTradePayMode() { + return this.authTradePayMode; + } + + public AlipayTradePayResponse setChargeAmount(String chargeAmount) { + this.chargeAmount = chargeAmount; + return this; + } + public String getChargeAmount() { + return this.chargeAmount; + } + + public AlipayTradePayResponse setChargeFlags(String chargeFlags) { + this.chargeFlags = chargeFlags; + return this; + } + public String getChargeFlags() { + return this.chargeFlags; + } + + public AlipayTradePayResponse setSettlementId(String settlementId) { + this.settlementId = settlementId; + return this; + } + public String getSettlementId() { + return this.settlementId; + } + + public AlipayTradePayResponse setBusinessParams(String businessParams) { + this.businessParams = businessParams; + return this; + } + public String getBusinessParams() { + return this.businessParams; + } + + public AlipayTradePayResponse setBuyerUserType(String buyerUserType) { + this.buyerUserType = buyerUserType; + return this; + } + public String getBuyerUserType() { + return this.buyerUserType; + } + + public AlipayTradePayResponse setMdiscountAmount(String mdiscountAmount) { + this.mdiscountAmount = mdiscountAmount; + return this; + } + public String getMdiscountAmount() { + return this.mdiscountAmount; + } + + public AlipayTradePayResponse setDiscountAmount(String discountAmount) { + this.discountAmount = discountAmount; + return this; + } + public String getDiscountAmount() { + return this.discountAmount; + } + + public AlipayTradePayResponse setBuyerUserName(String buyerUserName) { + this.buyerUserName = buyerUserName; + return this; + } + public String getBuyerUserName() { + return this.buyerUserName; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/AlipayTradePrecreateResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/AlipayTradePrecreateResponse.java new file mode 100644 index 0000000..dab81b6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/AlipayTradePrecreateResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.facetoface.models; + +import com.aliyun.tea.*; + +public class AlipayTradePrecreateResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("out_trade_no") + @Validation(required = true) + public String outTradeNo; + + @NameInMap("qr_code") + @Validation(required = true) + public String qrCode; + + public static AlipayTradePrecreateResponse build(java.util.Map map) throws Exception { + AlipayTradePrecreateResponse self = new AlipayTradePrecreateResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradePrecreateResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayTradePrecreateResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayTradePrecreateResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayTradePrecreateResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayTradePrecreateResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayTradePrecreateResponse setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + return this; + } + public String getOutTradeNo() { + return this.outTradeNo; + } + + public AlipayTradePrecreateResponse setQrCode(String qrCode) { + this.qrCode = qrCode; + return this; + } + public String getQrCode() { + return this.qrCode; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/TradeFundBill.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/TradeFundBill.java new file mode 100644 index 0000000..382d50d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/TradeFundBill.java @@ -0,0 +1,60 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.facetoface.models; + +import com.aliyun.tea.*; + +public class TradeFundBill extends TeaModel { + @NameInMap("fund_channel") + @Validation(required = true) + public String fundChannel; + + @NameInMap("bank_code") + @Validation(required = true) + public String bankCode; + + @NameInMap("amount") + @Validation(required = true) + public String amount; + + @NameInMap("real_amount") + @Validation(required = true) + public String realAmount; + + public static TradeFundBill build(java.util.Map map) throws Exception { + TradeFundBill self = new TradeFundBill(); + return TeaModel.build(map, self); + } + + public TradeFundBill setFundChannel(String fundChannel) { + this.fundChannel = fundChannel; + return this; + } + public String getFundChannel() { + return this.fundChannel; + } + + public TradeFundBill setBankCode(String bankCode) { + this.bankCode = bankCode; + return this; + } + public String getBankCode() { + return this.bankCode; + } + + public TradeFundBill setAmount(String amount) { + this.amount = amount; + return this; + } + public String getAmount() { + return this.amount; + } + + public TradeFundBill setRealAmount(String realAmount) { + this.realAmount = realAmount; + return this; + } + public String getRealAmount() { + return this.realAmount; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/VoucherDetail.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/VoucherDetail.java new file mode 100644 index 0000000..0cdbe1c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/facetoface/models/VoucherDetail.java @@ -0,0 +1,144 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.facetoface.models; + +import com.aliyun.tea.*; + +public class VoucherDetail extends TeaModel { + @NameInMap("id") + @Validation(required = true) + public String id; + + @NameInMap("name") + @Validation(required = true) + public String name; + + @NameInMap("type") + @Validation(required = true) + public String type; + + @NameInMap("amount") + @Validation(required = true) + public String amount; + + @NameInMap("merchant_contribute") + @Validation(required = true) + public String merchantContribute; + + @NameInMap("other_contribute") + @Validation(required = true) + public String otherContribute; + + @NameInMap("memo") + @Validation(required = true) + public String memo; + + @NameInMap("template_id") + @Validation(required = true) + public String templateId; + + @NameInMap("purchase_buyer_contribute") + @Validation(required = true) + public String purchaseBuyerContribute; + + @NameInMap("purchase_merchant_contribute") + @Validation(required = true) + public String purchaseMerchantContribute; + + @NameInMap("purchase_ant_contribute") + @Validation(required = true) + public String purchaseAntContribute; + + public static VoucherDetail build(java.util.Map map) throws Exception { + VoucherDetail self = new VoucherDetail(); + return TeaModel.build(map, self); + } + + public VoucherDetail setId(String id) { + this.id = id; + return this; + } + public String getId() { + return this.id; + } + + public VoucherDetail setName(String name) { + this.name = name; + return this; + } + public String getName() { + return this.name; + } + + public VoucherDetail setType(String type) { + this.type = type; + return this; + } + public String getType() { + return this.type; + } + + public VoucherDetail setAmount(String amount) { + this.amount = amount; + return this; + } + public String getAmount() { + return this.amount; + } + + public VoucherDetail setMerchantContribute(String merchantContribute) { + this.merchantContribute = merchantContribute; + return this; + } + public String getMerchantContribute() { + return this.merchantContribute; + } + + public VoucherDetail setOtherContribute(String otherContribute) { + this.otherContribute = otherContribute; + return this; + } + public String getOtherContribute() { + return this.otherContribute; + } + + public VoucherDetail setMemo(String memo) { + this.memo = memo; + return this; + } + public String getMemo() { + return this.memo; + } + + public VoucherDetail setTemplateId(String templateId) { + this.templateId = templateId; + return this; + } + public String getTemplateId() { + return this.templateId; + } + + public VoucherDetail setPurchaseBuyerContribute(String purchaseBuyerContribute) { + this.purchaseBuyerContribute = purchaseBuyerContribute; + return this; + } + public String getPurchaseBuyerContribute() { + return this.purchaseBuyerContribute; + } + + public VoucherDetail setPurchaseMerchantContribute(String purchaseMerchantContribute) { + this.purchaseMerchantContribute = purchaseMerchantContribute; + return this; + } + public String getPurchaseMerchantContribute() { + return this.purchaseMerchantContribute; + } + + public VoucherDetail setPurchaseAntContribute(String purchaseAntContribute) { + this.purchaseAntContribute = purchaseAntContribute; + return this; + } + public String getPurchaseAntContribute() { + return this.purchaseAntContribute; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/huabei/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/huabei/Client.java new file mode 100644 index 0000000..f78465e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/huabei/Client.java @@ -0,0 +1,179 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.huabei; + +import com.aliyun.tea.*; +import com.alipay.easysdk.payment.huabei.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayTradeCreateResponse create(String subject, String outTradeNo, String totalAmount, String buyerId, HuabeiConfig extendParams) throws Exception { + TeaModel.validateParams(extendParams, "extendParams"); + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.create"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("subject", subject), + new TeaPair("out_trade_no", outTradeNo), + new TeaPair("total_amount", totalAmount), + new TeaPair("buyer_id", buyerId), + new TeaPair("extend_params", extendParams) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.trade.create"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeCreateResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayTradeCreateResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/huabei/models/AlipayTradeCreateResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/huabei/models/AlipayTradeCreateResponse.java new file mode 100644 index 0000000..d44470c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/huabei/models/AlipayTradeCreateResponse.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.huabei.models; + +import com.aliyun.tea.*; + +public class AlipayTradeCreateResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("out_trade_no") + @Validation(required = true) + public String outTradeNo; + + @NameInMap("trade_no") + @Validation(required = true) + public String tradeNo; + + public static AlipayTradeCreateResponse build(java.util.Map map) throws Exception { + AlipayTradeCreateResponse self = new AlipayTradeCreateResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradeCreateResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayTradeCreateResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayTradeCreateResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayTradeCreateResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayTradeCreateResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipayTradeCreateResponse setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + return this; + } + public String getOutTradeNo() { + return this.outTradeNo; + } + + public AlipayTradeCreateResponse setTradeNo(String tradeNo) { + this.tradeNo = tradeNo; + return this; + } + public String getTradeNo() { + return this.tradeNo; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/huabei/models/HuabeiConfig.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/huabei/models/HuabeiConfig.java new file mode 100644 index 0000000..4cc7add --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/huabei/models/HuabeiConfig.java @@ -0,0 +1,36 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.huabei.models; + +import com.aliyun.tea.*; + +public class HuabeiConfig extends TeaModel { + @NameInMap("hb_fq_num") + @Validation(required = true) + public String hbFqNum; + + @NameInMap("hb_fq_seller_percent") + @Validation(required = true) + public String hbFqSellerPercent; + + public static HuabeiConfig build(java.util.Map map) throws Exception { + HuabeiConfig self = new HuabeiConfig(); + return TeaModel.build(map, self); + } + + public HuabeiConfig setHbFqNum(String hbFqNum) { + this.hbFqNum = hbFqNum; + return this; + } + public String getHbFqNum() { + return this.hbFqNum; + } + + public HuabeiConfig setHbFqSellerPercent(String hbFqSellerPercent) { + this.hbFqSellerPercent = hbFqSellerPercent; + return this; + } + public String getHbFqSellerPercent() { + return this.hbFqSellerPercent; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/page/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/page/Client.java new file mode 100644 index 0000000..beb5c12 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/page/Client.java @@ -0,0 +1,118 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.page; + +import com.aliyun.tea.*; +import com.alipay.easysdk.payment.page.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + + public AlipayTradePagePayResponse pay(String subject, String outTradeNo, String totalAmount, String returnUrl) throws Exception { + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.page.pay"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("subject", subject), + new TeaPair("out_trade_no", outTradeNo), + new TeaPair("total_amount", totalAmount), + new TeaPair("product_code", "FAST_INSTANT_TRADE_PAY") + ); + java.util.Map textParams = TeaConverter.buildMap( + new TeaPair("return_url", returnUrl) + ); + String sign = _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey")); + java.util.Map response = TeaConverter.buildMap( + new TeaPair("body", _kernel.generatePage("POST", systemParams, bizParams, textParams, sign)) + ); + return TeaModel.toModel(response, new AlipayTradePagePayResponse()); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/page/models/AlipayTradePagePayResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/page/models/AlipayTradePagePayResponse.java new file mode 100644 index 0000000..b920b0c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/page/models/AlipayTradePagePayResponse.java @@ -0,0 +1,25 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.page.models; + +import com.aliyun.tea.*; + +public class AlipayTradePagePayResponse extends TeaModel { + // 订单信息,Form表单形式 + @NameInMap("body") + @Validation(required = true) + public String body; + + public static AlipayTradePagePayResponse build(java.util.Map map) throws Exception { + AlipayTradePagePayResponse self = new AlipayTradePagePayResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradePagePayResponse setBody(String body) { + this.body = body; + return this; + } + public String getBody() { + return this.body; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/wap/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/wap/Client.java new file mode 100644 index 0000000..1625217 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/wap/Client.java @@ -0,0 +1,119 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.wap; + +import com.aliyun.tea.*; +import com.alipay.easysdk.payment.wap.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + + public AlipayTradeWapPayResponse pay(String subject, String outTradeNo, String totalAmount, String quitUrl, String returnUrl) throws Exception { + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.trade.wap.pay"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("subject", subject), + new TeaPair("out_trade_no", outTradeNo), + new TeaPair("total_amount", totalAmount), + new TeaPair("quit_url", quitUrl), + new TeaPair("product_code", "QUICK_WAP_WAY") + ); + java.util.Map textParams = TeaConverter.buildMap( + new TeaPair("return_url", returnUrl) + ); + String sign = _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey")); + java.util.Map response = TeaConverter.buildMap( + new TeaPair("body", _kernel.generatePage("POST", systemParams, bizParams, textParams, sign)) + ); + return TeaModel.toModel(response, new AlipayTradeWapPayResponse()); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/wap/models/AlipayTradeWapPayResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/wap/models/AlipayTradeWapPayResponse.java new file mode 100644 index 0000000..cb6561b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/payment/wap/models/AlipayTradeWapPayResponse.java @@ -0,0 +1,25 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.payment.wap.models; + +import com.aliyun.tea.*; + +public class AlipayTradeWapPayResponse extends TeaModel { + // 订单信息,Form表单形式 + @NameInMap("body") + @Validation(required = true) + public String body; + + public static AlipayTradeWapPayResponse build(java.util.Map map) throws Exception { + AlipayTradeWapPayResponse self = new AlipayTradeWapPayResponse(); + return TeaModel.build(map, self); + } + + public AlipayTradeWapPayResponse setBody(String body) { + this.body = body; + return this; + } + public String getBody() { + return this.body; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/security/textrisk/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/security/textrisk/Client.java new file mode 100644 index 0000000..b3f1159 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/security/textrisk/Client.java @@ -0,0 +1,174 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.security.textrisk; + +import com.aliyun.tea.*; +import com.alipay.easysdk.security.textrisk.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipaySecurityRiskContentDetectResponse detect(String content) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.security.risk.content.detect"), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + java.util.Map bizParams = TeaConverter.buildMap( + new TeaPair("content", content) + ); + java.util.Map textParams = new java.util.HashMap<>(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, "alipay.security.risk.content.detect"); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipaySecurityRiskContentDetectResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipaySecurityRiskContentDetectResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/security/textrisk/models/AlipaySecurityRiskContentDetectResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/security/textrisk/models/AlipaySecurityRiskContentDetectResponse.java new file mode 100644 index 0000000..082f082 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/security/textrisk/models/AlipaySecurityRiskContentDetectResponse.java @@ -0,0 +1,109 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.security.textrisk.models; + +import com.aliyun.tea.*; + +public class AlipaySecurityRiskContentDetectResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("action") + @Validation(required = true) + public String action; + + @NameInMap("keywords") + @Validation(required = true) + public java.util.List keywords; + + @NameInMap("unique_id") + @Validation(required = true) + public String uniqueId; + + public static AlipaySecurityRiskContentDetectResponse build(java.util.Map map) throws Exception { + AlipaySecurityRiskContentDetectResponse self = new AlipaySecurityRiskContentDetectResponse(); + return TeaModel.build(map, self); + } + + public AlipaySecurityRiskContentDetectResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipaySecurityRiskContentDetectResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipaySecurityRiskContentDetectResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipaySecurityRiskContentDetectResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipaySecurityRiskContentDetectResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + + public AlipaySecurityRiskContentDetectResponse setAction(String action) { + this.action = action; + return this; + } + public String getAction() { + return this.action; + } + + public AlipaySecurityRiskContentDetectResponse setKeywords(java.util.List keywords) { + this.keywords = keywords; + return this; + } + public java.util.List getKeywords() { + return this.keywords; + } + + public AlipaySecurityRiskContentDetectResponse setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + return this; + } + public String getUniqueId() { + return this.uniqueId; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/aes/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/aes/Client.java new file mode 100644 index 0000000..eb160bf --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/aes/Client.java @@ -0,0 +1,97 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.util.aes; + +import com.aliyun.tea.*; + + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + + public String decrypt(String cipherText) throws Exception { + return _kernel.aesDecrypt(cipherText, _kernel.getConfig("encryptKey")); + } + + public String encrypt(String plainText) throws Exception { + return _kernel.aesEncrypt(plainText, _kernel.getConfig("encryptKey")); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/generic/Client.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/generic/Client.java new file mode 100644 index 0000000..04615d0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/generic/Client.java @@ -0,0 +1,273 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.util.generic; + +import com.aliyun.tea.*; +import com.alipay.easysdk.util.generic.models.*; + +public class Client { + + public com.alipay.easysdk.kernel.Client _kernel; + public Client(com.alipay.easysdk.kernel.Client kernel) throws Exception { + this._kernel = kernel; + } + + public AlipayOpenApiGenericResponse execute(String method, java.util.Map textParams, java.util.Map bizParams) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), + new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", method), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8") + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = Tea.toReadable(_kernel.toUrlEncodedRequestBody(bizParams)); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, method); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenApiGenericResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenApiGenericResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayOpenApiGenericResponse fileExecute(String method, java.util.Map textParams, java.util.Map bizParams, java.util.Map fileParams) throws Exception { + java.util.Map runtime_ = TeaConverter.buildMap( + new TeaPair("ignoreSSL", _kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", _kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 100000), + new TeaPair("readTimeout", 100000), + new TeaPair("retry", TeaConverter.buildMap( + new TeaPair("maxAttempts", 0) + )) + ); + + TeaRequest _lastRequest = null; + long _now = System.currentTimeMillis(); + int _retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime_.get("retry"), _retryTimes, _now)) { + if (_retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime_.get("backoff"), _retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + _retryTimes = _retryTimes + 1; + try { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", method), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + String boundary = _kernel.getRandomBoundary(); + request_.protocol = _kernel.getConfig("protocol"); + request_.method = "POST"; + request_.pathname = "/gateway.do"; + request_.headers = TeaConverter.buildMap( + new TeaPair("host", _kernel.getConfig("gatewayHost")), + new TeaPair("content-type", _kernel.concatStr("multipart/form-data;charset=utf-8;boundary=", boundary)) + ); + request_.query = _kernel.sortMap(TeaConverter.merge(String.class, + TeaConverter.buildMap( + new TeaPair("sign", _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey"))) + ), + systemParams, + textParams + )); + request_.body = _kernel.toMultipartRequestBody(textParams, fileParams, boundary); + _lastRequest = request_; + TeaResponse response_ = Tea.doAction(request_, runtime_); + + java.util.Map respMap = _kernel.readAsJson(response_, method); + if (_kernel.isCertMode()) { + if (_kernel.verify(respMap, _kernel.extractAlipayPublicKey(_kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenApiGenericResponse()); + } + + } else { + if (_kernel.verify(respMap, _kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(_kernel.toRespModel(respMap), new AlipayOpenApiGenericResponse()); + } + + } + + throw new TeaException(TeaConverter.buildMap( + new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。") + )); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(_lastRequest); + } + + public AlipayOpenApiGenericSDKResponse sdkExecute(String method, java.util.Map textParams, java.util.Map bizParams) throws Exception { + TeaRequest request_ = new TeaRequest(); + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", method), + new TeaPair("app_id", _kernel.getConfig("appId")), + new TeaPair("timestamp", _kernel.getTimestamp()), + new TeaPair("format", "json"), + new TeaPair("version", "1.0"), + new TeaPair("alipay_sdk", _kernel.getSdkVersion()), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", _kernel.getConfig("signType")), + new TeaPair("app_cert_sn", _kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", _kernel.getAlipayRootCertSN()) + ); + String sign = _kernel.sign(systemParams, bizParams, textParams, _kernel.getConfig("merchantPrivateKey")); + java.util.Map response = TeaConverter.buildMap( + new TeaPair("body", _kernel.generateOrderString(systemParams, bizParams, textParams, sign)) + ); + return TeaModel.toModel(response , new AlipayOpenApiGenericSDKResponse()); + } + + + /** + * ISV代商户代用,指定appAuthToken + * + * @param appAuthToken 代调用token + * @return 本客户端,便于链式调用 + */ + public Client agent(String appAuthToken) { + _kernel.injectTextParam("app_auth_token", appAuthToken); + return this; + } + + /** + * 用户授权调用,指定authToken + * + * @param authToken 用户授权token + * @return 本客户端,便于链式调用 + */ + public Client auth(String authToken) { + _kernel.injectTextParam("auth_token", authToken); + return this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param url 异步通知回调地址,例如:https://www.test.com/callback + * @return 本客户端,便于链式调用 + */ + public Client asyncNotify(String url) { + _kernel.injectTextParam("notify_url", url); + return this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param testUrl 后端系统测试地址 + * @return 本客户端,便于链式调用 + */ + public Client route(String testUrl) { + _kernel.injectTextParam("ws_service_url", testUrl); + return this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param key 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param value 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的Map指定各下级字段的值 + * 如果该字段是一个数组,请使用List储存各个值 + * 对于更复杂的情况,也支持Map和List的各种组合嵌套,比如参数是值是个List,List中的每种类型是一个复杂对象 + * @return 本客户端,便于链式调用 + */ + public Client optional(String key, Object value) { + _kernel.injectBizParam(key, value); + return this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param optionalArgs 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return 本客户端,便于链式调用 + */ + public Client batchOptional(java.util.Map optionalArgs) { + for (java.util.Map.Entry pair : optionalArgs.entrySet()) { + _kernel.injectBizParam(pair.getKey(), pair.getValue()); + } + return this; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/generic/models/AlipayOpenApiGenericResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/generic/models/AlipayOpenApiGenericResponse.java new file mode 100644 index 0000000..25c8bd0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/generic/models/AlipayOpenApiGenericResponse.java @@ -0,0 +1,73 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.util.generic.models; + +import com.aliyun.tea.*; + +public class AlipayOpenApiGenericResponse extends TeaModel { + // 响应原始字符串 + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + public static AlipayOpenApiGenericResponse build(java.util.Map map) throws Exception { + AlipayOpenApiGenericResponse self = new AlipayOpenApiGenericResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenApiGenericResponse setHttpBody(String httpBody) { + this.httpBody = httpBody; + return this; + } + public String getHttpBody() { + return this.httpBody; + } + + public AlipayOpenApiGenericResponse setCode(String code) { + this.code = code; + return this; + } + public String getCode() { + return this.code; + } + + public AlipayOpenApiGenericResponse setMsg(String msg) { + this.msg = msg; + return this; + } + public String getMsg() { + return this.msg; + } + + public AlipayOpenApiGenericResponse setSubCode(String subCode) { + this.subCode = subCode; + return this; + } + public String getSubCode() { + return this.subCode; + } + + public AlipayOpenApiGenericResponse setSubMsg(String subMsg) { + this.subMsg = subMsg; + return this; + } + public String getSubMsg() { + return this.subMsg; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/generic/models/AlipayOpenApiGenericSDKResponse.java b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/generic/models/AlipayOpenApiGenericSDKResponse.java new file mode 100644 index 0000000..11039dd --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/main/java/com/alipay/easysdk/util/generic/models/AlipayOpenApiGenericSDKResponse.java @@ -0,0 +1,25 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.util.generic.models; + +import com.aliyun.tea.*; + +public class AlipayOpenApiGenericSDKResponse extends TeaModel { + // 订单信息,字符串形式 + @NameInMap("body") + @Validation(required = true) + public String body; + + public static AlipayOpenApiGenericSDKResponse build(java.util.Map map) throws Exception { + AlipayOpenApiGenericSDKResponse self = new AlipayOpenApiGenericSDKResponse(); + return TeaModel.build(map, self); + } + + public AlipayOpenApiGenericSDKResponse setBody(String body) { + this.body = body; + return this; + } + public String getBody() { + return this.body; + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/TestAccount.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/TestAccount.java new file mode 100644 index 0000000..820abe0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/TestAccount.java @@ -0,0 +1,134 @@ +/** + * Alipay.com Inc. Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk; + +import com.alipay.easysdk.kernel.Config; +import com.alipay.easysdk.kms.aliyun.AliyunKMSConfig; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Map; + +/** + * @author zhongyu + * @version $Id: TestAccount.java, v 0.1 2020年01月19日 4:42 PM zhongyu Exp $ + */ +public class TestAccount { + /** + * 从文件中读取私钥 + *

+ * 注意:实际开发过程中,请务必注意不要将私钥信息配置在源码中(比如配置为常量或储存在配置文件的某个字段中等),因为私钥的保密等级往往比源码高得多,将会增加私钥泄露的风险。推荐将私钥信息储存在专用的私钥文件中, + * 将私钥文件通过安全的流程分发到服务器的安全储存区域上,仅供自己的应用运行时读取。 + *

+ * 此处为了单元测试执行的环境普适性,私钥文件配置在resources资源下,实际过程中请不要这样做。 + * + * @param appId 私钥对应的APP_ID + * @return 私钥字符串 + */ + private static String getPrivateKey(String appId) { + InputStream stream = TestAccount.class.getResourceAsStream("/fixture/privateKey.json"); + Map result = new Gson().fromJson(new InputStreamReader(stream), new TypeToken>() {}.getType()); + return result.get(appId); + } + + /** + * 从文件中读取阿里云AccessKey配置信息 + * 此处为了单元测试执行的环境普适性,AccessKey信息配置在resources资源下,实际过程中请不要这样做。 + * @param key AccessKey配置对应的key + * @return AccessKey配置字符串 + */ + private static String getAliyunAccessKey(String key){ + InputStream stream = TestAccount.class.getResourceAsStream("/fixture/aliyunAccessKey.json"); + Map result = new Gson().fromJson(new InputStreamReader(stream), new TypeToken>() {}.getType()); + return result.get(key); + } + + /** + * 线上小程序测试账号 + */ + public static class Mini { + public static final Config CONFIG = getConfig(); + + public static Config getConfig() { + Config config = new Config(); + config.protocol = "https"; + config.gatewayHost = "openapi.alipay.com"; + config.appId = "2019022663440152"; + config.signType = "RSA2"; + + config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumX1EaLM4ddn1Pia4SxTRb62aVYxU8I2mHMqrc" + + "pQU6F01mIO/DjY7R4xUWcLi0I2oH/BK/WhckEDCFsGrT7mO+JX8K4sfaWZx1aDGs0m25wOCNjp+DCVBXotXSCurqgGI/9UrY+" + + "QydYDnsl4jB65M3p8VilF93MfS01omEDjUW+1MM4o3FP0khmcKsoHnYGs21btEeh0LK1gnnTDlou6Jwv3Ew36CbCNY2cYkuyP" + + "AW0j47XqzhWJ7awAx60fwgNBq6ZOEPJnODqH20TAdTLNxPSl4qGxamjBO+RuInBy+Bc2hFHq3pNv6hTAfktggRKkKzDlDEUwg" + + "SLE7d2eL7P6rwIDAQAB"; + config.merchantPrivateKey = getPrivateKey(config.appId); + config.notifyUrl = "https://www.test.com/callback"; + return config; + } + } + + /** + * 线上生活号测试账号 + */ + public static class OpenLife { + public static final Config CONFIG = getConfig(); + + private static Config getConfig() { + Config config = new Config(); + config.protocol = "https"; + config.gatewayHost = "openapi.alipay.com"; + config.appId = "2019051064521003"; + config.signType = "RSA2"; + + config.alipayCertPath = "src/test/resources/fixture/alipayCertPublicKey_RSA2.crt"; + config.alipayRootCertPath = "src/test/resources/fixture/alipayRootCert.crt"; + config.merchantCertPath = "src/test/resources/fixture/appCertPublicKey_2019051064521003.crt"; + config.merchantPrivateKey = getPrivateKey(config.appId); + return config; + } + } + + /** + * Aliyun KMS签名测试账号 + */ + public static class AliyunKMS { + public static final AliyunKMSConfig CONFIG = getConfig(); + + private static AliyunKMSConfig getConfig() { + AliyunKMSConfig config = new AliyunKMSConfig(); + config.protocol = "https"; + config.gatewayHost = "openapi.alipay.com"; + config.appId = "2021001163614348"; + config.signType = "RSA2"; + config.notifyUrl = "https://www.test.com/callback"; + + config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiOgupSXhUE3GkMDeCpeDwoEM2z+krBpaKPFbfS" + + "JgFVoN/M1s62VC6LhFI9aL4F76bqMGilQPpe2ukW5UmLR+C3OmliuqE/v5/UEpasnndcZMEKadQbWOpQ4eBHGkKTASQhtbgYb3U" + + "WS+viD5MfHS0+3h+sko8cW06jONmjG2tvFpnmooIjMawXByK8/f4vBMBk4ZQQodo4TT18mhyyyIoilhLH2EatQp/lov54ZhwHi9" + + "8LXeLw7Yt4QK8q7u+lB34V8lsu9zVMEMZExhoblsdjgzFAY6KzCn/QGnQE5e54i59+wONAyf2npUkz4cpPDJPLQ7KBu1febsZjk" + + "g9vZrXwIDAQAB"; + + //如果使用阿里云KMS签名,则不需要配置私钥 + //config.merchantPrivateKey = getPrivateKey(config.appId); + + //如果使用第三方签名服务,则需要指定签名提供方名称,阿里云KMS的名称为"AliyunKMS" + config.signProvider = "AliyunKMS"; + + //如果使用阿里云KMS签名,需要更换为您的阿里云账号信息 + config.aliyunAccessKeyId = getAliyunAccessKey("AccessKeyId"); + config.aliyunAccessKeySecret = getAliyunAccessKey("AccessKeySecret"); + config.kmsKeyId = "4358f298-8e30-4849-9791-52e68dbd9d1e"; + config.kmsKeyVersionId = "e71daa69-c321-4014-b0c4-ba070c7839ee"; + + //如果使用阿里云KMS签名,需要更换为您的KMS服务地址 + // KMS服务地址列表详情,请参考: + // https://help.aliyun.com/document_detail/69006.html?spm=a2c4g.11186623.2.9.783f77cfAoNhY6#concept-69006-zh + config.kmsEndpoint = "kms.cn-hangzhou.aliyuncs.com"; + + return config; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/image/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/image/ClientTest.java new file mode 100644 index 0000000..d9099ad --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/image/ClientTest.java @@ -0,0 +1,38 @@ +package com.alipay.easysdk.base.image; + +import com.alipay.easysdk.TestAccount.Mini; +import com.alipay.easysdk.base.image.models.AlipayOfflineMaterialImageUploadResponse; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.factory.Factory.Base; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(Mini.CONFIG); + } + + @Test + public void testUpload() throws Exception { + AlipayOfflineMaterialImageUploadResponse response = Base.Image().upload("测试图片", + "src/test/resources/fixture/sample.png"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.imageId, not(nullValue())); + assertThat(response.imageUrl, startsWith("https://")); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/oauth/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/oauth/ClientTest.java new file mode 100644 index 0000000..646fa50 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/oauth/ClientTest.java @@ -0,0 +1,44 @@ +package com.alipay.easysdk.base.oauth; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.base.oauth.models.AlipaySystemOauthTokenResponse; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testGetToken() throws Exception { + AlipaySystemOauthTokenResponse response = Factory.Base.OAuth().getToken("fe1ae5abacd54ba2a6c8f6902533TX64"); + + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40002")); + assertThat(response.msg, is("Invalid Arguments")); + assertThat(response.subCode, is("isv.code-invalid")); + assertThat(response.subMsg, is("授权码code无效")); + assertThat(response.httpBody, not(nullValue())); + } + + @Test + public void testRefreshToken() throws Exception { + AlipaySystemOauthTokenResponse response = Factory.Base.OAuth().refreshToken("1234567890"); + + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40002")); + assertThat(response.msg, is("Invalid Arguments")); + assertThat(response.subCode, is("isv.refresh-token-invalid")); + assertThat(response.subMsg, is("刷新令牌refresh_token无效")); + assertThat(response.httpBody, not(nullValue())); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/qrcode/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/qrcode/ClientTest.java new file mode 100644 index 0000000..bd8a133 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/qrcode/ClientTest.java @@ -0,0 +1,34 @@ +package com.alipay.easysdk.base.qrcode; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.base.qrcode.models.AlipayOpenAppQrcodeCreateResponse; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +public class ClientTest { + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testCreate() throws Exception { + AlipayOpenAppQrcodeCreateResponse response = Factory.Base.Qrcode().create( + "https://opendocs.alipay.com", "ageIndex=1", "文档站点"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.qrCodeUrl, not(nullValue())); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/video/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/video/ClientTest.java new file mode 100644 index 0000000..e400cbc --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/base/video/ClientTest.java @@ -0,0 +1,38 @@ +package com.alipay.easysdk.base.video; + +import com.alipay.easysdk.TestAccount.Mini; +import com.alipay.easysdk.base.video.models.AlipayOfflineMaterialImageUploadResponse; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.factory.Factory.Base; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(Mini.CONFIG); + } + + @Test + public void testUpload() throws Exception { + AlipayOfflineMaterialImageUploadResponse response = Base.Video().upload("测试视频", + "src/test/resources/fixture/sample.mp4"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.imageId, not(nullValue())); + assertThat(response.imageUrl, startsWith("https://")); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/factory/FactoryTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/factory/FactoryTest.java new file mode 100644 index 0000000..89d5ae0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/factory/FactoryTest.java @@ -0,0 +1,32 @@ +package com.alipay.easysdk.factory; + +import com.alipay.easysdk.TestAccount.Mini; +import com.alipay.easysdk.payment.common.Client; +import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +public class FactoryTest { + @Before + public void setUp() { + Factory.setOptions(Mini.CONFIG); + } + + @Test + public void testGetClient() throws Exception { + AlipayTradeRefundResponse response = Factory.getClient(Client.class).refund( + "64628156-f784-4572-9540-485b7c91b850", "0.01"); + + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.refundFee, is("0.01")); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/marketing/openlife/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/marketing/openlife/ClientTest.java new file mode 100644 index 0000000..ccb6998 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/marketing/openlife/ClientTest.java @@ -0,0 +1,201 @@ +package com.alipay.easysdk.marketing.openlife; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.factory.Factory.Marketing; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.marketing.openlife.models.AlipayOpenPublicLifeMsgRecallResponse; +import com.alipay.easysdk.marketing.openlife.models.AlipayOpenPublicMessageContentCreateResponse; +import com.alipay.easysdk.marketing.openlife.models.AlipayOpenPublicMessageContentModifyResponse; +import com.alipay.easysdk.marketing.openlife.models.AlipayOpenPublicMessageSingleSendResponse; +import com.alipay.easysdk.marketing.openlife.models.AlipayOpenPublicMessageTotalSendResponse; +import com.alipay.easysdk.marketing.openlife.models.AlipayOpenPublicSettingCategoryQueryResponse; +import com.alipay.easysdk.marketing.openlife.models.AlipayOpenPublicTemplateMessageIndustryModifyResponse; +import com.alipay.easysdk.marketing.openlife.models.Article; +import com.alipay.easysdk.marketing.openlife.models.Context; +import com.alipay.easysdk.marketing.openlife.models.Keyword; +import com.alipay.easysdk.marketing.openlife.models.Template; +import com.google.common.collect.Lists; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(TestAccount.OpenLife.CONFIG); + } + + @Test + public void testCreateImageTextContent() throws Exception { + AlipayOpenPublicMessageContentCreateResponse response = Marketing.OpenLife().createImageTextContent("标题", + "http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED", + "示例", "T", "activity", "满100减10", + "关键,热度", "13434343432,xxx@163.com"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.contentId, is(notNullValue())); + assertThat(response.contentUrl, is(notNullValue())); + } + + @Test + public void testModifyImageTextContent() throws Exception { + AlipayOpenPublicMessageContentModifyResponse response = Marketing.OpenLife().modifyImageTextContent( + "20190510645210035577f788-d6cd-4020-9dba-1a195edb7342", "新标题", + "http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED", + "新示例", "T", "activity", "满100减20", + "关键,热度", "13434343432,xxx@163.com"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.contentId, is("20190510645210035577f788-d6cd-4020-9dba-1a195edb7342")); + assertThat(response.contentUrl, is(notNullValue())); + } + + @Test + public void testSendText() throws Exception { + AlipayOpenPublicMessageTotalSendResponse response = Marketing.OpenLife().sendText("测试"); + + if (response.code.equals("10000")) { + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.messageId, is(notNullValue())); + } else { + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40004")); + assertThat(response.msg, is("Business Failed")); + assertThat(response.subCode, is("PUB.MSG_BATCH_SD_OVER")); + assertThat(response.subMsg, is("批量发送消息频率超限")); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.messageId, is(nullValue())); + } + } + + @Test + public void testSendImageText() throws Exception { + Article article = new Article(); + article.actionName = "测试"; + article.desc = "测试"; + article.title = "测试"; + article.imageUrl = "http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED"; + article.url = "https://docs.open.alipay.com/api_6/alipay.open.public.message.total.send"; + AlipayOpenPublicMessageTotalSendResponse response = Marketing.OpenLife().sendImageText(Lists.newArrayList(article)); + + if (response.code.equals("10000")) { + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.messageId, is(notNullValue())); + } else { + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40004")); + assertThat(response.msg, is("Business Failed")); + assertThat(response.subCode, is("PUB.MSG_BATCH_SD_OVER")); + assertThat(response.subMsg, is("批量发送消息频率超限")); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.messageId, is(nullValue())); + } + } + + @Test + public void testSendSingleMessage() throws Exception { + Keyword keyword = new Keyword(); + keyword.color = "#85be53"; + keyword.value = "HU7142"; + + Context context = new Context(); + context.headColor = "#85be53"; + context.url = "https://docs.open.alipay.com/api_6/alipay.open.public.message.single.send"; + context.actionName = "查看详情"; + context.keyword1 = keyword; + context.keyword2 = keyword; + context.first = keyword; + context.remark = keyword; + + Template template = new Template(); + template.templateId = "e44cd3e52ffa46b1a50afc145f55d1ea"; + template.context = context; + + AlipayOpenPublicMessageSingleSendResponse response = Marketing.OpenLife().sendSingleMessage( + "2088002656718920", template); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + } + + @Test + public void testRecallMessage() throws Exception { + AlipayOpenPublicLifeMsgRecallResponse response = Marketing.OpenLife().recallMessage( + "201905106452100327f456f6-8dd2-4a06-8b0e-ec8a3a85c46a"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + } + + @Test + public void testSetIndustry() throws Exception { + AlipayOpenPublicTemplateMessageIndustryModifyResponse response = Marketing.OpenLife().setIndustry( + "10001/20102", "IT科技/IT软件与服务", + "10001/20102", "IT科技/IT软件与服务"); + + if (response.code.equals("10000")) { + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + } else { + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40004")); + assertThat(response.msg, is("Business Failed")); + assertThat(response.subCode, is("3002")); + assertThat(response.subMsg, is("模板消息行业一月只能修改一次")); + assertThat(response.httpBody, not(nullValue())); + } + } + + @Test + public void testGetIndustry() throws Exception { + AlipayOpenPublicSettingCategoryQueryResponse response = Marketing.OpenLife().getIndustry(); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.primaryCategory, is("IT科技/IT软件与服务")); + assertThat(response.secondaryCategory, is("IT科技/IT软件与服务")); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/marketing/pass/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/marketing/pass/ClientTest.java new file mode 100644 index 0000000..ee56282 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/marketing/pass/ClientTest.java @@ -0,0 +1,100 @@ +package com.alipay.easysdk.marketing.pass; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.marketing.pass.models.AlipayPassInstanceAddResponse; +import com.alipay.easysdk.marketing.pass.models.AlipayPassInstanceUpdateResponse; +import com.alipay.easysdk.marketing.pass.models.AlipayPassTemplateAddResponse; +import com.alipay.easysdk.marketing.pass.models.AlipayPassTemplateUpdateResponse; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testCreateTemplate() throws Exception { + AlipayPassTemplateAddResponse response = Factory.Marketing.Pass().createTemplate("123456789", getTplContent()); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.success, is(true)); + assertThat(response.result, containsString("tpl_id")); + } + + @Test + public void testUpdateTemplate() throws Exception { + AlipayPassTemplateUpdateResponse response = Factory.Marketing.Pass().updateTemplate("2020012014534017917956080", getTplContent()); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.success, is(true)); + assertThat(response.result, containsString("tpl_id")); + } + + @Test + public void testAddInstance() throws Exception { + AlipayPassInstanceAddResponse response = Factory.Marketing.Pass().addInstance("2020012014534017917956080", "{}", + "1", "{\"partner_id\":\"2088102114633762\",\"out_trade_no\":\"1234567\"}"); + + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40004")); + assertThat(response.msg, is("Business Failed")); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.success, is(false)); + } + + @Test + public void testUpdateInstance() throws Exception { + AlipayPassInstanceUpdateResponse response = Factory.Marketing.Pass().updateInstance("209919213", + "2088918273", "{}", "USED", "8612231273", "wave"); + + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40004")); + assertThat(response.msg, is("Business Failed")); + assertThat(response.subCode, is("KP.AE_ALIPASS_NOTEXIST")); + assertThat(response.subMsg, is("卡券不存在")); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.success, is(false)); + assertThat(response.result, containsString("{\"operate\":\"UPDATE\"}")); + } + + private String getTplContent() { + return "{\"logo\":\"http://img01.taobaocdn.com/top/i1/LB1NDJuQpXXXXbYXFXXXXXXXXXX\",\"strip\":null,\"icon\":null," + + "\"content\":{\"evoucherInfo\":{\"goodsId\":\"\",\"title\":\"test\",\"type\":\"boardingPass\"," + + "\"product\":\"air\",\"startDate\":\"2020-01-20 13:45:56\",\"endDate\":\"2020-01-25 13:45:56\"," + + "\"operation\":[{\"message\":{\"img\":\"http://img01.taobaocdn.com/top/i1/LB1NDJuQpXXXXbYXFXXXXXXXXXX\"," + + "\"target\":\"\"},\"format\":\"img\",\"messageEncoding\":\"utf-8\",\"altText\":\"\"}]," + + "\"einfo\":{\"logoText\":\"test\",\"headFields\":[{\"key\":\"test\",\"label\":\"测试\",\"value\":\"\"," + + "\"type\":\"text\"}],\"primaryFields\":[{\"key\":\"from\",\"label\":\"测试\",\"value\":\"\",\"type\":\"text\"}," + + "{\"key\":\"to\",\"label\":\"测试\",\"value\":\"\",\"type\":\"text\"}],\"secondaryFields\":[{\"key\":\"fltNo\"," + + "\"label\":\"航班号\",\"value\":\"CA123\",\"type\":\"text\"}],\"auxiliaryFields\":[{\"key\":\"test\"," + + "\"label\":\"测试\",\"value\":\"\",\"type\":\"text\"}],\"backFields\":[]},\"locations\":[]}," + + "\"merchant\":{\"mname\":\"钟雨\",\"mtel\":\"\",\"minfo\":\"\"},\"platform\":{\"channelID\":\"2088201564809153\"," + + "\"webServiceUrl\":\"https://alipass.alipay.com/builder/syncRecord.htm?tempId=2020012013442621326446216\"}," + + "\"style\":{\"backgroundColor\":\"RGB(26,150,219)\"},\"fileInfo\":{\"formatVersion\":\"2\",\"canShare\":true," + + "\"canBuy\":false,\"canPresent\":true,\"serialNumber\":\"2020012013520759738677158\",\"supportTaxi\":\"true\"," + + "\"taxiSchemaUrl\":\"alipays://platformapi/startapp?appId=20000778&bizid=260&channel=71322\"}," + + "\"appInfo\":{\"app\":{\"android_appid\":\"\",\"ios_appid\":\"\",\"android_launch\":\"\",\"ios_launch\":\"\"," + + "\"android_download\":\"\",\"ios_download\":\"\"},\"label\":\"测试\",\"message\":\"\"}," + + "\"source\":\"alipassprod\",\"alipayVerify\":[\"qrcode\"]}}"; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/marketing/templatemessage/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/marketing/templatemessage/ClientTest.java new file mode 100644 index 0000000..721a87f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/marketing/templatemessage/ClientTest.java @@ -0,0 +1,39 @@ +package com.alipay.easysdk.marketing.templatemessage; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.factory.Factory.Marketing; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.marketing.templatemessage.models.AlipayOpenAppMiniTemplatemessageSendResponse; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testSend() throws Exception { + AlipayOpenAppMiniTemplatemessageSendResponse response = Marketing.TemplateMessage().send( + "2088102122458832", + "2017010100000000580012345678", + "MDI4YzIxMDE2M2I5YTQzYjUxNWE4MjA4NmU1MTIyYmM=", + "page/component/index", + "{\"keyword1\": {\"value\" : \"12:00\"},\"keyword2\": {\"value\" : \"20180808\"},\"keyword3\": {\"value\" : \"支付宝\"}}"); + + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40004")); + assertThat(response.msg, is("Business Failed")); + assertThat(response.subCode, is("USER_TEMPLATE_ILLEGAL")); + assertThat(response.subMsg, is("模板非法")); + assertThat(response.httpBody, not(nullValue())); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/member/identification/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/member/identification/ClientTest.java new file mode 100644 index 0000000..cfbc3bf --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/member/identification/ClientTest.java @@ -0,0 +1,74 @@ +package com.alipay.easysdk.member.identification; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.factory.Factory.Member; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.member.identification.models.AlipayUserCertifyOpenCertifyResponse; +import com.alipay.easysdk.member.identification.models.AlipayUserCertifyOpenInitializeResponse; +import com.alipay.easysdk.member.identification.models.AlipayUserCertifyOpenQueryResponse; +import com.alipay.easysdk.member.identification.models.IdentityParam; +import com.alipay.easysdk.member.identification.models.MerchantConfig; +import org.junit.Before; +import org.junit.Test; + +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testInit() throws Exception { + IdentityParam identityParam = new IdentityParam(); + identityParam.identityType = "CERT_INFO"; + identityParam.certType = "IDENTITY_CARD"; + identityParam.certName = "张三"; + identityParam.certNo = "5139011988090987631"; + MerchantConfig merchantConfig = new MerchantConfig(); + merchantConfig.returnUrl = "www.taobao.com"; + AlipayUserCertifyOpenInitializeResponse response = Member.Identification().init( + UUID.randomUUID().toString(), "FACE", identityParam, merchantConfig); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.certifyId, not(nullValue())); + } + + @Test + public void testCertify() throws Exception { + AlipayUserCertifyOpenCertifyResponse response = Member.Identification().certify("1226a454daf65c2abbbe0b7b8dc30d20"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.body, containsString("https://openapi.alipay.com/gateway.do?alipay_sdk=alipay-easysdk-java-")); + assertThat(response.body, containsString("sign")); + } + + @Test + public void testQuery() throws Exception { + AlipayUserCertifyOpenQueryResponse response = Member.Identification().query("89ad1f1b8171d9741c3e5620fd77f9de"); + + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40004")); + assertThat(response.msg, is("Business Failed")); + assertThat(response.subCode, is("CERTIFY_ID_EXPIRED")); + assertThat(response.subMsg, is("认证已失效")); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.passed, is(nullValue())); + assertThat(response.identityInfo, is(nullValue())); + assertThat(response.materialInfo, is(nullValue())); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/multipleFactory/MultipleFactoryTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/multipleFactory/MultipleFactoryTest.java new file mode 100644 index 0000000..5a3fc9d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/multipleFactory/MultipleFactoryTest.java @@ -0,0 +1,62 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.multipleFactory; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.base.image.models.AlipayOfflineMaterialImageUploadResponse; +import com.alipay.easysdk.factory.MultipleFactory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.marketing.openlife.models.AlipayOpenPublicMessageContentCreateResponse; +import org.junit.Assert; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author junying + * @version : MultipleFactoryTest.java, v 0.1 2020年12月23日 4:19 下午 junying Exp $ + */ +public class MultipleFactoryTest { + + @Test + public void testImageUpload() throws Exception { + + MultipleFactory factory = new MultipleFactory(); + factory.setOptions(TestAccount.Mini.CONFIG); + + AlipayOfflineMaterialImageUploadResponse response = factory.Image().upload("测试图片", + "src/test/resources/fixture/sample.png"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.imageId, not(nullValue())); + assertThat(response.imageUrl, startsWith("https://")); + } + + @Test + public void testCreateImageTextContent() throws Exception { + MultipleFactory factory = new MultipleFactory(); + factory.setOptions(TestAccount.OpenLife.CONFIG); + + AlipayOpenPublicMessageContentCreateResponse response = factory.OpenLife().createImageTextContent("标题", + "http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED", + "示例", "T", "activity", "满100减10", + "关键,热度", "13434343432,xxx@163.com"); + + Assert.assertThat(ResponseChecker.success(response), is(true)); + Assert.assertThat(response.code, is("10000")); + Assert.assertThat(response.msg, is("Success")); + Assert.assertThat(response.subCode, is(nullValue())); + Assert.assertThat(response.subMsg, is(nullValue())); + Assert.assertThat(response.httpBody, not(nullValue())); + Assert.assertThat(response.contentId, is(notNullValue())); + Assert.assertThat(response.contentUrl, is(notNullValue())); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/app/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/app/ClientTest.java new file mode 100644 index 0000000..30abf0e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/app/ClientTest.java @@ -0,0 +1,62 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.payment.app; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testPay() throws Exception { + AlipayTradeAppPayResponse response = Factory.Payment.App().pay("iPhone6 16G", + "f4833085-0c46-4bb0-8e5f-622a02a4cffc", "0.10"); + + assertThat(ResponseChecker.success(response), is(true)); + Assert.assertThat(response.body, containsString("app_id=2019022663440152&biz_content=%7B%22" + + "out_trade_no%22%3A%22f4833085-0c46-4bb0-8e5f-622a02a4cffc%22%2C%22" + + "total_amount%22%3A%220.10%22%2C%22subject%22%3A%22iPhone6+16G%22%7D&" + + "charset=UTF-8&format=json&method=alipay.trade.app.pay" + + "¬ify_url=https%3A%2F%2Fwww.test.com%2Fcallback&sign=")); + } + + @Test + public void testPayWithOptional() throws Exception { + AlipayTradeAppPayResponse response = Factory.Payment.App() + .agent("ca34ea491e7146cc87d25fca24c4cD11") + .optional("extend_params", getHuabeiConfig()) + .pay("iPhone6 16G", "f4833085-0c46-4bb0-8e5f-622a02a4cffc", "0.10"); + + Assert.assertThat(response.body, containsString("app_auth_token=ca34ea491e7146cc87d25fca24c4cD11&" + + "app_id=2019022663440152&biz_content=%7B%22extend_params%22%3A%7B%22hb_fq_seller_percent%22%3A%22100%22%2C%22" + + "hb_fq_num%22%3A%223%22%7D%2C%22out_trade_no%22%3A%22f4833085-0c46-4bb0-8e5f-622a02a4cffc%22%2C%22" + + "total_amount%22%3A%220.10%22%2C%22subject%22%3A%22iPhone6+16G%22%7D&charset=UTF-8&format=json&" + + "method=alipay.trade.app.pay¬ify_url=https%3A%2F%2Fwww.test.com%2Fcallback&sign=")); + } + + private Map getHuabeiConfig() { + Map extendParams = new HashMap<>(); + extendParams.put("hb_fq_num", "3"); + extendParams.put("hb_fq_seller_percent", "100"); + return extendParams; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/common/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/common/ClientTest.java new file mode 100644 index 0000000..58dafc8 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/common/ClientTest.java @@ -0,0 +1,154 @@ +package com.alipay.easysdk.payment.common; + +import com.alipay.easysdk.TestAccount.Mini; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.payment.common.models.AlipayDataDataserviceBillDownloadurlQueryResponse; +import com.alipay.easysdk.payment.common.models.AlipayTradeCancelResponse; +import com.alipay.easysdk.payment.common.models.AlipayTradeCloseResponse; +import com.alipay.easysdk.payment.common.models.AlipayTradeCreateResponse; +import com.alipay.easysdk.payment.common.models.AlipayTradeFastpayRefundQueryResponse; +import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse; +import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + @Before + public void setUp() { + Factory.setOptions(Mini.CONFIG); + } + + @Test + public void testCreate() throws Exception { + String outTradeNo = UUID.randomUUID().toString(); + AlipayTradeCreateResponse response = Factory.Payment.Common().create( + "iPhone6 16G", outTradeNo, "0.01", "2088002656718920"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.outTradeNo, is(outTradeNo)); + assertThat(response.tradeNo, startsWith("202")); + } + + @Test + public void testCreateWithOptional() throws Exception { + String outTradeNo = UUID.randomUUID().toString(); + AlipayTradeCreateResponse response = Factory.Payment.Common().optional("goods_detail", getGoodsDetail()) + .create("iPhone6 16G", outTradeNo, "0.01", "2088002656718920"); + + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.outTradeNo, is(outTradeNo)); + assertThat(response.tradeNo, startsWith("202")); + } + + private List getGoodsDetail() { + List goodsDetail = new ArrayList<>(); + Map goodDetail = new HashMap<>(); + goodDetail.put("goods_id", "apple-01"); + goodDetail.put("goods_name", "iPhone6 16G"); + goodDetail.put("quantity", 1); + goodDetail.put("price", "0.01"); + goodsDetail.add(goodDetail); + return goodsDetail; + } + + @Test + public void testQuery() throws Exception { + AlipayTradeQueryResponse response = Factory.Payment.Common().query("6f149ddb-ab8c-4546-81fb-5880b4aaa318"); + + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.outTradeNo, is("6f149ddb-ab8c-4546-81fb-5880b4aaa318")); + } + + @Test + public void testCancel() throws Exception { + AlipayTradeCancelResponse response = Factory.Payment.Common().cancel(createNewAndReturnOutTradeNo()); + + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.action, is("close")); + } + + @Test + public void testClose() throws Exception { + AlipayTradeCloseResponse response = Factory.Payment.Common().close(createNewAndReturnOutTradeNo()); + + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + } + + @Test + public void testRefund() throws Exception { + AlipayTradeRefundResponse response = Factory.Payment.Common().refund( + "64628156-f784-4572-9540-485b7c91b850", "0.01"); + + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.refundFee, is("0.01")); + } + + @Test + public void testQueryRefund() throws Exception { + AlipayTradeFastpayRefundQueryResponse response = Factory.Payment.Common().queryRefund( + "64628156-f784-4572-9540-485b7c91b850", "64628156-f784-4572-9540-485b7c91b850"); + + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.refundAmount, is("0.01")); + assertThat(response.totalAmount, is("0.01")); + } + + @Test + public void testDownloadBill() throws Exception { + AlipayDataDataserviceBillDownloadurlQueryResponse response = Factory.Payment.Common().downloadBill("trade", "2020-01"); + + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.billDownloadUrl.startsWith("http://dwbillcenter.alipay.com/"), is(true)); + } + + private String createNewAndReturnOutTradeNo() throws Exception { + return Factory.Payment.Common().create("iPhone6 16G", UUID.randomUUID().toString(), + "88.88", "2088002656718920").outTradeNo; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/facetoface/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/facetoface/ClientTest.java new file mode 100644 index 0000000..14c599e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/facetoface/ClientTest.java @@ -0,0 +1,56 @@ +package com.alipay.easysdk.payment.facetoface; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.payment.facetoface.models.AlipayTradePayResponse; +import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse; +import org.junit.Before; +import org.junit.Test; + +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testPay() throws Exception { + AlipayTradePayResponse response = Factory.Payment.FaceToFace().pay("iPhone6 16G", + "64628156-f784-4572-9540-485b7c91b850", "0.01", "289821051157962364"); + + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("40004")); + assertThat(response.msg, is("Business Failed")); + assertThat(response.subCode, is("ACQ.PAYMENT_AUTH_CODE_INVALID")); + assertThat(response.subMsg, is("支付失败,获取顾客账户信息失败,请顾客刷新付款码后重新收款,如再次收款失败,请联系管理员处理。[SOUNDWAVE_PARSER_FAIL]")); + assertThat(response.httpBody, not(nullValue())); + } + + @Test + public void testPreCreate() throws Exception { + AlipayTradePrecreateResponse response = Factory.Payment.FaceToFace().preCreate("iPhone6 16G", + createNewAndReturnOutTradeNo(), "0.10"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.qrCode.startsWith("https://qr.alipay.com/"), is(true)); + } + + private String createNewAndReturnOutTradeNo() throws Exception { + return Factory.Payment.Common().create("Iphone6 16G", UUID.randomUUID().toString(), + "88.88", "2088002656718920").outTradeNo; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/huabei/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/huabei/ClientTest.java new file mode 100644 index 0000000..021fb8f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/huabei/ClientTest.java @@ -0,0 +1,45 @@ +package com.alipay.easysdk.payment.huabei; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.payment.huabei.models.AlipayTradeCreateResponse; +import com.alipay.easysdk.payment.huabei.models.HuabeiConfig; +import org.junit.Before; +import org.junit.Test; + +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testCreate() throws Exception { + String outTradeNo = UUID.randomUUID().toString(); + + HuabeiConfig config = new HuabeiConfig(); + config.hbFqNum = "3"; + config.hbFqSellerPercent = "0"; + AlipayTradeCreateResponse response = Factory.Payment.Huabei().create("Iphone6 16G", + outTradeNo, "0.10", "2088002656718920", config); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.outTradeNo, is(outTradeNo)); + assertThat(response.tradeNo, startsWith("202")); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/page/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/page/ClientTest.java new file mode 100644 index 0000000..75d54bf --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/page/ClientTest.java @@ -0,0 +1,58 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.payment.page; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testPay() throws Exception { + AlipayTradePagePayResponse response = Factory.Payment.Page().pay("iPhone6 16G", + "e5b5bd79-8310-447d-b63b-0fe3a393324d", "0.10", "https://www.taobao.com"); + + Assert.assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.body.contains(""), is(true)); + assertThat(response.body.contains(""), is(true)); + assertThat(response.body.contains(""), is(true)); + } + + @Test + public void testPayWithOptionalNotify() throws Exception { + AlipayTradePagePayResponse response = Factory.Payment.Page().asyncNotify("https://www.test2.com/newCallback") + .pay("iPhone6 16G", "e5b5bd79-8310-447d-b63b-0fe3a393324d", + "0.10", "https://www.taobao.com"); + + Assert.assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.body.contains(""), is(true)); + assertThat(response.body.contains(""), is(true)); + assertThat(response.body.contains(""), is(true)); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/wap/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/wap/ClientTest.java new file mode 100644 index 0000000..fa53911 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/payment/wap/ClientTest.java @@ -0,0 +1,74 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.payment.wap; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.payment.wap.models.AlipayTradeWapPayResponse; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testPay() throws Exception { + AlipayTradeWapPayResponse response = Factory.Payment.Wap().pay("iPhone6 16G", + "b7f4bc7d-ea4b-4efd-9072-d8ea913c8946", "0.10", + "https://www.taobao.com", "https://www.taobao.com"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.body.contains(""), is(true)); + assertThat(response.body.contains(""), is(true)); + assertThat(response.body.contains(""), is(true)); + } + + @Test + public void testPayWithOptional() throws Exception { + AlipayTradeWapPayResponse response = Factory.Payment.Wap() + .agent("ca34ea491e7146cc87d25fca24c4cD11").batchOptional(getOptionalArgs()) + .pay("iPhone6 16G", "b7f4bc7d-ea4b-4efd-9072-d8ea913c8946", "0.10", + "https://www.taobao.com", "https://www.taobao.com"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.body.contains(""), is(true)); + assertThat(response.body.contains(""), is(true)); + assertThat(response.body.contains(""), is(true)); + } + + private Map getOptionalArgs() { + Map optionalArgs = new HashMap<>(); + optionalArgs.put("timeout_express", "10m"); + optionalArgs.put("body", "iPhone6 16G"); + return optionalArgs; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/security/textrisk/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/security/textrisk/ClientTest.java new file mode 100644 index 0000000..14d8b4e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/security/textrisk/ClientTest.java @@ -0,0 +1,36 @@ +package com.alipay.easysdk.security.textrisk; + +import com.alipay.easysdk.TestAccount; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.factory.Factory.Security; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.security.textrisk.models.AlipaySecurityRiskContentDetectResponse; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(TestAccount.Mini.CONFIG); + } + + @Test + public void testDetect() throws Exception { + AlipaySecurityRiskContentDetectResponse response = Security.TextRisk().detect("test"); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + assertThat(response.action, is("PASSED")); + assertThat(response.uniqueId, not(nullValue())); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/util/aes/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/util/aes/ClientTest.java new file mode 100644 index 0000000..78af7c8 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/util/aes/ClientTest.java @@ -0,0 +1,36 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.util.aes; + +import com.alipay.easysdk.TestAccount.Mini; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.Config; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Config config = Mini.getConfig(); + config.encryptKey = "aa4BtZ4tspm2wnXLb1ThQA=="; + Factory.setOptions(config); + } + + @Test + public void testDecrypt() throws Exception { + String plainText = Factory.Util.AES().decrypt("ILpoMowjIQjfYMR847rnFQ=="); + assertThat(plainText, is("test1234567")); + } + + @Test + public void testEncrypt() throws Exception { + String cipherText = Factory.Util.AES().encrypt("test1234567"); + assertThat(cipherText, is("ILpoMowjIQjfYMR847rnFQ==")); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/util/generic/ClientTest.java b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/util/generic/ClientTest.java new file mode 100644 index 0000000..3065f4a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/java/com/alipay/easysdk/util/generic/ClientTest.java @@ -0,0 +1,117 @@ +package com.alipay.easysdk.util.generic; + +import com.alipay.easysdk.TestAccount.Mini; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.util.generic.models.AlipayOpenApiGenericResponse; +import com.alipay.easysdk.util.generic.models.AlipayOpenApiGenericSDKResponse; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; + +public class ClientTest { + + @Before + public void setUp() { + Factory.setOptions(Mini.CONFIG); + } + + @Test + public void testSDKExecute() throws Exception { + Map bizParams = new HashMap<>(); + bizParams.put("subject", "iPhone6 16G"); + bizParams.put("out_trade_no", "f4833085-0c46-4bb0-8e5f-622a02a4cffc"); + bizParams.put("total_amount", "0.10"); + + java.util.Map textParams = new java.util.HashMap<>(); + + AlipayOpenApiGenericSDKResponse response = Factory.Util.Generic().sdkExecute("alipay.trade.app.pay", textParams, bizParams); + + Assert.assertThat(ResponseChecker.success(response), is(true)); + Assert.assertThat(response.body, containsString("app_id=2019022663440152&biz_content=%7B%22" + + "out_trade_no%22%3A%22f4833085-0c46-4bb0-8e5f-622a02a4cffc%22%2C%22" + + "total_amount%22%3A%220.10%22%2C%22subject%22%3A%22iPhone6+16G%22%7D&" + + "charset=UTF-8&format=json&method=alipay.trade.app.pay" + + "¬ify_url=https%3A%2F%2Fwww.test.com%2Fcallback&sign=")); + } + + @Test + public void testFileExecute() throws Exception { + Map textParams = new HashMap<>(); + textParams.put("image_type", "png"); + textParams.put("image_name", "海底捞"); + textParams.put("image_pid", "22088021822217233"); + + Map fileParams = new HashMap<>(); + fileParams.put("image_content", "src/test/resources/fixture/sample.png"); + + AlipayOpenApiGenericResponse response = Factory.Util.Generic().fileExecute("alipay.offline.material.image.upload", textParams, null, fileParams); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + + } + + + @Test + public void testExecuteWithoutAppAuthToken() throws Exception { + String outTradeNo = UUID.randomUUID().toString(); + AlipayOpenApiGenericResponse response = Factory.Util.Generic().execute( + "alipay.trade.create", null, getBizParams(outTradeNo)); + + assertThat(ResponseChecker.success(response), is(true)); + assertThat(response.code, is("10000")); + assertThat(response.msg, is("Success")); + assertThat(response.subCode, is(nullValue())); + assertThat(response.subMsg, is(nullValue())); + assertThat(response.httpBody, not(nullValue())); + } + + @Test + public void testExecuteWithAppAuthToken() throws Exception { + String outTradeNo = UUID.randomUUID().toString(); + AlipayOpenApiGenericResponse response = Factory.Util.Generic().execute( + "alipay.trade.create", getTextParams(), getBizParams(outTradeNo)); + + assertThat(ResponseChecker.success(response), is(false)); + assertThat(response.code, is("20001")); + assertThat(response.msg, is("Insufficient Token Permissions")); + assertThat(response.subCode, is("aop.invalid-app-auth-token")); + assertThat(response.subMsg, is("无效的应用授权令牌")); + assertThat(response.httpBody, not(nullValue())); + } + + private Map getTextParams() { + Map bizParams = new HashMap<>(); + bizParams.put("app_auth_token", "201712BB_D0804adb2e743078d1822d536956X34"); + return bizParams; + } + + private Map getBizParams(String outTradeNo) { + Map bizParams = new HashMap<>(); + bizParams.put("subject", "Iphone6 16G"); + bizParams.put("out_trade_no", outTradeNo); + bizParams.put("total_amount", "0.10"); + bizParams.put("buyer_id", "2088002656718920"); + bizParams.put("extend_params", getHuabeiParams()); + return bizParams; + } + + private Map getHuabeiParams() { + Map extendParams = new HashMap<>(); + extendParams.put("hb_fq_num", "3"); + extendParams.put("hb_fq_seller_percent", "3"); + return extendParams; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/alipayCertPublicKey_RSA2.crt b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/alipayCertPublicKey_RSA2.crt new file mode 100644 index 0000000..fd7c0a0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/alipayCertPublicKey_RSA2.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIQIBkJAnXy/rwX3BTZaKNEzjANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MTkwNwYDVQQDDDBBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IENs +YXNzIDIgUjEwHhcNMTkwOTAyMTI0NDIyWhcNMjEwOTAxMTI0NDIyWjB0MQswCQYDVQQGEwJDTjEP +MA0GA1UECgwG6ZKf6ZuoMQ8wDQYDVQQLDAZBbGlwYXkxQzBBBgNVBAMMOuaUr+S7mOWunSjkuK3l +m70p572R57uc5oqA5pyv5pyJ6ZmQ5YWs5Y+4LTIwODgwMDI2NTY3MTg5MjAwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDQxh7MsF7bsPyQlToJWOPlmGfqUerZI2o2725LUqrabGYOaAgx +a8OAm6sFXoq6TykRltIBEmAjYjMYudQelwxSv8NhQ1eLEFrY7o2Z3TQ+y8lvlLmvqWnEMzOqq4Fc +UN6gzd1nissGVtzUkmx9ErB+89g6WAKV1bFCZBQHIjzfMIqcZkddUZ4SiksMKB/ncKFOJPJf2CUI +i31URny3WlIoC44jG1SiX2sPKdbkbsSGQcDfGIpNRQBNJxlXX/8Y8D7RrFCWHtjh4ONSMT29+xjS +8HNM0gSR2y4QKXyRupXrNY9yTTtkPhQIEjfSjsQPnuM+3b7VFd3GSDcDbvskNRNLAgMBAAGjEjAQ +MA4GA1UdDwEB/wQEAwID+DANBgkqhkiG9w0BAQsFAAOCAQEAf8Qx2UsLFqPDTxKk9eT0np75NqJ8 +MexTuPJ/gC+Lp20YzEUyYW2rPlDFhDmFztlqk9RdynLRqyjB5dOAdWlxhgDlEqB9E6DvkVKtpIaL +7h7zqJei9gb/STAyf5vTVWR/WTmOhp3vQhaj7+lt14JwK/ELYMdBLD2IdmFis7YdzhCsGo7Y4FPb +BuHCV8Ngfaf2PvDlKaFOVzDg8tGnMBbAOgpe+mhxKUdhNG3eXcO0Z813rNIC15YAvWm68tNAwuZJ +rIVgK+049WUojwUJxOwVyzewob/8Gx7o8ipIV5E/bMrduSvigsj7OmNzwQ5/iSm31dfcXi3fOXXz +BLMb888PlA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE4jCCAsqgAwIBAgIIYsSr5bKAMl8wDQYJKoZIhvcNAQELBQAwejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMjE0MzQxNVoXDTM3MTEyNjE0MzQxNVowgYIxCzAJBgNVBAYTAkNOMRYwFAYDVQQKDA1BbnQgRmluYW5jaWFsMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE5MDcGA1UEAwwwQW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDbGFzcyAyIFIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsLMfYaoRoPRbmDcAfXPCmKf43pWRN5yTXa/KJWO0l+mrgQvs89bANEvbDUxlkGwycwtwi5DgBuBgVhLliXu+R9CYgr2dXs8D8Hx/gsggDcyGPLmVrDOnL+dyeauheARZfA3du60fwEwwbGcVIpIxPa/4n3IS/ElxQa6DNgqxh8J9Xwh7qMGl0JK9+bALuxf7B541Gr4p0WENG8fhgjBV4w4ut9eQLOoa1eddOUSZcy46Z7allwowwgt7b5VFfx/P1iKJ3LzBMgkCK7GZ2kiLrL7RiqV+h482J7hkJD+ardoc6LnrHO/hIZymDxok+VH9fVeUdQa29IZKrIDVj65THQIDAQABo2MwYTAfBgNVHSMEGDAWgBRfdLQEwE8HWurlsdsio4dBspzhATAdBgNVHQ4EFgQUSqHkYINtUSAtDPnS8XoyoP9p7qEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAIQ8TzFy4bVIVb8+WhHKCkKNPcJe2EZuIcqvRoi727lZTJOfYy/JzLtckyZYfEI8J0lasZ29wkTta1IjSo+a6XdhudU4ONVBrL70U8Kzntplw/6TBNbLFpp7taRALjUgbCOk4EoBMbeCL0GiYYsTS0mw7xdySzmGQku4GTyqutIGPQwKxSj9iSFw1FCZqr4VP4tyXzMUgc52SzagA6i7AyLedd3tbS6lnR5BL+W9Kx9hwT8L7WANAxQzv/jGldeuSLN8bsTxlOYlsdjmIGu/C9OWblPYGpjQQIRyvs4Cc/mNhrh+14EQgwuemIIFDLOgcD+iISoN8CqegelNcJndFw1PDN6LkVoiHz9p7jzsge8RKay/QW6C03KNDpWZEUCgCUdfHfo8xKeR+LL1cfn24HKJmZt8L/aeRZwZ1jwePXFRVtiXELvgJuM/tJDIFj2KD337iV64fWcKQ/ydDVGqfDZAdcU4hQdsrPWENwPTQPfVPq2NNLMyIH9+WKx9Ed6/WzeZmIy5ZWpX1TtTolo6OJXQFeItMAjHxW/ZSZTok5IS3FuRhExturaInnzjYpx50a6kS34c5+c8hYq7sAtZ/CNLZmBnBCFDaMQqT8xFZJ5uolUaSeXxg7JFY1QsYp5RKvj4SjFwCGKJ2+hPPe9UyyltxOidNtxjaknOCeBHytOr +-----END CERTIFICATE----- diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/alipayRootCert.crt b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/alipayRootCert.crt new file mode 100644 index 0000000..76417c5 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/alipayRootCert.crt @@ -0,0 +1,88 @@ +-----BEGIN CERTIFICATE----- +MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG +EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw +MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO +UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE +MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT +V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti +W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ +MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b +53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI +pDoiVhsLwg== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIF0zCCA7ugAwIBAgIIH8+hjWpIDREwDQYJKoZIhvcNAQELBQAwejELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMTEzNDg0MFoXDTM4MDIyODEzNDg0 +MFowejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNV +BAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAtytTRcBNuur5h8xuxnlKJetT65cHGemGi8oD+beHFPTk +rUTlFt9Xn7fAVGo6QSsPb9uGLpUFGEdGmbsQ2q9cV4P89qkH04VzIPwT7AywJdt2 +xAvMs+MgHFJzOYfL1QkdOOVO7NwKxH8IvlQgFabWomWk2Ei9WfUyxFjVO1LVh0Bp +dRBeWLMkdudx0tl3+21t1apnReFNQ5nfX29xeSxIhesaMHDZFViO/DXDNW2BcTs6 +vSWKyJ4YIIIzStumD8K1xMsoaZBMDxg4itjWFaKRgNuPiIn4kjDY3kC66Sl/6yTl +YUz8AybbEsICZzssdZh7jcNb1VRfk79lgAprm/Ktl+mgrU1gaMGP1OE25JCbqli1 +Pbw/BpPynyP9+XulE+2mxFwTYhKAwpDIDKuYsFUXuo8t261pCovI1CXFzAQM2w7H +DtA2nOXSW6q0jGDJ5+WauH+K8ZSvA6x4sFo4u0KNCx0ROTBpLif6GTngqo3sj+98 +SZiMNLFMQoQkjkdN5Q5g9N6CFZPVZ6QpO0JcIc7S1le/g9z5iBKnifrKxy0TQjtG +PsDwc8ubPnRm/F82RReCoyNyx63indpgFfhN7+KxUIQ9cOwwTvemmor0A+ZQamRe +9LMuiEfEaWUDK+6O0Gl8lO571uI5onYdN1VIgOmwFbe+D8TcuzVjIZ/zvHrAGUcC +AwEAAaNdMFswCwYDVR0PBAQDAgEGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFF90 +tATATwda6uWx2yKjh0GynOEBMB8GA1UdIwQYMBaAFF90tATATwda6uWx2yKjh0Gy +nOEBMA0GCSqGSIb3DQEBCwUAA4ICAQCVYaOtqOLIpsrEikE5lb+UARNSFJg6tpkf +tJ2U8QF/DejemEHx5IClQu6ajxjtu0Aie4/3UnIXop8nH/Q57l+Wyt9T7N2WPiNq +JSlYKYbJpPF8LXbuKYG3BTFTdOVFIeRe2NUyYh/xs6bXGr4WKTXb3qBmzR02FSy3 +IODQw5Q6zpXj8prYqFHYsOvGCEc1CwJaSaYwRhTkFedJUxiyhyB5GQwoFfExCVHW +05ZFCAVYFldCJvUzfzrWubN6wX0DD2dwultgmldOn/W/n8at52mpPNvIdbZb2F41 +T0YZeoWnCJrYXjq/32oc1cmifIHqySnyMnavi75DxPCdZsCOpSAT4j4lAQRGsfgI +kkLPGQieMfNNkMCKh7qjwdXAVtdqhf0RVtFILH3OyEodlk1HYXqX5iE5wlaKzDop +PKwf2Q3BErq1xChYGGVS+dEvyXc/2nIBlt7uLWKp4XFjqekKbaGaLJdjYP5b2s7N +1dM0MXQ/f8XoXKBkJNzEiM3hfsU6DOREgMc1DIsFKxfuMwX3EkVQM1If8ghb6x5Y +jXayv+NLbidOSzk4vl5QwngO/JYFMkoc6i9LNwEaEtR9PhnrdubxmrtM+RjfBm02 +77q3dSWFESFQ4QxYWew4pHE0DpWbWy/iMIKQ6UZ5RLvB8GEcgt8ON7BBJeMc+Dyi +kT9qhqn+lw== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIICiDCCAgygAwIBAgIIQX76UsB/30owDAYIKoZIzj0EAwMFADB6MQswCQYDVQQG +EwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UECwwXQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNpYWwgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgRTEwHhcNMTkwNDI4MTYyMDQ0WhcNNDkwNDIwMTYyMDQ0 +WjB6MQswCQYDVQQGEwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UE +CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNp +YWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRTEwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAASCCRa94QI0vR5Up9Yr9HEupz6hSoyjySYqo7v837KnmjveUIUNiuC9pWAU +WP3jwLX3HkzeiNdeg22a0IZPoSUCpasufiLAnfXh6NInLiWBrjLJXDSGaY7vaokt +rpZvAdmjXTBbMAsGA1UdDwQEAwIBBjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRZ +4ZTgDpksHL2qcpkFkxD2zVd16TAfBgNVHSMEGDAWgBRZ4ZTgDpksHL2qcpkFkxD2 +zVd16TAMBggqhkjOPQQDAwUAA2gAMGUCMQD4IoqT2hTUn0jt7oXLdMJ8q4vLp6sg +wHfPiOr9gxreb+e6Oidwd2LDnC4OUqCWiF8CMAzwKs4SnDJYcMLf2vpkbuVE4dTH +Rglz+HGcTLWsFs4KxLsq7MuU+vJTBUeDJeDjdA== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIUEMdk6dVgOEIS2cCP0Q43P90Ps5YwDQYJKoZIhvcNAQEF +BQAwajELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM +E0NoaW5hIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMMH2lUcnVzQ2hpbmEgQ2xhc3Mg +MiBSb290IENBIC0gRzMwHhcNMTMwNDE4MDkzNjU2WhcNMzMwNDE4MDkzNjU2WjBq +MQswCQYDVQQGEwJDTjETMBEGA1UECgwKaVRydXNDaGluYTEcMBoGA1UECwwTQ2hp +bmEgVHJ1c3QgTmV0d29yazEoMCYGA1UEAwwfaVRydXNDaGluYSBDbGFzcyAyIFJv +b3QgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPPShpV +nJbMqqCw6Bz1kehnoPst9pkr0V9idOwU2oyS47/HjJXk9Rd5a9xfwkPO88trUpz5 +4GmmwspDXjVFu9L0eFaRuH3KMha1Ak01citbF7cQLJlS7XI+tpkTGHEY5pt3EsQg +wykfZl/A1jrnSkspMS997r2Gim54cwz+mTMgDRhZsKK/lbOeBPpWtcFizjXYCqhw +WktvQfZBYi6o4sHCshnOswi4yV1p+LuFcQ2ciYdWvULh1eZhLxHbGXyznYHi0dGN +z+I9H8aXxqAQfHVhbdHNzi77hCxFjOy+hHrGsyzjrd2swVQ2iUWP8BfEQqGLqM1g +KgWKYfcTGdbPB1MCAwEAAaNjMGEwHQYDVR0OBBYEFG/oAMxTVe7y0+408CTAK8hA +uTyRMB8GA1UdIwQYMBaAFG/oAMxTVe7y0+408CTAK8hAuTyRMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBLnUTfW7hp +emMbuUGCk7RBswzOT83bDM6824EkUnf+X0iKS95SUNGeeSWK2o/3ALJo5hi7GZr3 +U8eLaWAcYizfO99UXMRBPw5PRR+gXGEronGUugLpxsjuynoLQu8GQAeysSXKbN1I +UugDo9u8igJORYA+5ms0s5sCUySqbQ2R5z/GoceyI9LdxIVa1RjVX8pYOj8JFwtn +DJN3ftSFvNMYwRuILKuqUYSHc2GPYiHVflDh5nDymCMOQFcFG3WsEuB+EYQPFgIU +1DHmdZcz7Llx8UOZXX2JupWCYzK1XhJb+r4hK5ncf/w8qGtYlmyJpxk3hr1TfUJX +Yf4Zr0fJsGuv +-----END CERTIFICATE----- \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/aliyunAccessKey.json b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/aliyunAccessKey.json new file mode 100644 index 0000000..6a20aab --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/aliyunAccessKey.json @@ -0,0 +1,4 @@ +{ + "AccessKeyId": "<- 已脱敏,如想要执行单元测试,请开发者自行替换 ->", + "AccessKeySecret": "<- 已脱敏,如想要执行单元测试,请开发者自行替换 ->" +} diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/appCertPublicKey_2019051064521003.crt b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/appCertPublicKey_2019051064521003.crt new file mode 100644 index 0000000..ad22ab9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/appCertPublicKey_2019051064521003.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIEkzCCA3ugAwIBAgIQICABI1M0G1IN1Hv7M5NTmjANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MTkwNwYDVQQDDDBBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IENs +YXNzIDEgUjEwHhcNMjAwMTIzMDc0NTQ3WhcNMjIwMTIyMDc0NTQ3WjBbMQswCQYDVQQGEwJDTjEP +MA0GA1UECgwG6ZKf6ZuoMQ8wDQYDVQQLDAZBbGlwYXkxKjAoBgNVBAMMITIwODgwMDI2NTY3MTg5 +MjAtMjAxOTA1MTA2NDUyMTAwMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIRaW3zN +ZGJY3oOUL41KMZqcoyI9JyDWG/fyb8qShWgH9NGinO6JeGWWX2pU2b5GKCd1CB6imnbD5U3zvErR +Z6h9Kc9pD4M22MNqnpuFontWuFXhq01MIbuolV5zTw94nrMR4aMPgTt7wX6svcQ8cKyg+v7Xz4DH +QCQOPhtFM3aL1UHsEZhLp+F2xNENTGpphmlV7D50ahnAo3A8Jdkt9ZBIzkWk4CoMdeoYk6BlOETG +XZ93Mc1TKR6cLNPj7LIUKb7xUh4ekaRoky2RP7k9NgBLsZLDjMkqZmzvHHhnstddmq5Er49Ger9b +VHnKsWNMWtN0Oi+ZyWTDcwvACdCgLbcCAwEAAaOCASkwggElMB8GA1UdIwQYMBaAFHEH4gRhFuTl +8mXrMQ/J4PQ8mtWRMB0GA1UdDgQWBBSNSXcCsxvjAa3v5QcTyVZ183CMjzBABgNVHSAEOTA3MDUG +B2CBHAFuAQEwKjAoBggrBgEFBQcCARYcaHR0cDovL2NhLmFsaXBheS5jb20vY3BzLnBkZjAOBgNV +HQ8BAf8EBAMCBsAwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2NhLmFsaXBheS5jb20vY3JsMzcu +Y3JsMGAGCCsGAQUFBwEBBFQwUjAoBggrBgEFBQcwAoYcaHR0cDovL2NhLmFsaXBheS5jb20vY2E2 +LmNlcjAmBggrBgEFBQcwAYYaaHR0cDovL2NhLmFsaXBheS5jb206ODM0MC8wDQYJKoZIhvcNAQEL +BQADggEBAA0l9rTtjEl4uqE4RP4Nd+A0KgM8NmWQHLxsubDRMSeYVFMzrpSm8V9zhlxLmKdFxWP/ +OuY4SHRe8eOSA++5yJc3ihg9B7/ddK2kNTsnaB7Xtvex685kvDDR8DMZmQYeirDThGVPhUeBgPdk +wY0R5KU6mEh2FzT3QIxDzP6t4ssSyYHhFPssZ4PXHFQ5eHzmdpJ81/85crfques67JxAm4CCfldb +bX0DH1BUrPxcnvz4Kj5lKv1qIvBR71yUnrGFOKAVCx04VYK4dTNDI70W9lLgX1aTfLGUBTYiJe/J +Zq/XlYhQP/T7t8HOAaCQFf2hM9tRq62EaL1UbExV2hcAP/E= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/privateKey.json b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/privateKey.json new file mode 100644 index 0000000..39daf4d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/privateKey.json @@ -0,0 +1,4 @@ +{ + "2019022663440152": "<- 已脱敏,如想要执行单元测试,请开发者自行替换TestAccount中的相关账号并在此重新配置新的APPID与私钥的关联 ->", + "2019051064521003": "<- 已脱敏,如想要执行单元测试,请开发者自行替换TestAccount中的相关账号并在此重新配置新的APPID与私钥的关联 ->" +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/sample.mp4 b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/sample.mp4 new file mode 100644 index 0000000..26fb8b2 Binary files /dev/null and b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/sample.mp4 differ diff --git a/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/sample.png b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/sample.png new file mode 100644 index 0000000..066ec3b Binary files /dev/null and b/serve/vendor/alipaysdk/easysdk/java/src/test/resources/fixture/sample.png differ diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel.sln b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel.sln new file mode 100644 index 0000000..ad94854 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasySDKKernel", "EasySDKKernel\EasySDKKernel.csproj", "{71E029F7-98A5-40E8-8491-E75DD680E9CF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71E029F7-98A5-40E8-8491-E75DD680E9CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71E029F7-98A5-40E8-8491-E75DD680E9CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71E029F7-98A5-40E8-8491-E75DD680E9CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71E029F7-98A5-40E8-8491-E75DD680E9CF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/EasySDKKernel.csproj b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/EasySDKKernel.csproj new file mode 100644 index 0000000..402d777 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/EasySDKKernel.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.0;net461 + true + AlipayEasySDK.Kernel + antopen + antopen + Alipay Easy SDK for .NET allows you to enjoy a minimalist programming experience and quickly access the various high-frequency capabilities of the Alipay Open Platform. + zh + https://github.com/alipay/alipay-easysdk/blob/master/LICENSE + https://github.com/alipay/alipay-easysdk + Alipay Easy SDK for .NET allows you to enjoy a minimalist programming experience and quickly access the various high-frequency capabilities of the Alipay Open Platform. + Kernel for Alipay Easy SDK + 1.0.5 + + + + + + + + diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/AlipayConstants.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/AlipayConstants.cs new file mode 100644 index 0000000..f1b0f5a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/AlipayConstants.cs @@ -0,0 +1,65 @@ +using System; +using System.Text; + +namespace Alipay.EasySDK.Kernel +{ + /// + /// 支付宝开放平台网关交互常用常量 + /// + public static class AlipayConstants + { + /// + /// Config配置参数Key值 + /// + public const string PROTOCOL_CONFIG_KEY = "protocol"; + public const string HOST_CONFIG_KEY = "gatewayHost"; + public const string ALIPAY_CERT_PATH_CONFIG_KEY = "alipayCertPath"; + public const string MERCHANT_CERT_PATH_CONFIG_KEY = "merchantCertPath"; + public const string ALIPAY_ROOT_CERT_PATH_CONFIG_KEY = "alipayRootCertPath"; + public const string SIGN_TYPE_CONFIG_KEY = "signType"; + public const string NOTIFY_URL_CONFIG_KEY = "notifyUrl"; + + /// + /// 与网关HTTP交互中涉及到的字段值 + /// + public const string BIZ_CONTENT_FIELD = "biz_content"; + public const string ALIPAY_CERT_SN_FIELD = "alipay_cert_sn"; + public const string SIGN_FIELD = "sign"; + public const string SIGN_TYPE_FIELD = "sign_type"; + public const string BODY_FIELD = "http_body"; + public const string NOTIFY_URL_FIELD = "notify_url"; + public const string METHOD_FIELD = "method"; + public const string RESPONSE_SUFFIX = "_response"; + public const string ERROR_RESPONSE = "error_response"; + + /// + /// 默认字符集编码,EasySDK统一固定使用UTF-8编码,无需用户感知编码,用户面对的总是String而不是bytes + /// + public readonly static Encoding DEFAULT_CHARSET = Encoding.UTF8; + + /// + /// 默认的签名算法,EasySDK统一固定使用RSA2签名算法(即SHA_256_WITH_RSA),但此参数依然需要用户指定以便用户感知,因为在开放平台接口签名配置界面中需要选择同样的算法 + /// + public const string RSA2 = "RSA2"; + + /// + /// RSA2对应的真实签名算法名称 + /// + public const string SHA_256_WITH_RSA = "SHA256WithRSA"; + + /// + /// RSA2对应的真实非对称加密算法名称 + /// + public const string RSA = "RSA"; + + /// + /// 申请生成的重定向网页的请求类型,GET表示生成URL + /// + public const string GET = "GET"; + + /// + /// 申请生成的重定向网页的请求类型,POST表示生成form表单 + /// + public const string POST = "POST"; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/CertEnvironment.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/CertEnvironment.cs new file mode 100644 index 0000000..2597cbe --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/CertEnvironment.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Org.BouncyCastle.X509; +using Alipay.EasySDK.Kernel.Util; +using System.Linq; + +namespace Alipay.EasySDK.Kernel +{ + /// + /// 证书模式运行时环境 + /// + public class CertEnvironment + { + + /// + /// 支付宝根证书内容 + /// + public string RootCertContent { get; set; } + + /// + /// 支付宝根证书序列号 + /// + public string RootCertSN { get; set; } + + /// + /// 商户应用公钥证书序列号 + /// + public string MerchantCertSN { get; set; } + + /// + /// 缓存的不同支付宝公钥证书序列号对应的支付宝公钥 + /// + private readonly Dictionary CachedAlipayPublicKey = new Dictionary(); + + /// + /// 构造证书运行环境 + /// + /// 商户公钥证书路径 + /// 支付宝公钥证书路径 + /// 支付宝根证书路径 + public CertEnvironment(string merchantCertPath, string alipayCertPath, string alipayRootCertPath) + { + if (string.IsNullOrEmpty(merchantCertPath) || string.IsNullOrEmpty(alipayCertPath) || string.IsNullOrEmpty(alipayCertPath)) + { + throw new Exception("证书参数merchantCertPath、alipayCertPath或alipayRootCertPath设置不完整。"); + } + + this.RootCertContent = File.ReadAllText(alipayRootCertPath); + this.RootCertSN = AntCertificationUtil.GetRootCertSN(RootCertContent); + + X509Certificate merchantCert = AntCertificationUtil.ParseCert(File.ReadAllText(merchantCertPath)); + this.MerchantCertSN = AntCertificationUtil.GetCertSN(merchantCert); + + X509Certificate alipayCert = AntCertificationUtil.ParseCert(File.ReadAllText(alipayCertPath)); + string alipayCertSN = AntCertificationUtil.GetCertSN(alipayCert); + string alipayPublicKey = AntCertificationUtil.ExtractPemPublicKeyFromCert(alipayCert); + CachedAlipayPublicKey[alipayCertSN] = alipayPublicKey; + } + + public string GetAlipayPublicKey(string sn) + { + //如果没有指定sn,则默认取缓存中的第一个值 + if (string.IsNullOrEmpty(sn)) + { + return CachedAlipayPublicKey.Values.FirstOrDefault(); + } + + if (CachedAlipayPublicKey.ContainsKey(sn)) + { + return CachedAlipayPublicKey[sn]; + } + else + { + //网关在支付宝公钥证书变更前,一定会确认通知到商户并在商户做出反馈后,才会更新该商户的支付宝公钥证书 + //TODO: 后续可以考虑加入自动升级支付宝公钥证书逻辑,注意并发更新冲突问题 + throw new Exception("支付宝公钥证书[" + sn + "]已过期,请重新下载最新支付宝公钥证书并替换原证书文件"); + } + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Client.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Client.cs new file mode 100644 index 0000000..dfb84df --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Client.cs @@ -0,0 +1,521 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Web; +using System.IO; +using System.Threading.Tasks; +using Newtonsoft.Json; + +using Alipay.EasySDK.Kernel.Util; + +using Tea; + +namespace Alipay.EasySDK.Kernel +{ + /// + /// Tea DSL编排所需实现的原子方法 + /// + public class Client + { + /// + /// 构造成本较高的一些参数缓存在上下文中 + /// + private readonly Context context; + + /// + /// 注入的可选额外文本参数集合 + /// + private readonly Dictionary optionalTextParams = new Dictionary(); + + /// + /// 注入的可选业务参数集合 + /// + private readonly Dictionary optionalBizParams = new Dictionary(); + + /// + /// 构造函数 + /// + /// 上下文对象 + public Client(Context context) + { + this.context = context; + } + + /// + /// 注入额外文本参数 + /// + /// 参数名称 + /// 参数的值 + /// 本客户端本身,便于链路调用 + public Client InjectTextParam(String key, String value) + { + optionalTextParams.Add(key, value); + return this; + } + + /// + /// 注入额外业务参数 + /// + /// 参数名称 + /// 参数的值 + /// 本客户端本身,便于链式调用 + public Client InjectBizParam(String key, Object value) + { + optionalBizParams.Add(key, value); + return this; + } + + /// + /// 获取Config中的配置项 + /// + /// 配置项的名称 + /// 配置项的值 + public string GetConfig(string key) + { + return context.GetConfig(key); + } + + /// + /// 是否是证书模式 + /// + /// true:是;false:不是 + public bool IsCertMode() + { + return context.CertEnvironment != null; + } + + /// + /// 获取时间戳,格式yyyy-MM-dd HH:mm:ss + /// + /// 当前时间戳 + public string GetTimestamp() + { + return DateTime.UtcNow.AddHours(8).ToString("yyyy-MM-dd HH:mm:ss"); + } + + /// + /// 计算签名,注意要去除key或value为null的键值对 + /// + /// 系统参数集合 + /// 业务参数集合 + /// 其他额外文本参数集合 + /// 私钥 + /// 签名值的Base64串 + public string Sign(Dictionary systemParams, Dictionary bizParams, + Dictionary textParams, string privateKey) + { + IDictionary sortedMap = GetSortedMap(systemParams, bizParams, textParams); + + StringBuilder content = new StringBuilder(); + foreach (var pair in sortedMap) + { + if (!string.IsNullOrEmpty(pair.Key) && !string.IsNullOrEmpty(pair.Value)) + { + content.Append(pair.Key).Append("=").Append(pair.Value).Append("&"); + } + } + if (content.Length > 0) + { + //去除尾巴上的& + content.Remove(content.Length - 1, 1); + } + + return Signer.Sign(content.ToString(), privateKey); + } + + private IDictionary GetSortedMap(Dictionary systemParams, + Dictionary bizParams, Dictionary textParams) + { + AddOtherParams(textParams, bizParams); + + IDictionary sortedMap = new SortedDictionary(systemParams, StringComparer.Ordinal); + if (bizParams != null && bizParams.Count != 0) + { + sortedMap.Add(AlipayConstants.BIZ_CONTENT_FIELD, JsonUtil.ToJsonString(bizParams)); + } + + if (textParams != null) + { + foreach (var pair in textParams) + { + sortedMap.Add(pair.Key, pair.Value); + } + } + + SetNotifyUrl(sortedMap); + + return sortedMap; + } + + private void SetNotifyUrl(IDictionary paramters) + { + if (GetConfig(AlipayConstants.NOTIFY_URL_CONFIG_KEY) != null && !paramters.ContainsKey(AlipayConstants.NOTIFY_URL_FIELD)) + { + paramters.Add(AlipayConstants.NOTIFY_URL_FIELD, GetConfig(AlipayConstants.NOTIFY_URL_CONFIG_KEY)); + } + } + + /// + /// 获取商户应用公钥证书序列号,从证书模式运行时环境对象中直接读取 + /// + /// 商户应用公钥证书序列号 + public string GetMerchantCertSN() + { + if (context.CertEnvironment == null) + { + return null; + } + + return context.CertEnvironment.MerchantCertSN; + } + + /// + /// 获取支付宝根证书序列号,从证书模式运行时环境对象中直接读取 + /// + /// 支付宝根证书序列号 + public string GetAlipayRootCertSN() + { + if (context.CertEnvironment == null) + { + return null; + } + return context.CertEnvironment.RootCertSN; + } + + /// + /// 将业务参数和其他额外文本参数按www-form-urlencoded格式转换成HTTP Body中的字节数组,注意要做URL Encode + /// + /// 业务参数 + /// HTTP Body中的字节数组 + public byte[] ToUrlEncodedRequestBody(Dictionary bizParams) + { + + IDictionary sortedMap = GetSortedMap(new Dictionary(), bizParams, null); + return AlipayConstants.DEFAULT_CHARSET.GetBytes(BuildQueryString(sortedMap)); + } + + private string BuildQueryString(IDictionary sortedMap) + { + StringBuilder content = new StringBuilder(); + int index = 0; + foreach (var pair in sortedMap) + { + if (!string.IsNullOrEmpty(pair.Key) && !string.IsNullOrEmpty(pair.Value)) + { + content.Append(index == 0 ? "" : "&") + .Append(pair.Key) + .Append("=") + .Append(HttpUtility.UrlEncode(pair.Value, AlipayConstants.DEFAULT_CHARSET)); + index++; + } + } + return content.ToString(); + } + + /// + /// 生成随机分界符,用于multipart格式的HTTP请求Body的多个字段间的分隔 + /// + /// 随机分界符 + public string GetRandomBoundary() + { + return DateTime.Now.Ticks.ToString("X"); + } + + /// + /// 字符串拼接 + /// + /// 字符串a + /// 字符串b + /// 字符串a和b拼接后的字符串 + public string ConcatStr(string a, string b) + { + return a + b; + } + + /// + /// 将其他额外文本参数和文件参数按multipart/form-data格式转换成HTTP Body中的字节数组流 + /// + /// 其他额外文本参数 + /// 业务文件参数 + /// HTTP Body中multipart格式的分隔符 + /// Multipart格式的字节流 + public Stream ToMultipartRequestBody(Dictionary textParams, Dictionary fileParams, string boundary) + { + MemoryStream stream = new MemoryStream(); + + //补充其他额外参数 + AddOtherParams(textParams, null); + + foreach (var pair in textParams) + { + if (!string.IsNullOrEmpty(pair.Key) && !string.IsNullOrEmpty(pair.Value)) + { + MultipartUtil.WriteToStream(stream, MultipartUtil.GetEntryBoundary(boundary)); + MultipartUtil.WriteToStream(stream, MultipartUtil.GetTextEntry(pair.Key, pair.Value)); + } + } + + //组装文件参数 + foreach (var pair in fileParams) + { + if (!string.IsNullOrEmpty(pair.Key) && pair.Value != null) + { + MultipartUtil.WriteToStream(stream, MultipartUtil.GetEntryBoundary(boundary)); + MultipartUtil.WriteToStream(stream, MultipartUtil.GetFileEntry(pair.Key, pair.Value)); + MultipartUtil.WriteToStream(stream, File.ReadAllBytes(pair.Value)); + } + } + + //添加结束标记 + MultipartUtil.WriteToStream(stream, MultipartUtil.GetEndBoundary(boundary)); + + stream.Seek(0, SeekOrigin.Begin); + return stream; + } + + /// + /// 将网关响应发序列化成Map,同时将API的接口名称和响应原文插入到响应Map的method和body字段中 + /// + /// HTTP响应 + /// 调用的OpenAPI的接口名称 + /// 响应反序列化的Map + public Dictionary ReadAsJson(TeaResponse response, string method) + { + string responseBody = TeaCore.GetResponseBody(response); + Dictionary dictionary = JsonConvert.DeserializeObject>(responseBody); + dictionary.Add(AlipayConstants.BODY_FIELD, responseBody); + dictionary.Add(AlipayConstants.METHOD_FIELD, method); + return DictionaryUtil.ObjToDictionary(dictionary); + } + + /// + /// 适配Tea DSL自动生成的代码 + /// + public async Task> ReadAsJsonAsync(TeaResponse response, string method) + { + return ReadAsJson(response, method); + } + + /// + /// 从响应Map中提取支付宝公钥证书序列号 + /// + /// 响应Map + /// 支付宝公钥证书序列号 + public string GetAlipayCertSN(Dictionary respMap) + { + return (string)respMap[AlipayConstants.ALIPAY_CERT_SN_FIELD]; + } + + /// + /// 获取支付宝公钥,从证书运行时环境对象中直接读取 + /// 如果缓存的用户指定的支付宝公钥证书的序列号与网关响应中携带的支付宝公钥证书序列号不一致,需要报错给出提示或自动更新支付宝公钥证书 + /// + /// 网关响应中携带的支付宝公钥证书序列号 + /// 支付宝公钥 + public string ExtractAlipayPublicKey(string alipayCertSN) + { + if (context.CertEnvironment == null) + { + return null; + } + return context.CertEnvironment.GetAlipayPublicKey(alipayCertSN); + } + + /// + /// 验证签名 + /// + /// 响应Map,可以从中提取出sign和body + /// 支付宝公钥 + /// true:验签通过;false:验签不通过 + public bool Verify(Dictionary respMap, string alipayPublicKey) + { + string sign = (string)respMap[AlipayConstants.SIGN_FIELD]; + string content = SignContentExtractor.GetSignSourceData((string)respMap[AlipayConstants.BODY_FIELD], + (string)respMap[AlipayConstants.METHOD_FIELD]); + return Signer.Verify(content, sign, alipayPublicKey); + } + + /// + /// 从响应Map中提取返回值对象的Map,并将响应原文插入到body字段中 + /// + /// 响应Map + /// 返回值对象Map + public Dictionary ToRespModel(Dictionary respMap) + { + string methodName = (string)respMap[AlipayConstants.METHOD_FIELD]; + string responseNodeName = methodName.Replace('.', '_') + AlipayConstants.RESPONSE_SUFFIX; + string errorNodeName = AlipayConstants.ERROR_RESPONSE; + + //先找正常响应节点 + foreach (var pair in respMap) + { + if (responseNodeName.Equals(pair.Key)) + { + Dictionary model = (Dictionary)pair.Value; + model.Add(AlipayConstants.BODY_FIELD, respMap[AlipayConstants.BODY_FIELD]); + return model; + } + } + + //再找异常响应节点 + foreach (var pair in respMap) + { + if (errorNodeName.Equals(pair.Key)) + { + Dictionary model = (Dictionary)pair.Value; + model.Add(AlipayConstants.BODY_FIELD, respMap[AlipayConstants.BODY_FIELD]); + return model; + } + } + + throw new Exception("响应格式不符合预期,找不到" + responseNodeName + "节点"); + } + + /// + /// 生成页面类请求所需URL或Form表单 + /// + /// GET或POST,决定是生成URL还是Form表单 + /// 系统参数集合 + /// 业务参数集合 + /// 其他额外文本参数集合 + /// 所有参数的签名值 + /// 生成的URL字符串或表单 + public string GeneratePage(string method, Dictionary systemParams, Dictionary bizParams, + Dictionary textParams, string sign) + { + if (AlipayConstants.GET.Equals(method)) + { + //采集并排序所有参数 + IDictionary sortedMap = GetSortedMap(systemParams, bizParams, textParams); + sortedMap.Add(AlipayConstants.SIGN_FIELD, sign); + + //将所有参数置于URL中 + return GetGatewayServerUrl() + "?" + BuildQueryString(sortedMap); + } + else if (AlipayConstants.POST.Equals(method)) + { + //将系统参数、额外文本参数排序后置于URL中 + IDictionary urlParams = GetSortedMap(systemParams, null, textParams); + urlParams.Add(AlipayConstants.SIGN_FIELD, sign); + string actionUrl = GetGatewayServerUrl() + "?" + BuildQueryString(urlParams); + + //将业务参数排序后置于form表单中 + AddOtherParams(null, bizParams); + IDictionary formParams = new SortedDictionary() + { + { AlipayConstants.BIZ_CONTENT_FIELD, JsonUtil.ToJsonString(bizParams)} + }; + return PageUtil.BuildForm(actionUrl, formParams); + } + else + { + throw new Exception("_generatePage中method只支持传入GET或POST"); + } + } + + /// + /// 生成订单串 + /// + /// 系统参数集合 + /// 业务参数集合 + /// 其他文本参数集合 + /// 所有参数的签名值 + /// 订单串 + public string GenerateOrderString(Dictionary systemParams, Dictionary bizParams, + Dictionary textParams, string sign) + { + //采集并排序所有参数 + IDictionary sortedMap = GetSortedMap(systemParams, bizParams, textParams); + sortedMap.Add(AlipayConstants.SIGN_FIELD, sign); + + //将所有参数置于URL中 + return BuildQueryString(sortedMap); + } + + private string GetGatewayServerUrl() + { + return GetConfig(AlipayConstants.PROTOCOL_CONFIG_KEY) + "://" + GetConfig(AlipayConstants.HOST_CONFIG_KEY) + "/gateway.do"; + } + + /// + /// AES加密 + /// + /// 明文 + /// 密钥 + /// 密文 + public string AesEncrypt(string plainText, string key) + { + return AES.Encrypt(plainText, key); + } + + /// + /// AES解密 + /// + /// 密文 + /// 密钥 + /// 明文 + public string AesDecrypt(string chiperText, string key) + { + return AES.Decrypt(chiperText, key); + } + + /// + /// 对支付类请求的异步通知的参数集合进行验签 + /// + /// 参数集合 + /// 支付宝公钥 + /// true:验证成功;false:验证失败 + public bool VerifyParams(Dictionary parameters, string alipayPublicKey) + { + return Signer.VerifyParams(parameters, alipayPublicKey); + } + + /// + /// 获取SDK版本信息 + /// + /// SDK版本信息 + public string GetSdkVersion() + { + return context.SdkVersion; + } + + /// + /// 将随机顺序的Map转换为有序的Map + /// + /// 随机顺序的Map + /// 有序的Map + public Dictionary SortMap(Dictionary input) + { + //GO语言的Map是随机顺序的,每次访问顺序都不同,才需排序 + return input; + } + + private void AddOtherParams(Dictionary textParams, Dictionary bizParams) + { + //为null表示此处不是扩展此类参数的时机 + if (textParams != null) + { + foreach (var pair in optionalTextParams) + { + if (!textParams.ContainsKey(pair.Key)) + { + textParams.Add(pair.Key, pair.Value); + } + } + SetNotifyUrl(textParams); + } + + //为null表示此处不是扩展此类参数的时机 + if (bizParams != null) + { + foreach (var pair in optionalBizParams) + { + if (!bizParams.ContainsKey(pair.Key)) + { + bizParams.Add(pair.Key, pair.Value); + } + } + } + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Config.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Config.cs new file mode 100644 index 0000000..8ea7802 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Config.cs @@ -0,0 +1,106 @@ +using Tea; + +namespace Alipay.EasySDK.Kernel +{ + /// + /// 客户端配置参数模型 + /// + public class Config : TeaModel + { + /// + /// 通信协议,通常填写https + /// + [NameInMap("protocol")] + [Validation(Required = true)] + public string Protocol { get; set; } = "https"; + + /// + /// 网关域名 + /// 线上为:openapi.alipay.com + /// 沙箱为:openapi.alipaydev.com + /// + [NameInMap("gatewayHost")] + [Validation(Required = true)] + public string GatewayHost { get; set; } = "openapi.alipay.com"; + + /// + /// AppId + /// + [NameInMap("appId")] + [Validation(Required = true)] + public string AppId { get; set; } + + /// + /// 签名类型,Alipay Easy SDK只推荐使用RSA2,估此处固定填写RSA2 + /// + [NameInMap("signType")] + [Validation(Required = true)] + public string SignType { get; set; } = "RSA2"; + + /// + /// 支付宝公钥 + /// + [NameInMap("alipayPublicKey")] + [Validation(Required = true)] + public string AlipayPublicKey { get; set; } + + /// + /// 应用私钥 + /// + [NameInMap("merchantPrivateKey")] + [Validation(Required = true)] + public string MerchantPrivateKey { get; set; } + + /// + /// 应用公钥证书文件路径 + /// + [NameInMap("merchantCertPath")] + [Validation(Required = true)] + public string MerchantCertPath { get; set; } + + /// + /// 支付宝公钥证书文件路径 + /// + [NameInMap("alipayCertPath")] + [Validation(Required = true)] + public string AlipayCertPath { get; set; } + + /// + /// 支付宝根证书文件路径 + /// + [NameInMap("alipayRootCertPath")] + [Validation(Required = true)] + public string AlipayRootCertPath { get; set; } + + /// + /// 异步通知回调地址(可选) + /// + [NameInMap("notifyUrl")] + [Validation(Required = true)] + public string NotifyUrl { get; set; } + + /// + /// AES密钥(可选) + /// + [NameInMap("encryptKey")] + [Validation(Required = true)] + public string EncryptKey { get; set; } + + + /// + /// 代理地址(可选)例如:http://127.0.0.1:8080 + /// + [NameInMap("httpProxy")] + [Validation(Required = true)] + public string HttpProxy { get; set; } + + /// + /// 忽略证书校验(可选) + /// + [NameInMap("ignoreSSL")] + [Validation(Required = true)] + public string IgnoreSSL { get; set; } + + } + +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Context.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Context.cs new file mode 100644 index 0000000..1a4d8a9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Context.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Tea; +using Alipay.EasySDK.Kernel.Util; + +namespace Alipay.EasySDK.Kernel +{ + public class Context + { + /// + /// 客户端配置参数 + /// + private readonly Dictionary config; + + /// + /// 证书模式运行时环境 + /// + public CertEnvironment CertEnvironment { get; } + + /// + /// SDK版本号 + /// + public string SdkVersion { get; set; } + + public Context(Config config, string sdkVersion) + { + this.config = config.ToMap(); + SdkVersion = sdkVersion; + ArgumentValidator.CheckArgument(AlipayConstants.RSA2.Equals(GetConfig(AlipayConstants.SIGN_TYPE_CONFIG_KEY)), + "Alipay Easy SDK只允许使用RSA2签名方式,RSA签名方式由于安全性相比RSA2弱已不再推荐。"); + + if (!string.IsNullOrEmpty(GetConfig(AlipayConstants.ALIPAY_CERT_PATH_CONFIG_KEY))) + { + CertEnvironment = new CertEnvironment( + GetConfig(AlipayConstants.MERCHANT_CERT_PATH_CONFIG_KEY), + GetConfig(AlipayConstants.ALIPAY_CERT_PATH_CONFIG_KEY), + GetConfig(AlipayConstants.ALIPAY_ROOT_CERT_PATH_CONFIG_KEY)); + } + } + + public string GetConfig(string key) + { + return (string)config[key]; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/AES.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/AES.cs new file mode 100644 index 0000000..351acb7 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/AES.cs @@ -0,0 +1,88 @@ +using System; +using System.Text; +using System.Security.Cryptography; + +namespace Alipay.EasySDK.Kernel.Util +{ + public class AES + { + /// + /// 128位全0初始向量 + /// + private static readonly byte[] AES_IV = InitIV(16); + + /// + /// AES加密 + /// + /// 明文 + /// 对称密钥 + /// 密文 + public static string Encrypt(string plainText, string key) + { + try + { + byte[] keyBytes = Convert.FromBase64String(key); + byte[] plainBytes = AlipayConstants.DEFAULT_CHARSET.GetBytes(plainText); ; + + RijndaelManaged rijndatel = new RijndaelManaged + { + Key = keyBytes, + Mode = CipherMode.CBC, + Padding = PaddingMode.PKCS7, + IV = AES_IV + }; + + ICryptoTransform transform = rijndatel.CreateEncryptor(rijndatel.Key, rijndatel.IV); + byte[] cipherBytes = transform.TransformFinalBlock(plainBytes, 0, plainBytes.Length); + return Convert.ToBase64String(cipherBytes); + } + catch (Exception e) + { + throw new Exception("AES加密失败,plainText=" + plainText + + ",keySize=" + key.Length + "。" + e.Message, e); + } + } + + /// + /// AES解密 + /// + /// 密文 + /// 对称密钥 + /// 明文 + public static string Decrypt(string cipherText, string key) + { + try + { + byte[] keyBytes = Convert.FromBase64String(key); + byte[] cipherBytes = Convert.FromBase64String(cipherText); + + RijndaelManaged rijndatel = new RijndaelManaged + { + Key = keyBytes, + Mode = CipherMode.CBC, + Padding = PaddingMode.PKCS7, + IV = AES_IV + }; + + ICryptoTransform transform = rijndatel.CreateDecryptor(rijndatel.Key, rijndatel.IV); + byte[] plainBytes = transform.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length); + return AlipayConstants.DEFAULT_CHARSET.GetString(plainBytes); + } + catch (Exception e) + { + throw new Exception("AES解密失败,ciphertext=" + cipherText + + ",keySize=" + key.Length + "。" + e.Message, e); + } + } + + private static byte[] InitIV(int blockSize) + { + byte[] iv = new byte[blockSize]; + for (int i = 0; i < blockSize; ++i) + { + iv[i] = 0x0; + } + return iv; + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/AntCertificationUtil.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/AntCertificationUtil.cs new file mode 100644 index 0000000..006d70f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/AntCertificationUtil.cs @@ -0,0 +1,326 @@ +using System.Collections.Generic; +using System; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using System.Security.Cryptography; +using System.Text; +using System.Linq; + +namespace Alipay.EasySDK.Kernel.Util +{ + /// + /// 证书相关工具类 + /// + public static class AntCertificationUtil + { + /// + /// 提取根证书序列号 + /// + /// 根证书文本 + /// 根证书序列号 + public static string GetRootCertSN(string rootCertContent) + { + string rootCertSN = ""; + try + { + List x509Certificates = ReadPemCertChain(rootCertContent); + foreach (X509Certificate cert in x509Certificates) + { + //只提取与指定算法类型匹配的证书的序列号 + if (cert.SigAlgOid.StartsWith("1.2.840.113549.1.1", StringComparison.Ordinal)) + { + string certSN = GetCertSN(cert); + if (string.IsNullOrEmpty(rootCertSN)) + { + rootCertSN = certSN; + } + else + { + rootCertSN = rootCertSN + "_" + certSN; + } + } + } + } + catch (Exception ex) + { + throw new Exception("提取根证书序列号失败。" + ex.Message); + } + return rootCertSN; + } + + /// + /// 反序列化证书文本 + /// + /// 证书文本 + /// X509Certificate证书对象 + public static X509Certificate ParseCert(string certContent) + { + return new X509CertificateParser().ReadCertificate(Encoding.UTF8.GetBytes(certContent)); + } + + /// + /// 计算指定证书的序列号 + /// + /// 证书 + /// 序列号 + public static string GetCertSN(X509Certificate cert) + { + string issuerDN = cert.IssuerDN.ToString(); + //提取出的证书的issuerDN本身是以CN开头的,则无需逆序,直接返回 + if (issuerDN.StartsWith("CN", StringComparison.Ordinal)) + { + return CalculateMd5(issuerDN + cert.SerialNumber); + } + List attributes = issuerDN.Split(',').ToList(); + attributes.Reverse(); + return CalculateMd5(string.Join(",", attributes.ToArray()) + cert.SerialNumber); + } + + /// + /// 校验证书链是否可信 + /// + /// 需要验证的目标证书或者证书链文本 + /// 可信根证书列表文本 + /// true:证书可信;false:证书不可信 + public static bool IsTrusted(string certContent, string rootCertContent) + { + List certs = ReadPemCertChain(certContent); + List rootCerts = ReadPemCertChain(rootCertContent); + return VerifyCertChain(certs, rootCerts); + } + + /// + /// 从证书链文本反序列化证书链集合 + /// + /// 证书链文本 + /// 证书链集合 + private static List ReadPemCertChain(string cert) + { + System.Collections.ICollection collection = new X509CertificateParser().ReadCertificates(Encoding.UTF8.GetBytes(cert)); + List result = new List(); + foreach (var each in collection) + { + result.Add((X509Certificate)each); + } + return result; + } + + /// + /// 将证书链按照完整的签发顺序进行排序,排序后证书链为:[issuerA, subjectA]-[issuerA, subjectB]-[issuerB, subjectC]-[issuerC, subjectD]... + /// + /// 未排序的证书链 + /// true:排序成功;false:证书链不完整 + private static bool SortCertChain(List certChain) + { + //主题和证书的映射 + Dictionary subject2CertMap = new Dictionary(); + //签发者和证书的映射 + Dictionary issuer2CertMap = new Dictionary(); + //是否包含自签名证书 + bool hasSelfSignedCert = false; + foreach (X509Certificate cert in certChain) + { + if (IsSelfSigned(cert)) + { + if (hasSelfSignedCert) + { + //同一条证书链中只能有一个自签名证书 + return false; + } + hasSelfSignedCert = true; + } + subject2CertMap[cert.SubjectDN] = cert; + issuer2CertMap[cert.IssuerDN] = cert; + } + + List orderedCertChain = new List(); + + X509Certificate current = certChain[0]; + + AddressingUp(subject2CertMap, orderedCertChain, current); + AddressingDown(issuer2CertMap, orderedCertChain, current); + + //说明证书链不完整 + if (certChain.Count != orderedCertChain.Count) + { + return false; + } + + //用排序后的结果覆盖传入的证书链集合 + for (int i = 0; i < orderedCertChain.Count; i++) + { + certChain[i] = orderedCertChain[i]; + } + return true; + } + + private static bool IsSelfSigned(X509Certificate cert) + { + return cert.SubjectDN.Equivalent(cert.IssuerDN); + } + + /// + /// 向上构造证书链 + /// + /// 主题与证书的映射 + /// 储存排序后的证书链集合 + /// 当前需要插入排序后的证书链集合中的证书 + private static void AddressingUp(Dictionary subject2CertMap, + List orderedCertChain, X509Certificate current) + { + orderedCertChain.Insert(0, current); + if (IsSelfSigned(current)) + { + return; + } + + if (!subject2CertMap.ContainsKey(current.IssuerDN)) + { + return; + } + + X509Certificate issuer = subject2CertMap[current.IssuerDN]; + AddressingUp(subject2CertMap, orderedCertChain, issuer); + } + + /// + /// 向下构造证书链 + /// + /// 签发者和证书的映射 + /// 储存排序后的证书链集合 + /// 当前需要插入排序后的证书链集合中的证书 + private static void AddressingDown(Dictionary issuer2CertMap, + List certChain, X509Certificate current) + { + if (!issuer2CertMap.ContainsKey(current.SubjectDN)) + { + return; + } + + X509Certificate subject = issuer2CertMap[current.SubjectDN]; + if (IsSelfSigned(subject)) + { + return; + } + certChain.Add(subject); + AddressingDown(issuer2CertMap, certChain, subject); + } + + /// + /// 验证证书是否是信任证书库中的证书签发的 + /// + /// 待验证证书 + /// 可信根证书列表 + /// true:验证通过;false:验证不通过 + private static bool VerifyCert(X509Certificate cert, List rootCerts) + { + if (!cert.IsValidNow) + { + return false; + } + + Dictionary subject2CertMap = new Dictionary(); + foreach (X509Certificate root in rootCerts) + { + subject2CertMap[root.SubjectDN] = root; + } + + X509Name issuerDN = cert.IssuerDN; + if (!subject2CertMap.ContainsKey(issuerDN)) + { + return false; + } + + X509Certificate issuer = subject2CertMap[issuerDN]; + try + { + AsymmetricKeyParameter publicKey = issuer.GetPublicKey(); + cert.Verify(publicKey); + } + catch (Exception ex) + { + Console.WriteLine("证书验证出现异常。" + ex.Message); + return false; + } + return true; + } + + /// + /// 验证证书列表 + /// + /// 待验证的证书列表 + /// 可信根证书列表 + /// true:验证通过;false:验证不通过 + private static bool VerifyCertChain(List certs, List rootCerts) + { + //证书列表排序,形成排序后的证书链 + bool sorted = SortCertChain(certs); + if (!sorted) + { + //不是完整的证书链 + return false; + } + + //先验证第一个证书是不是信任库中证书签发的 + X509Certificate previous = certs[0]; + bool firstOK = VerifyCert(previous, rootCerts); + if (!firstOK || certs.Count == 1) + { + return firstOK; + } + + //验证证书链 + for (int i = 1; i < certs.Count; i++) + { + try + { + X509Certificate cert = certs[i]; + if (!cert.IsValidNow) + { + return false; + } + + //用上级证书的公钥验证本证书是否是上级证书签发的 + cert.Verify(previous.GetPublicKey()); + + previous = cert; + } + catch (Exception ex) + { + //证书链验证失败 + Console.WriteLine("证书链验证失败。" + ex.Message); + return false; + } + } + + return true; + } + + + private static string CalculateMd5(string input) + { + using (MD5 md5 = new MD5CryptoServiceProvider()) + { + string result = ""; + byte[] bytes = md5.ComputeHash(Encoding.GetEncoding("utf-8").GetBytes(input)); + for (int i = 0; i < bytes.Length; i++) + { + result += bytes[i].ToString("x2"); + } + return result; + } + } + + /// + /// 从证书中提取公钥并转换为PEM编码 + /// + /// 证书 + /// PEM编码公钥 + public static string ExtractPemPublicKeyFromCert(X509Certificate input) + { + SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(input.GetPublicKey()); + return Convert.ToBase64String(subjectPublicKeyInfo.GetDerEncoded()); + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/ArgumentValidator.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/ArgumentValidator.cs new file mode 100644 index 0000000..228f898 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/ArgumentValidator.cs @@ -0,0 +1,34 @@ +using System; + +namespace Alipay.EasySDK.Kernel.Util +{ + /// + /// 参数校验类 + /// + public static class ArgumentValidator + { + public static void CheckArgument(bool expression, string errorMessage) + { + if (!expression) + { + throw new Exception(errorMessage); + } + } + + public static void CheckNotNull(object value, string errorMessage) + { + if (value == null) + { + throw new Exception(errorMessage); + } + } + + public static void EnsureNull(object value, string errorMessage) + { + if (value != null) + { + throw new Exception(errorMessage); + } + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/DictionaryUtil.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/DictionaryUtil.cs new file mode 100644 index 0000000..e9e843f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/DictionaryUtil.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; + +namespace Alipay.EasySDK.Kernel.Util +{ + /// + /// 字典工具类 + /// + public static class DictionaryUtil + { + /// + /// 将字典各层次Value中的JObject和JArray转换成C#标准库中的Dictionary和List + /// + /// 输入字典 + /// 转换后的输出字典 + public static Dictionary ObjToDictionary(Dictionary dicObj) + { + Dictionary dic = new Dictionary(); + foreach (string key in dicObj.Keys) + { + if (dicObj[key] is JArray) + { + List> dicObjList = ((JArray)dicObj[key]).ToObject>>(); + List> dicList = new List>(); + foreach (Dictionary objItem in dicObjList) + { + dicList.Add(ObjToDictionary(objItem)); + } + dic.Add(key, dicList); + } + else if (dicObj[key] is JObject) + { + Dictionary dicJObj = ((JObject)dicObj[key]).ToObject>(); + dic.Add(key, ObjToDictionary(dicJObj)); + } + else + { + dic.Add(key, dicObj[key]); + } + } + return dic; + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/JsonUtil.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/JsonUtil.cs new file mode 100644 index 0000000..61ba186 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/JsonUtil.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using Tea; +using Newtonsoft.Json; + +namespace Alipay.EasySDK.Kernel.Util +{ + /// + /// JSON工具类 + /// + public class JsonUtil + { + /// + /// 将字典集合转换为Json字符串,转换过程中对于TeaModel,使用标注的字段名称而不是字段的变量名 + /// + /// 字典集合 + /// Json字符串 + public static string ToJsonString(IDictionary input) + { + IDictionary result = new Dictionary(); + foreach (var pair in input) + { + if (pair.Value is TeaModel) + { + result.Add(pair.Key, GetTeaModelMap((TeaModel)pair.Value)); + } + else + { + result.Add(pair.Key, pair.Value); + } + } + return JsonConvert.SerializeObject(result); + } + + private static IDictionary GetTeaModelMap(TeaModel teaModel) + { + + IDictionary result = new Dictionary(); + IDictionary teaModelMap = teaModel.ToMap(); + foreach (var pair in teaModelMap) + { + if (pair.Value is TeaModel) + { + result.Add(pair.Key, GetTeaModelMap((TeaModel)pair.Value)); + } + else + { + result.Add(pair.Key, pair.Value); + } + } + return result; + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/MultipartUtil.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/MultipartUtil.cs new file mode 100644 index 0000000..bec7d38 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/MultipartUtil.cs @@ -0,0 +1,79 @@ +using System; +using System.Text; +using System.IO; + +namespace Alipay.EasySDK.Kernel.Util +{ + /// + /// HTTP multipart/form-data格式相关工具类 + /// + public static class MultipartUtil + { + /// + /// 获取Multipart分界符 + /// + /// 用作分界的随机字符串 + /// Multipart分界符 + public static byte[] GetEntryBoundary(string boundary) + { + return Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n"); + } + + /// + /// 获取Multipart结束标记 + /// + /// 用作分界的随机字符串 + /// Multipart结束标记 + public static byte[] GetEndBoundary(string boundary) + { + return Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n"); + } + + /// + /// 获取Multipart中的文本参数结构 + /// + /// 字段名称 + /// 字段值 + /// 文本参数结构 + public static byte[] GetTextEntry(string fieldName, string fieldValue) + { + string entry = "Content-Disposition:form-data;name=\"" + + fieldName + + "\"\r\nContent-Type:text/plain\r\n\r\n" + + fieldValue; + return AlipayConstants.DEFAULT_CHARSET.GetBytes(entry); + } + + /// + /// 获取Multipart中的文件参数结构(不含文件内容,只有文件元数据) + /// + /// 字段名称 + /// 文件路径 + /// 文件参数结构(不含文件内容) + public static byte[] GetFileEntry(String fieldName, String filePath) + { + ArgumentValidator.CheckArgument(File.Exists(filePath), + Path.GetFullPath(filePath) + "文件不存在"); + ArgumentValidator.CheckArgument(Path.GetFileName(filePath).Contains("."), + "文件名必须带上正确的扩展名"); + + String entry = "Content-Disposition:form-data;name=\"" + + fieldName + + "\";filename=\"" + + Path.GetFileName(filePath) + + "\"\r\nContent-Type:application/octet-stream" + + "\r\n\r\n"; + return AlipayConstants.DEFAULT_CHARSET.GetBytes(entry); + } + + /// + /// 往指定流中写入整个字节数组 + /// + /// 流 + /// 字节数组 + public static void WriteToStream(Stream stream, byte[] content) + { + stream.Write(content, 0, content.Length); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/PageUtil.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/PageUtil.cs new file mode 100644 index 0000000..e6a0a2b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/PageUtil.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Alipay.EasySDK.Kernel.Util +{ + /// + /// 生成页面信息辅助类 + /// + public static class PageUtil + { + /// + /// 生成表单 + /// + /// 表单提交链接 + /// 表单参数 + /// 表单字符串 + public static string BuildForm(string actionUrl, IDictionary parameters) + { + return "\n" + + BuildHiddenFields(parameters) + + "\n" + + "\n" + + ""; + } + + private static string BuildHiddenFields(IDictionary parameters) + { + if (parameters == null || parameters.Count == 0) + { + return ""; + } + StringBuilder stringBuilder = new StringBuilder(); + foreach (var pair in parameters) + { + if (pair.Key == null || pair.Value == null) + { + continue; + } + stringBuilder.Append(BuildHiddenField(pair.Key, pair.Value)); + } + return stringBuilder.ToString(); + } + + private static string BuildHiddenField(string key, string value) + { + StringBuilder builder = new StringBuilder(64); + builder.Append("\n"); + return builder.ToString(); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/ResponseChecker.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/ResponseChecker.cs new file mode 100644 index 0000000..040c3d1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/ResponseChecker.cs @@ -0,0 +1,31 @@ +using System.Reflection; +using Tea; + +namespace Alipay.EasySDK.Kernel.Util +{ + /// + /// 响应检查工具类 + /// + public class ResponseChecker + { + public const string SUB_CODE_FIELD_NAME = "SubCode"; + + /// + /// 判断一个请求返回的响应是否成功 + /// + /// 响应对象 + /// true:成功;false:失败 + public static bool Success(TeaModel response) + { + PropertyInfo propertyInfo = response.GetType().GetProperty(SUB_CODE_FIELD_NAME); + if (propertyInfo == null) + { + //没有SubCode属性的响应对象,通常是那些无需跟网关远程通信的API,只要本地执行完成都视为成功 + return true; + } + + string subCode = (string)propertyInfo.GetValue(response); + return string.IsNullOrEmpty(subCode); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/SignContentExtractor.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/SignContentExtractor.cs new file mode 100644 index 0000000..1dda8b1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/SignContentExtractor.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; + +namespace Alipay.EasySDK.Kernel.Util +{ + /// + /// 待验签原文提取器 + /// 注:此处不可使用JSON反序列化工具进行提取,会破坏原有格式,对于签名而言差个空格都会验签不通过 + /// + public class SignContentExtractor + { + /// + /// 左大括号 + /// + public const char LEFT_BRACE = '{'; + + /// + /// 右大括号 + /// + public const char RIGHT_BRACE = '}'; + + /// + /// 双引号 + /// + public const char DOUBLE_QUOTES = '"'; + + /// + /// 获取待验签的原文 + /// + /// 网关的整体响应字符串 + /// 本次调用的OpenAPI接口名称 + /// 待验签的原文 + public static string GetSignSourceData(string body, string method) + { + string rootNode = method.Replace(".", "_") + AlipayConstants.RESPONSE_SUFFIX; + string errorRootNode = AlipayConstants.ERROR_RESPONSE; + + int indexOfRootNode = body.IndexOf(rootNode, StringComparison.Ordinal); + int indexOfErrorRoot = body.IndexOf(errorRootNode, StringComparison.Ordinal); + + string result = null; + if (indexOfRootNode > 0) + { + result = ParseSignSourceData(body, rootNode, indexOfRootNode); + } + else if (indexOfErrorRoot > 0) + { + result = ParseSignSourceData(body, errorRootNode, indexOfErrorRoot); + } + + return result; + } + + private static string ParseSignSourceData(string body, string rootNode, int indexOfRootNode) + { + int signDataStartIndex = indexOfRootNode + rootNode.Length + 2; + int indexOfSign = body.IndexOf("\"" + AlipayConstants.SIGN_FIELD + "\"", StringComparison.Ordinal); + if (indexOfSign < 0) + { + return null; + } + SignSourceData signSourceData = ExtractSignContent(body, signDataStartIndex); + + //如果提取的待验签原始内容后还有rootNode + if (body.LastIndexOf(rootNode, StringComparison.Ordinal) > signSourceData.EndIndex) + { + throw new Exception("检测到响应报文中有重复的" + rootNode + ",验签失败。"); + } + + return signSourceData.SourceData; + } + + private static SignSourceData ExtractSignContent(string str, int begin) + { + if (str == null) + { + return null; + } + + int beginIndex = ExtractBeginPosition(str, begin); + if (beginIndex >= str.Length) + { + return null; + } + + int endIndex = ExtractEndPosition(str, beginIndex); + return new SignSourceData() + { + SourceData = str.Substring(beginIndex, endIndex - beginIndex), + BeginIndex = beginIndex, + EndIndex = endIndex + }; + } + + private static int ExtractBeginPosition(string responseString, int begin) + { + int beginPosition = begin; + //找到第一个左大括号(对应响应的是JSON对象的情况:普通调用OpenAPI响应明文) + //或者双引号(对应响应的是JSON字符串的情况:加密调用OpenAPI响应Base64串),作为待验签内容的起点 + while (beginPosition < responseString.Length + && responseString[beginPosition] != LEFT_BRACE + && responseString[beginPosition] != DOUBLE_QUOTES) + { + ++beginPosition; + } + return beginPosition; + } + + private static int ExtractEndPosition(string responseString, int beginPosition) + { + //提取明文验签内容终点 + if (responseString[beginPosition] == LEFT_BRACE) + { + return ExtractJsonObjectEndPosition(responseString, beginPosition); + } + //提取密文验签内容终点 + else + { + return ExtractJsonBase64ValueEndPosition(responseString, beginPosition); + } + } + + private static int ExtractJsonBase64ValueEndPosition(string responseString, int beginPosition) + { + for (int index = beginPosition; index < responseString.Length; ++index) + { + //找到第2个双引号作为终点,由于中间全部是Base64编码的密文,所以不会有干扰的特殊字符 + if (responseString[index] == DOUBLE_QUOTES && index != beginPosition) + { + return index + 1; + } + } + //如果没有找到第2个双引号,说明验签内容片段提取失败,直接尝试选取剩余整个响应字符串进行验签 + return responseString.Length; + } + + private static int ExtractJsonObjectEndPosition(string responseString, int beginPosition) + { + //记录当前尚未发现配对闭合的大括号 + LinkedList braces = new LinkedList(); + //记录当前字符是否在双引号中 + bool inQuotes = false; + //记录当前字符前面连续的转义字符个数 + int consecutiveEscapeCount = 0; + //从待验签字符的起点开始遍历后续字符串,找出待验签字符串的终止点,终点即是与起点{配对的} + for (int index = beginPosition; index < responseString.Length; ++index) + { + //提取当前字符 + char currentChar = responseString[index]; + + //如果当前字符是"且前面有偶数个转义标记(0也是偶数) + if (currentChar == DOUBLE_QUOTES && consecutiveEscapeCount % 2 == 0) + { + //是否在引号中的状态取反 + inQuotes = !inQuotes; + } + //如果当前字符是{且不在引号中 + else if (currentChar == LEFT_BRACE && !inQuotes) + { + //将该{加入未闭合括号中 + braces.AddLast(LEFT_BRACE); + } + //如果当前字符是}且不在引号中 + else if (currentChar == RIGHT_BRACE && !inQuotes) + { + //弹出一个未闭合括号 + braces.RemoveLast(); + //如果弹出后,未闭合括号为空,说明已经找到终点 + if (braces.Count == 0) + { + return index + 1; + } + } + + //如果当前字符是转义字符 + if (currentChar == '\\') + { + //连续转义字符个数+1 + ++consecutiveEscapeCount; + } + else + { + //连续转义字符个数置0 + consecutiveEscapeCount = 0; + } + } + + //如果没有找到配对的闭合括号,说明验签内容片段提取失败,直接尝试选取剩余整个响应字符串进行验签 + return responseString.Length; + } + + /// + /// 从响应字符串中提取到的待验签原始内容 + /// + public class SignSourceData + { + /// + /// 待验签原始内容 + /// + public string SourceData { get; set; } + + /// + /// 待验签原始内容在响应字符串中的起始位置 + /// + public int BeginIndex { get; set; } + + /// + /// 待验签原始内容在响应字符串中的结束位置 + /// + public int EndIndex { get; set; } + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/Signer.cs b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/Signer.cs new file mode 100644 index 0000000..2924689 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/csharp/EasySDKKernel/Kernel/Util/Signer.cs @@ -0,0 +1,260 @@ +using System; +using System.Text; +using System.Security.Cryptography; +using System.IO; +using System.Collections.Generic; + +namespace Alipay.EasySDK.Kernel.Util +{ + /// + /// SHA256WithRSA签名器 + /// + public class Signer + { + /// + /// 计算签名 + /// + /// 待签名的内容 + /// 私钥 + /// 签名值的Base64串 + public static string Sign(string content, string privateKeyPem) + { + try + { + using (RSACryptoServiceProvider rsaService = BuildRSAServiceProvider(Convert.FromBase64String(privateKeyPem))) + { + byte[] data = AlipayConstants.DEFAULT_CHARSET.GetBytes(content); + byte[] sign = rsaService.SignData(data, "SHA256"); + return Convert.ToBase64String(sign); + } + } + catch (Exception e) + { + string errorMessage = "签名遭遇异常,content=" + content + " privateKeySize=" + privateKeyPem.Length + " reason=" + e.Message; + Console.WriteLine(errorMessage); + throw new Exception(errorMessage, e); + } + } + + /// + /// 验证签名 + /// + /// 待验签的内容 + /// 签名值的Base64串 + /// 支付宝公钥 + /// true:验证成功;false:验证失败 + public static bool Verify(string content, string sign, string publicKeyPem) + { + try + { + using (RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider()) + { + rsaService.PersistKeyInCsp = false; + rsaService.ImportParameters(ConvertFromPemPublicKey(publicKeyPem)); + return rsaService.VerifyData(AlipayConstants.DEFAULT_CHARSET.GetBytes(content), + "SHA256", Convert.FromBase64String(sign)); + } + } + catch (Exception e) + { + string errorMessage = "验签遭遇异常,content=" + content + " sign=" + sign + + " publicKey=" + publicKeyPem + " reason=" + e.Message; + Console.WriteLine(errorMessage); + throw new Exception(errorMessage, e); + } + + } + + /// + /// 对参数集合进行验签 + /// + /// 参数集合 + /// 支付宝公钥 + /// true:验证成功;false:验证失败 + public static bool VerifyParams(Dictionary parameters, string publicKeyPem) + { + string sign = parameters[AlipayConstants.SIGN_FIELD]; + parameters.Remove(AlipayConstants.SIGN_FIELD); + parameters.Remove(AlipayConstants.SIGN_TYPE_FIELD); + + string content = GetSignContent(parameters); + + return Verify(content, sign, publicKeyPem); + } + + private static string GetSignContent(IDictionary parameters) + { + // 把字典按Key的字母顺序排序 + IDictionary sortedParams = new SortedDictionary(parameters, StringComparer.Ordinal); + IEnumerator> iterator = sortedParams.GetEnumerator(); + + // 把所有参数名和参数值串在一起 + StringBuilder query = new StringBuilder(""); + while (iterator.MoveNext()) + { + string key = iterator.Current.Key; + string value = iterator.Current.Value; + query.Append(key).Append("=").Append(value).Append("&"); + } + string content = query.ToString().Substring(0, query.Length - 1); + + return content; + } + + private static RSAParameters ConvertFromPemPublicKey(string pemPublickKey) + { + if (string.IsNullOrEmpty(pemPublickKey)) + { + throw new Exception("PEM格式公钥不可为空。"); + } + + //移除干扰文本 + pemPublickKey = pemPublickKey.Replace("-----BEGIN PUBLIC KEY-----", "") + .Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", ""); + + byte[] keyData = Convert.FromBase64String(pemPublickKey); + bool keySize1024 = (keyData.Length == 162); + bool keySize2048 = (keyData.Length == 294); + if (!(keySize1024 || keySize2048)) + { + throw new Exception("公钥长度只支持1024和2048。"); + } + byte[] pemModulus = (keySize1024 ? new byte[128] : new byte[256]); + byte[] pemPublicExponent = new byte[3]; + Array.Copy(keyData, (keySize1024 ? 29 : 33), pemModulus, 0, (keySize1024 ? 128 : 256)); + Array.Copy(keyData, (keySize1024 ? 159 : 291), pemPublicExponent, 0, 3); + RSAParameters para = new RSAParameters + { + Modulus = pemModulus, + Exponent = pemPublicExponent + }; + return para; + } + + private static RSACryptoServiceProvider BuildRSAServiceProvider(byte[] privateKey) + { + byte[] MODULUS, E, D, P, Q, DP, DQ, IQ; + byte bt = 0; + ushort twobytes = 0; + int elems = 0; + + //set up stream to decode the asn.1 encoded RSA private key + //wrap Memory Stream with BinaryReader for easy reading + using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(privateKey))) + { + twobytes = binaryReader.ReadUInt16(); + //data read as little endian order (actual data order for Sequence is 30 81) + if (twobytes == 0x8130) + { + //advance 1 byte + binaryReader.ReadByte(); + } + else if (twobytes == 0x8230) + { + //advance 2 bytes + binaryReader.ReadInt16(); + } + else + { + return null; + } + + twobytes = binaryReader.ReadUInt16(); + //version number + if (twobytes != 0x0102) + { + return null; + } + bt = binaryReader.ReadByte(); + if (bt != 0x00) + { + return null; + } + + //all private key components are Integer sequences + elems = GetIntegerSize(binaryReader); + MODULUS = binaryReader.ReadBytes(elems); + + elems = GetIntegerSize(binaryReader); + E = binaryReader.ReadBytes(elems); + + elems = GetIntegerSize(binaryReader); + D = binaryReader.ReadBytes(elems); + + elems = GetIntegerSize(binaryReader); + P = binaryReader.ReadBytes(elems); + + elems = GetIntegerSize(binaryReader); + Q = binaryReader.ReadBytes(elems); + + elems = GetIntegerSize(binaryReader); + DP = binaryReader.ReadBytes(elems); + + elems = GetIntegerSize(binaryReader); + DQ = binaryReader.ReadBytes(elems); + + elems = GetIntegerSize(binaryReader); + IQ = binaryReader.ReadBytes(elems); + + //create RSACryptoServiceProvider instance and initialize with public key + RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider(); + RSAParameters rsaParams = new RSAParameters + { + Modulus = MODULUS, + Exponent = E, + D = D, + P = P, + Q = Q, + DP = DP, + DQ = DQ, + InverseQ = IQ + }; + rsaService.ImportParameters(rsaParams); + return rsaService; + } + } + + private static int GetIntegerSize(BinaryReader binaryReader) + { + byte bt = 0; + byte lowbyte = 0x00; + byte highbyte = 0x00; + int count = 0; + + bt = binaryReader.ReadByte(); + + //expect integer + if (bt != 0x02) + { + return 0; + } + bt = binaryReader.ReadByte(); + + if (bt == 0x81) + { + //data size in next byte + count = binaryReader.ReadByte(); + } + else if (bt == 0x82) + { + //data size in next 2 bytes + highbyte = binaryReader.ReadByte(); + lowbyte = binaryReader.ReadByte(); + byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; + count = BitConverter.ToInt32(modint, 0); + } + else + { + //we already have the data size + count = bt; + } + while (binaryReader.ReadByte() == 0x00) + { //remove high order zeros in data + count -= 1; + } + //last ReadByte wasn't a removed zero, so back up a byte + binaryReader.BaseStream.Seek(-1, SeekOrigin.Current); + return count; + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/pom.xml b/serve/vendor/alipaysdk/easysdk/kernel/java/pom.xml new file mode 100644 index 0000000..8a66e6b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/pom.xml @@ -0,0 +1,215 @@ + + + 4.0.0 + com.alipay.sdk + easysdk-kernel + 1.0.8 + Alipay Easy SDK Kernel + https://open.alipay.com + Alipay Easy SDK for Java + allows you to enjoy a minimalist programming experience + and quickly access the various high-frequency capabilities of the Alipay Open Platform. + + + + mvnrepository + mvnrepository + http://www.mvnrepository.com/ + default + + true + + + false + + + + + UTF-8 + 1.7 + 1.7 + + + + junit + junit + 4.11 + test + + + ch.qos.logback + logback-core + 1.2.3 + test + + + ch.qos.logback + logback-classic + 1.2.3 + test + + + ch.qos.logback + logback-access + 1.2.3 + test + + + org.mockito + mockito-core + 3.2.0 + test + + + org.slf4j + slf4j-api + 1.7.25 + + + com.aliyun + tea + 1.0.7 + + + com.google.guava + guava + 28.1-jre + + + com.google.code.gson + gson + 2.8.6 + + + org.bouncycastle + bcprov-jdk15on + 1.64 + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + sonatype-nexus-staging + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + MIT License + http://www.opensource.org/licenses/mit-license.php + + + + scm:git:git@github.com:alipay/alipay-easysdk.git + scm:git:ssh://github.com:alipay/alipay-easysdk.git + http://github.com/alipay/alipay-easysdk/tree/master/java + + + + antopen + antopen + antopen@aliyun.com + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + UTF-8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.3.2 + + + + + maven-deploy-plugin + 2.8.2 + + + default-deploy + deploy + + deploy + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + + + org.apache.maven.plugins + maven-scm-plugin + 1.8.1 + + + org.apache.maven.plugins + maven-source-plugin + 2.1.2 + + + attach-sources + verify + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + true + UTF-8 + UTF-8 + UTF-8 + -Xdoclint:none + + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/AlipayConstants.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/AlipayConstants.java new file mode 100644 index 0000000..a7208cf --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/AlipayConstants.java @@ -0,0 +1,75 @@ +/** + * Alipay.com Inc. Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.kernel; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * 支付宝开放平台网关交互常用常量 + * + * @author zhongyu + * @version $Id: AlipayConstants.java, v 0.1 2020年01月02日 7:53 PM zhongyu Exp $ + */ +public final class AlipayConstants { + /** + * Config配置参数Key值 + */ + public static final String PROTOCOL_CONFIG_KEY = "protocol"; + public static final String HOST_CONFIG_KEY = "gatewayHost"; + public static final String ALIPAY_CERT_PATH_CONFIG_KEY = "alipayCertPath"; + public static final String MERCHANT_CERT_PATH_CONFIG_KEY = "merchantCertPath"; + public static final String ALIPAY_ROOT_CERT_PATH_CONFIG_KEY = "alipayRootCertPath"; + public static final String SIGN_TYPE_CONFIG_KEY = "signType"; + public static final String NOTIFY_URL_CONFIG_KEY = "notifyUrl"; + public static final String SIGN_PROVIDER_CONFIG_KEY = "signProvider"; + + /** + * 与网关HTTP交互中涉及到的字段值 + */ + public static final String BIZ_CONTENT_FIELD = "biz_content"; + public static final String ALIPAY_CERT_SN_FIELD = "alipay_cert_sn"; + public static final String SIGN_FIELD = "sign"; + public static final String SIGN_TYPE_FIELD = "sign_type"; + public static final String BODY_FIELD = "http_body"; + public static final String NOTIFY_URL_FIELD = "notify_url"; + public static final String METHOD_FIELD = "method"; + public static final String RESPONSE_SUFFIX = "_response"; + public static final String ERROR_RESPONSE = "error_response"; + + /** + * 默认字符集编码,EasySDK统一固定使用UTF-8编码,无需用户感知编码,用户面对的总是String而不是bytes + */ + public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + + /** + * 默认的签名算法,EasySDK统一固定使用RSA2签名算法(即SHA_256_WITH_RSA),但此参数依然需要用户指定以便用户感知,因为在开放平台接口签名配置界面中需要选择同样的算法 + */ + public static final String RSA2 = "RSA2"; + + /** + * RSA2对应的真实签名算法名称 + */ + public static final String SHA_256_WITH_RSA = "SHA256WithRSA"; + + /** + * RSA2对应的真实非对称加密算法名称 + */ + public static final String RSA = "RSA"; + + /** + * 申请生成的重定向网页的请求类型,GET表示生成URL + */ + public static final String GET = "GET"; + + /** + * 申请生成的重定向网页的请求类型,POST表示生成form表单 + */ + public static final String POST = "POST"; + + /** + * 使用Aliyun KMS签名服务时签名提供方的名称 + */ + public static final String AliyunKMS = "AliyunKMS"; +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/CertEnvironment.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/CertEnvironment.java new file mode 100644 index 0000000..835456d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/CertEnvironment.java @@ -0,0 +1,82 @@ +/** + * Alipay.com Inc. Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.kernel; + +import com.alipay.easysdk.kernel.util.AntCertificationUtil; +import com.google.common.base.Strings; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 证书模式运行时环境 + * + * @author zhongyu + * @version $Id: CertEnvironment.java, v 0.1 2020年01月02日 5:21 PM zhongyu Exp $ + */ +public class CertEnvironment { + /** + * 支付宝根证书内容 + */ + private String rootCertContent; + + /** + * 支付宝根证书序列号 + */ + private String rootCertSN; + + /** + * 商户应用公钥证书序列号 + */ + private String merchantCertSN; + + /** + * 缓存的不同支付宝公钥证书序列号对应的支付宝公钥 + */ + private Map cachedAlipayPublicKey = new ConcurrentHashMap(); + + /** + * 构造证书运行环境 + * + * @param merchantCertPath 商户公钥证书路径 + * @param alipayCertPath 支付宝公钥证书路径 + * @param alipayRootCertPath 支付宝根证书路径 + */ + public CertEnvironment(String merchantCertPath, String alipayCertPath, String alipayRootCertPath) { + if (Strings.isNullOrEmpty(merchantCertPath) || Strings.isNullOrEmpty(alipayCertPath) || Strings.isNullOrEmpty(alipayCertPath)) { + throw new RuntimeException("证书参数merchantCertPath、alipayCertPath或alipayRootCertPath设置不完整。"); + } + + this.rootCertContent = AntCertificationUtil.readCertContent(alipayRootCertPath); + this.rootCertSN = AntCertificationUtil.getRootCertSN(rootCertContent); + this.merchantCertSN = AntCertificationUtil.getCertSN(AntCertificationUtil.readCertContent((merchantCertPath))); + + String alipayPublicCertContent = AntCertificationUtil.readCertContent(alipayCertPath); + cachedAlipayPublicKey.put(AntCertificationUtil.getCertSN(alipayPublicCertContent), + AntCertificationUtil.getCertPublicKey(alipayPublicCertContent)); + } + + public String getRootCertSN() { + return rootCertSN; + } + + public String getMerchantCertSN() { + return merchantCertSN; + } + + public String getAlipayPublicKey(String sn) { + //如果没有指定sn,则默认取缓存中的第一个值 + if (Strings.isNullOrEmpty(sn)) { + return cachedAlipayPublicKey.values().iterator().next(); + } + + if (cachedAlipayPublicKey.containsKey(sn)) { + return cachedAlipayPublicKey.get(sn); + } else { + //网关在支付宝公钥证书变更前,一定会确认通知到商户并在商户做出反馈后,才会更新该商户的支付宝公钥证书 + //TODO: 后续可以考虑加入自动升级支付宝公钥证书逻辑,注意并发更新冲突问题 + throw new RuntimeException("支付宝公钥证书[" + sn + "]已过期,请重新下载最新支付宝公钥证书并替换原证书文件"); + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/Client.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/Client.java new file mode 100644 index 0000000..950f874 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/Client.java @@ -0,0 +1,476 @@ +// This file is auto-generated, don't edit it. Thanks. +package com.alipay.easysdk.kernel; + +import com.alipay.easysdk.kernel.util.AES; +import com.alipay.easysdk.kernel.util.JsonUtil; +import com.alipay.easysdk.kernel.util.MultipartUtil; +import com.alipay.easysdk.kernel.util.PageUtil; +import com.alipay.easysdk.kernel.util.SignContentExtractor; +import com.alipay.easysdk.kernel.util.Signer; +import com.aliyun.tea.TeaResponse; +import com.google.common.base.Strings; +import com.google.common.io.Files; +import com.google.gson.Gson; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TimeZone; +import java.util.TreeMap; + +public class Client { + /** + * 构造成本较高的一些参数缓存在上下文中 + */ + private final Context context; + + /** + * 注入的可选额外文本参数集合 + */ + private final Map optionalTextParams = new HashMap<>(); + + /** + * 注入的可选业务参数集合 + */ + private final Map optionalBizParams = new HashMap<>(); + + /** + * 构造函数 + * + * @param context 上下文对象 + */ + public Client(Context context) { + this.context = context; + } + + /** + * 注入额外文本参数 + * + * @param key 参数名称 + * @param value 参数的值 + * @return 本客户端本身,便于链路调用 + */ + public Client injectTextParam(String key, String value) { + optionalTextParams.put(key, value); + return this; + } + + /** + * 注入额外业务参数 + * + * @param key 业务参数名称 + * @param value 业务参数的值 + * @return 本客户端本身,便于链式调用 + */ + public Client injectBizParam(String key, Object value) { + optionalBizParams.put(key, value); + return this; + } + + /** + * 获取时间戳,格式yyyy-MM-dd HH:mm:ss + * + * @return 当前时间戳 + */ + public String getTimestamp() throws Exception { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("GMT+8")); + return df.format(new Date()); + } + + /** + * 获取Config中的配置项 + * + * @param key 配置项的名称 + * @return 配置项的值 + */ + public String getConfig(String key) throws Exception { + return context.getConfig(key); + } + + /** + * 获取SDK版本信息 + * + * @return SDK版本信息 + */ + public String getSdkVersion() throws Exception { + return context.getSdkVersion(); + } + + /** + * 将业务参数和其他额外文本参数按www-form-urlencoded格式转换成HTTP Body中的字节数组,注意要做URL Encode + * + * @param bizParams 业务参数 + * @return HTTP Body中的字节数组 + */ + public byte[] toUrlEncodedRequestBody(java.util.Map bizParams) throws Exception { + Map sortedMap = getSortedMap(Collections.emptyMap(), bizParams, null); + return buildQueryString(sortedMap).getBytes(AlipayConstants.DEFAULT_CHARSET); + } + + /** + * 将网关响应发序列化成Map,同时将API的接口名称和响应原文插入到响应Map的method和body字段中 + * + * @param response HTTP响应 + * @param method 调用的OpenAPI的接口名称 + * @return 响应反序列化的Map + */ + public java.util.Map readAsJson(TeaResponse response, String method) throws Exception { + String responseBody = response.getResponseBody(); + Map map = new Gson().fromJson(responseBody, Map.class); + map.put(AlipayConstants.BODY_FIELD, responseBody); + map.put(AlipayConstants.METHOD_FIELD, method); + return map; + } + + /** + * 从响应Map中提取返回值对象的Map,并将响应原文插入到body字段中 + * + * @param respMap 响应Map + * @return 返回值对象Map + */ + public java.util.Map toRespModel(java.util.Map respMap) throws Exception { + String methodName = (String) respMap.get(AlipayConstants.METHOD_FIELD); + String responseNodeName = methodName.replace('.', '_') + AlipayConstants.RESPONSE_SUFFIX; + String errorNodeName = AlipayConstants.ERROR_RESPONSE; + + //先找正常响应节点 + for (Entry pair : respMap.entrySet()) { + if (responseNodeName.equals(pair.getKey())) { + Map model = (Map) pair.getValue(); + model.put(AlipayConstants.BODY_FIELD, respMap.get(AlipayConstants.BODY_FIELD)); + return model; + } + } + + //再找异常响应节点 + for (Entry pair : respMap.entrySet()) { + if (errorNodeName.equals(pair.getKey())) { + Map model = (Map) pair.getValue(); + model.put(AlipayConstants.BODY_FIELD, respMap.get(AlipayConstants.BODY_FIELD)); + return model; + } + } + + throw new RuntimeException("响应格式不符合预期,找不到" + responseNodeName + "或" + errorNodeName + "节点"); + } + + /** + * 生成随机分界符,用于multipart格式的HTTP请求Body的多个字段间的分隔 + * + * @return 随机分界符 + */ + public String getRandomBoundary() throws Exception { + return System.currentTimeMillis() + ""; + } + + /** + * 将其他额外文本参数和文件参数按multipart/form-data格式转换成HTTP Body中的字节数组流 + * + * @param textParams 其他额外文本参数 + * @param fileParams 业务文件参数 + * @param boundary HTTP Body中multipart格式的分隔符 + * @return Multipart格式的字节流 + */ + public java.io.InputStream toMultipartRequestBody(java.util.Map textParams, + java.util.Map fileParams, String boundary) throws Exception { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + //补充其他额外参数 + addOtherParams(textParams, null); + + for (Entry pair : textParams.entrySet()) { + if (!Strings.isNullOrEmpty(pair.getKey()) && !Strings.isNullOrEmpty(pair.getValue())) { + stream.write(MultipartUtil.getEntryBoundary(boundary)); + stream.write(MultipartUtil.getTextEntry(pair.getKey(), pair.getValue())); + } + } + + //组装文件参数 + for (Entry pair : fileParams.entrySet()) { + if (!Strings.isNullOrEmpty(pair.getKey()) && pair.getValue() != null) { + stream.write(MultipartUtil.getEntryBoundary(boundary)); + stream.write(MultipartUtil.getFileEntry(pair.getKey(), pair.getValue())); + stream.write(Files.toByteArray(new File(pair.getValue()))); + } + } + + //添加结束标记 + stream.write(MultipartUtil.getEndBoundary(boundary)); + + return new ByteArrayInputStream(stream.toByteArray()); + } + + private void addOtherParams(Map textParams, Map bizParams) throws Exception { + //为null表示此处不是扩展此类参数的时机 + if (textParams != null) { + for (Entry pair : optionalTextParams.entrySet()) { + if (!textParams.containsKey(pair.getKey())) { + textParams.put(pair.getKey(), pair.getValue()); + } + } + setNotifyUrl(textParams); + } + + //为null表示此处不是扩展此类参数的时机 + if (bizParams != null) { + for (Entry pair : optionalBizParams.entrySet()) { + if (!bizParams.containsKey(pair.getKey())) { + ((Map) bizParams).put(pair.getKey(), pair.getValue()); + } + } + } + } + + /** + * 生成页面类请求所需URL或Form表单 + * + * @param method GET或POST,决定是生成URL还是Form表单 + * @param systemParams 系统参数集合 + * @param bizParams 业务参数集合 + * @param textParams 其他额外文本参数集合 + * @param sign 所有参数的签名值 + * @return 生成的URL字符串或表单 + */ + public String generatePage(String method, java.util.Map systemParams, java.util.Map bizParams, + java.util.Map textParams, String sign) throws Exception { + if (AlipayConstants.GET.equalsIgnoreCase(method)) { + //采集并排序所有参数 + Map sortedMap = getSortedMap(systemParams, bizParams, textParams); + sortedMap.put(AlipayConstants.SIGN_FIELD, sign); + + //将所有参数置于URL中 + return getGatewayServerUrl() + "?" + buildQueryString(sortedMap); + } else if (AlipayConstants.POST.equalsIgnoreCase(method)) { + //将系统参数、额外文本参数排序后置于URL中 + Map urlParams = getSortedMap(systemParams, null, textParams); + urlParams.put(AlipayConstants.SIGN_FIELD, sign); + String actionUrl = getGatewayServerUrl() + "?" + buildQueryString(urlParams); + + //将业务参数置于form表单中 + addOtherParams(null, bizParams); + Map formParams = new TreeMap<>(); + formParams.put(AlipayConstants.BIZ_CONTENT_FIELD, JsonUtil.toJsonString(bizParams)); + return PageUtil.buildForm(actionUrl, formParams); + } else { + throw new RuntimeException("_generatePage中method只支持传入GET或POST"); + } + } + + /** + * 获取商户应用公钥证书序列号,从证书模式运行时环境对象中直接读取 + * + * @return 商户应用公钥证书序列号 + */ + public String getMerchantCertSN() throws Exception { + if (context.getCertEnvironment() == null) { + return null; + } + return context.getCertEnvironment().getMerchantCertSN(); + } + + /** + * 从响应Map中提取支付宝公钥证书序列号 + * + * @param respMap 响应Map + * @return 支付宝公钥证书序列号 + */ + public String getAlipayCertSN(java.util.Map respMap) throws Exception { + return (String) respMap.get(AlipayConstants.ALIPAY_CERT_SN_FIELD); + } + + /** + * 获取支付宝根证书序列号,从证书模式运行时环境对象中直接读取 + * + * @return 支付宝根证书序列号 + */ + public String getAlipayRootCertSN() throws Exception { + if (context.getCertEnvironment() == null) { + return null; + } + return context.getCertEnvironment().getRootCertSN(); + } + + /** + * 是否是证书模式 + * + * @return true:是;false:不是 + */ + public Boolean isCertMode() throws Exception { + return context.getCertEnvironment() != null; + } + + /** + * 获取支付宝公钥,从证书运行时环境对象中直接读取 + * 如果缓存的用户指定的支付宝公钥证书的序列号与网关响应中携带的支付宝公钥证书序列号不一致,需要报错给出提示或自动更新支付宝公钥证书 + * + * @param alipayCertSN 网关响应中携带的支付宝公钥证书序列号 + * @return 支付宝公钥 + */ + public String extractAlipayPublicKey(String alipayCertSN) throws Exception { + if (context.getCertEnvironment() == null) { + return null; + } + return context.getCertEnvironment().getAlipayPublicKey(alipayCertSN); + } + + /** + * 验证签名 + * + * @param respMap 响应Map,可以从中提取出sign和body + * @param alipayPublicKey 支付宝公钥 + * @return true:验签通过;false:验签不通过 + */ + public Boolean verify(java.util.Map respMap, String alipayPublicKey) throws Exception { + String sign = (String) respMap.get(AlipayConstants.SIGN_FIELD); + String content = SignContentExtractor.getSignSourceData((String) respMap.get(AlipayConstants.BODY_FIELD), + (String) respMap.get(AlipayConstants.METHOD_FIELD)); + return Signer.verify(content, sign, alipayPublicKey); + } + + /** + * 计算签名,注意要去除key或value为null的键值对 + * + * @param systemParams 系统参数集合 + * @param bizParams 业务参数集合 + * @param textParams 其他额外文本参数集合 + * @param merchantPrivateKey 私钥 + * @return 签名值的Base64串 + */ + public String sign(java.util.Map systemParams, java.util.Map bizParams, + java.util.Map textParams, String merchantPrivateKey) throws Exception { + Map sortedMap = getSortedMap(systemParams, bizParams, textParams); + + StringBuilder content = new StringBuilder(); + int index = 0; + for (Entry pair : sortedMap.entrySet()) { + if (!Strings.isNullOrEmpty(pair.getKey()) && !Strings.isNullOrEmpty(pair.getValue())) { + content.append(index == 0 ? "" : "&").append(pair.getKey()).append("=").append(pair.getValue()); + index++; + } + } + return context.getSigner().sign(content.toString(), merchantPrivateKey); + } + + /** + * 将随机顺序的Map转换为有序的Map + * + * @param input 随机顺序的Map + * @return 有序的Map + */ + public java.util.Map sortMap(java.util.Map input) throws Exception { + //GO语言的Map是随机顺序的,每次访问顺序都不同,才需排序 + return input; + } + + /** + * AES加密 + * + * @param plainText 明文 + * @param key 密钥 + * @return 密文 + */ + public String aesEncrypt(String plainText, String key) throws Exception { + return AES.encrypt(plainText, key); + } + + /** + * AES解密 + * + * @param cipherText 密文 + * @param key 密钥 + * @return 明文 + */ + public String aesDecrypt(String cipherText, String key) throws Exception { + return AES.decrypt(cipherText, key); + } + + /** + * 生成订单串 + * + * @param systemParams 系统参数集合 + * @param bizParams 业务参数集合 + * @param textParams 额外文本参数集合 + * @param sign 所有参数的签名值 + * @return 订单串 + */ + public String generateOrderString(java.util.Map systemParams, java.util.Map bizParams, + java.util.Map textParams, String sign) throws Exception { + //采集并排序所有参数 + Map sortedMap = getSortedMap(systemParams, bizParams, textParams); + sortedMap.put(AlipayConstants.SIGN_FIELD, sign); + + //将所有参数置于URL中 + return buildQueryString(sortedMap); + } + + /** + * 对支付类请求的异步通知的参数集合进行验签 + * + * @param parameters 参数集合 + * @param publicKey 支付宝公钥 + * @return true:验证成功;false:验证失败 + */ + public Boolean verifyParams(java.util.Map parameters, String publicKey) throws Exception { + return Signer.verifyParams(parameters, publicKey); + } + + private Map getSortedMap(Map systemParams, Map bizParams, + Map textParams) throws Exception { + addOtherParams(textParams, bizParams); + + Map sortedMap = new TreeMap<>(systemParams); + if (bizParams != null && !bizParams.isEmpty()) { + sortedMap.put(AlipayConstants.BIZ_CONTENT_FIELD, JsonUtil.toJsonString(bizParams)); + } + if (textParams != null) { + sortedMap.putAll(textParams); + } + return sortedMap; + } + + private void setNotifyUrl(Map params) throws Exception { + if (getConfig(AlipayConstants.NOTIFY_URL_CONFIG_KEY) != null && !params.containsKey(AlipayConstants.NOTIFY_URL_FIELD)) { + params.put(AlipayConstants.NOTIFY_URL_FIELD, getConfig(AlipayConstants.NOTIFY_URL_CONFIG_KEY)); + } + } + + /** + * 字符串拼接 + * + * @param a 字符串a + * @param b 字符串b + * @return 字符串a和b拼接后的字符串 + */ + public String concatStr(String a, String b) { + return a + b; + } + + private String buildQueryString(Map sortedMap) throws UnsupportedEncodingException { + StringBuilder content = new StringBuilder(); + int index = 0; + for (Entry pair : sortedMap.entrySet()) { + if (!Strings.isNullOrEmpty(pair.getKey()) && !Strings.isNullOrEmpty(pair.getValue())) { + content.append(index == 0 ? "" : "&") + .append(pair.getKey()) + .append("=") + .append(URLEncoder.encode(pair.getValue(), AlipayConstants.DEFAULT_CHARSET.name())); + index++; + } + } + return content.toString(); + } + + private String getGatewayServerUrl() throws Exception { + return getConfig(AlipayConstants.PROTOCOL_CONFIG_KEY) + "://" + getConfig(AlipayConstants.HOST_CONFIG_KEY) + "/gateway.do"; + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/Config.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/Config.java new file mode 100644 index 0000000..c50b326 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/Config.java @@ -0,0 +1,110 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.kernel; + +import com.aliyun.tea.NameInMap; +import com.aliyun.tea.TeaModel; +import com.aliyun.tea.Validation; + +/** + * @author zhongyu + * @version : Config.java, v 0.1 2020年05月22日 4:25 下午 zhongyu Exp $ + */ +public class Config extends TeaModel { + + /** + * 通信协议,通常填写https + */ + @NameInMap("protocol") + @Validation(required = true) + public String protocol; + + /** + * 网关域名 + * 线上为:openapi.alipay.com + * 沙箱为:openapi.alipaydev.com + */ + @NameInMap("gatewayHost") + @Validation(required = true) + public String gatewayHost; + + /** + * AppId + */ + @NameInMap("appId") + @Validation(required = true) + public String appId; + + /** + * 签名类型,Alipay Easy SDK只推荐使用RSA2,估此处固定填写RSA2 + */ + @NameInMap("signType") + @Validation(required = true) + public String signType; + + /** + * 支付宝公钥 + */ + @NameInMap("alipayPublicKey") + public String alipayPublicKey; + + /** + * 应用私钥 + */ + @NameInMap("merchantPrivateKey") + @Validation(required = true) + public String merchantPrivateKey; + + /** + * 应用公钥证书文件路径 + */ + @NameInMap("merchantCertPath") + public String merchantCertPath; + + /** + * 支付宝公钥证书文件路径 + */ + @NameInMap("alipayCertPath") + public String alipayCertPath; + + /** + * 支付宝根证书文件路径 + */ + @NameInMap("alipayRootCertPath") + public String alipayRootCertPath; + + /** + * 异步通知回调地址(可选) + */ + @NameInMap("notifyUrl") + public String notifyUrl; + + /** + * AES密钥(可选) + */ + @NameInMap("encryptKey") + public String encryptKey; + + /** + * 签名提供方的名称(可选),例:Aliyun KMS签名,signProvider = "AliyunKMS" + */ + @NameInMap("signProvider") + public String signProvider; + + /** + * 代理地址(可选) + * 例如:http://127.0.0.1:8080 + */ + @NameInMap("httpProxy") + public String httpProxy; + + + /** + * 忽略证书校验(可选) + */ + @NameInMap("ignoreSSL") + public boolean ignoreSSL; + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/Context.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/Context.java new file mode 100644 index 0000000..7c949e6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/Context.java @@ -0,0 +1,81 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.kernel; + +import com.alipay.easysdk.kernel.util.Signer; +import com.aliyun.tea.TeaModel; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; + +import java.util.Map; + +/** + * @author zhongyu + * @version : Context.java, v 0.1 2020年05月24日 10:41 上午 zhongyu Exp $ + */ +public class Context { + /** + * 客户端配置参数 + */ + private final Map config; + + /** + * SDK版本号 + */ + private String sdkVersion; + + /** + * 证书模式运行时环境 + */ + private CertEnvironment certEnvironment; + + /** + * SHA256WithRSA签名器 + */ + private Signer signer; + + public Context(Config options, String sdkVersion) throws Exception { + config = TeaModel.buildMap(options); + this.sdkVersion = sdkVersion; + Preconditions.checkArgument(AlipayConstants.RSA2.equals(getConfig(AlipayConstants.SIGN_TYPE_CONFIG_KEY)), + "Alipay Easy SDK只允许使用RSA2签名方式,RSA签名方式由于安全性相比RSA2弱已不再推荐。"); + + if (!Strings.isNullOrEmpty(getConfig(AlipayConstants.ALIPAY_CERT_PATH_CONFIG_KEY))) { + certEnvironment = new CertEnvironment( + getConfig(AlipayConstants.MERCHANT_CERT_PATH_CONFIG_KEY), + getConfig(AlipayConstants.ALIPAY_CERT_PATH_CONFIG_KEY), + getConfig(AlipayConstants.ALIPAY_ROOT_CERT_PATH_CONFIG_KEY)); + } + signer = new Signer(); + } + + public String getConfig(String key) { + if (String.valueOf(config.get(key)) == "null") { + return null; + } else { + return String.valueOf(config.get(key)); + } + } + + public String getSdkVersion() { + return sdkVersion; + } + + public void setSdkVersion(String sdkVersion) { + this.sdkVersion = sdkVersion; + } + + public CertEnvironment getCertEnvironment() { + return certEnvironment; + } + + public Signer getSigner() { + return signer; + } + + public void setSigner(Signer signer) { + this.signer = signer; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/AES.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/AES.java new file mode 100644 index 0000000..1f6af4e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/AES.java @@ -0,0 +1,88 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.kernel.util; + +import com.alipay.easysdk.kernel.AlipayConstants; +import org.bouncycastle.util.encoders.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * 加密工具 + */ +public class AES { + private static final String AES_ALG = "AES"; + private static final String AES_CBC_PCK_ALG = "AES/CBC/PKCS5Padding"; + private static final byte[] AES_IV = initIV(); + + /** + * AES加密 + * + * @param plainText 明文 + * @param key 对称密钥 + * @return 密文 + */ + public static String encrypt(String plainText, String key) { + try { + Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG); + + IvParameterSpec iv = new IvParameterSpec(AES_IV); + cipher.init(Cipher.ENCRYPT_MODE, + new SecretKeySpec(Base64.decode(key.getBytes()), AES_ALG), iv); + + byte[] encryptBytes = cipher.doFinal(plainText.getBytes(AlipayConstants.DEFAULT_CHARSET)); + return new String(Base64.encode(encryptBytes)); + } catch (Exception e) { + throw new RuntimeException("AES加密失败,plainText=" + plainText + + ",keySize=" + key.length() + "。" + e.getMessage(), e); + } + } + + /** + * 密文 + * + * @param cipherText 密文 + * @param key 对称密钥 + * @return 明文 + */ + public static String decrypt(String cipherText, String key) { + try { + Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG); + IvParameterSpec iv = new IvParameterSpec(AES_IV); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decode(key.getBytes()), AES_ALG), iv); + + byte[] cleanBytes = cipher.doFinal(Base64.decode(cipherText.getBytes())); + return new String(cleanBytes, AlipayConstants.DEFAULT_CHARSET); + } catch (Exception e) { + throw new RuntimeException("AES解密失败,cipherText=" + cipherText + + ",keySize=" + key.length() + "。" + e.getMessage(), e); + } + } + + /** + * 初始向量的方法,全部为0 + * 这里的写法适合于其它算法,AES算法IV值一定是128位的(16字节) + */ + private static byte[] initIV() { + try { + Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG); + int blockSize = cipher.getBlockSize(); + byte[] iv = new byte[blockSize]; + for (int i = 0; i < blockSize; ++i) { + iv[i] = 0; + } + return iv; + } catch (Exception e) { + int blockSize = 16; + byte[] iv = new byte[blockSize]; + for (int i = 0; i < blockSize; ++i) { + iv[i] = 0; + } + return iv; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/AntCertificationUtil.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/AntCertificationUtil.java new file mode 100644 index 0000000..f7ebf50 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/AntCertificationUtil.java @@ -0,0 +1,396 @@ +package com.alipay.easysdk.kernel.util; + +import com.google.common.base.Strings; +import com.google.common.io.ByteStreams; +import com.google.common.io.Files; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.encoders.Base64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.Security; +import java.security.SignatureException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 证书文件可信校验 + * + * @author junying.wjy + * @version $Id: AntCertificationUtil.java, v 0.1 2019-07-29 下午04:46 junying.wjy Exp $ + */ +public class AntCertificationUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(AntCertificationUtil.class); + + private static BouncyCastleProvider provider; + + static { + provider = new BouncyCastleProvider(); + Security.addProvider(provider); + } + + /** + * 验证证书是否可信 + * + * @param certContent 需要验证的目标证书或者证书链 + * @param rootCertContent 可信根证书列表 + */ + public static boolean isTrusted(String certContent, String rootCertContent) { + X509Certificate[] certificates; + try { + certificates = readPemCertChain(certContent); + } catch (Exception e) { + LOGGER.error("读取证书失败", e); + throw new RuntimeException(e); + } + + List rootCerts = new ArrayList(); + try { + X509Certificate[] certs = readPemCertChain(rootCertContent); + rootCerts.addAll(Arrays.asList(certs)); + } catch (Exception e) { + LOGGER.error("读取根证书失败", e); + throw new RuntimeException(e); + } + + return verifyCertChain(certificates, rootCerts.toArray(new X509Certificate[rootCerts.size()])); + } + + /** + * 验证证书是否是信任证书库中证书签发的 + * + * @param cert 目标验证证书 + * @param rootCerts 可信根证书列表 + * @return 验证结果 + */ + private static boolean verifyCert(X509Certificate cert, X509Certificate[] rootCerts) { + try { + cert.checkValidity(); + } catch (CertificateExpiredException e) { + LOGGER.error("证书已经过期", e); + return false; + } catch (CertificateNotYetValidException e) { + LOGGER.error("证书未激活", e); + return false; + } + + Map subjectMap = new HashMap(); + + for (X509Certificate root : rootCerts) { + subjectMap.put(root.getSubjectDN(), root); + } + + Principal issuerDN = cert.getIssuerDN(); + X509Certificate issuer = subjectMap.get(issuerDN); + if (issuer == null) { + LOGGER.error("证书链验证失败"); + return false; + } + try { + PublicKey publicKey = issuer.getPublicKey(); + verifySignature(publicKey, cert); + } catch (Exception e) { + LOGGER.error("证书链验证失败", e); + return false; + } + return true; + } + + /** + * 验证证书链是否是信任证书库中证书签发的 + * + * @param certs 目标验证证书列表 + * @param rootCerts 可信根证书列表 + * @return 验证结果 + */ + private static boolean verifyCertChain(X509Certificate[] certs, X509Certificate[] rootCerts) { + boolean sorted = sortByDn(certs); + if (!sorted) { + LOGGER.error("证书链验证失败:不是完整的证书链"); + return false; + } + + //先验证第一个证书是不是信任库中证书签发的 + X509Certificate prev = certs[0]; + boolean firstOK = verifyCert(prev, rootCerts); + if (!firstOK || certs.length == 1) { + return firstOK; + } + + //验证证书链 + for (int i = 1; i < certs.length; i++) { + try { + X509Certificate cert = certs[i]; + try { + cert.checkValidity(); + } catch (CertificateExpiredException e) { + LOGGER.error("证书已经过期"); + return false; + } catch (CertificateNotYetValidException e) { + LOGGER.error("证书未激活"); + return false; + } + verifySignature(prev.getPublicKey(), cert); + prev = cert; + } catch (Exception e) { + LOGGER.error("证书链验证失败"); + return false; + } + } + + return true; + } + + private static void verifySignature(PublicKey publicKey, X509Certificate cert) + throws NoSuchProviderException, CertificateException, NoSuchAlgorithmException, InvalidKeyException, + SignatureException { + cert.verify(publicKey, provider.getName()); + } + + /** + * 将证书链按照完整的签发顺序进行排序,排序后证书链为:[issuerA, subjectA]-[issuerA, subjectB]-[issuerB, subjectC]-[issuerC, subjectD]... + * + * @param certs 证书链 + * @return true:排序成功,false:证书链不完整 + */ + private static boolean sortByDn(X509Certificate[] certs) { + //主题和证书的映射 + Map subjectMap = new HashMap(); + //签发者和证书的映射 + Map issuerMap = new HashMap(); + //是否包含自签名证书 + boolean hasSelfSignedCert = false; + + for (X509Certificate cert : certs) { + if (isSelfSigned(cert)) { + if (hasSelfSignedCert) { + return false; + } + hasSelfSignedCert = true; + } + + Principal subjectDN = cert.getSubjectDN(); + Principal issuerDN = cert.getIssuerDN(); + + subjectMap.put(subjectDN, cert); + issuerMap.put(issuerDN, cert); + } + + List certChain = new ArrayList(); + + X509Certificate current = certs[0]; + addressingUp(subjectMap, certChain, current); + addressingDown(issuerMap, certChain, current); + + //说明证书链不完整 + if (certs.length != certChain.size()) { + return false; + } + + //将证书链复制到原先的数据 + for (int i = 0; i < certChain.size(); i++) { + certs[i] = certChain.get(i); + } + return true; + } + + /** + * 验证证书是否是自签发的 + * + * @param cert 目标证书 + * @return true;自签发,false;不是自签发 + */ + private static boolean isSelfSigned(X509Certificate cert) { + return cert.getSubjectDN().equals(cert.getIssuerDN()); + } + + /** + * 向上构造证书链 + * + * @param subjectMap 主题和证书的映射 + * @param certChain 证书链 + * @param current 当前需要插入证书链的证书,include + */ + private static void addressingUp(final Map subjectMap, List certChain, + final X509Certificate current) { + certChain.add(0, current); + if (isSelfSigned(current)) { + return; + } + Principal issuerDN = current.getIssuerDN(); + X509Certificate issuer = subjectMap.get(issuerDN); + if (issuer == null) { + return; + } + addressingUp(subjectMap, certChain, issuer); + } + + /** + * 向下构造证书链 + * + * @param issuerMap 签发者和证书的映射 + * @param certChain 证书链 + * @param current 当前需要插入证书链的证书,exclude + */ + private static void addressingDown(final Map issuerMap, List certChain, + final X509Certificate current) { + Principal subjectDN = current.getSubjectDN(); + X509Certificate subject = issuerMap.get(subjectDN); + if (subject == null) { + return; + } + if (isSelfSigned(subject)) { + return; + } + certChain.add(subject); + addressingDown(issuerMap, certChain, subject); + } + + private static X509Certificate[] readPemCertChain(String cert) throws CertificateException { + ByteArrayInputStream inputStream = new ByteArrayInputStream(cert.getBytes()); + CertificateFactory factory = CertificateFactory.getInstance("X.509", provider); + Collection certificates = factory.generateCertificates(inputStream); + return certificates.toArray(new X509Certificate[certificates.size()]); + } + + /** + * 获取支付宝根证书序列号 + * + * @param rootCertContent 支付宝根证书内容 + * @return 支付宝根证书序列号 + */ + public static String getRootCertSN(String rootCertContent) { + String rootCertSN = null; + try { + X509Certificate[] x509Certificates = readPemCertChain(rootCertContent); + MessageDigest md = MessageDigest.getInstance("MD5"); + for (X509Certificate c : x509Certificates) { + if (c.getSigAlgOID().startsWith("1.2.840.113549.1.1")) { + md.update((c.getIssuerX500Principal().getName() + c.getSerialNumber()).getBytes()); + String certSN = new BigInteger(1, md.digest()).toString(16); + //BigInteger会把0省略掉,需补全至32位 + certSN = fillMD5(certSN); + if (Strings.isNullOrEmpty(rootCertSN)) { + rootCertSN = certSN; + } else { + rootCertSN = rootCertSN + "_" + certSN; + } + } + + } + } catch (Exception e) { + LOGGER.error("提取根证书失败"); + } + return rootCertSN; + } + + /** + * 获取公钥证书序列号 + * + * @param certContent 公钥证书内容 + * @return 公钥证书序列号 + */ + public static String getCertSN(String certContent) { + try { + InputStream inputStream = new ByteArrayInputStream(certContent.getBytes()); + CertificateFactory factory = CertificateFactory.getInstance("X.509", "BC"); + X509Certificate cert = (X509Certificate) factory.generateCertificate(inputStream); + return md5((cert.getIssuerX500Principal().getName() + cert.getSerialNumber()).getBytes()); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + private static String md5(byte[] bytes) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(bytes); + String certSN = new BigInteger(1, md.digest()).toString(16); + //BigInteger会把0省略掉,需补全至32位 + certSN = fillMD5(certSN); + return certSN; + } + + private static String fillMD5(String md5) { + return md5.length() == 32 ? md5 : fillMD5("0" + md5); + } + + /** + * 提取公钥证书中的公钥 + * + * @param certContent 公钥证书内容 + * @return 公钥证书中的公钥 + */ + public static String getCertPublicKey(String certContent) { + try { + InputStream inputStream = new ByteArrayInputStream(certContent.getBytes()); + CertificateFactory factory = CertificateFactory.getInstance("X.509", "BC"); + X509Certificate cert = (X509Certificate) factory.generateCertificate(inputStream); + return Base64.toBase64String(cert.getPublicKey().getEncoded()); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + /** + * 从文件中读取证书内容 + * + * @param certPath 证书路径 + * @return 证书内容 + */ + public static String readCertContent(String certPath) { + if (existsInFileSystem(certPath)) { + return readFromFileSystem(certPath); + } + return readFromClassPath(certPath); + } + + private static boolean existsInFileSystem(String certPath) { + try { + return new File(certPath).exists(); + } catch (Throwable e) { + return false; + } + } + + private static String readFromFileSystem(String certPath) { + try { + return new String(Files.toByteArray(new File(certPath)), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("从文件系统中读取[" + certPath + "]失败," + e.getMessage(), e); + } + } + + private static String readFromClassPath(String certPath) { + try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(certPath)) { + return new String(ByteStreams.toByteArray(inputStream), StandardCharsets.UTF_8); + } catch (Exception e) { + String errorMessage = e.getMessage() == null ? "" : e.getMessage() + "。"; + if (certPath.startsWith("/")) { + errorMessage += "ClassPath路径不可以/开头,请去除后重试。"; + } + throw new RuntimeException("读取[" + certPath + "]失败。" + errorMessage, e); + } + } +} diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/JsonUtil.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/JsonUtil.java new file mode 100644 index 0000000..c9838fd --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/JsonUtil.java @@ -0,0 +1,51 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.kernel.util; + +import com.aliyun.tea.TeaModel; +import com.google.gson.Gson; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +/** + * JSON工具类 + * + * @author zhongyu + * @version : JsonUtil.java, v 0.1 2020年02月18日 8:20 下午 zhongyu Exp $ + */ +public class JsonUtil { + /** + * 将Map转换为Json字符串,转换过程中对于TeaModel,使用标注的字段名称而不是字段的变量名 + * + * @param input 输入的Map + * @return Json字符串 + */ + public static String toJsonString(Map input) { + Map result = new HashMap<>(); + for (Entry pair : input.entrySet()) { + if (pair.getValue() instanceof TeaModel) { + result.put(pair.getKey(), getTeaModelMap((TeaModel) pair.getValue())); + } else { + result.put(pair.getKey(), pair.getValue()); + } + } + return new Gson().toJson(result); + } + + private static Map getTeaModelMap(TeaModel teaModel) { + Map result = new HashMap<>(); + Map teaModelMap = teaModel.toMap(); + for (Entry pair : teaModelMap.entrySet()) { + if (pair.getValue() instanceof TeaModel) { + result.put(pair.getKey(), getTeaModelMap((TeaModel) pair.getValue())); + } else { + result.put(pair.getKey(), pair.getValue()); + } + } + return result; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/MultipartUtil.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/MultipartUtil.java new file mode 100644 index 0000000..baa73a2 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/MultipartUtil.java @@ -0,0 +1,77 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.kernel.util; + +import com.alipay.easysdk.kernel.AlipayConstants; +import com.google.common.base.Preconditions; + +import java.io.File; + +/** + * HTTP multipart/form-data格式相关工具类 + * + * @author zhongyu + * @version : MulitpartUtil.java, v 0.1 2020年02月08日 11:26 上午 zhongyu Exp $ + */ +public class MultipartUtil { + /** + * 获取Multipart分界符 + * + * @param boundary 用作分界的随机字符串 + * @return Multipart分界符 + */ + public static byte[] getEntryBoundary(String boundary) { + return ("\r\n--" + boundary + "\r\n").getBytes(); + } + + /** + * 获取Multipart结束标记 + * + * @param boundary 用作分界的随机字符串 + * @return Multipart结束标记 + */ + public static byte[] getEndBoundary(String boundary) { + return ("\r\n--" + boundary + "--\r\n").getBytes(); + } + + /** + * 获取Multipart中的文本参数结构 + * + * @param fieldName 字段名称 + * @param fieldValue 字段值 + * @return 文本参数结构 + */ + public static byte[] getTextEntry(String fieldName, String fieldValue) { + String entry = "Content-Disposition:form-data;name=\"" + + fieldName + + "\"\r\nContent-Type:text/plain\r\n\r\n" + + fieldValue; + return entry.getBytes(AlipayConstants.DEFAULT_CHARSET); + } + + /** + * 获取Multipart中的文件参数结构(不含文件内容,只有文件元数据) + * + * @param fieldName 字段名称 + * @param filePath 文件路径 + * @return 文件参数结构(不含文件内容) + */ + public static byte[] getFileEntry(String fieldName, String filePath) { + String entry = "Content-Disposition:form-data;name=\"" + + fieldName + + "\";filename=\"" + + getFile(filePath).getName() + + "\"\r\nContent-Type:application/octet-stream" + + "\r\n\r\n"; + return entry.getBytes(AlipayConstants.DEFAULT_CHARSET); + } + + private static File getFile(String filePath) { + File file = new File(filePath); + Preconditions.checkArgument(file.exists(), file.getAbsolutePath() + "文件不存在"); + Preconditions.checkArgument(file.getName().contains("."), "文件名必须带上正确的扩展名"); + return file; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/PageUtil.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/PageUtil.java new file mode 100644 index 0000000..6cd98d8 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/PageUtil.java @@ -0,0 +1,59 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.kernel.util; + +import java.util.Map; +import java.util.Map.Entry; + +/** + * 生成页面信息辅助类 + * + * @author zhongyu + * @version : PageUtil.java, v 0.1 2020年02月12日 3:11 下午 zhongyu Exp $ + */ +public class PageUtil { + /** + * 生成表单 + * + * @param actionUrl 表单提交链接 + * @param parameters 表单参数 + * @return 表单字符串 + */ + public static String buildForm(String actionUrl, Map parameters) { + return "
\n" + + buildHiddenFields(parameters) + + "\n" + + "
\n" + + ""; + } + + private static String buildHiddenFields(Map parameters) { + if (parameters == null || parameters.isEmpty()) { + return ""; + } + StringBuilder builder = new StringBuilder(); + for (Entry pair : parameters.entrySet()) { + // 除去参数中的空值 + if (pair.getKey() == null || pair.getValue() == null) { + continue; + } + builder.append(buildHiddenField(pair.getKey(), pair.getValue())); + } + return builder.toString(); + } + + private static String buildHiddenField(String key, String value) { + StringBuilder builder = new StringBuilder(64); + builder.append("\n"); + return builder.toString(); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/ResponseChecker.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/ResponseChecker.java new file mode 100644 index 0000000..97bed6f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/ResponseChecker.java @@ -0,0 +1,39 @@ +/** + * Alipay.com Inc. + * Copyright (c) 2004-2020 All Rights Reserved. + */ +package com.alipay.easysdk.kernel.util; + +import com.aliyun.tea.TeaModel; +import com.google.common.base.Strings; + +import java.lang.reflect.Field; + +/** + * 响应检查工具类 + * + * @author zhongyu + * @version : ResponseChecker.java, v 0.1 2020年06月02日 10:42 上午 zhongyu Exp $ + */ +public class ResponseChecker { + + public static final String SUB_CODE_FIELD_NAME = "subCode"; + + /** + * 判断一个请求返回的响应是否成功 + * + * @param response 响应对象 + * @return true:成功;false:失败 + */ + public static boolean success(TeaModel response) { + try { + Field subCodeField = response.getClass().getField(SUB_CODE_FIELD_NAME); + subCodeField.setAccessible(true); + String subCode = (String) subCodeField.get(response); + return Strings.isNullOrEmpty(subCode); + } catch (NoSuchFieldException | IllegalAccessException e) { + //没有subCode字段的响应对象,通常是那些无需跟网关远程通信的API,只要本地执行完成都视为成功 + return true; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/SignContentExtractor.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/SignContentExtractor.java new file mode 100644 index 0000000..403c89c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/SignContentExtractor.java @@ -0,0 +1,203 @@ +/** + * Alipay.com Inc. Copyright (c) 2004-2019 All Rights Reserved. + */ +package com.alipay.easysdk.kernel.util; + +import com.alipay.easysdk.kernel.AlipayConstants; + +import java.util.LinkedList; + +/** + * 待验签原文提取器 + *

+ * 注:此处不可使用JSON反序列化工具进行提取,会破坏原有格式,对于签名而言差个空格都会验签不通过 + * + * @author zhongyu + * @version $Id: SignContentExtractor.java, v 0.1 2019年12月19日 9:07 PM zhongyu Exp $ + */ +public class SignContentExtractor { + /** + * 左大括号 + */ + public static final char LEFT_BRACE = '{'; + + /** + * 右大括号 + */ + public static final char RIGHT_BRACE = '}'; + + /** + * 双引号 + */ + public static final char DOUBLE_QUOTES = '"'; + + /** + * 获取待验签的原文 + * + * @param body 网关的整体响应字符串 + * @param method 本次调用的OpenAPI接口名称 + * @return 待验签的原文 + */ + public static String getSignSourceData(String body, String method) { + // 加签源串起点 + String rootNode = method.replace('.', '_') + AlipayConstants.RESPONSE_SUFFIX; + String errorRootNode = AlipayConstants.ERROR_RESPONSE; + + int indexOfRootNode = body.indexOf(rootNode); + int indexOfErrorRoot = body.indexOf(errorRootNode); + + if (indexOfRootNode > 0) { + return parseSignSourceData(body, rootNode, indexOfRootNode); + } else if (indexOfErrorRoot > 0) { + return parseSignSourceData(body, errorRootNode, indexOfErrorRoot); + } else { + return null; + } + } + + private static String parseSignSourceData(String body, String rootNode, int indexOfRootNode) { + //第一个字母 + 长度 + 冒号 + 引号 + int signDataStartIndex = indexOfRootNode + rootNode.length() + 2; + + int indexOfSign = body.indexOf("\"" + AlipayConstants.SIGN_FIELD + "\""); + if (indexOfSign < 0) { + return null; + } + + SignSourceData signSourceData = extractSignContent(body, signDataStartIndex); + + //如果提取的待验签原始内容后还有rootNode + if (body.lastIndexOf(rootNode) > signSourceData.getEndIndex()) { + throw new RuntimeException("检测到响应报文中有重复的" + rootNode + ",验签失败。"); + } + + return signSourceData.getSourceData(); + } + + private static SignSourceData extractSignContent(String str, int begin) { + if (str == null) { + return null; + } + + int beginIndex = extractBeginPosition(str, begin); + if (beginIndex >= str.length()) { + return null; + } + + int endIndex = extractEndPosition(str, beginIndex); + return new SignSourceData(str.substring(beginIndex, endIndex), beginIndex, endIndex); + } + + private static int extractBeginPosition(String responseString, int begin) { + int beginPosition = begin; + //找到第一个左大括号(对应响应的是JSON对象的情况:普通调用OpenAPI响应明文) + //或者双引号(对应响应的是JSON字符串的情况:加密调用OpenAPI响应Base64串),作为待验签内容的起点 + while (beginPosition < responseString.length() + && responseString.charAt(beginPosition) != LEFT_BRACE + && responseString.charAt(beginPosition) != DOUBLE_QUOTES) { + ++beginPosition; + } + return beginPosition; + } + + private static int extractEndPosition(String responseString, int beginPosition) { + //提取明文验签内容终点 + if (responseString.charAt(beginPosition) == LEFT_BRACE) { + return extractJsonObjectEndPosition(responseString, beginPosition); + } + //提取密文验签内容终点 + else { + return extractJsonBase64ValueEndPosition(responseString, beginPosition); + } + } + + private static int extractJsonBase64ValueEndPosition(String responseString, int beginPosition) { + for (int index = beginPosition; index < responseString.length(); ++index) { + //找到第2个双引号作为终点,由于中间全部是Base64编码的密文,所以不会有干扰的特殊字符 + if (responseString.charAt(index) == DOUBLE_QUOTES && index != beginPosition) { + return index + 1; + } + } + //如果没有找到第2个双引号,说明验签内容片段提取失败,直接尝试选取剩余整个响应字符串进行验签 + return responseString.length(); + } + + private static int extractJsonObjectEndPosition(String responseString, int beginPosition) { + //记录当前尚未发现配对闭合的大括号 + LinkedList braces = new LinkedList(); + //记录当前字符是否在双引号中 + boolean inQuotes = false; + //记录当前字符前面连续的转义字符个数 + int consecutiveEscapeCount = 0; + //从待验签字符的起点开始遍历后续字符串,找出待验签字符串的终止点,终点即是与起点{配对的} + for (int index = beginPosition; index < responseString.length(); ++index) { + //提取当前字符 + char currentChar = responseString.charAt(index); + + //如果当前字符是"且前面有偶数个转义标记(0也是偶数) + if (currentChar == DOUBLE_QUOTES && consecutiveEscapeCount % 2 == 0) { + //是否在引号中的状态取反 + inQuotes = !inQuotes; + } + //如果当前字符是{且不在引号中 + else if (currentChar == LEFT_BRACE && !inQuotes) { + //将该{加入未闭合括号中 + braces.push(LEFT_BRACE); + } + //如果当前字符是}且不在引号中 + else if (currentChar == RIGHT_BRACE && !inQuotes) { + //弹出一个未闭合括号 + braces.pop(); + //如果弹出后,未闭合括号为空,说明已经找到终点 + if (braces.isEmpty()) { + return index + 1; + } + } + + //如果当前字符是转义字符 + if (currentChar == '\\') { + //连续转义字符个数+1 + ++consecutiveEscapeCount; + } else { + //连续转义字符个数置0 + consecutiveEscapeCount = 0; + } + } + + //如果没有找到配对的闭合括号,说明验签内容片段提取失败,直接尝试选取剩余整个响应字符串进行验签 + return responseString.length(); + } + + private static class SignSourceData { + /** + * 待验签原始内容 + */ + private final String sourceData; + /** + * 待验签原始内容在响应字符串中的起始位置 + */ + private final int beginIndex; + /** + * 待验签原始内容在响应字符串中的结束位置 + */ + private final int endIndex; + + SignSourceData(String sourceData, int beginIndex, int endIndex) { + this.sourceData = sourceData; + this.beginIndex = beginIndex; + this.endIndex = endIndex; + } + + String getSourceData() { + return sourceData; + } + + public int getBeginIndex() { + return beginIndex; + } + + int getEndIndex() { + return endIndex; + } + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/Signer.java b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/Signer.java new file mode 100644 index 0000000..ee81789 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/kernel/java/src/main/java/com/alipay/easysdk/kernel/util/Signer.java @@ -0,0 +1,115 @@ +/** + * Alipay.com Inc. Copyright (c) 2004-2019 All Rights Reserved. + */ +package com.alipay.easysdk.kernel.util; + +import com.alipay.easysdk.kernel.AlipayConstants; +import org.bouncycastle.util.encoders.Base64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * SHA256WithRSA签名器 + * + * @author zhongyu + * @version $Id: Signer.java, v 0.1 2019年12月19日 9:10 PM zhongyu Exp $ + */ +public class Signer { + private static final Logger LOGGER = LoggerFactory.getLogger(Signer.class); + + public static String getSignCheckContent(Map params) { + if (params == null) { + return null; + } + + StringBuilder content = new StringBuilder(); + List keys = new ArrayList<>(params.keySet()); + Collections.sort(keys); + for (int i = 0; i < keys.size(); i++) { + String key = keys.get(i); + String value = params.get(key); + content.append(i == 0 ? "" : "&").append(key).append("=").append(value); + } + return content.toString(); + } + + /** + * 验证签名 + * + * @param content 待验签的内容 + * @param sign 签名值的Base64串 + * @param publicKeyPem 支付宝公钥 + * @return true:验证成功;false:验证失败 + */ + public static boolean verify(String content, String sign, String publicKeyPem) { + try { + KeyFactory keyFactory = KeyFactory.getInstance(AlipayConstants.RSA); + byte[] encodedKey = publicKeyPem.getBytes(); + encodedKey = Base64.decode(encodedKey); + PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); + + Signature signature = Signature.getInstance(AlipayConstants.SHA_256_WITH_RSA); + signature.initVerify(publicKey); + signature.update(content.getBytes(AlipayConstants.DEFAULT_CHARSET)); + return signature.verify(Base64.decode(sign.getBytes())); + } catch (Exception e) { + String errorMessage = "验签遭遇异常,content=" + content + " sign=" + sign + + " publicKey=" + publicKeyPem + " reason=" + e.getMessage(); + LOGGER.error(errorMessage, e); + throw new RuntimeException(errorMessage, e); + } + } + + /** + * 计算签名 + * + * @param content 待签名的内容 + * @param privateKeyPem 私钥 + * @return 签名值的Base64串 + */ + public String sign(String content, String privateKeyPem) { + try { + byte[] encodedKey = privateKeyPem.getBytes(); + encodedKey = Base64.decode(encodedKey); + PrivateKey privateKey = KeyFactory.getInstance(AlipayConstants.RSA).generatePrivate(new PKCS8EncodedKeySpec(encodedKey)); + + Signature signature = Signature.getInstance(AlipayConstants.SHA_256_WITH_RSA); + signature.initSign(privateKey); + signature.update(content.getBytes(AlipayConstants.DEFAULT_CHARSET)); + byte[] signed = signature.sign(); + return new String(Base64.encode(signed)); + } catch (Exception e) { + String errorMessage = "签名遭遇异常,content=" + content + " privateKeySize=" + privateKeyPem.length() + " reason=" + e.getMessage(); + LOGGER.error(errorMessage, e); + throw new RuntimeException(errorMessage, e); + } + } + + /** + * 对参数集合进行验签 + * + * @param parameters 参数集合 + * @param publicKey 支付宝公钥 + * @return true:验证成功;false:验证失败 + */ + public static boolean verifyParams(Map parameters, String publicKey) { + String sign = parameters.get(AlipayConstants.SIGN_FIELD); + parameters.remove(AlipayConstants.SIGN_FIELD); + parameters.remove(AlipayConstants.SIGN_TYPE_FIELD); + + String content = getSignCheckContent(parameters); + + return verify(content, sign, publicKey); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/README.md b/serve/vendor/alipaysdk/easysdk/php/README.md new file mode 100644 index 0000000..c145d52 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/README.md @@ -0,0 +1,229 @@ +[![Latest Stable Version](https://poser.pugx.org/alipaysdk/easysdk/v/stable)](https://packagist.org/packages/alipaysdk/easysdk) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk?ref=badge_shield) + +欢迎使用 Alipay **Easy** SDK for PHP 。 + +Alipay Esay SDK for PHP让您不用复杂编程即可访支付宝开放平台开放的各项常用能力,SDK可以自动帮您满足能力调用过程中所需的证书校验、加签、验签、发送HTTP请求等非功能性要求。 + +下面向您介绍Alipay Easy SDK for PHP 的基本设计理念和使用方法。 + +## 设计理念 +不同于原有的[Alipay SDK](https://openhome.alipay.com/doc/sdkDownload.resource?sdkType=PHP)通用而全面的设计理念,Alipay Easy SDK对开放能力的API进行了更加贴近高频场景的精心设计与裁剪,简化了服务端调用方式,让调用API像使用语言内置的函数一样简便。 + +Alipay Easy SDK提供了与[能力地图](https://opendocs.alipay.com/mini/00am3f)相对应的代码组织结构,让开发者可以快速找到不同能力对应的API。 + +Alipay Easy SDK主要目标是提升开发者在**服务端**集成支付宝开放平台开放的各类核心能力的效率。 + +## 环境要求 +1. Alipay Easy SDK for PHP 需要配合`PHP 7.0`或其以上版本。 + +2. 使用 Alipay Easy SDK for PHP 之前 ,您需要先前往[支付宝开发平台-开发者中心](https://openhome.alipay.com/platform/developerIndex.htm)完成开发者接入的一些准备工作,包括创建应用、为应用添加功能包、设置应用的接口加签方式等。 + +3. 准备工作完成后,注意保存如下信息,后续将作为使用SDK的输入。 + +* 加签模式为公钥证书模式时(推荐) + +`AppId`、`应用的私钥`、`应用公钥证书文件`、`支付宝公钥证书文件`、`支付宝根证书文件` + +* 加签模式为公钥模式时 + +`AppId`、`应用的私钥`、`支付宝公钥` + +## 安装依赖 +### 通过[Composer](https://packagist.org/packages/alipaysdk/easysdk/)在线安装依赖(推荐) + +`composer require alipaysdk/easysdk:^2.2` + +### 本地手动集成依赖(适用于自己修改源码后的本地重新打包安装) +1. 本机安装配置[Composer](https://getcomposer.org/)工具。 +2. 在本`README.md`所在目录下,执行`composer install`,下载SDK依赖。 +3. 依赖文件会下载到`vendor`目录下。 + +## 快速使用 +以下这段代码示例向您展示了使用Alipay Easy SDK for PHP调用一个API的3个主要步骤: + +1. 设置参数(全局只需设置一次)。 +2. 发起API调用。 +3. 处理响应或异常。 + +```php +common()->create("iPhone6 16G", "20200326235526001", "88.88", "2088002656718920"); + $responseChecker = new ResponseChecker(); + //3. 处理响应或异常 + if ($responseChecker->success($result)) { + echo "调用成功". PHP_EOL; + } else { + echo "调用失败,原因:". $result->msg.",".$result->subMsg.PHP_EOL; + } +} catch (Exception $e) { + echo "调用失败,". $e->getMessage(). PHP_EOL;; +} + +function getOptions() +{ + $options = new Config(); + $options->protocol = 'https'; + $options->gatewayHost = 'openapi.alipay.com'; + $options->signType = 'RSA2'; + + $options->appId = '<-- 请填写您的AppId,例如:2019022663440152 -->'; + + // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中 + $options->merchantPrivateKey = '<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->'; + + $options->alipayCertPath = '<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->'; + $options->alipayRootCertPath = '<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt" -->'; + $options->merchantCertPath = '<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->'; + + //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可 + // $options->alipayPublicKey = '<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->'; + + //可设置异步通知接收服务地址(可选) + $options->notifyUrl = "<-- 请填写您的支付类接口异步通知接收服务地址,例如:https://www.test.com/callback -->"; + + //可设置AES密钥,调用AES加解密相关接口时需要(可选) + $options->encryptKey = "<-- 请填写您的AES密钥,例如:aa4BtZ4tspm2wnXLb1ThQA== -->"; + + + + return $options; +} + +``` + +### 扩展调用 +#### ISV代调用 + +```php +Factory::payment()->faceToFace() + // 调用agent扩展方法,设置app_auth_token,完成ISV代调用 + ->agent("ca34ea491e7146cc87d25fca24c4cD11") + ->preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +#### 设置独立的异步通知地址 + +```php +Factory::payment()->faceToFace() + // 调用asyncNotify扩展方法,可以为每此API调用,设置独立的异步通知地址 + // 此处设置的异步通知地址的优先级高于全局Config中配置的异步通知地址 + ->asyncNotify("https://www.test.com/callback") + ->preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +#### 设置可选业务参数 + +```php +$goodDetail = array( + "goods_id" => "apple-01", + "goods_name" => "iPhone6 16G", + "quantity" => 1, + "price" => "5799" + ); + $goodsDetail[0] = $goodDetail; + +Factory::payment()->faceToFace() + // 调用optional扩展方法,完成可选业务参数(biz_content下的可选字段)的设置 + ->optional("seller_id", "2088102146225135") + ->optional("discountable_amount", "8.88") + ->optional("goods_detail", $goodsDetail) + ->preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); + + +$optionalArgs = array( + "timeout_express" => "10m", + "body" => "Iphone6 16G" + ); + +Factory::payment()->faceToFace() + // 也可以调用batchOptional扩展方法,批量设置可选业务参数(biz_content下的可选字段) + ->batchOptional($optionalArgs) + ->preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` +#### 多种扩展灵活组合 + +```php +// 多种扩展方式可灵活组装(对扩展方法的调用顺序没有要求) +Factory::payment()->faceToFace() + ->agent("ca34ea491e7146cc87d25fca24c4cD11") + ->asyncNotify("https://www.test.com/callback") + ->optional("seller_id", "2088102146225135") + ->preCreate("Apple iPhone11 128G", "2234567890", "5799.00"); +``` + +## API组织规范 +在Alipay Easy SDK中,API的引用路径与能力地图的组织层次一致,遵循如下规范 + +> Factory::能力名称()->场景名称()->接口方法名称( ... ) + +比如,如果您想要使用[能力地图](https://opendocs.alipay.com/mini/00am3f)中`营销能力`下的`模板消息`场景中的`小程序发送模板消息`,只需按如下形式编写调用代码即可(不同编程语言的连接符号可能不同)。 + +`Factory::marketing()->templateMessage()->send( ... )` + +其中,接口方法名称通常是对其依赖的OpenAPI功能的一个最简概况,接口方法的出入参与OpenAPI中同名参数含义一致,可参照OpenAPI相关参数的使用说明。 + +Alipay Easy SDK将致力于保持良好的API命名,以符合开发者的编程直觉。 +## 已支持的API列表 + +| 能力类别 | 场景类别 | 接口方法名称 | 调用的OpenAPI名称 | +|-----------|-----------------|------------------------|-----------------------------------------------------------| +| Base | OAuth | getToken | alipay\.system\.oauth\.token | +| Base | OAuth | refreshToken | alipay\.system\.oauth\.token | +| Base | Qrcode | create | alipay\.open\.app\.qrcode\.create | +| Base | Image | upload | alipay\.offline\.material\.image\.upload | +| Base | Video | upload | alipay\.offline\.material\.image\.upload | +| Member | Identification | init | alipay\.user\.certify\.open\.initialize | +| Member | Identification | certify | alipay\.user\.certify\.open\.certify | +| Member | Identification | query | alipay\.user\.certify\.open\.query | +| Payment | Common | create | alipay\.trade\.create | +| Payment | Common | query | alipay\.trade\.query | +| Payment | Common | refund | alipay\.trade\.refund | +| Payment | Common | close | alipay\.trade\.close | +| Payment | Common | cancel | alipay\.trade\.cancel | +| Payment | Common | queryRefund | alipay\.trade\.fastpay\.refund\.query | +| Payment | Common | downloadBill | alipay\.data\.dataservice\.bill\.downloadurl\.query | +| Payment | Common | verifyNotify | - | +| Payment | Huabei | create | alipay\.trade\.create | +| Payment | FaceToFace | pay | alipay\.trade\.pay | +| Payment | FaceToFace | precreate | alipay\.trade\.precreate | +| Payment | App | pay | alipay\.trade\.app\.pay | +| Payment | Page | pay | alipay\.trade\.page\.pay | +| Payment | Wap | pay | alipay\.trade\.wap\.pay | +| Security | TextRisk | detect | alipay\.security\.risk\.content\.detect | +| Marketing | Pass | createTemplate | alipay\.pass\.template\.add | +| Marketing | Pass | updateTemplate | alipay\.pass\.template\.update | +| Marketing | Pass | addInstance | alipay\.pass\.instance\.add | +| Marketing | Pass | updateInstance | alipay\.pass\.instance\.update | +| Marketing | TemplateMessage | send | alipay\.open\.app\.mini\.templatemessage\.send | +| Marketing | OpenLife | createImageTextContent | alipay\.open\.public\.message\.content\.create | +| Marketing | OpenLife | modifyImageTextContent | alipay\.open\.public\.message\.content\.modify | +| Marketing | OpenLife | sendText | alipay\.open\.public\.message\.total\.send | +| Marketing | OpenLife | sendImageText | alipay\.open\.public\.message\.total\.send | +| Marketing | OpenLife | sendSingleMessage | alipay\.open\.public\.message\.single\.send | +| Marketing | OpenLife | recallMessage | alipay\.open\.public\.life\.msg\.recall | +| Marketing | OpenLife | setIndustry | alipay\.open\.public\.template\.message\.industry\.modify | +| Marketing | OpenLife | getIndustry | alipay\.open\.public\.setting\.category\.query | +| Util | AES | decrypt | - | +| Util | AES | encrypt | - | +| Util | Generic | execute | - | +| Util | Generic | sdkExecute | - | +| Util | Generic | fileExecute | - | + +> 注:更多高频场景的API持续更新中,敬请期待。 + +## 文档 +[API Doc](./../APIDoc.md) + +[Alipay Easy SDK](./../README.md) diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Base/Image/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Base/Image/Client.php new file mode 100644 index 0000000..6458572 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Base/Image/Client.php @@ -0,0 +1,198 @@ +_kernel = $kernel; + } + + /** + * @param string $imageName + * @param string $imageFilePath + * @return AlipayOfflineMaterialImageUploadResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function upload($imageName, $imageFilePath){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 100000, + "readTimeout" => 100000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.offline.material.image.upload", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = []; + $textParams = [ + "image_type" => "jpg", + "image_name" => $imageName + ]; + $fileParams = [ + "image_content" => $imageFilePath + ]; + $boundary = $this->_kernel->getRandomBoundary(); + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => $this->_kernel->concatStr("multipart/form-data;charset=utf-8;boundary=", $boundary) + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams)); + $_request->body = $this->_kernel->toMultipartRequestBody($textParams, $fileParams, $boundary); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.offline.material.image.upload"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOfflineMaterialImageUploadResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOfflineMaterialImageUploadResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Base/Image/Models/AlipayOfflineMaterialImageUploadResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Base/Image/Models/AlipayOfflineMaterialImageUploadResponse.php new file mode 100644 index 0000000..2e55ea3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Base/Image/Models/AlipayOfflineMaterialImageUploadResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'imageId' => 'image_id', + 'imageUrl' => 'image_url', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('imageId', $this->imageId, true); + Model::validateRequired('imageUrl', $this->imageUrl, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->imageId) { + $res['image_id'] = $this->imageId; + } + if (null !== $this->imageUrl) { + $res['image_url'] = $this->imageUrl; + } + return $res; + } + /** + * @param array $map + * @return AlipayOfflineMaterialImageUploadResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['image_id'])){ + $model->imageId = $map['image_id']; + } + if(isset($map['image_url'])){ + $model->imageUrl = $map['image_url']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $imageId; + + /** + * @var string + */ + public $imageUrl; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Base/OAuth/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Base/OAuth/Client.php new file mode 100644 index 0000000..1f4e531 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Base/OAuth/Client.php @@ -0,0 +1,283 @@ +_kernel = $kernel; + } + + /** + * @param string $code + * @return AlipaySystemOauthTokenResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function getToken($code){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.system.oauth.token", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = []; + $textParams = [ + "grant_type" => "authorization_code", + "code" => $code + ]; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.system.oauth.token"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipaySystemOauthTokenResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipaySystemOauthTokenResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $refreshToken + * @return AlipaySystemOauthTokenResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function refreshToken($refreshToken){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.system.oauth.token", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = []; + $textParams = [ + "grant_type" => "refresh_token", + "refresh_token" => $refreshToken + ]; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.system.oauth.token"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipaySystemOauthTokenResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipaySystemOauthTokenResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Base/OAuth/Models/AlipaySystemOauthTokenResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Base/OAuth/Models/AlipaySystemOauthTokenResponse.php new file mode 100644 index 0000000..eee2163 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Base/OAuth/Models/AlipaySystemOauthTokenResponse.php @@ -0,0 +1,156 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'userId' => 'user_id', + 'accessToken' => 'access_token', + 'expiresIn' => 'expires_in', + 'refreshToken' => 'refresh_token', + 'reExpiresIn' => 're_expires_in', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('userId', $this->userId, true); + Model::validateRequired('accessToken', $this->accessToken, true); + Model::validateRequired('expiresIn', $this->expiresIn, true); + Model::validateRequired('refreshToken', $this->refreshToken, true); + Model::validateRequired('reExpiresIn', $this->reExpiresIn, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->userId) { + $res['user_id'] = $this->userId; + } + if (null !== $this->accessToken) { + $res['access_token'] = $this->accessToken; + } + if (null !== $this->expiresIn) { + $res['expires_in'] = $this->expiresIn; + } + if (null !== $this->refreshToken) { + $res['refresh_token'] = $this->refreshToken; + } + if (null !== $this->reExpiresIn) { + $res['re_expires_in'] = $this->reExpiresIn; + } + return $res; + } + /** + * @param array $map + * @return AlipaySystemOauthTokenResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['user_id'])){ + $model->userId = $map['user_id']; + } + if(isset($map['access_token'])){ + $model->accessToken = $map['access_token']; + } + if(isset($map['expires_in'])){ + $model->expiresIn = $map['expires_in']; + } + if(isset($map['refresh_token'])){ + $model->refreshToken = $map['refresh_token']; + } + if(isset($map['re_expires_in'])){ + $model->reExpiresIn = $map['re_expires_in']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $userId; + + /** + * @var string + */ + public $accessToken; + + /** + * @var int + */ + public $expiresIn; + + /** + * @var string + */ + public $refreshToken; + + /** + * @var int + */ + public $reExpiresIn; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Base/Qrcode/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Base/Qrcode/Client.php new file mode 100644 index 0000000..1e8cd1f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Base/Qrcode/Client.php @@ -0,0 +1,196 @@ +_kernel = $kernel; + } + + /** + * @param string $urlParam + * @param string $queryParam + * @param string $describe + * @return AlipayOpenAppQrcodeCreateResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function create($urlParam, $queryParam, $describe){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.app.qrcode.create", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "url_param" => $urlParam, + "query_param" => $queryParam, + "describe" => $describe + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.app.qrcode.create"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenAppQrcodeCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenAppQrcodeCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Base/Qrcode/Models/AlipayOpenAppQrcodeCreateResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Base/Qrcode/Models/AlipayOpenAppQrcodeCreateResponse.php new file mode 100644 index 0000000..88f254f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Base/Qrcode/Models/AlipayOpenAppQrcodeCreateResponse.php @@ -0,0 +1,104 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'qrCodeUrl' => 'qr_code_url', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('qrCodeUrl', $this->qrCodeUrl, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->qrCodeUrl) { + $res['qr_code_url'] = $this->qrCodeUrl; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenAppQrcodeCreateResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['qr_code_url'])){ + $model->qrCodeUrl = $map['qr_code_url']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $qrCodeUrl; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Base/Video/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Base/Video/Client.php new file mode 100644 index 0000000..dac3d80 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Base/Video/Client.php @@ -0,0 +1,198 @@ +_kernel = $kernel; + } + + /** + * @param string $videoName + * @param string $videoFilePath + * @return AlipayOfflineMaterialImageUploadResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function upload($videoName, $videoFilePath){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 100000, + "readTimeout" => 100000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.offline.material.image.upload", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = []; + $textParams = [ + "image_type" => "mp4", + "image_name" => $videoName + ]; + $fileParams = [ + "image_content" => $videoFilePath + ]; + $boundary = $this->_kernel->getRandomBoundary(); + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => $this->_kernel->concatStr("multipart/form-data;charset=utf-8;boundary=", $boundary) + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams)); + $_request->body = $this->_kernel->toMultipartRequestBody($textParams, $fileParams, $boundary); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.offline.material.image.upload"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOfflineMaterialImageUploadResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOfflineMaterialImageUploadResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Base/Video/Models/AlipayOfflineMaterialImageUploadResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Base/Video/Models/AlipayOfflineMaterialImageUploadResponse.php new file mode 100644 index 0000000..12afa5b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Base/Video/Models/AlipayOfflineMaterialImageUploadResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'imageId' => 'image_id', + 'imageUrl' => 'image_url', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('imageId', $this->imageId, true); + Model::validateRequired('imageUrl', $this->imageUrl, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->imageId) { + $res['image_id'] = $this->imageId; + } + if (null !== $this->imageUrl) { + $res['image_url'] = $this->imageUrl; + } + return $res; + } + /** + * @param array $map + * @return AlipayOfflineMaterialImageUploadResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['image_id'])){ + $model->imageId = $map['image_id']; + } + if(isset($map['image_url'])){ + $model->imageUrl = $map['image_url']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $imageId; + + /** + * @var string + */ + public $imageUrl; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/AlipayConstants.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/AlipayConstants.php new file mode 100644 index 0000000..6b16ee7 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/AlipayConstants.php @@ -0,0 +1,63 @@ +rootCertSN = $antCertificationUtil->getRootCertSN($alipayRootCertPath); + $this->merchantCertSN = $antCertificationUtil->getCertSN($merchantCertPath); + $this->cachedAlipayPublicKey = $antCertificationUtil->getPublicKey($alipayCertPath); + } + + /** + * @return mixed + */ + public function getRootCertSN() + { + return $this->rootCertSN; + } + + /** + * @return mixed + */ + public function getMerchantCertSN() + { + return $this->merchantCertSN; + } + + /** + * @return mixed + */ + public function getCachedAlipayPublicKey() + { + return $this->cachedAlipayPublicKey; + } + + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Config.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Config.php new file mode 100644 index 0000000..43ce1a4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Config.php @@ -0,0 +1,26 @@ +config = $config; + } + + public function injectTextParam($key, $value) + { + if ($key != null) { + $this->optionalTextParams[$key] = $value; + } + } + + public function injectBizParam($key, $value) + { + if ($key != null) { + $this->optionalBizParams[$key] = $value; + } + } + + /** + * 获取时间戳,格式yyyy-MM-dd HH:mm:ss + * @return false|string 当前时间戳 + */ + public function getTimestamp() + { + return date("Y-m-d H:i:s"); + } + + public function getConfig($key) + { + return $this->config->$key; + } + + public function getSdkVersion() + { + return AlipayConstants::SDK_VERSION; + } + + /** + * 将业务参数和其他额外文本参数按www-form-urlencoded格式转换成HTTP Body中的字节数组,注意要做URL Encode + * + * @param $bizParams array 业务参数 + * @return false|string|null + */ + public function toUrlEncodedRequestBody($bizParams) + { + $sortedMap = $this->getSortedMap(null, $bizParams, null); + if (empty($sortedMap)) { + return null; + } + return $this->buildQueryString($sortedMap); + } + + /** + * 解析网关响应内容,同时将API的接口名称和响应原文插入到响应数组的method和body字段中 + * + * @param $response ResponseInterface HTTP响应 + * @param $method string 调用的OpenAPI的接口名称 + * @return array 响应的结果 + */ + public function readAsJson($response, $method) + { + $responseBody = (string)$response->getBody(); + $map = []; + $map[AlipayConstants::BODY_FIELD] = $responseBody; + $map[AlipayConstants::METHOD_FIELD] = $method; + return $map; + } + + /** + * 生成随机分界符,用于multipart格式的HTTP请求Body的多个字段间的分隔 + * + * @return string 随机分界符 + */ + public function getRandomBoundary() + { + return date("Y-m-d H:i:s") . ''; + } + + /** + * 将其他额外文本参数和文件参数按multipart/form-data格式转换成HTTP Body中 + * @param $textParams + * @param $fileParams + * @param $boundary + * @return false|string + */ + public function toMultipartRequestBody($textParams, $fileParams, $boundary) + { + $this->textParams = $textParams; + if ($textParams != null && $this->optionalTextParams != null) { + $this->textParams = array_merge($textParams, $this->optionalTextParams); + } else if ($textParams == null) { + $this->textParams = $this->optionalTextParams; + } + if (count($fileParams) > 0) { + + foreach ($fileParams as $key => $value) { + $fileField = new FileField(); + $fileField->filename = $value; + $fileField->contentType = 'multipart/form-data;charset=utf-8;boundary=' . $boundary; + $fileField->content = new Stream(fopen($value, 'r')); + $this->textParams[$key] = $fileField; + } + } + $stream = FileForm::toFileForm($this->textParams, $boundary); + + do { + $readLength = $stream->read(1024); + } while (0 != $readLength); + return $stream; + } + + /** + * 生成页面类请求所需URL或Form表单 + * @param $method + * @param $systemParams + * @param $bizParams + * @param $textParams + * @param $sign + * @return string + * @throws \Exception + */ + public function generatePage($method, $systemParams, $bizParams, $textParams, $sign) + { + if ($method == AlipayConstants::GET) { + //采集并排序所有参数 + $sortedMap = $this->getSortedMap($systemParams, $bizParams, $textParams); + $sortedMap[AlipayConstants::SIGN_FIELD] = $sign; + return $this->getGatewayServerUrl() . '?' . $this->buildQueryString($sortedMap); + } elseif ($method == AlipayConstants::POST) { + //采集并排序所有参数 + $sortedMap = $this->getSortedMap($systemParams, $this->bizParams, $this->textParams); + $sortedMap[AlipayConstants::SIGN_FIELD] = $sign; + $pageUtil = new PageUtil(); + return $pageUtil->buildForm($this->getGatewayServerUrl(), $sortedMap); + } else { + throw new \Exception("不支持" . $method); + } + } + + /** + * 获取商户应用公钥证书序列号,从证书模式运行时环境对象中直接读取 + * + * @return mixed 商户应用公钥证书序列号 + */ + public function getMerchantCertSN() + { + return $this->config->merchantCertSN; + } + + /** + * 从响应Map中提取支付宝公钥证书序列号 + * + * @param array $respMap string 响应Map + * @return mixed 支付宝公钥证书序列号 + */ + public function getAlipayCertSN(array $respMap) + { + if (!empty($this->config->merchantCertSN)) { + $body = json_decode($respMap[AlipayConstants::BODY_FIELD]); + $alipayCertSN = $body->alipay_cert_sn; + return $alipayCertSN; + } + } + + /** + * 获取支付宝根证书序列号,从证书模式运行时环境对象中直接读取 + * + * @return mixed 支付宝根证书序列号 + */ + public function getAlipayRootCertSN() + { + return $this->config->alipayRootCertSN; + } + + /** + * 是否是证书模式 + * @return mixed true:是;false:不是 + */ + public function isCertMode() + { + return $this->config->merchantCertSN; + } + + public function extractAlipayPublicKey($alipayCertSN) + { + // PHP 版本只存储一个版本支付宝公钥 + return $this->config->alipayPublicKey; + } + + /** + * 验证签名 + * + * @param $respMap string 响应内容,可以从中提取出sign和body + * @param $alipayPublicKey string 支付宝公钥 + * @return bool true:验签通过;false:验签不通过 + * @throws \Exception + */ + public function verify($respMap, $alipayPublicKey) + { + $resp = json_decode($respMap[AlipayConstants::BODY_FIELD], true); + $sign = $resp[AlipayConstants::SIGN_FIELD]; + $signContentExtractor = new SignContentExtractor(); + $content = $signContentExtractor->getSignSourceData($respMap[AlipayConstants::BODY_FIELD], + $respMap[AlipayConstants::METHOD_FIELD]); + $signer = new Signer(); + return $signer->verify($content, $sign, $alipayPublicKey); + } + + /** + * 计算签名,注意要去除key或value为null的键值对 + * + * @param $systemParams array 系统参数集合 + * @param $bizParams array 业务参数集合 + * @param $textParams array 其他额外文本参数集合 + * @param $privateKey string 私钥 + * @return string 签名值的Base64串 + */ + public function sign($systemParams, $bizParams, $textParams, $privateKey) + { + $sortedMap = $this->getSortedMap($systemParams, $bizParams, $textParams); + $data = $this->getSignContent($sortedMap); + $sign = new Signer(); + return $sign->sign($data, $privateKey); + } + + /** + * AES加密 + * @param $content + * @param $encryptKey + * @return string + * @throws \Exception + */ + public function aesEncrypt($content, $encryptKey) + { + $aes = new AES(); + return $aes->aesEncrypt($content, $encryptKey); + } + + /** + * AES解密 + * @param $content + * @param $encryptKey + * @return false|string + * @throws \Exception + */ + public function aesDecrypt($content, $encryptKey) + { + $aes = new AES(); + return $aes->aesDecrypt($content, $encryptKey); + } + + /** + * 生成sdkExecute类请求所需URL + * + * @param $systemParams + * @param $bizParams + * @param $textParams + * @param $sign + * @return string + */ + public function generateOrderString($systemParams, $bizParams, $textParams, $sign) + { + //采集并排序所有参数 + $sortedMap = $this->getSortedMap($systemParams, $bizParams, $textParams); + $sortedMap[AlipayConstants::SIGN_FIELD] = $sign; + return http_build_query($sortedMap); + } + + public function sortMap($randomMap) + { + return $randomMap; + } + + + /** + * 从响应Map中提取返回值对象的Map,并将响应原文插入到body字段中 + * + * @param $respMap string 响应内容 + * @return mixed + */ + public function toRespModel($respMap) + { + $body = $respMap[AlipayConstants::BODY_FIELD]; + $methodName = $respMap[AlipayConstants::METHOD_FIELD]; + $responseNodeName = str_replace(".", "_", $methodName) . AlipayConstants::RESPONSE_SUFFIX; + + $model = json_decode($body, true); + if (strpos($body, AlipayConstants::ERROR_RESPONSE)) { + $result = $model[AlipayConstants::ERROR_RESPONSE]; + $result[AlipayConstants::BODY_FIELD] = $body; + } else { + $result = $model[$responseNodeName]; + $result[AlipayConstants::BODY_FIELD] = $body; + } + return $result; + } + + public function verifyParams($parameters, $publicKey) + { + $sign = new Signer(); + return $sign->verifyParams($parameters, $publicKey); + } + + /** + * 字符串拼接 + * + * @param $a + * @param $b + * @return string 字符串a和b拼接后的字符串 + */ + public function concatStr($a, $b) + { + return $a . $b; + } + + + private function buildQueryString(array $sortedMap) + { + $requestUrl = null; + foreach ($sortedMap as $sysParamKey => $sysParamValue) { + $requestUrl .= "$sysParamKey=" . urlencode($this->characet($sysParamValue, AlipayConstants::DEFAULT_CHARSET)) . "&"; + } + $requestUrl = substr($requestUrl, 0, -1); + return $requestUrl; + + } + + private function getSortedMap($systemParams, $bizParams, $textParams) + { + $this->textParams = $textParams; + $this->bizParams = $bizParams; + if ($textParams != null && $this->optionalTextParams != null) { + $this->textParams = array_merge($textParams, $this->optionalTextParams); + } else if ($textParams == null) { + $this->textParams = $this->optionalTextParams; + } + if ($bizParams != null && $this->optionalBizParams != null) { + $this->bizParams = array_merge($bizParams, $this->optionalBizParams); + } else if ($bizParams == null) { + $this->bizParams = $this->optionalBizParams; + } + $json = new JsonUtil(); + if ($this->bizParams != null) { + $bizParams = $json->toJsonString($this->bizParams); + } + $sortedMap = $systemParams; + if (!empty($bizParams)) { + $sortedMap[AlipayConstants::BIZ_CONTENT_FIELD] = json_encode($bizParams, JSON_UNESCAPED_UNICODE); + } + if (!empty($this->textParams)) { + if (!empty($sortedMap)) { + $sortedMap = array_merge($sortedMap, $this->textParams); + } else { + $sortedMap = $this->textParams; + } + } + if ($this->getConfig(AlipayConstants::NOTIFY_URL_CONFIG_KEY) != null) { + $sortedMap[AlipayConstants::NOTIFY_URL_FIELD] = $this->getConfig(AlipayConstants::NOTIFY_URL_CONFIG_KEY); + } + return $sortedMap; + } + + /** + * 获取签名字符串 + * + * @param $params + * @return string + */ + private function getSignContent($params) + { + ksort($params); + $stringToBeSigned = ""; + $i = 0; + foreach ($params as $k => $v) { + if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) { + // 转换成目标字符集 + $v = $this->characet($v, AlipayConstants::DEFAULT_CHARSET); + if ($i == 0) { + $stringToBeSigned .= "$k" . "=" . "$v"; + } else { + $stringToBeSigned .= "&" . "$k" . "=" . "$v"; + } + $i++; + } + } + unset ($k, $v); + return $stringToBeSigned; + } + + private function setNotifyUrl($params) + { + if ($this->config(AlipayConstants::NOTIFY_URL_CONFIG_KEY) != null && $params(AlipayConstants::NOTIFY_URL_CONFIG_KEY) == null) { + $params[AlipayConstants::NOTIFY_URL_CONFIG_KEY] = $this->config(AlipayConstants::NOTIFY_URL_CONFIG_KEY); + } + } + + private function getGatewayServerUrl() + { + return $this->getConfig(AlipayConstants::PROTOCOL_CONFIG_KEY) . '://' . $this->getConfig(AlipayConstants::HOST_CONFIG_KEY) . '/gateway.do'; + } + + /** + * 校验$value是否非空 + * + * @param $value + * @return bool if not set ,return true;if is null , return true; + */ + function checkEmpty($value) + { + if (!isset($value)) + return true; + if ($value === null) + return true; + if (trim($value) === "") + return true; + return false; + } + + /** + * 转换字符集编码 + * @param $data + * @param $targetCharset + * @return string + */ + function characet($data, $targetCharset) + { + if (!empty($data)) { + $fileType = AlipayConstants::DEFAULT_CHARSET; + if (strcasecmp($fileType, $targetCharset) != 0) { + $data = mb_convert_encoding($data, $targetCharset, $fileType); + } + } + return $data; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Exceptions/RuntimeException.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Exceptions/RuntimeException.php new file mode 100644 index 0000000..cd6ca67 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Exceptions/RuntimeException.php @@ -0,0 +1,10 @@ +alipayCertPath)) { + $certEnvironment = new CertEnvironment(); + $certEnvironment->certEnvironment( + $config->merchantCertPath, + $config->alipayCertPath, + $config->alipayRootCertPath + ); + $config->merchantCertSN = $certEnvironment->getMerchantCertSN(); + $config->alipayRootCertSN = $certEnvironment->getRootCertSN(); + $config->alipayPublicKey = $certEnvironment->getCachedAlipayPublicKey(); + } + + $kernel = new EasySDKKernel($config); + self::$base = new Base($kernel); + self::$marketing = new Marketing($kernel); + self::$member = new Member($kernel); + self::$payment = new Payment($kernel); + self::$security = new Security($kernel); + self::$util = new Util($kernel); + } + + public static function setOptions($config) + { + if (!(self::$instance instanceof self)) { + self::$instance = new self($config); + } + return self::$instance; + } + + private function __clone() + { + } + + public static function base() + { + return self::$base; + } + + public static function marketing() + { + return self::$marketing; + } + + public static function member() + { + return self::$member; + } + + public static function payment() + { + return self::$payment; + } + + public static function security() + { + return self::$security; + } + + public static function util() + { + return self::$util; + } +} + + +class Base +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function image() + { + return new imageClient($this->kernel); + } + + public function oauth() + { + return new oauthClient($this->kernel); + } + + public function qrcode() + { + return new qrcodeClient($this->kernel); + } + + public function video() + { + return new videoClient($this->kernel); + } +} + +class Marketing +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function openLife() + { + return new openLifeClient($this->kernel); + } + + public function pass() + { + return new passClient($this->kernel); + } + + public function templateMessage() + { + return new templateMessageClient($this->kernel); + } +} + +class Member +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function identification() + { + return new identificationClient($this->kernel); + } +} + +class Payment +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function app() + { + return new appClient($this->kernel); + } + + public function common() + { + return new commonClient($this->kernel); + } + + public function faceToFace() + { + return new faceToFaceClient($this->kernel); + } + + public function huabei() + { + return new huabeiClient($this->kernel); + } + + public function page() + { + return new pageClient($this->kernel); + } + + public function wap() + { + return new wapClient($this->kernel); + } +} + +class Security +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function textRisk() + { + return new textRiskClient($this->kernel); + } +} + +class Util +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function generic() + { + return new genericClient($this->kernel); + } + + public function aes(){ + return new aesClient($this->kernel); + } +} + diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/MultipleFactory.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/MultipleFactory.php new file mode 100644 index 0000000..02a039f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/MultipleFactory.php @@ -0,0 +1,249 @@ +alipayCertPath)) { + $certEnvironment = new CertEnvironment(); + $certEnvironment->certEnvironment( + $config->merchantCertPath, + $config->alipayCertPath, + $config->alipayRootCertPath + ); + $config->merchantCertSN = $certEnvironment->getMerchantCertSN(); + $config->alipayRootCertSN = $certEnvironment->getRootCertSN(); + $config->alipayPublicKey = $certEnvironment->getCachedAlipayPublicKey(); + } + + $kernel = new EasySDKKernel($config); + self::$base = new Base($kernel); + self::$marketing = new Marketing($kernel); + self::$member = new Member($kernel); + self::$payment = new Payment($kernel); + self::$security = new Security($kernel); + self::$util = new Util($kernel); + } + + public static function setOptions($config) + { + self::$instance = new self($config); + return self::$instance; + } + + private function __clone() + { + } + + public static function base() + { + return self::$base; + } + + public static function marketing() + { + return self::$marketing; + } + + public static function member() + { + return self::$member; + } + + public static function payment() + { + return self::$payment; + } + + public static function security() + { + return self::$security; + } + + public static function util() + { + return self::$util; + } +} + + +class Base +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function image() + { + return new imageClient($this->kernel); + } + + public function oauth() + { + return new oauthClient($this->kernel); + } + + public function qrcode() + { + return new qrcodeClient($this->kernel); + } + + public function video() + { + return new videoClient($this->kernel); + } +} + +class Marketing +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function openLife() + { + return new openLifeClient($this->kernel); + } + + public function pass() + { + return new passClient($this->kernel); + } + + public function templateMessage() + { + return new templateMessageClient($this->kernel); + } +} + +class Member +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function identification() + { + return new identificationClient($this->kernel); + } +} + +class Payment +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function app() + { + return new appClient($this->kernel); + } + + public function common() + { + return new commonClient($this->kernel); + } + + public function faceToFace() + { + return new faceToFaceClient($this->kernel); + } + + public function huabei() + { + return new huabeiClient($this->kernel); + } + + public function page() + { + return new pageClient($this->kernel); + } + + public function wap() + { + return new wapClient($this->kernel); + } +} + +class Security +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function textRisk() + { + return new textRiskClient($this->kernel); + } +} + +class Util +{ + private $kernel; + + public function __construct($kernel) + { + $this->kernel = $kernel; + } + + public function generic() + { + return new genericClient($this->kernel); + } + + public function aes() + { + return new aesClient($this->kernel); + } +} + diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/AES.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/AES.php new file mode 100644 index 0000000..284e723 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/AES.php @@ -0,0 +1,94 @@ +addPKCS7Padding($str); + $iv = str_repeat("\0", 16); + $encrypt_str = openssl_encrypt($str, 'aes-128-cbc', $screct_key, OPENSSL_NO_PADDING, $iv); + return base64_encode($encrypt_str); + } catch (\Exception $e) { + throw new \Exception("AES加密失败,plainText=".$plainText.",keySize=".strlen($key)."。".$e->getMessage()); + } + } + + + /** + * AES解密 + * + * @param $cipherText String 密文 + * @param $key String 对称密钥 + * @return false|string + * @throws \Exception + */ + public function aesDecrypt($cipherText, $key) + { + try{ + if(strlen($key) == 0){ + throw new \Exception("AES加密失败,plainText=".$cipherText.",AES密钥为空。"); + } + //AES, 128 模式加密数据 CBC + $str = base64_decode($cipherText); + $screct_key = base64_decode($key); + $iv = str_repeat("\0", 16); + $decrypt_str = openssl_decrypt($str, 'aes-128-cbc', $screct_key, OPENSSL_NO_PADDING, $iv); + $decrypt_str = $this->stripPKSC7Padding($decrypt_str); + return $decrypt_str; + }catch (\Exception $e){ + throw new \Exception("AES解密失败,cipherText=".$cipherText.",keySize=".strlen($key)."。".$e->getMessage()); + } + } + + /** + * 填充算法 + * @param string $source + * @return string + */ + private 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 + */ + private function stripPKSC7Padding($source) + { + $char = substr($source, -1); + $num = ord($char); + if ($num == 62) return $source; + $source = substr($source, 0, -$num); + return $source; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/AlipayEncrypt.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/AlipayEncrypt.php new file mode 100644 index 0000000..71ecff5 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/AlipayEncrypt.php @@ -0,0 +1,12 @@ +array2string(array_reverse($ssl['issuer'])) . $ssl['serialNumber']); + return $SN; + } + + /** + * 从证书中提取公钥 + * @param $certPath + * @return mixed + */ + public function getPublicKey($certPath) + { + $cert = file_get_contents($certPath); + $pkey = openssl_pkey_get_public($cert); + $keyData = openssl_pkey_get_details($pkey); + $public_key = str_replace('-----BEGIN PUBLIC KEY-----', '', $keyData['key']); + $public_key = trim(str_replace('-----END PUBLIC KEY-----', '', $public_key)); + return $public_key; + } + + /** + * 提取根证书序列号 + * @param $certPath string 根证书 + * @return string|null + */ + public function getRootCertSN($certPath) + { + $cert = file_get_contents($certPath); + $this->rootCertContent = $cert; + $array = explode("-----END CERTIFICATE-----", $cert); + $SN = null; + for ($i = 0; $i < count($array) - 1; $i++) { + $ssl[$i] = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----"); + if (strpos($ssl[$i]['serialNumber'], '0x') === 0) { + $ssl[$i]['serialNumber'] = $this->hex2dec($ssl[$i]['serialNumber']); + } + if ($ssl[$i]['signatureTypeLN'] == "sha1WithRSAEncryption" || $ssl[$i]['signatureTypeLN'] == "sha256WithRSAEncryption") { + if ($SN == null) { + $SN = md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']); + } else { + + $SN = $SN . "_" . md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']); + } + } + } + return $SN; + } + + + /** + * 0x转高精度数字 + * @param $hex + * @return int|string + */ + function hex2dec($hex) + { + $dec = 0; + $len = strlen($hex); + for ($i = 1; $i <= $len; $i++) { + $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i)))); + } + return $dec; + } + + + /** + * 验证支付宝公钥证书是否可信 + * @param $alipayCert 支付宝公钥证书 + * @param $rootCert 支付宝根证书 + * @return bool 验证证书是否可信 + */ + function isTrusted($alipayCert, $rootCert) + { + $alipayCerts = $this->readPemCertChain($alipayCert); + $rootCerts = $this->readPemCertChain($rootCert); + if ($this->verifyCertChain($alipayCerts, $rootCerts)) { + return $this->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 = $this->isCertSigner($alipayCertArray[0] . "-----END CERTIFICATE-----", $alipayCertArray[1] . "-----END CERTIFICATE-----"); + if (!$checkSign) { + $checkSign = $this->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) { + $this->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 = $this->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 = $this->array2string($rootCerts[$i]['subject']); + $subjectMap[$subjectDN] = $rootCerts[$i]; + } + $issuerDN = $this->array2string(($prev['issuer'])); + if (!array_key_exists($issuerDN, $subjectMap)) { + echo "证书链验证失败"; + return false; + } + return true; + } + + /** + * 验证证书链是否是信任证书库中证书签发的 + * @param $alipayCerts array 目标验证证书列表 + * @param $rootCerts array 可信根证书列表 + * @return bool + */ + function verifyCertChain($alipayCerts, $rootCerts) + { + $sorted = $this->sortByDn($alipayCerts); + if (!$sorted) { + echo "证书链验证失败:不是完整的证书链"; + return false; + } + //先验证第一个证书是不是信任库中证书签发的 + $prev = $alipayCerts[0]; + $firstOK = $this->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 array 证书链 + * @return bool + */ + function sortByDn(&$certs) + { + //是否包含自签名证书 + $hasSelfSignedCert = false; + $subjectMap = null; + $issuerMap = null; + for ($i = 0; $i < count($certs); $i++) { + if ($this->isSelfSigned($certs[$i])) { + if ($hasSelfSignedCert) { + return false; + } + $hasSelfSignedCert = true; + } + $subjectDN = $this->array2string($certs[$i]['subject']); + $issuerDN = $this->array2string(($certs[$i]['issuer'])); + $subjectMap[$subjectDN] = $certs[$i]; + $issuerMap[$issuerDN] = $certs[$i]; + } + $certChain = null; + $this->addressingUp($subjectMap, $certChain, $certs[0]); + $this->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 array 目标证书 + * @return bool + */ + function isSelfSigned($cert) + { + $subjectDN = $this->array2string($cert['subject']); + $issuerDN = $this->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 array 主题和证书的映射 + * @param $certChain array 证书链 + * @param $current 当前需要插入证书链的证书,include + */ + function addressingUp($subjectMap, &$certChain, $current) + { + $certChain[] = $current; + if ($this->isSelfSigned($current)) { + return; + } + $issuerDN = $this->array2string($current['issuer']); + + if (!array_key_exists($issuerDN, $subjectMap)) { + return; + } + $this->addressingUp($subjectMap, $certChain, $subjectMap[$issuerDN]); + } + + /** + * 向下构造证书链 + * @param $issuerMap 签发者和证书的映射 + * @param $certChain 证书链 + * @param $current 当前需要插入证书链的证书,exclude + * @return mixed + */ + function addressingDown($issuerMap, &$certChain, $current) + { + $subjectDN = $this->array2string($current['subject']); + if (!array_key_exists($subjectDN, $issuerMap)) { + return $certChain; + } + $certChain[] = $issuerMap[$subjectDN]; + $this->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); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/JsonUtil.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/JsonUtil.php new file mode 100644 index 0000000..65f0ab3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/JsonUtil.php @@ -0,0 +1,56 @@ + $v) { + if ($v instanceof Model) { + $result[$k] = $this->getTeaModelMap($v); + } else { + $result[$k] = $v; + } + } + return $result; + } + + private function getTeaModelMap(Model $teaModel) + { + $result = []; + foreach ($teaModel as $k => $v) { + if ($v instanceof Model) { + $k = $this->toUnderScore($k); + $result[$k] = $this->getTeaModelMap($v); + } else { + if (empty($result)) { + $k = $this->toUnderScore($k); + $result[$k] = $v; + } else { + $k = $this->toUnderScore($k); + $result[$k] = $v; + } + } + } + return $result; + } + + /** + * 驼峰命名转下划线命名 + * @param $str + * @return string + */ + private function toUnderScore($str) + { + $dstr = preg_replace_callback('/([A-Z]+)/', function ($matchs) { + return '_' . strtolower($matchs[0]); + }, $str); + return trim(preg_replace('/_{2,}/', '_', $dstr), '_'); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/PageUtil.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/PageUtil.php new file mode 100644 index 0000000..a0bdf6d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/PageUtil.php @@ -0,0 +1,60 @@ +"; + while (list ($key, $val) = $this->fun_adm_each($parameters)) { + if (false === $this->checkEmpty($val)) { + $val = str_replace("'", "'", $val); + //$val = str_replace("\"",""",$val); + $sHtml .= ""; + } + } + + //submit按钮控件请不要含有name属性 + $sHtml = $sHtml . ""; + + $sHtml = $sHtml . ""; + + return $sHtml; + } + + protected function fun_adm_each(&$array) + { + $res = array(); + $key = key($array); + if ($key !== null) { + next($array); + $res[1] = $res['value'] = $array[$key]; + $res[0] = $res['key'] = $key; + } else { + $res = false; + } + return $res; + } + + /** + * 校验$value是否非空 + * if not set ,return true; + * if is null , return true; + **/ + protected function checkEmpty($value) + { + if (!isset($value)) + return true; + if ($value === null) + return true; + if (trim($value) === "") + return true; + + return false; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/ResponseChecker.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/ResponseChecker.php new file mode 100644 index 0000000..dc374cd --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/ResponseChecker.php @@ -0,0 +1,19 @@ +code) && $response->code == 10000) { + return true; + } + if (empty($response->code) && empty($response->subCode)) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/SignContentExtractor.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/SignContentExtractor.php new file mode 100644 index 0000000..83eff2c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/SignContentExtractor.php @@ -0,0 +1,58 @@ +RESPONSE_SUFFIX; + $rootIndex = strpos($body, $rootNodeName); + if ($rootIndex !== strrpos($body, $rootNodeName)) { + throw new \Exception('检测到响应报文中有重复的' . $rootNodeName . ',验签失败。'); + } + $errorIndex = strpos($body, $this->ERROR_RESPONSE); + if ($rootIndex > 0) { + return $this->parserJSONSource($body, $rootNodeName, $rootIndex); + } else if ($errorIndex > 0) { + return $this->parserJSONSource($body, $this->ERROR_RESPONSE, $errorIndex); + } else { + return null; + } + } + + /** + * + * @param $responseContent + * @param $nodeName + * @param $nodeIndex + * @return false|string|null + */ + function parserJSONSource($responseContent, $nodeName, $nodeIndex) + { + $signDataStartIndex = $nodeIndex + strlen($nodeName) + 2; + if (strrpos($responseContent, AlipayConstants::ALIPAY_CERT_SN_FIELD)) { + $signIndex = strrpos($responseContent, "\"" . AlipayConstants::ALIPAY_CERT_SN_FIELD . "\""); + } else { + $signIndex = strrpos($responseContent, "\"" . AlipayConstants::SIGN_FIELD . "\""); + } + // 签名前-逗号 + $signDataEndIndex = $signIndex - 1; + $indexLen = $signDataEndIndex - $signDataStartIndex; + if ($indexLen < 0) { + return null; + } + return substr($responseContent, $signDataStartIndex, $indexLen); + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/Signer.php b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/Signer.php new file mode 100644 index 0000000..fb5e314 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Kernel/Util/Signer.php @@ -0,0 +1,72 @@ +getSignContent($parameters); + return $this->verify($content, $sign, $publicKey); + } + + public function getSignContent($params) + { + ksort($params); + unset($params['sign']); + unset($params['sign_type']); + $stringToBeSigned = ""; + $i = 0; + foreach ($params as $k => $v) { + if ("@" != substr($v, 0, 1)) { + if ($i == 0) { + $stringToBeSigned .= "$k" . "=" . "$v"; + } else { + $stringToBeSigned .= "&" . "$k" . "=" . "$v"; + } + $i++; + } + } + unset ($k, $v); + return $stringToBeSigned; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Client.php new file mode 100644 index 0000000..c23bdb9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Client.php @@ -0,0 +1,866 @@ +_kernel = $kernel; + } + + /** + * @param string $title + * @param string $cover + * @param string $content + * @param string $contentComment + * @param string $ctype + * @param string $benefit + * @param string $extTags + * @param string $loginIds + * @return AlipayOpenPublicMessageContentCreateResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function createImageTextContent($title, $cover, $content, $contentComment, $ctype, $benefit, $extTags, $loginIds){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.public.message.content.create", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "title" => $title, + "cover" => $cover, + "content" => $content, + "could_comment" => $contentComment, + "ctype" => $ctype, + "benefit" => $benefit, + "ext_tags" => $extTags, + "login_ids" => $loginIds + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.public.message.content.create"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenPublicMessageContentCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenPublicMessageContentCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $contentId + * @param string $title + * @param string $cover + * @param string $content + * @param string $couldComment + * @param string $ctype + * @param string $benefit + * @param string $extTags + * @param string $loginIds + * @return AlipayOpenPublicMessageContentModifyResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function modifyImageTextContent($contentId, $title, $cover, $content, $couldComment, $ctype, $benefit, $extTags, $loginIds){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.public.message.content.modify", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "content_id" => $contentId, + "title" => $title, + "cover" => $cover, + "content" => $content, + "could_comment" => $couldComment, + "ctype" => $ctype, + "benefit" => $benefit, + "ext_tags" => $extTags, + "login_ids" => $loginIds + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.public.message.content.modify"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenPublicMessageContentModifyResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenPublicMessageContentModifyResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $text + * @return AlipayOpenPublicMessageTotalSendResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function sendText($text){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.public.message.total.send", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $textObj = new Text([ + "title" => "", + "content" => $text + ]); + $bizParams = [ + "msg_type" => "text", + "text" => $textObj + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.public.message.total.send"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenPublicMessageTotalSendResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenPublicMessageTotalSendResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param Article[] $articles + * @return AlipayOpenPublicMessageTotalSendResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function sendImageText($articles){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.public.message.total.send", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "msg_type" => "image-text", + "articles" => $articles + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.public.message.total.send"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenPublicMessageTotalSendResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenPublicMessageTotalSendResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $toUserId + * @param Template $template + * @return AlipayOpenPublicMessageSingleSendResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function sendSingleMessage($toUserId, $template){ + $template->validate(); + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.public.message.single.send", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "to_user_id" => $toUserId, + "template" => $template + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.public.message.single.send"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenPublicMessageSingleSendResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenPublicMessageSingleSendResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $messageId + * @return AlipayOpenPublicLifeMsgRecallResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function recallMessage($messageId){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.public.life.msg.recall", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "message_id" => $messageId + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.public.life.msg.recall"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenPublicLifeMsgRecallResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenPublicLifeMsgRecallResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $primaryIndustryCode + * @param string $primaryIndustryName + * @param string $secondaryIndustryCode + * @param string $secondaryIndustryName + * @return AlipayOpenPublicTemplateMessageIndustryModifyResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function setIndustry($primaryIndustryCode, $primaryIndustryName, $secondaryIndustryCode, $secondaryIndustryName){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.public.template.message.industry.modify", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "primary_industry_code" => $primaryIndustryCode, + "primary_industry_name" => $primaryIndustryName, + "secondary_industry_code" => $secondaryIndustryCode, + "secondary_industry_name" => $secondaryIndustryName + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.public.template.message.industry.modify"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenPublicTemplateMessageIndustryModifyResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenPublicTemplateMessageIndustryModifyResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @return AlipayOpenPublicSettingCategoryQueryResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function getIndustry(){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.public.setting.category.query", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = []; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.public.setting.category.query"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenPublicSettingCategoryQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenPublicSettingCategoryQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicLifeMsgRecallResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicLifeMsgRecallResponse.php new file mode 100644 index 0000000..986ca03 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicLifeMsgRecallResponse.php @@ -0,0 +1,91 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenPublicLifeMsgRecallResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentCreateResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentCreateResponse.php new file mode 100644 index 0000000..b14b219 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentCreateResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'contentId' => 'content_id', + 'contentUrl' => 'content_url', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('contentId', $this->contentId, true); + Model::validateRequired('contentUrl', $this->contentUrl, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->contentId) { + $res['content_id'] = $this->contentId; + } + if (null !== $this->contentUrl) { + $res['content_url'] = $this->contentUrl; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenPublicMessageContentCreateResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['content_id'])){ + $model->contentId = $map['content_id']; + } + if(isset($map['content_url'])){ + $model->contentUrl = $map['content_url']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $contentId; + + /** + * @var string + */ + public $contentUrl; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentModifyResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentModifyResponse.php new file mode 100644 index 0000000..7d365ed --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageContentModifyResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'contentId' => 'content_id', + 'contentUrl' => 'content_url', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('contentId', $this->contentId, true); + Model::validateRequired('contentUrl', $this->contentUrl, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->contentId) { + $res['content_id'] = $this->contentId; + } + if (null !== $this->contentUrl) { + $res['content_url'] = $this->contentUrl; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenPublicMessageContentModifyResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['content_id'])){ + $model->contentId = $map['content_id']; + } + if(isset($map['content_url'])){ + $model->contentUrl = $map['content_url']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $contentId; + + /** + * @var string + */ + public $contentUrl; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageSingleSendResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageSingleSendResponse.php new file mode 100644 index 0000000..e4f9169 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageSingleSendResponse.php @@ -0,0 +1,91 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenPublicMessageSingleSendResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageTotalSendResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageTotalSendResponse.php new file mode 100644 index 0000000..b9c2901 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicMessageTotalSendResponse.php @@ -0,0 +1,104 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'messageId' => 'message_id', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('messageId', $this->messageId, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->messageId) { + $res['message_id'] = $this->messageId; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenPublicMessageTotalSendResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['message_id'])){ + $model->messageId = $map['message_id']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $messageId; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicSettingCategoryQueryResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicSettingCategoryQueryResponse.php new file mode 100644 index 0000000..b78fdbe --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicSettingCategoryQueryResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'primaryCategory' => 'primary_category', + 'secondaryCategory' => 'secondary_category', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('primaryCategory', $this->primaryCategory, true); + Model::validateRequired('secondaryCategory', $this->secondaryCategory, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->primaryCategory) { + $res['primary_category'] = $this->primaryCategory; + } + if (null !== $this->secondaryCategory) { + $res['secondary_category'] = $this->secondaryCategory; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenPublicSettingCategoryQueryResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['primary_category'])){ + $model->primaryCategory = $map['primary_category']; + } + if(isset($map['secondary_category'])){ + $model->secondaryCategory = $map['secondary_category']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $primaryCategory; + + /** + * @var string + */ + public $secondaryCategory; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicTemplateMessageIndustryModifyResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicTemplateMessageIndustryModifyResponse.php new file mode 100644 index 0000000..8f40765 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/AlipayOpenPublicTemplateMessageIndustryModifyResponse.php @@ -0,0 +1,91 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenPublicTemplateMessageIndustryModifyResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Article.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Article.php new file mode 100644 index 0000000..cdabefa --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Article.php @@ -0,0 +1,87 @@ + 'title', + 'desc' => 'desc', + 'imageUrl' => 'image_url', + 'url' => 'url', + 'actionName' => 'action_name', + ]; + public function validate() { + Model::validateRequired('desc', $this->desc, true); + Model::validateRequired('url', $this->url, true); + } + public function toMap() { + $res = []; + if (null !== $this->title) { + $res['title'] = $this->title; + } + if (null !== $this->desc) { + $res['desc'] = $this->desc; + } + if (null !== $this->imageUrl) { + $res['image_url'] = $this->imageUrl; + } + if (null !== $this->url) { + $res['url'] = $this->url; + } + if (null !== $this->actionName) { + $res['action_name'] = $this->actionName; + } + return $res; + } + /** + * @param array $map + * @return Article + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['title'])){ + $model->title = $map['title']; + } + if(isset($map['desc'])){ + $model->desc = $map['desc']; + } + if(isset($map['image_url'])){ + $model->imageUrl = $map['image_url']; + } + if(isset($map['url'])){ + $model->url = $map['url']; + } + if(isset($map['action_name'])){ + $model->actionName = $map['action_name']; + } + return $model; + } + /** + * @var string + */ + public $title; + + /** + * @var string + */ + public $desc; + + /** + * @var string + */ + public $imageUrl; + + /** + * @var string + */ + public $url; + + /** + * @var string + */ + public $actionName; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Context.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Context.php new file mode 100644 index 0000000..30dcfae --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Context.php @@ -0,0 +1,114 @@ + 'head_color', + 'url' => 'url', + 'actionName' => 'action_name', + 'keyword1' => 'keyword1', + 'keyword2' => 'keyword2', + 'first' => 'first', + 'remark' => 'remark', + ]; + public function validate() { + Model::validateRequired('headColor', $this->headColor, true); + Model::validateRequired('url', $this->url, true); + Model::validateRequired('actionName', $this->actionName, true); + } + public function toMap() { + $res = []; + if (null !== $this->headColor) { + $res['head_color'] = $this->headColor; + } + if (null !== $this->url) { + $res['url'] = $this->url; + } + if (null !== $this->actionName) { + $res['action_name'] = $this->actionName; + } + if (null !== $this->keyword1) { + $res['keyword1'] = null !== $this->keyword1 ? $this->keyword1->toMap() : null; + } + if (null !== $this->keyword2) { + $res['keyword2'] = null !== $this->keyword2 ? $this->keyword2->toMap() : null; + } + if (null !== $this->first) { + $res['first'] = null !== $this->first ? $this->first->toMap() : null; + } + if (null !== $this->remark) { + $res['remark'] = null !== $this->remark ? $this->remark->toMap() : null; + } + return $res; + } + /** + * @param array $map + * @return Context + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['head_color'])){ + $model->headColor = $map['head_color']; + } + if(isset($map['url'])){ + $model->url = $map['url']; + } + if(isset($map['action_name'])){ + $model->actionName = $map['action_name']; + } + if(isset($map['keyword1'])){ + $model->keyword1 = Keyword::fromMap($map['keyword1']); + } + if(isset($map['keyword2'])){ + $model->keyword2 = Keyword::fromMap($map['keyword2']); + } + if(isset($map['first'])){ + $model->first = Keyword::fromMap($map['first']); + } + if(isset($map['remark'])){ + $model->remark = Keyword::fromMap($map['remark']); + } + return $model; + } + /** + * @var string + */ + public $headColor; + + /** + * @var string + */ + public $url; + + /** + * @var string + */ + public $actionName; + + /** + * @var Keyword + */ + public $keyword1; + + /** + * @var Keyword + */ + public $keyword2; + + /** + * @var Keyword + */ + public $first; + + /** + * @var Keyword + */ + public $remark; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Keyword.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Keyword.php new file mode 100644 index 0000000..438b28e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Keyword.php @@ -0,0 +1,51 @@ + 'color', + 'value' => 'value', + ]; + public function validate() { + Model::validateRequired('color', $this->color, true); + Model::validateRequired('value', $this->value, true); + } + public function toMap() { + $res = []; + if (null !== $this->color) { + $res['color'] = $this->color; + } + if (null !== $this->value) { + $res['value'] = $this->value; + } + return $res; + } + /** + * @param array $map + * @return Keyword + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['color'])){ + $model->color = $map['color']; + } + if(isset($map['value'])){ + $model->value = $map['value']; + } + return $model; + } + /** + * @var string + */ + public $color; + + /** + * @var string + */ + public $value; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Template.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Template.php new file mode 100644 index 0000000..bec9c7b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Template.php @@ -0,0 +1,53 @@ + 'template_id', + 'context' => 'context', + ]; + public function validate() { + Model::validateRequired('templateId', $this->templateId, true); + Model::validateRequired('context', $this->context, true); + } + public function toMap() { + $res = []; + if (null !== $this->templateId) { + $res['template_id'] = $this->templateId; + } + if (null !== $this->context) { + $res['context'] = null !== $this->context ? $this->context->toMap() : null; + } + return $res; + } + /** + * @param array $map + * @return Template + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['template_id'])){ + $model->templateId = $map['template_id']; + } + if(isset($map['context'])){ + $model->context = Context::fromMap($map['context']); + } + return $model; + } + /** + * @var string + */ + public $templateId; + + /** + * @var Context + */ + public $context; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Text.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Text.php new file mode 100644 index 0000000..bbd9582 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/OpenLife/Models/Text.php @@ -0,0 +1,51 @@ + 'title', + 'content' => 'content', + ]; + public function validate() { + Model::validateRequired('title', $this->title, true); + Model::validateRequired('content', $this->content, true); + } + public function toMap() { + $res = []; + if (null !== $this->title) { + $res['title'] = $this->title; + } + if (null !== $this->content) { + $res['content'] = $this->content; + } + return $res; + } + /** + * @param array $map + * @return Text + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['title'])){ + $model->title = $map['title']; + } + if(isset($map['content'])){ + $model->content = $map['content']; + } + return $model; + } + /** + * @var string + */ + public $title; + + /** + * @var string + */ + public $content; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Client.php new file mode 100644 index 0000000..94afce6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Client.php @@ -0,0 +1,482 @@ +_kernel = $kernel; + } + + /** + * @param string $uniqueId + * @param string $tplContent + * @return AlipayPassTemplateAddResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function createTemplate($uniqueId, $tplContent){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.pass.template.add", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "unique_id" => $uniqueId, + "tpl_content" => $tplContent + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.pass.template.add"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayPassTemplateAddResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayPassTemplateAddResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $tplId + * @param string $tplContent + * @return AlipayPassTemplateUpdateResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function updateTemplate($tplId, $tplContent){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.pass.template.update", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "tpl_id" => $tplId, + "tpl_content" => $tplContent + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.pass.template.update"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayPassTemplateUpdateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayPassTemplateUpdateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $tplId + * @param string $tplParams + * @param string $recognitionType + * @param string $recognitionInfo + * @return AlipayPassInstanceAddResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function addInstance($tplId, $tplParams, $recognitionType, $recognitionInfo){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.pass.instance.add", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "tpl_id" => $tplId, + "tpl_params" => $tplParams, + "recognition_type" => $recognitionType, + "recognition_info" => $recognitionInfo + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.pass.instance.add"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayPassInstanceAddResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayPassInstanceAddResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $serialNumber + * @param string $channelId + * @param string $tplParams + * @param string $status + * @param string $verifyCode + * @param string $verifyType + * @return AlipayPassInstanceUpdateResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function updateInstance($serialNumber, $channelId, $tplParams, $status, $verifyCode, $verifyType){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.pass.instance.update", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "serial_number" => $serialNumber, + "channel_id" => $channelId, + "tpl_params" => $tplParams, + "status" => $status, + "verify_code" => $verifyCode, + "verify_type" => $verifyType + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.pass.instance.update"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayPassInstanceUpdateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayPassInstanceUpdateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassInstanceAddResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassInstanceAddResponse.php new file mode 100644 index 0000000..02dc9a3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassInstanceAddResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'success' => 'success', + 'result' => 'result', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('success', $this->success, true); + Model::validateRequired('result', $this->result, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->success) { + $res['success'] = $this->success; + } + if (null !== $this->result) { + $res['result'] = $this->result; + } + return $res; + } + /** + * @param array $map + * @return AlipayPassInstanceAddResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['success'])){ + $model->success = $map['success']; + } + if(isset($map['result'])){ + $model->result = $map['result']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var bool + */ + public $success; + + /** + * @var string + */ + public $result; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassInstanceUpdateResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassInstanceUpdateResponse.php new file mode 100644 index 0000000..d2f7189 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassInstanceUpdateResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'success' => 'success', + 'result' => 'result', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('success', $this->success, true); + Model::validateRequired('result', $this->result, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->success) { + $res['success'] = $this->success; + } + if (null !== $this->result) { + $res['result'] = $this->result; + } + return $res; + } + /** + * @param array $map + * @return AlipayPassInstanceUpdateResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['success'])){ + $model->success = $map['success']; + } + if(isset($map['result'])){ + $model->result = $map['result']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var bool + */ + public $success; + + /** + * @var string + */ + public $result; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassTemplateAddResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassTemplateAddResponse.php new file mode 100644 index 0000000..825a0f6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassTemplateAddResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'success' => 'success', + 'result' => 'result', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('success', $this->success, true); + Model::validateRequired('result', $this->result, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->success) { + $res['success'] = $this->success; + } + if (null !== $this->result) { + $res['result'] = $this->result; + } + return $res; + } + /** + * @param array $map + * @return AlipayPassTemplateAddResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['success'])){ + $model->success = $map['success']; + } + if(isset($map['result'])){ + $model->result = $map['result']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var bool + */ + public $success; + + /** + * @var string + */ + public $result; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassTemplateUpdateResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassTemplateUpdateResponse.php new file mode 100644 index 0000000..6d70475 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/Pass/Models/AlipayPassTemplateUpdateResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'success' => 'success', + 'result' => 'result', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('success', $this->success, true); + Model::validateRequired('result', $this->result, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->success) { + $res['success'] = $this->success; + } + if (null !== $this->result) { + $res['result'] = $this->result; + } + return $res; + } + /** + * @param array $map + * @return AlipayPassTemplateUpdateResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['success'])){ + $model->success = $map['success']; + } + if(isset($map['result'])){ + $model->result = $map['result']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var bool + */ + public $success; + + /** + * @var string + */ + public $result; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/TemplateMessage/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/TemplateMessage/Client.php new file mode 100644 index 0000000..0863bb1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/TemplateMessage/Client.php @@ -0,0 +1,200 @@ +_kernel = $kernel; + } + + /** + * @param string $toUserId + * @param string $formId + * @param string $userTemplateId + * @param string $page + * @param string $data + * @return AlipayOpenAppMiniTemplatemessageSendResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function send($toUserId, $formId, $userTemplateId, $page, $data){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.open.app.mini.templatemessage.send", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "to_user_id" => $toUserId, + "form_id" => $formId, + "user_template_id" => $userTemplateId, + "page" => $page, + "data" => $data + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.open.app.mini.templatemessage.send"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenAppMiniTemplatemessageSendResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenAppMiniTemplatemessageSendResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Marketing/TemplateMessage/Models/AlipayOpenAppMiniTemplatemessageSendResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/TemplateMessage/Models/AlipayOpenAppMiniTemplatemessageSendResponse.php new file mode 100644 index 0000000..6af50e7 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Marketing/TemplateMessage/Models/AlipayOpenAppMiniTemplatemessageSendResponse.php @@ -0,0 +1,91 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenAppMiniTemplatemessageSendResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Client.php new file mode 100644 index 0000000..e0af64c --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Client.php @@ -0,0 +1,321 @@ +_kernel = $kernel; + } + + /** + * @param string $outerOrderNo + * @param string $bizCode + * @param IdentityParam $identityParam + * @param MerchantConfig $merchantConfig + * @return AlipayUserCertifyOpenInitializeResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function init($outerOrderNo, $bizCode, $identityParam, $merchantConfig){ + $identityParam->validate(); + $merchantConfig->validate(); + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.user.certify.open.initialize", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "outer_order_no" => $outerOrderNo, + "biz_code" => $bizCode, + "identity_param" => $identityParam, + "merchant_config" => $merchantConfig + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.user.certify.open.initialize"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayUserCertifyOpenInitializeResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayUserCertifyOpenInitializeResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $certifyId + * @return AlipayUserCertifyOpenQueryResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function query($certifyId){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.user.certify.open.query", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "certify_id" => $certifyId + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.user.certify.open.query"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayUserCertifyOpenQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayUserCertifyOpenQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $certifyId + * @return AlipayUserCertifyOpenCertifyResponse + */ + public function certify($certifyId){ + $systemParams = [ + "method" => "alipay.user.certify.open.certify", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "certify_id" => $certifyId + ]; + $textParams = []; + $sign = $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")); + $response = [ + "body" => $this->_kernel->generatePage("GET", $systemParams, $bizParams, $textParams, $sign) + ]; + return AlipayUserCertifyOpenCertifyResponse::fromMap($response); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/AlipayUserCertifyOpenCertifyResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/AlipayUserCertifyOpenCertifyResponse.php new file mode 100644 index 0000000..19d786d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/AlipayUserCertifyOpenCertifyResponse.php @@ -0,0 +1,39 @@ + 'body', + ]; + public function validate() { + Model::validateRequired('body', $this->body, true); + } + public function toMap() { + $res = []; + if (null !== $this->body) { + $res['body'] = $this->body; + } + return $res; + } + /** + * @param array $map + * @return AlipayUserCertifyOpenCertifyResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['body'])){ + $model->body = $map['body']; + } + return $model; + } + /** + * @description 认证服务请求地址 + * @var string + */ + public $body; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/AlipayUserCertifyOpenInitializeResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/AlipayUserCertifyOpenInitializeResponse.php new file mode 100644 index 0000000..fd3e3d5 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/AlipayUserCertifyOpenInitializeResponse.php @@ -0,0 +1,104 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'certifyId' => 'certify_id', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('certifyId', $this->certifyId, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->certifyId) { + $res['certify_id'] = $this->certifyId; + } + return $res; + } + /** + * @param array $map + * @return AlipayUserCertifyOpenInitializeResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['certify_id'])){ + $model->certifyId = $map['certify_id']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $certifyId; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/AlipayUserCertifyOpenQueryResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/AlipayUserCertifyOpenQueryResponse.php new file mode 100644 index 0000000..612ae04 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/AlipayUserCertifyOpenQueryResponse.php @@ -0,0 +1,130 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'passed' => 'passed', + 'identityInfo' => 'identity_info', + 'materialInfo' => 'material_info', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('passed', $this->passed, true); + Model::validateRequired('identityInfo', $this->identityInfo, true); + Model::validateRequired('materialInfo', $this->materialInfo, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->passed) { + $res['passed'] = $this->passed; + } + if (null !== $this->identityInfo) { + $res['identity_info'] = $this->identityInfo; + } + if (null !== $this->materialInfo) { + $res['material_info'] = $this->materialInfo; + } + return $res; + } + /** + * @param array $map + * @return AlipayUserCertifyOpenQueryResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['passed'])){ + $model->passed = $map['passed']; + } + if(isset($map['identity_info'])){ + $model->identityInfo = $map['identity_info']; + } + if(isset($map['material_info'])){ + $model->materialInfo = $map['material_info']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $passed; + + /** + * @var string + */ + public $identityInfo; + + /** + * @var string + */ + public $materialInfo; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/IdentityParam.php b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/IdentityParam.php new file mode 100644 index 0000000..f4183b6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/IdentityParam.php @@ -0,0 +1,77 @@ + 'identity_type', + 'certType' => 'cert_type', + 'certName' => 'cert_name', + 'certNo' => 'cert_no', + ]; + public function validate() { + Model::validateRequired('identityType', $this->identityType, true); + Model::validateRequired('certType', $this->certType, true); + Model::validateRequired('certName', $this->certName, true); + Model::validateRequired('certNo', $this->certNo, true); + } + public function toMap() { + $res = []; + if (null !== $this->identityType) { + $res['identity_type'] = $this->identityType; + } + if (null !== $this->certType) { + $res['cert_type'] = $this->certType; + } + if (null !== $this->certName) { + $res['cert_name'] = $this->certName; + } + if (null !== $this->certNo) { + $res['cert_no'] = $this->certNo; + } + return $res; + } + /** + * @param array $map + * @return IdentityParam + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['identity_type'])){ + $model->identityType = $map['identity_type']; + } + if(isset($map['cert_type'])){ + $model->certType = $map['cert_type']; + } + if(isset($map['cert_name'])){ + $model->certName = $map['cert_name']; + } + if(isset($map['cert_no'])){ + $model->certNo = $map['cert_no']; + } + return $model; + } + /** + * @var string + */ + public $identityType; + + /** + * @var string + */ + public $certType; + + /** + * @var string + */ + public $certName; + + /** + * @var string + */ + public $certNo; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/MerchantConfig.php b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/MerchantConfig.php new file mode 100644 index 0000000..c2aab27 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Member/Identification/Models/MerchantConfig.php @@ -0,0 +1,38 @@ + 'return_url', + ]; + public function validate() { + Model::validateRequired('returnUrl', $this->returnUrl, true); + } + public function toMap() { + $res = []; + if (null !== $this->returnUrl) { + $res['return_url'] = $this->returnUrl; + } + return $res; + } + /** + * @param array $map + * @return MerchantConfig + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['return_url'])){ + $model->returnUrl = $map['return_url']; + } + return $model; + } + /** + * @var string + */ + public $returnUrl; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/App/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/App/Client.php new file mode 100644 index 0000000..bbd1ff6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/App/Client.php @@ -0,0 +1,129 @@ +_kernel = $kernel; + } + + /** + * @param string $subject + * @param string $outTradeNo + * @param string $totalAmount + * @return AlipayTradeAppPayResponse + */ + public function pay($subject, $outTradeNo, $totalAmount){ + $systemParams = [ + "method" => "alipay.trade.app.pay", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "subject" => $subject, + "out_trade_no" => $outTradeNo, + "total_amount" => $totalAmount + ]; + $textParams = []; + $sign = $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")); + $response = [ + "body" => $this->_kernel->generateOrderString($systemParams, $bizParams, $textParams, $sign) + ]; + return AlipayTradeAppPayResponse::fromMap($response); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/App/Models/AlipayTradeAppPayResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/App/Models/AlipayTradeAppPayResponse.php new file mode 100644 index 0000000..496f2ec --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/App/Models/AlipayTradeAppPayResponse.php @@ -0,0 +1,39 @@ + 'body', + ]; + public function validate() { + Model::validateRequired('body', $this->body, true); + } + public function toMap() { + $res = []; + if (null !== $this->body) { + $res['body'] = $this->body; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradeAppPayResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['body'])){ + $model->body = $map['body']; + } + return $model; + } + /** + * @description 订单信息,字符串形式 + * @var string + */ + public $body; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Client.php new file mode 100644 index 0000000..82afe06 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Client.php @@ -0,0 +1,757 @@ +_kernel = $kernel; + } + + /** + * @param string $subject + * @param string $outTradeNo + * @param string $totalAmount + * @param string $buyerId + * @return AlipayTradeCreateResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function create($subject, $outTradeNo, $totalAmount, $buyerId){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.trade.create", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "subject" => $subject, + "out_trade_no" => $outTradeNo, + "total_amount" => $totalAmount, + "buyer_id" => $buyerId + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.create"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayTradeCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayTradeCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $outTradeNo + * @return AlipayTradeQueryResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function query($outTradeNo){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.trade.query", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "out_trade_no" => $outTradeNo + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.query"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayTradeQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayTradeQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $outTradeNo + * @param string $refundAmount + * @return AlipayTradeRefundResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function refund($outTradeNo, $refundAmount){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.trade.refund", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "out_trade_no" => $outTradeNo, + "refund_amount" => $refundAmount + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.refund"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayTradeRefundResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayTradeRefundResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $outTradeNo + * @return AlipayTradeCloseResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function close($outTradeNo){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.trade.close", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "out_trade_no" => $outTradeNo + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.close"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayTradeCloseResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayTradeCloseResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $outTradeNo + * @return AlipayTradeCancelResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function cancel($outTradeNo){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.trade.cancel", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "out_trade_no" => $outTradeNo + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.cancel"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayTradeCancelResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayTradeCancelResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $outTradeNo + * @param string $outRequestNo + * @return AlipayTradeFastpayRefundQueryResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function queryRefund($outTradeNo, $outRequestNo){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.trade.fastpay.refund.query", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "out_trade_no" => $outTradeNo, + "out_request_no" => $outRequestNo + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.fastpay.refund.query"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayTradeFastpayRefundQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayTradeFastpayRefundQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $billType + * @param string $billDate + * @return AlipayDataDataserviceBillDownloadurlQueryResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function downloadBill($billType, $billDate){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.data.dataservice.bill.downloadurl.query", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "bill_type" => $billType, + "bill_date" => $billDate + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.data.dataservice.bill.downloadurl.query"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayDataDataserviceBillDownloadurlQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayDataDataserviceBillDownloadurlQueryResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string[] $parameters + * @return bool + */ + public function verifyNotify($parameters){ + if ($this->_kernel->isCertMode()) { + return $this->_kernel->verifyParams($parameters, $this->_kernel->extractAlipayPublicKey("")); + } + else { + return $this->_kernel->verifyParams($parameters, $this->_kernel->getConfig("alipayPublicKey")); + } + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayDataDataserviceBillDownloadurlQueryResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayDataDataserviceBillDownloadurlQueryResponse.php new file mode 100644 index 0000000..cff56a2 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayDataDataserviceBillDownloadurlQueryResponse.php @@ -0,0 +1,104 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'billDownloadUrl' => 'bill_download_url', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('billDownloadUrl', $this->billDownloadUrl, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->billDownloadUrl) { + $res['bill_download_url'] = $this->billDownloadUrl; + } + return $res; + } + /** + * @param array $map + * @return AlipayDataDataserviceBillDownloadurlQueryResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['bill_download_url'])){ + $model->billDownloadUrl = $map['bill_download_url']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $billDownloadUrl; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeCancelResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeCancelResponse.php new file mode 100644 index 0000000..9ff93d4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeCancelResponse.php @@ -0,0 +1,169 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'tradeNo' => 'trade_no', + 'outTradeNo' => 'out_trade_no', + 'retryFlag' => 'retry_flag', + 'action' => 'action', + 'gmtRefundPay' => 'gmt_refund_pay', + 'refundSettlementId' => 'refund_settlement_id', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('tradeNo', $this->tradeNo, true); + Model::validateRequired('outTradeNo', $this->outTradeNo, true); + Model::validateRequired('retryFlag', $this->retryFlag, true); + Model::validateRequired('action', $this->action, true); + Model::validateRequired('gmtRefundPay', $this->gmtRefundPay, true); + Model::validateRequired('refundSettlementId', $this->refundSettlementId, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->tradeNo) { + $res['trade_no'] = $this->tradeNo; + } + if (null !== $this->outTradeNo) { + $res['out_trade_no'] = $this->outTradeNo; + } + if (null !== $this->retryFlag) { + $res['retry_flag'] = $this->retryFlag; + } + if (null !== $this->action) { + $res['action'] = $this->action; + } + if (null !== $this->gmtRefundPay) { + $res['gmt_refund_pay'] = $this->gmtRefundPay; + } + if (null !== $this->refundSettlementId) { + $res['refund_settlement_id'] = $this->refundSettlementId; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradeCancelResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['trade_no'])){ + $model->tradeNo = $map['trade_no']; + } + if(isset($map['out_trade_no'])){ + $model->outTradeNo = $map['out_trade_no']; + } + if(isset($map['retry_flag'])){ + $model->retryFlag = $map['retry_flag']; + } + if(isset($map['action'])){ + $model->action = $map['action']; + } + if(isset($map['gmt_refund_pay'])){ + $model->gmtRefundPay = $map['gmt_refund_pay']; + } + if(isset($map['refund_settlement_id'])){ + $model->refundSettlementId = $map['refund_settlement_id']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $tradeNo; + + /** + * @var string + */ + public $outTradeNo; + + /** + * @var string + */ + public $retryFlag; + + /** + * @var string + */ + public $action; + + /** + * @var string + */ + public $gmtRefundPay; + + /** + * @var string + */ + public $refundSettlementId; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeCloseResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeCloseResponse.php new file mode 100644 index 0000000..3946bb4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeCloseResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'tradeNo' => 'trade_no', + 'outTradeNo' => 'out_trade_no', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('tradeNo', $this->tradeNo, true); + Model::validateRequired('outTradeNo', $this->outTradeNo, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->tradeNo) { + $res['trade_no'] = $this->tradeNo; + } + if (null !== $this->outTradeNo) { + $res['out_trade_no'] = $this->outTradeNo; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradeCloseResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['trade_no'])){ + $model->tradeNo = $map['trade_no']; + } + if(isset($map['out_trade_no'])){ + $model->outTradeNo = $map['out_trade_no']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $tradeNo; + + /** + * @var string + */ + public $outTradeNo; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeCreateResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeCreateResponse.php new file mode 100644 index 0000000..2a30216 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeCreateResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'outTradeNo' => 'out_trade_no', + 'tradeNo' => 'trade_no', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('outTradeNo', $this->outTradeNo, true); + Model::validateRequired('tradeNo', $this->tradeNo, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->outTradeNo) { + $res['out_trade_no'] = $this->outTradeNo; + } + if (null !== $this->tradeNo) { + $res['trade_no'] = $this->tradeNo; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradeCreateResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['out_trade_no'])){ + $model->outTradeNo = $map['out_trade_no']; + } + if(isset($map['trade_no'])){ + $model->tradeNo = $map['trade_no']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $outTradeNo; + + /** + * @var string + */ + public $tradeNo; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeFastpayRefundQueryResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeFastpayRefundQueryResponse.php new file mode 100644 index 0000000..66b2b1b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeFastpayRefundQueryResponse.php @@ -0,0 +1,352 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'errorCode' => 'error_code', + 'gmtRefundPay' => 'gmt_refund_pay', + 'industrySepcDetail' => 'industry_sepc_detail', + 'outRequestNo' => 'out_request_no', + 'outTradeNo' => 'out_trade_no', + 'presentRefundBuyerAmount' => 'present_refund_buyer_amount', + 'presentRefundDiscountAmount' => 'present_refund_discount_amount', + 'presentRefundMdiscountAmount' => 'present_refund_mdiscount_amount', + 'refundAmount' => 'refund_amount', + 'refundChargeAmount' => 'refund_charge_amount', + 'refundDetailItemList' => 'refund_detail_item_list', + 'refundReason' => 'refund_reason', + 'refundRoyaltys' => 'refund_royaltys', + 'refundSettlementId' => 'refund_settlement_id', + 'refundStatus' => 'refund_status', + 'sendBackFee' => 'send_back_fee', + 'totalAmount' => 'total_amount', + 'tradeNo' => 'trade_no', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('errorCode', $this->errorCode, true); + Model::validateRequired('gmtRefundPay', $this->gmtRefundPay, true); + Model::validateRequired('industrySepcDetail', $this->industrySepcDetail, true); + Model::validateRequired('outRequestNo', $this->outRequestNo, true); + Model::validateRequired('outTradeNo', $this->outTradeNo, true); + Model::validateRequired('presentRefundBuyerAmount', $this->presentRefundBuyerAmount, true); + Model::validateRequired('presentRefundDiscountAmount', $this->presentRefundDiscountAmount, true); + Model::validateRequired('presentRefundMdiscountAmount', $this->presentRefundMdiscountAmount, true); + Model::validateRequired('refundAmount', $this->refundAmount, true); + Model::validateRequired('refundChargeAmount', $this->refundChargeAmount, true); + Model::validateRequired('refundDetailItemList', $this->refundDetailItemList, true); + Model::validateRequired('refundReason', $this->refundReason, true); + Model::validateRequired('refundRoyaltys', $this->refundRoyaltys, true); + Model::validateRequired('refundSettlementId', $this->refundSettlementId, true); + Model::validateRequired('refundStatus', $this->refundStatus, true); + Model::validateRequired('sendBackFee', $this->sendBackFee, true); + Model::validateRequired('totalAmount', $this->totalAmount, true); + Model::validateRequired('tradeNo', $this->tradeNo, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->errorCode) { + $res['error_code'] = $this->errorCode; + } + if (null !== $this->gmtRefundPay) { + $res['gmt_refund_pay'] = $this->gmtRefundPay; + } + if (null !== $this->industrySepcDetail) { + $res['industry_sepc_detail'] = $this->industrySepcDetail; + } + if (null !== $this->outRequestNo) { + $res['out_request_no'] = $this->outRequestNo; + } + if (null !== $this->outTradeNo) { + $res['out_trade_no'] = $this->outTradeNo; + } + if (null !== $this->presentRefundBuyerAmount) { + $res['present_refund_buyer_amount'] = $this->presentRefundBuyerAmount; + } + if (null !== $this->presentRefundDiscountAmount) { + $res['present_refund_discount_amount'] = $this->presentRefundDiscountAmount; + } + if (null !== $this->presentRefundMdiscountAmount) { + $res['present_refund_mdiscount_amount'] = $this->presentRefundMdiscountAmount; + } + if (null !== $this->refundAmount) { + $res['refund_amount'] = $this->refundAmount; + } + if (null !== $this->refundChargeAmount) { + $res['refund_charge_amount'] = $this->refundChargeAmount; + } + if (null !== $this->refundDetailItemList) { + $res['refund_detail_item_list'] = []; + if(null !== $this->refundDetailItemList && is_array($this->refundDetailItemList)){ + $n = 0; + foreach($this->refundDetailItemList as $item){ + $res['refund_detail_item_list'][$n++] = null !== $item ? $item->toMap() : $item; + } + } + } + if (null !== $this->refundReason) { + $res['refund_reason'] = $this->refundReason; + } + if (null !== $this->refundRoyaltys) { + $res['refund_royaltys'] = []; + if(null !== $this->refundRoyaltys && is_array($this->refundRoyaltys)){ + $n = 0; + foreach($this->refundRoyaltys as $item){ + $res['refund_royaltys'][$n++] = null !== $item ? $item->toMap() : $item; + } + } + } + if (null !== $this->refundSettlementId) { + $res['refund_settlement_id'] = $this->refundSettlementId; + } + if (null !== $this->refundStatus) { + $res['refund_status'] = $this->refundStatus; + } + if (null !== $this->sendBackFee) { + $res['send_back_fee'] = $this->sendBackFee; + } + if (null !== $this->totalAmount) { + $res['total_amount'] = $this->totalAmount; + } + if (null !== $this->tradeNo) { + $res['trade_no'] = $this->tradeNo; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradeFastpayRefundQueryResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['error_code'])){ + $model->errorCode = $map['error_code']; + } + if(isset($map['gmt_refund_pay'])){ + $model->gmtRefundPay = $map['gmt_refund_pay']; + } + if(isset($map['industry_sepc_detail'])){ + $model->industrySepcDetail = $map['industry_sepc_detail']; + } + if(isset($map['out_request_no'])){ + $model->outRequestNo = $map['out_request_no']; + } + if(isset($map['out_trade_no'])){ + $model->outTradeNo = $map['out_trade_no']; + } + if(isset($map['present_refund_buyer_amount'])){ + $model->presentRefundBuyerAmount = $map['present_refund_buyer_amount']; + } + if(isset($map['present_refund_discount_amount'])){ + $model->presentRefundDiscountAmount = $map['present_refund_discount_amount']; + } + if(isset($map['present_refund_mdiscount_amount'])){ + $model->presentRefundMdiscountAmount = $map['present_refund_mdiscount_amount']; + } + if(isset($map['refund_amount'])){ + $model->refundAmount = $map['refund_amount']; + } + if(isset($map['refund_charge_amount'])){ + $model->refundChargeAmount = $map['refund_charge_amount']; + } + if(isset($map['refund_detail_item_list'])){ + if(!empty($map['refund_detail_item_list'])){ + $model->refundDetailItemList = []; + $n = 0; + foreach($map['refund_detail_item_list'] as $item) { + $model->refundDetailItemList[$n++] = null !== $item ? TradeFundBill::fromMap($item) : $item; + } + } + } + if(isset($map['refund_reason'])){ + $model->refundReason = $map['refund_reason']; + } + if(isset($map['refund_royaltys'])){ + if(!empty($map['refund_royaltys'])){ + $model->refundRoyaltys = []; + $n = 0; + foreach($map['refund_royaltys'] as $item) { + $model->refundRoyaltys[$n++] = null !== $item ? RefundRoyaltyResult::fromMap($item) : $item; + } + } + } + if(isset($map['refund_settlement_id'])){ + $model->refundSettlementId = $map['refund_settlement_id']; + } + if(isset($map['refund_status'])){ + $model->refundStatus = $map['refund_status']; + } + if(isset($map['send_back_fee'])){ + $model->sendBackFee = $map['send_back_fee']; + } + if(isset($map['total_amount'])){ + $model->totalAmount = $map['total_amount']; + } + if(isset($map['trade_no'])){ + $model->tradeNo = $map['trade_no']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $errorCode; + + /** + * @var string + */ + public $gmtRefundPay; + + /** + * @var string + */ + public $industrySepcDetail; + + /** + * @var string + */ + public $outRequestNo; + + /** + * @var string + */ + public $outTradeNo; + + /** + * @var string + */ + public $presentRefundBuyerAmount; + + /** + * @var string + */ + public $presentRefundDiscountAmount; + + /** + * @var string + */ + public $presentRefundMdiscountAmount; + + /** + * @var string + */ + public $refundAmount; + + /** + * @var string + */ + public $refundChargeAmount; + + /** + * @var TradeFundBill[] + */ + public $refundDetailItemList; + + /** + * @var string + */ + public $refundReason; + + /** + * @var RefundRoyaltyResult[] + */ + public $refundRoyaltys; + + /** + * @var string + */ + public $refundSettlementId; + + /** + * @var string + */ + public $refundStatus; + + /** + * @var string + */ + public $sendBackFee; + + /** + * @var string + */ + public $totalAmount; + + /** + * @var string + */ + public $tradeNo; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeQueryResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeQueryResponse.php new file mode 100644 index 0000000..03017d8 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeQueryResponse.php @@ -0,0 +1,573 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'tradeNo' => 'trade_no', + 'outTradeNo' => 'out_trade_no', + 'buyerLogonId' => 'buyer_logon_id', + 'tradeStatus' => 'trade_status', + 'totalAmount' => 'total_amount', + 'transCurrency' => 'trans_currency', + 'settleCurrency' => 'settle_currency', + 'settleAmount' => 'settle_amount', + 'payCurrency' => 'pay_currency', + 'payAmount' => 'pay_amount', + 'settleTransRate' => 'settle_trans_rate', + 'transPayRate' => 'trans_pay_rate', + 'buyerPayAmount' => 'buyer_pay_amount', + 'pointAmount' => 'point_amount', + 'invoiceAmount' => 'invoice_amount', + 'sendPayDate' => 'send_pay_date', + 'receiptAmount' => 'receipt_amount', + 'storeId' => 'store_id', + 'terminalId' => 'terminal_id', + 'fundBillList' => 'fund_bill_list', + 'storeName' => 'store_name', + 'buyerUserId' => 'buyer_user_id', + 'chargeAmount' => 'charge_amount', + 'chargeFlags' => 'charge_flags', + 'settlementId' => 'settlement_id', + 'tradeSettleInfo' => 'trade_settle_info', + 'authTradePayMode' => 'auth_trade_pay_mode', + 'buyerUserType' => 'buyer_user_type', + 'mdiscountAmount' => 'mdiscount_amount', + 'discountAmount' => 'discount_amount', + 'buyerUserName' => 'buyer_user_name', + 'subject' => 'subject', + 'body' => 'body', + 'alipaySubMerchantId' => 'alipay_sub_merchant_id', + 'extInfos' => 'ext_infos', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('tradeNo', $this->tradeNo, true); + Model::validateRequired('outTradeNo', $this->outTradeNo, true); + Model::validateRequired('buyerLogonId', $this->buyerLogonId, true); + Model::validateRequired('tradeStatus', $this->tradeStatus, true); + Model::validateRequired('totalAmount', $this->totalAmount, true); + Model::validateRequired('transCurrency', $this->transCurrency, true); + Model::validateRequired('settleCurrency', $this->settleCurrency, true); + Model::validateRequired('settleAmount', $this->settleAmount, true); + Model::validateRequired('payCurrency', $this->payCurrency, true); + Model::validateRequired('payAmount', $this->payAmount, true); + Model::validateRequired('settleTransRate', $this->settleTransRate, true); + Model::validateRequired('transPayRate', $this->transPayRate, true); + Model::validateRequired('buyerPayAmount', $this->buyerPayAmount, true); + Model::validateRequired('pointAmount', $this->pointAmount, true); + Model::validateRequired('invoiceAmount', $this->invoiceAmount, true); + Model::validateRequired('sendPayDate', $this->sendPayDate, true); + Model::validateRequired('receiptAmount', $this->receiptAmount, true); + Model::validateRequired('storeId', $this->storeId, true); + Model::validateRequired('terminalId', $this->terminalId, true); + Model::validateRequired('fundBillList', $this->fundBillList, true); + Model::validateRequired('storeName', $this->storeName, true); + Model::validateRequired('buyerUserId', $this->buyerUserId, true); + Model::validateRequired('chargeAmount', $this->chargeAmount, true); + Model::validateRequired('chargeFlags', $this->chargeFlags, true); + Model::validateRequired('settlementId', $this->settlementId, true); + Model::validateRequired('tradeSettleInfo', $this->tradeSettleInfo, true); + Model::validateRequired('authTradePayMode', $this->authTradePayMode, true); + Model::validateRequired('buyerUserType', $this->buyerUserType, true); + Model::validateRequired('mdiscountAmount', $this->mdiscountAmount, true); + Model::validateRequired('discountAmount', $this->discountAmount, true); + Model::validateRequired('buyerUserName', $this->buyerUserName, true); + Model::validateRequired('subject', $this->subject, true); + Model::validateRequired('body', $this->body, true); + Model::validateRequired('alipaySubMerchantId', $this->alipaySubMerchantId, true); + Model::validateRequired('extInfos', $this->extInfos, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->tradeNo) { + $res['trade_no'] = $this->tradeNo; + } + if (null !== $this->outTradeNo) { + $res['out_trade_no'] = $this->outTradeNo; + } + if (null !== $this->buyerLogonId) { + $res['buyer_logon_id'] = $this->buyerLogonId; + } + if (null !== $this->tradeStatus) { + $res['trade_status'] = $this->tradeStatus; + } + if (null !== $this->totalAmount) { + $res['total_amount'] = $this->totalAmount; + } + if (null !== $this->transCurrency) { + $res['trans_currency'] = $this->transCurrency; + } + if (null !== $this->settleCurrency) { + $res['settle_currency'] = $this->settleCurrency; + } + if (null !== $this->settleAmount) { + $res['settle_amount'] = $this->settleAmount; + } + if (null !== $this->payCurrency) { + $res['pay_currency'] = $this->payCurrency; + } + if (null !== $this->payAmount) { + $res['pay_amount'] = $this->payAmount; + } + if (null !== $this->settleTransRate) { + $res['settle_trans_rate'] = $this->settleTransRate; + } + if (null !== $this->transPayRate) { + $res['trans_pay_rate'] = $this->transPayRate; + } + if (null !== $this->buyerPayAmount) { + $res['buyer_pay_amount'] = $this->buyerPayAmount; + } + if (null !== $this->pointAmount) { + $res['point_amount'] = $this->pointAmount; + } + if (null !== $this->invoiceAmount) { + $res['invoice_amount'] = $this->invoiceAmount; + } + if (null !== $this->sendPayDate) { + $res['send_pay_date'] = $this->sendPayDate; + } + if (null !== $this->receiptAmount) { + $res['receipt_amount'] = $this->receiptAmount; + } + if (null !== $this->storeId) { + $res['store_id'] = $this->storeId; + } + if (null !== $this->terminalId) { + $res['terminal_id'] = $this->terminalId; + } + if (null !== $this->fundBillList) { + $res['fund_bill_list'] = []; + if(null !== $this->fundBillList && is_array($this->fundBillList)){ + $n = 0; + foreach($this->fundBillList as $item){ + $res['fund_bill_list'][$n++] = null !== $item ? $item->toMap() : $item; + } + } + } + if (null !== $this->storeName) { + $res['store_name'] = $this->storeName; + } + if (null !== $this->buyerUserId) { + $res['buyer_user_id'] = $this->buyerUserId; + } + if (null !== $this->chargeAmount) { + $res['charge_amount'] = $this->chargeAmount; + } + if (null !== $this->chargeFlags) { + $res['charge_flags'] = $this->chargeFlags; + } + if (null !== $this->settlementId) { + $res['settlement_id'] = $this->settlementId; + } + if (null !== $this->tradeSettleInfo) { + $res['trade_settle_info'] = []; + if(null !== $this->tradeSettleInfo && is_array($this->tradeSettleInfo)){ + $n = 0; + foreach($this->tradeSettleInfo as $item){ + $res['trade_settle_info'][$n++] = null !== $item ? $item->toMap() : $item; + } + } + } + if (null !== $this->authTradePayMode) { + $res['auth_trade_pay_mode'] = $this->authTradePayMode; + } + if (null !== $this->buyerUserType) { + $res['buyer_user_type'] = $this->buyerUserType; + } + if (null !== $this->mdiscountAmount) { + $res['mdiscount_amount'] = $this->mdiscountAmount; + } + if (null !== $this->discountAmount) { + $res['discount_amount'] = $this->discountAmount; + } + if (null !== $this->buyerUserName) { + $res['buyer_user_name'] = $this->buyerUserName; + } + if (null !== $this->subject) { + $res['subject'] = $this->subject; + } + if (null !== $this->body) { + $res['body'] = $this->body; + } + if (null !== $this->alipaySubMerchantId) { + $res['alipay_sub_merchant_id'] = $this->alipaySubMerchantId; + } + if (null !== $this->extInfos) { + $res['ext_infos'] = $this->extInfos; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradeQueryResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['trade_no'])){ + $model->tradeNo = $map['trade_no']; + } + if(isset($map['out_trade_no'])){ + $model->outTradeNo = $map['out_trade_no']; + } + if(isset($map['buyer_logon_id'])){ + $model->buyerLogonId = $map['buyer_logon_id']; + } + if(isset($map['trade_status'])){ + $model->tradeStatus = $map['trade_status']; + } + if(isset($map['total_amount'])){ + $model->totalAmount = $map['total_amount']; + } + if(isset($map['trans_currency'])){ + $model->transCurrency = $map['trans_currency']; + } + if(isset($map['settle_currency'])){ + $model->settleCurrency = $map['settle_currency']; + } + if(isset($map['settle_amount'])){ + $model->settleAmount = $map['settle_amount']; + } + if(isset($map['pay_currency'])){ + $model->payCurrency = $map['pay_currency']; + } + if(isset($map['pay_amount'])){ + $model->payAmount = $map['pay_amount']; + } + if(isset($map['settle_trans_rate'])){ + $model->settleTransRate = $map['settle_trans_rate']; + } + if(isset($map['trans_pay_rate'])){ + $model->transPayRate = $map['trans_pay_rate']; + } + if(isset($map['buyer_pay_amount'])){ + $model->buyerPayAmount = $map['buyer_pay_amount']; + } + if(isset($map['point_amount'])){ + $model->pointAmount = $map['point_amount']; + } + if(isset($map['invoice_amount'])){ + $model->invoiceAmount = $map['invoice_amount']; + } + if(isset($map['send_pay_date'])){ + $model->sendPayDate = $map['send_pay_date']; + } + if(isset($map['receipt_amount'])){ + $model->receiptAmount = $map['receipt_amount']; + } + if(isset($map['store_id'])){ + $model->storeId = $map['store_id']; + } + if(isset($map['terminal_id'])){ + $model->terminalId = $map['terminal_id']; + } + if(isset($map['fund_bill_list'])){ + if(!empty($map['fund_bill_list'])){ + $model->fundBillList = []; + $n = 0; + foreach($map['fund_bill_list'] as $item) { + $model->fundBillList[$n++] = null !== $item ? TradeFundBill::fromMap($item) : $item; + } + } + } + if(isset($map['store_name'])){ + $model->storeName = $map['store_name']; + } + if(isset($map['buyer_user_id'])){ + $model->buyerUserId = $map['buyer_user_id']; + } + if(isset($map['charge_amount'])){ + $model->chargeAmount = $map['charge_amount']; + } + if(isset($map['charge_flags'])){ + $model->chargeFlags = $map['charge_flags']; + } + if(isset($map['settlement_id'])){ + $model->settlementId = $map['settlement_id']; + } + if(isset($map['trade_settle_info'])){ + if(!empty($map['trade_settle_info'])){ + $model->tradeSettleInfo = []; + $n = 0; + foreach($map['trade_settle_info'] as $item) { + $model->tradeSettleInfo[$n++] = null !== $item ? TradeSettleInfo::fromMap($item) : $item; + } + } + } + if(isset($map['auth_trade_pay_mode'])){ + $model->authTradePayMode = $map['auth_trade_pay_mode']; + } + if(isset($map['buyer_user_type'])){ + $model->buyerUserType = $map['buyer_user_type']; + } + if(isset($map['mdiscount_amount'])){ + $model->mdiscountAmount = $map['mdiscount_amount']; + } + if(isset($map['discount_amount'])){ + $model->discountAmount = $map['discount_amount']; + } + if(isset($map['buyer_user_name'])){ + $model->buyerUserName = $map['buyer_user_name']; + } + if(isset($map['subject'])){ + $model->subject = $map['subject']; + } + if(isset($map['body'])){ + $model->body = $map['body']; + } + if(isset($map['alipay_sub_merchant_id'])){ + $model->alipaySubMerchantId = $map['alipay_sub_merchant_id']; + } + if(isset($map['ext_infos'])){ + $model->extInfos = $map['ext_infos']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $tradeNo; + + /** + * @var string + */ + public $outTradeNo; + + /** + * @var string + */ + public $buyerLogonId; + + /** + * @var string + */ + public $tradeStatus; + + /** + * @var string + */ + public $totalAmount; + + /** + * @var string + */ + public $transCurrency; + + /** + * @var string + */ + public $settleCurrency; + + /** + * @var string + */ + public $settleAmount; + + /** + * @var string + */ + public $payCurrency; + + /** + * @var string + */ + public $payAmount; + + /** + * @var string + */ + public $settleTransRate; + + /** + * @var string + */ + public $transPayRate; + + /** + * @var string + */ + public $buyerPayAmount; + + /** + * @var string + */ + public $pointAmount; + + /** + * @var string + */ + public $invoiceAmount; + + /** + * @var string + */ + public $sendPayDate; + + /** + * @var string + */ + public $receiptAmount; + + /** + * @var string + */ + public $storeId; + + /** + * @var string + */ + public $terminalId; + + /** + * @var TradeFundBill[] + */ + public $fundBillList; + + /** + * @var string + */ + public $storeName; + + /** + * @var string + */ + public $buyerUserId; + + /** + * @var string + */ + public $chargeAmount; + + /** + * @var string + */ + public $chargeFlags; + + /** + * @var string + */ + public $settlementId; + + /** + * @var TradeSettleInfo[] + */ + public $tradeSettleInfo; + + /** + * @var string + */ + public $authTradePayMode; + + /** + * @var string + */ + public $buyerUserType; + + /** + * @var string + */ + public $mdiscountAmount; + + /** + * @var string + */ + public $discountAmount; + + /** + * @var string + */ + public $buyerUserName; + + /** + * @var string + */ + public $subject; + + /** + * @var string + */ + public $body; + + /** + * @var string + */ + public $alipaySubMerchantId; + + /** + * @var string + */ + public $extInfos; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeRefundResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeRefundResponse.php new file mode 100644 index 0000000..84db87d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/AlipayTradeRefundResponse.php @@ -0,0 +1,313 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'tradeNo' => 'trade_no', + 'outTradeNo' => 'out_trade_no', + 'buyerLogonId' => 'buyer_logon_id', + 'fundChange' => 'fund_change', + 'refundFee' => 'refund_fee', + 'refundCurrency' => 'refund_currency', + 'gmtRefundPay' => 'gmt_refund_pay', + 'refundDetailItemList' => 'refund_detail_item_list', + 'storeName' => 'store_name', + 'buyerUserId' => 'buyer_user_id', + 'refundPresetPaytoolList' => 'refund_preset_paytool_list', + 'refundSettlementId' => 'refund_settlement_id', + 'presentRefundBuyerAmount' => 'present_refund_buyer_amount', + 'presentRefundDiscountAmount' => 'present_refund_discount_amount', + 'presentRefundMdiscountAmount' => 'present_refund_mdiscount_amount', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('tradeNo', $this->tradeNo, true); + Model::validateRequired('outTradeNo', $this->outTradeNo, true); + Model::validateRequired('buyerLogonId', $this->buyerLogonId, true); + Model::validateRequired('fundChange', $this->fundChange, true); + Model::validateRequired('refundFee', $this->refundFee, true); + Model::validateRequired('refundCurrency', $this->refundCurrency, true); + Model::validateRequired('gmtRefundPay', $this->gmtRefundPay, true); + Model::validateRequired('refundDetailItemList', $this->refundDetailItemList, true); + Model::validateRequired('storeName', $this->storeName, true); + Model::validateRequired('buyerUserId', $this->buyerUserId, true); + Model::validateRequired('refundPresetPaytoolList', $this->refundPresetPaytoolList, true); + Model::validateRequired('refundSettlementId', $this->refundSettlementId, true); + Model::validateRequired('presentRefundBuyerAmount', $this->presentRefundBuyerAmount, true); + Model::validateRequired('presentRefundDiscountAmount', $this->presentRefundDiscountAmount, true); + Model::validateRequired('presentRefundMdiscountAmount', $this->presentRefundMdiscountAmount, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->tradeNo) { + $res['trade_no'] = $this->tradeNo; + } + if (null !== $this->outTradeNo) { + $res['out_trade_no'] = $this->outTradeNo; + } + if (null !== $this->buyerLogonId) { + $res['buyer_logon_id'] = $this->buyerLogonId; + } + if (null !== $this->fundChange) { + $res['fund_change'] = $this->fundChange; + } + if (null !== $this->refundFee) { + $res['refund_fee'] = $this->refundFee; + } + if (null !== $this->refundCurrency) { + $res['refund_currency'] = $this->refundCurrency; + } + if (null !== $this->gmtRefundPay) { + $res['gmt_refund_pay'] = $this->gmtRefundPay; + } + if (null !== $this->refundDetailItemList) { + $res['refund_detail_item_list'] = []; + if(null !== $this->refundDetailItemList && is_array($this->refundDetailItemList)){ + $n = 0; + foreach($this->refundDetailItemList as $item){ + $res['refund_detail_item_list'][$n++] = null !== $item ? $item->toMap() : $item; + } + } + } + if (null !== $this->storeName) { + $res['store_name'] = $this->storeName; + } + if (null !== $this->buyerUserId) { + $res['buyer_user_id'] = $this->buyerUserId; + } + if (null !== $this->refundPresetPaytoolList) { + $res['refund_preset_paytool_list'] = []; + if(null !== $this->refundPresetPaytoolList && is_array($this->refundPresetPaytoolList)){ + $n = 0; + foreach($this->refundPresetPaytoolList as $item){ + $res['refund_preset_paytool_list'][$n++] = null !== $item ? $item->toMap() : $item; + } + } + } + if (null !== $this->refundSettlementId) { + $res['refund_settlement_id'] = $this->refundSettlementId; + } + if (null !== $this->presentRefundBuyerAmount) { + $res['present_refund_buyer_amount'] = $this->presentRefundBuyerAmount; + } + if (null !== $this->presentRefundDiscountAmount) { + $res['present_refund_discount_amount'] = $this->presentRefundDiscountAmount; + } + if (null !== $this->presentRefundMdiscountAmount) { + $res['present_refund_mdiscount_amount'] = $this->presentRefundMdiscountAmount; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradeRefundResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['trade_no'])){ + $model->tradeNo = $map['trade_no']; + } + if(isset($map['out_trade_no'])){ + $model->outTradeNo = $map['out_trade_no']; + } + if(isset($map['buyer_logon_id'])){ + $model->buyerLogonId = $map['buyer_logon_id']; + } + if(isset($map['fund_change'])){ + $model->fundChange = $map['fund_change']; + } + if(isset($map['refund_fee'])){ + $model->refundFee = $map['refund_fee']; + } + if(isset($map['refund_currency'])){ + $model->refundCurrency = $map['refund_currency']; + } + if(isset($map['gmt_refund_pay'])){ + $model->gmtRefundPay = $map['gmt_refund_pay']; + } + if(isset($map['refund_detail_item_list'])){ + if(!empty($map['refund_detail_item_list'])){ + $model->refundDetailItemList = []; + $n = 0; + foreach($map['refund_detail_item_list'] as $item) { + $model->refundDetailItemList[$n++] = null !== $item ? TradeFundBill::fromMap($item) : $item; + } + } + } + if(isset($map['store_name'])){ + $model->storeName = $map['store_name']; + } + if(isset($map['buyer_user_id'])){ + $model->buyerUserId = $map['buyer_user_id']; + } + if(isset($map['refund_preset_paytool_list'])){ + if(!empty($map['refund_preset_paytool_list'])){ + $model->refundPresetPaytoolList = []; + $n = 0; + foreach($map['refund_preset_paytool_list'] as $item) { + $model->refundPresetPaytoolList[$n++] = null !== $item ? PresetPayToolInfo::fromMap($item) : $item; + } + } + } + if(isset($map['refund_settlement_id'])){ + $model->refundSettlementId = $map['refund_settlement_id']; + } + if(isset($map['present_refund_buyer_amount'])){ + $model->presentRefundBuyerAmount = $map['present_refund_buyer_amount']; + } + if(isset($map['present_refund_discount_amount'])){ + $model->presentRefundDiscountAmount = $map['present_refund_discount_amount']; + } + if(isset($map['present_refund_mdiscount_amount'])){ + $model->presentRefundMdiscountAmount = $map['present_refund_mdiscount_amount']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $tradeNo; + + /** + * @var string + */ + public $outTradeNo; + + /** + * @var string + */ + public $buyerLogonId; + + /** + * @var string + */ + public $fundChange; + + /** + * @var string + */ + public $refundFee; + + /** + * @var string + */ + public $refundCurrency; + + /** + * @var string + */ + public $gmtRefundPay; + + /** + * @var TradeFundBill[] + */ + public $refundDetailItemList; + + /** + * @var string + */ + public $storeName; + + /** + * @var string + */ + public $buyerUserId; + + /** + * @var PresetPayToolInfo[] + */ + public $refundPresetPaytoolList; + + /** + * @var string + */ + public $refundSettlementId; + + /** + * @var string + */ + public $presentRefundBuyerAmount; + + /** + * @var string + */ + public $presentRefundDiscountAmount; + + /** + * @var string + */ + public $presentRefundMdiscountAmount; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/PresetPayToolInfo.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/PresetPayToolInfo.php new file mode 100644 index 0000000..eb1f0ea --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/PresetPayToolInfo.php @@ -0,0 +1,53 @@ + 'amount', + 'assertTypeCode' => 'assert_type_code', + ]; + public function validate() { + Model::validateRequired('amount', $this->amount, true); + Model::validateRequired('assertTypeCode', $this->assertTypeCode, true); + } + public function toMap() { + $res = []; + if (null !== $this->amount) { + $res['amount'] = $this->amount; + } + if (null !== $this->assertTypeCode) { + $res['assert_type_code'] = $this->assertTypeCode; + } + return $res; + } + /** + * @param array $map + * @return PresetPayToolInfo + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['amount'])){ + if(!empty($map['amount'])){ + $model->amount = $map['amount']; + } + } + if(isset($map['assert_type_code'])){ + $model->assertTypeCode = $map['assert_type_code']; + } + return $model; + } + /** + * @var string[] + */ + public $amount; + + /** + * @var string + */ + public $assertTypeCode; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/RefundRoyaltyResult.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/RefundRoyaltyResult.php new file mode 100644 index 0000000..f85e754 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/RefundRoyaltyResult.php @@ -0,0 +1,116 @@ + 'refund_amount', + 'royaltyType' => 'royalty_type', + 'resultCode' => 'result_code', + 'transOut' => 'trans_out', + 'transOutEmail' => 'trans_out_email', + 'transIn' => 'trans_in', + 'transInEmail' => 'trans_in_email', + ]; + public function validate() { + Model::validateRequired('refundAmount', $this->refundAmount, true); + Model::validateRequired('royaltyType', $this->royaltyType, true); + Model::validateRequired('resultCode', $this->resultCode, true); + Model::validateRequired('transOut', $this->transOut, true); + Model::validateRequired('transOutEmail', $this->transOutEmail, true); + Model::validateRequired('transIn', $this->transIn, true); + Model::validateRequired('transInEmail', $this->transInEmail, true); + } + public function toMap() { + $res = []; + if (null !== $this->refundAmount) { + $res['refund_amount'] = $this->refundAmount; + } + if (null !== $this->royaltyType) { + $res['royalty_type'] = $this->royaltyType; + } + if (null !== $this->resultCode) { + $res['result_code'] = $this->resultCode; + } + if (null !== $this->transOut) { + $res['trans_out'] = $this->transOut; + } + if (null !== $this->transOutEmail) { + $res['trans_out_email'] = $this->transOutEmail; + } + if (null !== $this->transIn) { + $res['trans_in'] = $this->transIn; + } + if (null !== $this->transInEmail) { + $res['trans_in_email'] = $this->transInEmail; + } + return $res; + } + /** + * @param array $map + * @return RefundRoyaltyResult + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['refund_amount'])){ + $model->refundAmount = $map['refund_amount']; + } + if(isset($map['royalty_type'])){ + $model->royaltyType = $map['royalty_type']; + } + if(isset($map['result_code'])){ + $model->resultCode = $map['result_code']; + } + if(isset($map['trans_out'])){ + $model->transOut = $map['trans_out']; + } + if(isset($map['trans_out_email'])){ + $model->transOutEmail = $map['trans_out_email']; + } + if(isset($map['trans_in'])){ + $model->transIn = $map['trans_in']; + } + if(isset($map['trans_in_email'])){ + $model->transInEmail = $map['trans_in_email']; + } + return $model; + } + /** + * @var string + */ + public $refundAmount; + + /** + * @var string + */ + public $royaltyType; + + /** + * @var string + */ + public $resultCode; + + /** + * @var string + */ + public $transOut; + + /** + * @var string + */ + public $transOutEmail; + + /** + * @var string + */ + public $transIn; + + /** + * @var string + */ + public $transInEmail; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/TradeFundBill.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/TradeFundBill.php new file mode 100644 index 0000000..3d20172 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/TradeFundBill.php @@ -0,0 +1,90 @@ + 'fund_channel', + 'bankCode' => 'bank_code', + 'amount' => 'amount', + 'realAmount' => 'real_amount', + 'fundType' => 'fund_type', + ]; + public function validate() { + Model::validateRequired('fundChannel', $this->fundChannel, true); + Model::validateRequired('bankCode', $this->bankCode, true); + Model::validateRequired('amount', $this->amount, true); + Model::validateRequired('realAmount', $this->realAmount, true); + Model::validateRequired('fundType', $this->fundType, true); + } + public function toMap() { + $res = []; + if (null !== $this->fundChannel) { + $res['fund_channel'] = $this->fundChannel; + } + if (null !== $this->bankCode) { + $res['bank_code'] = $this->bankCode; + } + if (null !== $this->amount) { + $res['amount'] = $this->amount; + } + if (null !== $this->realAmount) { + $res['real_amount'] = $this->realAmount; + } + if (null !== $this->fundType) { + $res['fund_type'] = $this->fundType; + } + return $res; + } + /** + * @param array $map + * @return TradeFundBill + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['fund_channel'])){ + $model->fundChannel = $map['fund_channel']; + } + if(isset($map['bank_code'])){ + $model->bankCode = $map['bank_code']; + } + if(isset($map['amount'])){ + $model->amount = $map['amount']; + } + if(isset($map['real_amount'])){ + $model->realAmount = $map['real_amount']; + } + if(isset($map['fund_type'])){ + $model->fundType = $map['fund_type']; + } + return $model; + } + /** + * @var string + */ + public $fundChannel; + + /** + * @var string + */ + public $bankCode; + + /** + * @var string + */ + public $amount; + + /** + * @var string + */ + public $realAmount; + + /** + * @var string + */ + public $fundType; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/TradeSettleDetail.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/TradeSettleDetail.php new file mode 100644 index 0000000..1bed575 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/TradeSettleDetail.php @@ -0,0 +1,103 @@ + 'operation_type', + 'operationSerial_no' => 'operation_serial_no', + 'operationDt' => 'operation_dt', + 'transOut' => 'trans_out', + 'transIn' => 'trans_in', + 'amount' => 'amount', + ]; + public function validate() { + Model::validateRequired('operationType', $this->operationType, true); + Model::validateRequired('operationSerial_no', $this->operationSerial_no, true); + Model::validateRequired('operationDt', $this->operationDt, true); + Model::validateRequired('transOut', $this->transOut, true); + Model::validateRequired('transIn', $this->transIn, true); + Model::validateRequired('amount', $this->amount, true); + } + public function toMap() { + $res = []; + if (null !== $this->operationType) { + $res['operation_type'] = $this->operationType; + } + if (null !== $this->operationSerial_no) { + $res['operation_serial_no'] = $this->operationSerial_no; + } + if (null !== $this->operationDt) { + $res['operation_dt'] = $this->operationDt; + } + if (null !== $this->transOut) { + $res['trans_out'] = $this->transOut; + } + if (null !== $this->transIn) { + $res['trans_in'] = $this->transIn; + } + if (null !== $this->amount) { + $res['amount'] = $this->amount; + } + return $res; + } + /** + * @param array $map + * @return TradeSettleDetail + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['operation_type'])){ + $model->operationType = $map['operation_type']; + } + if(isset($map['operation_serial_no'])){ + $model->operationSerial_no = $map['operation_serial_no']; + } + if(isset($map['operation_dt'])){ + $model->operationDt = $map['operation_dt']; + } + if(isset($map['trans_out'])){ + $model->transOut = $map['trans_out']; + } + if(isset($map['trans_in'])){ + $model->transIn = $map['trans_in']; + } + if(isset($map['amount'])){ + $model->amount = $map['amount']; + } + return $model; + } + /** + * @var string + */ + public $operationType; + + /** + * @var string + */ + public $operationSerial_no; + + /** + * @var string + */ + public $operationDt; + + /** + * @var string + */ + public $transOut; + + /** + * @var string + */ + public $transIn; + + /** + * @var string + */ + public $amount; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/TradeSettleInfo.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/TradeSettleInfo.php new file mode 100644 index 0000000..aa7720f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Common/Models/TradeSettleInfo.php @@ -0,0 +1,52 @@ + 'trade_settle_detail_list', + ]; + public function validate() { + Model::validateRequired('tradeSettleDetailList', $this->tradeSettleDetailList, true); + } + public function toMap() { + $res = []; + if (null !== $this->tradeSettleDetailList) { + $res['trade_settle_detail_list'] = []; + if(null !== $this->tradeSettleDetailList && is_array($this->tradeSettleDetailList)){ + $n = 0; + foreach($this->tradeSettleDetailList as $item){ + $res['trade_settle_detail_list'][$n++] = null !== $item ? $item->toMap() : $item; + } + } + } + return $res; + } + /** + * @param array $map + * @return TradeSettleInfo + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['trade_settle_detail_list'])){ + if(!empty($map['trade_settle_detail_list'])){ + $model->tradeSettleDetailList = []; + $n = 0; + foreach($map['trade_settle_detail_list'] as $item) { + $model->tradeSettleDetailList[$n++] = null !== $item ? TradeSettleDetail::fromMap($item) : $item; + } + } + } + return $model; + } + /** + * @var TradeSettleDetail[] + */ + public $tradeSettleDetailList; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Client.php new file mode 100644 index 0000000..b07f473 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Client.php @@ -0,0 +1,293 @@ +_kernel = $kernel; + } + + /** + * @param string $subject + * @param string $outTradeNo + * @param string $totalAmount + * @param string $authCode + * @return AlipayTradePayResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function pay($subject, $outTradeNo, $totalAmount, $authCode){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.trade.pay", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "subject" => $subject, + "out_trade_no" => $outTradeNo, + "total_amount" => $totalAmount, + "auth_code" => $authCode, + "scene" => "bar_code" + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.pay"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayTradePayResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayTradePayResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $subject + * @param string $outTradeNo + * @param string $totalAmount + * @return AlipayTradePrecreateResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function preCreate($subject, $outTradeNo, $totalAmount){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.trade.precreate", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "subject" => $subject, + "out_trade_no" => $outTradeNo, + "total_amount" => $totalAmount + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.precreate"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayTradePrecreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayTradePrecreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/AlipayTradePayResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/AlipayTradePayResponse.php new file mode 100644 index 0000000..faa193b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/AlipayTradePayResponse.php @@ -0,0 +1,534 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'tradeNo' => 'trade_no', + 'outTradeNo' => 'out_trade_no', + 'buyerLogonId' => 'buyer_logon_id', + 'settleAmount' => 'settle_amount', + 'payCurrency' => 'pay_currency', + 'payAmount' => 'pay_amount', + 'settleTransRate' => 'settle_trans_rate', + 'transPayRate' => 'trans_pay_rate', + 'totalAmount' => 'total_amount', + 'transCurrency' => 'trans_currency', + 'settleCurrency' => 'settle_currency', + 'receiptAmount' => 'receipt_amount', + 'buyerPayAmount' => 'buyer_pay_amount', + 'pointAmount' => 'point_amount', + 'invoiceAmount' => 'invoice_amount', + 'gmtPayment' => 'gmt_payment', + 'fundBillList' => 'fund_bill_list', + 'cardBalance' => 'card_balance', + 'storeName' => 'store_name', + 'buyerUserId' => 'buyer_user_id', + 'discountGoodsDetail' => 'discount_goods_detail', + 'voucherDetailList' => 'voucher_detail_list', + 'advanceAmount' => 'advance_amount', + 'authTradePayMode' => 'auth_trade_pay_mode', + 'chargeAmount' => 'charge_amount', + 'chargeFlags' => 'charge_flags', + 'settlementId' => 'settlement_id', + 'businessParams' => 'business_params', + 'buyerUserType' => 'buyer_user_type', + 'mdiscountAmount' => 'mdiscount_amount', + 'discountAmount' => 'discount_amount', + 'buyerUserName' => 'buyer_user_name', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('tradeNo', $this->tradeNo, true); + Model::validateRequired('outTradeNo', $this->outTradeNo, true); + Model::validateRequired('buyerLogonId', $this->buyerLogonId, true); + Model::validateRequired('settleAmount', $this->settleAmount, true); + Model::validateRequired('payCurrency', $this->payCurrency, true); + Model::validateRequired('payAmount', $this->payAmount, true); + Model::validateRequired('settleTransRate', $this->settleTransRate, true); + Model::validateRequired('transPayRate', $this->transPayRate, true); + Model::validateRequired('totalAmount', $this->totalAmount, true); + Model::validateRequired('transCurrency', $this->transCurrency, true); + Model::validateRequired('settleCurrency', $this->settleCurrency, true); + Model::validateRequired('receiptAmount', $this->receiptAmount, true); + Model::validateRequired('buyerPayAmount', $this->buyerPayAmount, true); + Model::validateRequired('pointAmount', $this->pointAmount, true); + Model::validateRequired('invoiceAmount', $this->invoiceAmount, true); + Model::validateRequired('gmtPayment', $this->gmtPayment, true); + Model::validateRequired('fundBillList', $this->fundBillList, true); + Model::validateRequired('cardBalance', $this->cardBalance, true); + Model::validateRequired('storeName', $this->storeName, true); + Model::validateRequired('buyerUserId', $this->buyerUserId, true); + Model::validateRequired('discountGoodsDetail', $this->discountGoodsDetail, true); + Model::validateRequired('voucherDetailList', $this->voucherDetailList, true); + Model::validateRequired('advanceAmount', $this->advanceAmount, true); + Model::validateRequired('authTradePayMode', $this->authTradePayMode, true); + Model::validateRequired('chargeAmount', $this->chargeAmount, true); + Model::validateRequired('chargeFlags', $this->chargeFlags, true); + Model::validateRequired('settlementId', $this->settlementId, true); + Model::validateRequired('businessParams', $this->businessParams, true); + Model::validateRequired('buyerUserType', $this->buyerUserType, true); + Model::validateRequired('mdiscountAmount', $this->mdiscountAmount, true); + Model::validateRequired('discountAmount', $this->discountAmount, true); + Model::validateRequired('buyerUserName', $this->buyerUserName, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->tradeNo) { + $res['trade_no'] = $this->tradeNo; + } + if (null !== $this->outTradeNo) { + $res['out_trade_no'] = $this->outTradeNo; + } + if (null !== $this->buyerLogonId) { + $res['buyer_logon_id'] = $this->buyerLogonId; + } + if (null !== $this->settleAmount) { + $res['settle_amount'] = $this->settleAmount; + } + if (null !== $this->payCurrency) { + $res['pay_currency'] = $this->payCurrency; + } + if (null !== $this->payAmount) { + $res['pay_amount'] = $this->payAmount; + } + if (null !== $this->settleTransRate) { + $res['settle_trans_rate'] = $this->settleTransRate; + } + if (null !== $this->transPayRate) { + $res['trans_pay_rate'] = $this->transPayRate; + } + if (null !== $this->totalAmount) { + $res['total_amount'] = $this->totalAmount; + } + if (null !== $this->transCurrency) { + $res['trans_currency'] = $this->transCurrency; + } + if (null !== $this->settleCurrency) { + $res['settle_currency'] = $this->settleCurrency; + } + if (null !== $this->receiptAmount) { + $res['receipt_amount'] = $this->receiptAmount; + } + if (null !== $this->buyerPayAmount) { + $res['buyer_pay_amount'] = $this->buyerPayAmount; + } + if (null !== $this->pointAmount) { + $res['point_amount'] = $this->pointAmount; + } + if (null !== $this->invoiceAmount) { + $res['invoice_amount'] = $this->invoiceAmount; + } + if (null !== $this->gmtPayment) { + $res['gmt_payment'] = $this->gmtPayment; + } + if (null !== $this->fundBillList) { + $res['fund_bill_list'] = []; + if(null !== $this->fundBillList && is_array($this->fundBillList)){ + $n = 0; + foreach($this->fundBillList as $item){ + $res['fund_bill_list'][$n++] = null !== $item ? $item->toMap() : $item; + } + } + } + if (null !== $this->cardBalance) { + $res['card_balance'] = $this->cardBalance; + } + if (null !== $this->storeName) { + $res['store_name'] = $this->storeName; + } + if (null !== $this->buyerUserId) { + $res['buyer_user_id'] = $this->buyerUserId; + } + if (null !== $this->discountGoodsDetail) { + $res['discount_goods_detail'] = $this->discountGoodsDetail; + } + if (null !== $this->voucherDetailList) { + $res['voucher_detail_list'] = []; + if(null !== $this->voucherDetailList && is_array($this->voucherDetailList)){ + $n = 0; + foreach($this->voucherDetailList as $item){ + $res['voucher_detail_list'][$n++] = null !== $item ? $item->toMap() : $item; + } + } + } + if (null !== $this->advanceAmount) { + $res['advance_amount'] = $this->advanceAmount; + } + if (null !== $this->authTradePayMode) { + $res['auth_trade_pay_mode'] = $this->authTradePayMode; + } + if (null !== $this->chargeAmount) { + $res['charge_amount'] = $this->chargeAmount; + } + if (null !== $this->chargeFlags) { + $res['charge_flags'] = $this->chargeFlags; + } + if (null !== $this->settlementId) { + $res['settlement_id'] = $this->settlementId; + } + if (null !== $this->businessParams) { + $res['business_params'] = $this->businessParams; + } + if (null !== $this->buyerUserType) { + $res['buyer_user_type'] = $this->buyerUserType; + } + if (null !== $this->mdiscountAmount) { + $res['mdiscount_amount'] = $this->mdiscountAmount; + } + if (null !== $this->discountAmount) { + $res['discount_amount'] = $this->discountAmount; + } + if (null !== $this->buyerUserName) { + $res['buyer_user_name'] = $this->buyerUserName; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradePayResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['trade_no'])){ + $model->tradeNo = $map['trade_no']; + } + if(isset($map['out_trade_no'])){ + $model->outTradeNo = $map['out_trade_no']; + } + if(isset($map['buyer_logon_id'])){ + $model->buyerLogonId = $map['buyer_logon_id']; + } + if(isset($map['settle_amount'])){ + $model->settleAmount = $map['settle_amount']; + } + if(isset($map['pay_currency'])){ + $model->payCurrency = $map['pay_currency']; + } + if(isset($map['pay_amount'])){ + $model->payAmount = $map['pay_amount']; + } + if(isset($map['settle_trans_rate'])){ + $model->settleTransRate = $map['settle_trans_rate']; + } + if(isset($map['trans_pay_rate'])){ + $model->transPayRate = $map['trans_pay_rate']; + } + if(isset($map['total_amount'])){ + $model->totalAmount = $map['total_amount']; + } + if(isset($map['trans_currency'])){ + $model->transCurrency = $map['trans_currency']; + } + if(isset($map['settle_currency'])){ + $model->settleCurrency = $map['settle_currency']; + } + if(isset($map['receipt_amount'])){ + $model->receiptAmount = $map['receipt_amount']; + } + if(isset($map['buyer_pay_amount'])){ + $model->buyerPayAmount = $map['buyer_pay_amount']; + } + if(isset($map['point_amount'])){ + $model->pointAmount = $map['point_amount']; + } + if(isset($map['invoice_amount'])){ + $model->invoiceAmount = $map['invoice_amount']; + } + if(isset($map['gmt_payment'])){ + $model->gmtPayment = $map['gmt_payment']; + } + if(isset($map['fund_bill_list'])){ + if(!empty($map['fund_bill_list'])){ + $model->fundBillList = []; + $n = 0; + foreach($map['fund_bill_list'] as $item) { + $model->fundBillList[$n++] = null !== $item ? TradeFundBill::fromMap($item) : $item; + } + } + } + if(isset($map['card_balance'])){ + $model->cardBalance = $map['card_balance']; + } + if(isset($map['store_name'])){ + $model->storeName = $map['store_name']; + } + if(isset($map['buyer_user_id'])){ + $model->buyerUserId = $map['buyer_user_id']; + } + if(isset($map['discount_goods_detail'])){ + $model->discountGoodsDetail = $map['discount_goods_detail']; + } + if(isset($map['voucher_detail_list'])){ + if(!empty($map['voucher_detail_list'])){ + $model->voucherDetailList = []; + $n = 0; + foreach($map['voucher_detail_list'] as $item) { + $model->voucherDetailList[$n++] = null !== $item ? VoucherDetail::fromMap($item) : $item; + } + } + } + if(isset($map['advance_amount'])){ + $model->advanceAmount = $map['advance_amount']; + } + if(isset($map['auth_trade_pay_mode'])){ + $model->authTradePayMode = $map['auth_trade_pay_mode']; + } + if(isset($map['charge_amount'])){ + $model->chargeAmount = $map['charge_amount']; + } + if(isset($map['charge_flags'])){ + $model->chargeFlags = $map['charge_flags']; + } + if(isset($map['settlement_id'])){ + $model->settlementId = $map['settlement_id']; + } + if(isset($map['business_params'])){ + $model->businessParams = $map['business_params']; + } + if(isset($map['buyer_user_type'])){ + $model->buyerUserType = $map['buyer_user_type']; + } + if(isset($map['mdiscount_amount'])){ + $model->mdiscountAmount = $map['mdiscount_amount']; + } + if(isset($map['discount_amount'])){ + $model->discountAmount = $map['discount_amount']; + } + if(isset($map['buyer_user_name'])){ + $model->buyerUserName = $map['buyer_user_name']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $tradeNo; + + /** + * @var string + */ + public $outTradeNo; + + /** + * @var string + */ + public $buyerLogonId; + + /** + * @var string + */ + public $settleAmount; + + /** + * @var string + */ + public $payCurrency; + + /** + * @var string + */ + public $payAmount; + + /** + * @var string + */ + public $settleTransRate; + + /** + * @var string + */ + public $transPayRate; + + /** + * @var string + */ + public $totalAmount; + + /** + * @var string + */ + public $transCurrency; + + /** + * @var string + */ + public $settleCurrency; + + /** + * @var string + */ + public $receiptAmount; + + /** + * @var string + */ + public $buyerPayAmount; + + /** + * @var string + */ + public $pointAmount; + + /** + * @var string + */ + public $invoiceAmount; + + /** + * @var string + */ + public $gmtPayment; + + /** + * @var TradeFundBill[] + */ + public $fundBillList; + + /** + * @var string + */ + public $cardBalance; + + /** + * @var string + */ + public $storeName; + + /** + * @var string + */ + public $buyerUserId; + + /** + * @var string + */ + public $discountGoodsDetail; + + /** + * @var VoucherDetail[] + */ + public $voucherDetailList; + + /** + * @var string + */ + public $advanceAmount; + + /** + * @var string + */ + public $authTradePayMode; + + /** + * @var string + */ + public $chargeAmount; + + /** + * @var string + */ + public $chargeFlags; + + /** + * @var string + */ + public $settlementId; + + /** + * @var string + */ + public $businessParams; + + /** + * @var string + */ + public $buyerUserType; + + /** + * @var string + */ + public $mdiscountAmount; + + /** + * @var string + */ + public $discountAmount; + + /** + * @var string + */ + public $buyerUserName; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/AlipayTradePrecreateResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/AlipayTradePrecreateResponse.php new file mode 100644 index 0000000..51db6be --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/AlipayTradePrecreateResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'outTradeNo' => 'out_trade_no', + 'qrCode' => 'qr_code', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('outTradeNo', $this->outTradeNo, true); + Model::validateRequired('qrCode', $this->qrCode, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->outTradeNo) { + $res['out_trade_no'] = $this->outTradeNo; + } + if (null !== $this->qrCode) { + $res['qr_code'] = $this->qrCode; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradePrecreateResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['out_trade_no'])){ + $model->outTradeNo = $map['out_trade_no']; + } + if(isset($map['qr_code'])){ + $model->qrCode = $map['qr_code']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $outTradeNo; + + /** + * @var string + */ + public $qrCode; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/TradeFundBill.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/TradeFundBill.php new file mode 100644 index 0000000..2da4b81 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/TradeFundBill.php @@ -0,0 +1,77 @@ + 'fund_channel', + 'bankCode' => 'bank_code', + 'amount' => 'amount', + 'realAmount' => 'real_amount', + ]; + public function validate() { + Model::validateRequired('fundChannel', $this->fundChannel, true); + Model::validateRequired('bankCode', $this->bankCode, true); + Model::validateRequired('amount', $this->amount, true); + Model::validateRequired('realAmount', $this->realAmount, true); + } + public function toMap() { + $res = []; + if (null !== $this->fundChannel) { + $res['fund_channel'] = $this->fundChannel; + } + if (null !== $this->bankCode) { + $res['bank_code'] = $this->bankCode; + } + if (null !== $this->amount) { + $res['amount'] = $this->amount; + } + if (null !== $this->realAmount) { + $res['real_amount'] = $this->realAmount; + } + return $res; + } + /** + * @param array $map + * @return TradeFundBill + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['fund_channel'])){ + $model->fundChannel = $map['fund_channel']; + } + if(isset($map['bank_code'])){ + $model->bankCode = $map['bank_code']; + } + if(isset($map['amount'])){ + $model->amount = $map['amount']; + } + if(isset($map['real_amount'])){ + $model->realAmount = $map['real_amount']; + } + return $model; + } + /** + * @var string + */ + public $fundChannel; + + /** + * @var string + */ + public $bankCode; + + /** + * @var string + */ + public $amount; + + /** + * @var string + */ + public $realAmount; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/VoucherDetail.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/VoucherDetail.php new file mode 100644 index 0000000..3789398 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/FaceToFace/Models/VoucherDetail.php @@ -0,0 +1,168 @@ + 'id', + 'name' => 'name', + 'type' => 'type', + 'amount' => 'amount', + 'merchantContribute' => 'merchant_contribute', + 'otherContribute' => 'other_contribute', + 'memo' => 'memo', + 'templateId' => 'template_id', + 'purchaseBuyerContribute' => 'purchase_buyer_contribute', + 'purchaseMerchantContribute' => 'purchase_merchant_contribute', + 'purchaseAntContribute' => 'purchase_ant_contribute', + ]; + public function validate() { + Model::validateRequired('id', $this->id, true); + Model::validateRequired('name', $this->name, true); + Model::validateRequired('type', $this->type, true); + Model::validateRequired('amount', $this->amount, true); + Model::validateRequired('merchantContribute', $this->merchantContribute, true); + Model::validateRequired('otherContribute', $this->otherContribute, true); + Model::validateRequired('memo', $this->memo, true); + Model::validateRequired('templateId', $this->templateId, true); + Model::validateRequired('purchaseBuyerContribute', $this->purchaseBuyerContribute, true); + Model::validateRequired('purchaseMerchantContribute', $this->purchaseMerchantContribute, true); + Model::validateRequired('purchaseAntContribute', $this->purchaseAntContribute, true); + } + public function toMap() { + $res = []; + if (null !== $this->id) { + $res['id'] = $this->id; + } + if (null !== $this->name) { + $res['name'] = $this->name; + } + if (null !== $this->type) { + $res['type'] = $this->type; + } + if (null !== $this->amount) { + $res['amount'] = $this->amount; + } + if (null !== $this->merchantContribute) { + $res['merchant_contribute'] = $this->merchantContribute; + } + if (null !== $this->otherContribute) { + $res['other_contribute'] = $this->otherContribute; + } + if (null !== $this->memo) { + $res['memo'] = $this->memo; + } + if (null !== $this->templateId) { + $res['template_id'] = $this->templateId; + } + if (null !== $this->purchaseBuyerContribute) { + $res['purchase_buyer_contribute'] = $this->purchaseBuyerContribute; + } + if (null !== $this->purchaseMerchantContribute) { + $res['purchase_merchant_contribute'] = $this->purchaseMerchantContribute; + } + if (null !== $this->purchaseAntContribute) { + $res['purchase_ant_contribute'] = $this->purchaseAntContribute; + } + return $res; + } + /** + * @param array $map + * @return VoucherDetail + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['id'])){ + $model->id = $map['id']; + } + if(isset($map['name'])){ + $model->name = $map['name']; + } + if(isset($map['type'])){ + $model->type = $map['type']; + } + if(isset($map['amount'])){ + $model->amount = $map['amount']; + } + if(isset($map['merchant_contribute'])){ + $model->merchantContribute = $map['merchant_contribute']; + } + if(isset($map['other_contribute'])){ + $model->otherContribute = $map['other_contribute']; + } + if(isset($map['memo'])){ + $model->memo = $map['memo']; + } + if(isset($map['template_id'])){ + $model->templateId = $map['template_id']; + } + if(isset($map['purchase_buyer_contribute'])){ + $model->purchaseBuyerContribute = $map['purchase_buyer_contribute']; + } + if(isset($map['purchase_merchant_contribute'])){ + $model->purchaseMerchantContribute = $map['purchase_merchant_contribute']; + } + if(isset($map['purchase_ant_contribute'])){ + $model->purchaseAntContribute = $map['purchase_ant_contribute']; + } + return $model; + } + /** + * @var string + */ + public $id; + + /** + * @var string + */ + public $name; + + /** + * @var string + */ + public $type; + + /** + * @var string + */ + public $amount; + + /** + * @var string + */ + public $merchantContribute; + + /** + * @var string + */ + public $otherContribute; + + /** + * @var string + */ + public $memo; + + /** + * @var string + */ + public $templateId; + + /** + * @var string + */ + public $purchaseBuyerContribute; + + /** + * @var string + */ + public $purchaseMerchantContribute; + + /** + * @var string + */ + public $purchaseAntContribute; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Huabei/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Huabei/Client.php new file mode 100644 index 0000000..756e5c0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Huabei/Client.php @@ -0,0 +1,202 @@ +_kernel = $kernel; + } + + /** + * @param string $subject + * @param string $outTradeNo + * @param string $totalAmount + * @param string $buyerId + * @param HuabeiConfig $extendParams + * @return AlipayTradeCreateResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function create($subject, $outTradeNo, $totalAmount, $buyerId, $extendParams){ + $extendParams->validate(); + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.trade.create", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "subject" => $subject, + "out_trade_no" => $outTradeNo, + "total_amount" => $totalAmount, + "buyer_id" => $buyerId, + "extend_params" => $extendParams + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.trade.create"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayTradeCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayTradeCreateResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Huabei/Models/AlipayTradeCreateResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Huabei/Models/AlipayTradeCreateResponse.php new file mode 100644 index 0000000..fae338f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Huabei/Models/AlipayTradeCreateResponse.php @@ -0,0 +1,117 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'outTradeNo' => 'out_trade_no', + 'tradeNo' => 'trade_no', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('outTradeNo', $this->outTradeNo, true); + Model::validateRequired('tradeNo', $this->tradeNo, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->outTradeNo) { + $res['out_trade_no'] = $this->outTradeNo; + } + if (null !== $this->tradeNo) { + $res['trade_no'] = $this->tradeNo; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradeCreateResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['out_trade_no'])){ + $model->outTradeNo = $map['out_trade_no']; + } + if(isset($map['trade_no'])){ + $model->tradeNo = $map['trade_no']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $outTradeNo; + + /** + * @var string + */ + public $tradeNo; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Huabei/Models/HuabeiConfig.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Huabei/Models/HuabeiConfig.php new file mode 100644 index 0000000..67f2818 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Huabei/Models/HuabeiConfig.php @@ -0,0 +1,51 @@ + 'hb_fq_num', + 'hbFqSellerPercent' => 'hb_fq_seller_percent', + ]; + public function validate() { + Model::validateRequired('hbFqNum', $this->hbFqNum, true); + Model::validateRequired('hbFqSellerPercent', $this->hbFqSellerPercent, true); + } + public function toMap() { + $res = []; + if (null !== $this->hbFqNum) { + $res['hb_fq_num'] = $this->hbFqNum; + } + if (null !== $this->hbFqSellerPercent) { + $res['hb_fq_seller_percent'] = $this->hbFqSellerPercent; + } + return $res; + } + /** + * @param array $map + * @return HuabeiConfig + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['hb_fq_num'])){ + $model->hbFqNum = $map['hb_fq_num']; + } + if(isset($map['hb_fq_seller_percent'])){ + $model->hbFqSellerPercent = $map['hb_fq_seller_percent']; + } + return $model; + } + /** + * @var string + */ + public $hbFqNum; + + /** + * @var string + */ + public $hbFqSellerPercent; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Page/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Page/Client.php new file mode 100644 index 0000000..335a781 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Page/Client.php @@ -0,0 +1,133 @@ +_kernel = $kernel; + } + + /** + * @param string $subject + * @param string $outTradeNo + * @param string $totalAmount + * @param string $returnUrl + * @return AlipayTradePagePayResponse + */ + public function pay($subject, $outTradeNo, $totalAmount, $returnUrl){ + $systemParams = [ + "method" => "alipay.trade.page.pay", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "subject" => $subject, + "out_trade_no" => $outTradeNo, + "total_amount" => $totalAmount, + "product_code" => "FAST_INSTANT_TRADE_PAY" + ]; + $textParams = [ + "return_url" => $returnUrl + ]; + $sign = $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")); + $response = [ + "body" => $this->_kernel->generatePage("POST", $systemParams, $bizParams, $textParams, $sign) + ]; + return AlipayTradePagePayResponse::fromMap($response); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Page/Models/AlipayTradePagePayResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Page/Models/AlipayTradePagePayResponse.php new file mode 100644 index 0000000..5fb93ae --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Page/Models/AlipayTradePagePayResponse.php @@ -0,0 +1,39 @@ + 'body', + ]; + public function validate() { + Model::validateRequired('body', $this->body, true); + } + public function toMap() { + $res = []; + if (null !== $this->body) { + $res['body'] = $this->body; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradePagePayResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['body'])){ + $model->body = $map['body']; + } + return $model; + } + /** + * @description 订单信息,Form表单形式 + * @var string + */ + public $body; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Wap/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Wap/Client.php new file mode 100644 index 0000000..f2ee732 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Wap/Client.php @@ -0,0 +1,135 @@ +_kernel = $kernel; + } + + /** + * @param string $subject + * @param string $outTradeNo + * @param string $totalAmount + * @param string $quitUrl + * @param string $returnUrl + * @return AlipayTradeWapPayResponse + */ + public function pay($subject, $outTradeNo, $totalAmount, $quitUrl, $returnUrl){ + $systemParams = [ + "method" => "alipay.trade.wap.pay", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "subject" => $subject, + "out_trade_no" => $outTradeNo, + "total_amount" => $totalAmount, + "quit_url" => $quitUrl, + "product_code" => "QUICK_WAP_WAY" + ]; + $textParams = [ + "return_url" => $returnUrl + ]; + $sign = $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")); + $response = [ + "body" => $this->_kernel->generatePage("POST", $systemParams, $bizParams, $textParams, $sign) + ]; + return AlipayTradeWapPayResponse::fromMap($response); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Payment/Wap/Models/AlipayTradeWapPayResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Wap/Models/AlipayTradeWapPayResponse.php new file mode 100644 index 0000000..1b577d9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Payment/Wap/Models/AlipayTradeWapPayResponse.php @@ -0,0 +1,39 @@ + 'body', + ]; + public function validate() { + Model::validateRequired('body', $this->body, true); + } + public function toMap() { + $res = []; + if (null !== $this->body) { + $res['body'] = $this->body; + } + return $res; + } + /** + * @param array $map + * @return AlipayTradeWapPayResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['body'])){ + $model->body = $map['body']; + } + return $model; + } + /** + * @description 订单信息,Form表单形式 + * @var string + */ + public $body; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Security/TextRisk/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Security/TextRisk/Client.php new file mode 100644 index 0000000..85ea51b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Security/TextRisk/Client.php @@ -0,0 +1,192 @@ +_kernel = $kernel; + } + + /** + * @param string $content + * @return AlipaySecurityRiskContentDetectResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function detect($content){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => "alipay.security.risk.content.detect", + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $bizParams = [ + "content" => $content + ]; + $textParams = []; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, "alipay.security.risk.content.detect"); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipaySecurityRiskContentDetectResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipaySecurityRiskContentDetectResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Security/TextRisk/Models/AlipaySecurityRiskContentDetectResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Security/TextRisk/Models/AlipaySecurityRiskContentDetectResponse.php new file mode 100644 index 0000000..6ffdff6 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Security/TextRisk/Models/AlipaySecurityRiskContentDetectResponse.php @@ -0,0 +1,132 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + 'action' => 'action', + 'keywords' => 'keywords', + 'uniqueId' => 'unique_id', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + Model::validateRequired('action', $this->action, true); + Model::validateRequired('keywords', $this->keywords, true); + Model::validateRequired('uniqueId', $this->uniqueId, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + if (null !== $this->action) { + $res['action'] = $this->action; + } + if (null !== $this->keywords) { + $res['keywords'] = $this->keywords; + } + if (null !== $this->uniqueId) { + $res['unique_id'] = $this->uniqueId; + } + return $res; + } + /** + * @param array $map + * @return AlipaySecurityRiskContentDetectResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + if(isset($map['action'])){ + $model->action = $map['action']; + } + if(isset($map['keywords'])){ + if(!empty($map['keywords'])){ + $model->keywords = $map['keywords']; + } + } + if(isset($map['unique_id'])){ + $model->uniqueId = $map['unique_id']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + + /** + * @var string + */ + public $action; + + /** + * @var string[] + */ + public $keywords; + + /** + * @var string + */ + public $uniqueId; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Util/AES/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Util/AES/Client.php new file mode 100644 index 0000000..c088121 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Util/AES/Client.php @@ -0,0 +1,111 @@ +_kernel = $kernel; + } + + /** + * @param string $cipherText + * @return string + */ + public function decrypt($cipherText){ + return $this->_kernel->aesDecrypt($cipherText, $this->_kernel->getConfig("encryptKey")); + } + + /** + * @param string $plainText + * @return string + */ + public function encrypt($plainText){ + return $this->_kernel->aesEncrypt($plainText, $this->_kernel->getConfig("encryptKey")); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Util/Generic/Client.php b/serve/vendor/alipaysdk/easysdk/php/src/Util/Generic/Client.php new file mode 100644 index 0000000..e2b152b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Util/Generic/Client.php @@ -0,0 +1,309 @@ +_kernel = $kernel; + } + + /** + * @param string $method + * @param string[] $textParams + * @param mixed[] $bizParams + * @return AlipayOpenApiGenericResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function execute($method, $textParams, $bizParams){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 15000, + "readTimeout" => 15000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => $method, + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => "application/x-www-form-urlencoded;charset=utf-8" + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toUrlEncodedRequestBody($bizParams); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, $method); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenApiGenericResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenApiGenericResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $method + * @param string[] $textParams + * @param mixed[] $bizParams + * @param string[] $fileParams + * @return AlipayOpenApiGenericResponse + * @throws TeaError + * @throws Exception + * @throws TeaUnableRetryError + */ + public function fileExecute($method, $textParams, $bizParams, $fileParams){ + $_runtime = [ + "ignoreSSL" => $this->_kernel->getConfig("ignoreSSL"), + "httpProxy" => $this->_kernel->getConfig("httpProxy"), + "connectTimeout" => 100000, + "readTimeout" => 100000, + "retry" => [ + "maxAttempts" => 0 + ] + ]; + $_lastRequest = null; + $_lastException = null; + $_now = time(); + $_retryTimes = 0; + while (Tea::allowRetry(@$_runtime["retry"], $_retryTimes, $_now)) { + if ($_retryTimes > 0) { + $_backoffTime = Tea::getBackoffTime(@$_runtime["backoff"], $_retryTimes); + if ($_backoffTime > 0) { + Tea::sleep($_backoffTime); + } + } + $_retryTimes = $_retryTimes + 1; + try { + $_request = new Request(); + $systemParams = [ + "method" => $method, + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $boundary = $this->_kernel->getRandomBoundary(); + $_request->protocol = $this->_kernel->getConfig("protocol"); + $_request->method = "POST"; + $_request->pathname = "/gateway.do"; + $_request->headers = [ + "host" => $this->_kernel->getConfig("gatewayHost"), + "content-type" => $this->_kernel->concatStr("multipart/form-data;charset=utf-8;boundary=", $boundary) + ]; + $_request->query = $this->_kernel->sortMap(Tea::merge([ + "sign" => $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")) + ], $systemParams, $textParams)); + $_request->body = $this->_kernel->toMultipartRequestBody($textParams, $fileParams, $boundary); + $_lastRequest = $_request; + $_response= Tea::send($_request, $_runtime); + $respMap = $this->_kernel->readAsJson($_response, $method); + if ($this->_kernel->isCertMode()) { + if ($this->_kernel->verify($respMap, $this->_kernel->extractAlipayPublicKey($this->_kernel->getAlipayCertSN($respMap)))) { + return AlipayOpenApiGenericResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + else { + if ($this->_kernel->verify($respMap, $this->_kernel->getConfig("alipayPublicKey"))) { + return AlipayOpenApiGenericResponse::fromMap($this->_kernel->toRespModel($respMap)); + } + } + throw new TeaError([ + "message" => "验签失败,请检查支付宝公钥设置是否正确。" + ]); + } + catch (Exception $e) { + if (!($e instanceof TeaError)) { + $e = new TeaError([], $e->getMessage(), $e->getCode(), $e); + } + if (Tea::isRetryable($e)) { + $_lastException = $e; + continue; + } + throw $e; + } + } + throw new TeaUnableRetryError($_lastRequest, $_lastException); + } + + /** + * @param string $method + * @param string[] $textParams + * @param mixed[] $bizParams + * @return AlipayOpenApiGenericSDKResponse + */ + public function sdkExecute($method, $textParams, $bizParams){ + $_request = new Request(); + $systemParams = [ + "method" => $method, + "app_id" => $this->_kernel->getConfig("appId"), + "timestamp" => $this->_kernel->getTimestamp(), + "format" => "json", + "version" => "1.0", + "alipay_sdk" => $this->_kernel->getSdkVersion(), + "charset" => "UTF-8", + "sign_type" => $this->_kernel->getConfig("signType"), + "app_cert_sn" => $this->_kernel->getMerchantCertSN(), + "alipay_root_cert_sn" => $this->_kernel->getAlipayRootCertSN() + ]; + $sign = $this->_kernel->sign($systemParams, $bizParams, $textParams, $this->_kernel->getConfig("merchantPrivateKey")); + $response = [ + "body" => $this->_kernel->generateOrderString($systemParams, $bizParams, $textParams, $sign) + ]; + return AlipayOpenApiGenericSDKResponse::fromMap($response); + $_lastRequest = $_request; + $_response= Tea::send($_request); + } + + /** + * ISV代商户代用,指定appAuthToken + * + * @param $appAuthToken String 代调用token + * @return $this 本客户端,便于链式调用 + */ + public function agent($appAuthToken) + { + $this->_kernel->injectTextParam("app_auth_token", $appAuthToken); + return $this; + } + + /** + * 用户授权调用,指定authToken + * + * @param $authToken String 用户授权token + * @return $this + */ + public function auth($authToken) + { + $this->_kernel->injectTextParam("auth_token", $authToken); + return $this; + } + + /** + * 设置异步通知回调地址,此处设置将在本调用中覆盖Config中的全局配置 + * + * @param $url String 异步通知回调地址,例如:https://www.test.com/callback + * @return $this + */ + public function asyncNotify($url) + { + $this->_kernel->injectTextParam("notify_url", $url); + return $this; + } + + /** + * 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效 + * + * @param $testUrl String 后端系统测试地址 + * @return $this + */ + public function route($testUrl) + { + $this->_kernel->injectTextParam("ws_service_url", $testUrl); + return $this; + } + + /** + * 设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * + * @param $key String 业务请求参数名称(biz_content下的字段名,比如timeout_express) + * @param $value object 业务请求参数的值,一个可以序列化成JSON的对象 + * 如果该字段是一个字符串类型(String、Price、Date在SDK中都是字符串),请使用String储存 + * 如果该字段是一个数值型类型(比如:Number),请使用Long储存 + * 如果该字段是一个复杂类型,请使用嵌套的array指定各下级字段的值 + * 如果该字段是一个数组,请使用array储存各个值 + * @return $this + */ + public function optional($key, $value) + { + $this->_kernel->injectBizParam($key, $value); + return $this; + } + + /** + * 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段) + * optional方法的批量版本 + * + * @param $optionalArgs array 可选参数集合,每个参数由key和value组成,key和value的格式请参见optional方法的注释 + * @return $this + */ + public function batchOptional($optionalArgs) + { + foreach ($optionalArgs as $key => $value) { + $this->_kernel->injectBizParam($key, $value); + } + return $this; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Util/Generic/Models/AlipayOpenApiGenericResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Util/Generic/Models/AlipayOpenApiGenericResponse.php new file mode 100644 index 0000000..825fd05 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Util/Generic/Models/AlipayOpenApiGenericResponse.php @@ -0,0 +1,91 @@ + 'http_body', + 'code' => 'code', + 'msg' => 'msg', + 'subCode' => 'sub_code', + 'subMsg' => 'sub_msg', + ]; + public function validate() { + Model::validateRequired('httpBody', $this->httpBody, true); + Model::validateRequired('code', $this->code, true); + Model::validateRequired('msg', $this->msg, true); + Model::validateRequired('subCode', $this->subCode, true); + Model::validateRequired('subMsg', $this->subMsg, true); + } + public function toMap() { + $res = []; + if (null !== $this->httpBody) { + $res['http_body'] = $this->httpBody; + } + if (null !== $this->code) { + $res['code'] = $this->code; + } + if (null !== $this->msg) { + $res['msg'] = $this->msg; + } + if (null !== $this->subCode) { + $res['sub_code'] = $this->subCode; + } + if (null !== $this->subMsg) { + $res['sub_msg'] = $this->subMsg; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenApiGenericResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['http_body'])){ + $model->httpBody = $map['http_body']; + } + if(isset($map['code'])){ + $model->code = $map['code']; + } + if(isset($map['msg'])){ + $model->msg = $map['msg']; + } + if(isset($map['sub_code'])){ + $model->subCode = $map['sub_code']; + } + if(isset($map['sub_msg'])){ + $model->subMsg = $map['sub_msg']; + } + return $model; + } + /** + * @description 响应原始字符串 + * @var string + */ + public $httpBody; + + /** + * @var string + */ + public $code; + + /** + * @var string + */ + public $msg; + + /** + * @var string + */ + public $subCode; + + /** + * @var string + */ + public $subMsg; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/src/Util/Generic/Models/AlipayOpenApiGenericSDKResponse.php b/serve/vendor/alipaysdk/easysdk/php/src/Util/Generic/Models/AlipayOpenApiGenericSDKResponse.php new file mode 100644 index 0000000..d4f9484 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/src/Util/Generic/Models/AlipayOpenApiGenericSDKResponse.php @@ -0,0 +1,39 @@ + 'body', + ]; + public function validate() { + Model::validateRequired('body', $this->body, true); + } + public function toMap() { + $res = []; + if (null !== $this->body) { + $res['body'] = $this->body; + } + return $res; + } + /** + * @param array $map + * @return AlipayOpenApiGenericSDKResponse + */ + public static function fromMap($map = []) { + $model = new self(); + if(isset($map['body'])){ + $model->body = $map['body']; + } + return $model; + } + /** + * @description 订单信息,字符串形式 + * @var string + */ + public $body; + +} diff --git a/serve/vendor/alipaysdk/easysdk/php/test/TestAccount.php b/serve/vendor/alipaysdk/easysdk/php/test/TestAccount.php new file mode 100644 index 0000000..abd2fec --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/TestAccount.php @@ -0,0 +1,45 @@ +protocol = 'https'; + $options->gatewayHost = 'openapi.alipay.com'; + $options->appId = '<-- 请填写您的AppId,例如:2019022663440152 -->'; + $options->signType = 'RSA2'; + $options->alipayPublicKey = '<-- 请填写您的支付宝公钥,例如:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumX1EaLM4ddn1Pia4SxTRb62aVYxU8I2mHMqrcpQU6F01mIO/DjY7R4xUWcLi0I2oH/BK/WhckEDCFsGrT7mO+JX8K4sfaWZx1aDGs0m25wOCNjp+DCVBXotXSCurqgGI/9UrY+QydYDnsl4jB65M3p8VilF93MfS01omEDjUW+1MM4o3FP0khmcKsoHnYGs21btEeh0LK1gnnTDlou6Jwv3Ew36CbCNY2cYkuyPAW0j47XqzhWJ7awAx60fwgNBq6ZOEPJnODqH20TAdTLNxPSl4qGxamjBO+RuInBy+Bc2hFHq3pNv6hTAfktggRKkKzDlDEUwgSLE7d2eL7P6rwIDAQAB -->'; + $options->merchantPrivateKey = $this->getPrivateKey($options->appId); + return $options; + } + + public function getTestCertAccount() + { + $options = new Config(); + $options->protocol = 'https'; + $options->gatewayHost = 'openapi.alipay.com'; + $options->appId = '<-- 请填写您的AppId,例如:2019051064521003 -->'; + $options->signType = 'RSA2'; + $options->alipayCertPath = '<-- 请填写您的支付宝公钥证书文件路径,例如:dirname(__FILE__) . "/resources/fixture/alipayCertPublicKey_RSA2.crt" -->'; + $options->alipayRootCertPath = '<-- 请填写您的支付宝根证书文件路径,例如:dirname(__FILE__) . "/resources/fixture/alipayRootCert.crt" -->'; + $options->merchantCertPath = '<-- 请填写您的应用公钥证书文件路径,例如:dirname(__FILE__) . "/resources/fixture/appCertPublicKey_2019051064521003.crt" -->'; + $options->merchantPrivateKey = $this->getPrivateKey($options->appId); + return $options; + } + + private function getPrivateKey($appId) + { + $filePath = dirname(__FILE__) . '/resources/fixture/privateKey.json'; + $stream = fopen($filePath, 'r'); + fwrite($stream, '$filePath'); + $result = json_decode(stream_get_contents($stream)); + return $result->$appId; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/base/image/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/base/image/ClientTest.php new file mode 100644 index 0000000..149a4e2 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/base/image/ClientTest.php @@ -0,0 +1,23 @@ +getTestAccount()); + $filePath = $account->getResourcesPath(). '/resources/fixture/sample.png'; + $result = Factory::base()->image()->upload("测试图片", $filePath); + $this->assertEquals(true, $responseChecker->success($result)); + $this->assertEquals('Success', $result->msg); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/base/oauth/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/base/oauth/ClientTest.php new file mode 100644 index 0000000..565334b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/base/oauth/ClientTest.php @@ -0,0 +1,37 @@ +getTestAccount()); + } + + public function testGetTokenWhenGrantTypeIsAuthorizationCode() + { + $result = Factory::base()->oauth()->getToken('ee4b3c871f7c4f30a82251908458VB64'); + $this->assertEquals('40002', $result->code); + $this->assertEquals('Invalid Arguments', $result->msg); + $this->assertEquals('isv.code-invalid', $result->subCode); + $this->assertEquals('授权码code无效', $result->subMsg); + } + + public function testGetTokenWhenGrantTypeIsRefreshToken() + { + $result = Factory::base()->oauth()->refreshToken('1234567890'); + $this->assertEquals('40002', $result->code); + $this->assertEquals('Invalid Arguments', $result->msg); + $this->assertEquals('isv.refresh-token-invalid', $result->subCode); + $this->assertEquals('刷新令牌refresh_token无效', $result->subMsg); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/base/qrcode/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/base/qrcode/ClientTest.php new file mode 100644 index 0000000..f8c75bb --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/base/qrcode/ClientTest.php @@ -0,0 +1,20 @@ +getTestAccount()); + $result = Factory::base()->qrcode()->create('https://opendocs.alipay.com','ageIndex=1','文档站点'); + $this->assertEquals(true, $responseChecker->success($result)); + $this->assertEquals('Success', $result->msg); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/base/video/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/base/video/ClientTest.php new file mode 100644 index 0000000..be9b189 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/base/video/ClientTest.php @@ -0,0 +1,24 @@ +getTestAccount()); + $filePath = $account->getResourcesPath() . '/resources/fixture/sample.mp4'; + $result = Factory::base()->video()->upload("测试视频", $filePath); + $this->assertEquals(true, $responseChecker->success($result)); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/marketing/openlife/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/marketing/openlife/ClientTest.php new file mode 100644 index 0000000..3b96d46 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/marketing/openlife/ClientTest.php @@ -0,0 +1,145 @@ +getTestCertAccount()); + } + + public function testCreateImageTextContent() + { + $result = Factory::marketing()->openLife()->createImageTextContent("标题", + "http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED", + "示例", "T", "activity", "满100减10", + "关键,热度", "13434343432,xxx@163.com"); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testModifyImageTextContent() + { + $result = Factory::marketing()->openLife()->modifyImageTextContent( + "20190510645210035577f788-d6cd-4020-9dba-1a195edb7342", "新标题", + "http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED", + "新示例", "T", "activity", "满100减20", + "关键,热度", "13434343432,xxx@163.com"); + if ($result->code == '10000') { + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } else { + $this->assertEquals('40004', $result->code); + $this->assertEquals('Business Failed', $result->msg); + $this->assertEquals('PUB.MSG_BATCH_SD_OVER', $result->subCode); + $this->assertEquals('批量发送消息频率超限', $result->subMsg); + } + + } + + public function testSendText() + { + $result = Factory::marketing()->openLife()->sendText("测试"); + if ($result->code == '10000') { + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } else { + $this->assertEquals('40004', $result->code); + $this->assertEquals('Business Failed', $result->msg); + $this->assertEquals('PUB.MSG_BATCH_SD_OVER', $result->subCode); + $this->assertEquals('批量发送消息频率超限', $result->subMsg); + } + } + + public function testSendImageText() + { + $article = new Article(); + $article->actionName = '测试'; + $article->desc = '测试'; + $article->title = '测试'; + $article->imageUrl = 'http://dl.django.t.taobao.com/rest/1.0/image?fileIds=hOTQ1lT1TtOjcxGflvnUXgAAACMAAQED'; + $article->url = 'https://docs.open.alipay.com/api_6/alipay.open.public.message.total.send'; + $result = Factory::marketing()->openLife()->sendImageText((array)$article); + if ($result->code == '10000') { + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } else { + $this->assertEquals('40004', $result->code); + $this->assertEquals('Business Failed', $result->msg); + $this->assertEquals('PUB.MSG_BATCH_SD_OVER', $result->subCode); + $this->assertEquals('批量发送消息频率超限', $result->subMsg); + } + } + + public function testSendSingleMessage() + { + $keyword = new Keyword(); + $keyword->color = "#85be53"; + $keyword->value = "HU7142"; + + $context = new Context(); + $context->headColor = "#85be53"; + $context->url = "https://docs.open.alipay.com/api_6/alipay.open.public.message.single.send"; + $context->actionName = "查看详情"; + $context->keyword1 = $keyword; + $context->keyword2 = $keyword; + $context->first = $keyword; + $context->remark = $keyword; + + $template = new Template(); + $template->templateId = "e44cd3e52ffa46b1a50afc145f55d1ea"; + $template->context = $context; + + $result = Factory::marketing()->openLife()->sendSingleMessage("2088002656718920", $template); + + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testRecallMessage() + { + $result = Factory::marketing()->openLife()->recallMessage("201905106452100327f456f6-8dd2-4a06-8b0e-ec8a3a85c46a"); + + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testSetIndustry() + { + $result = Factory::marketing()->openLife()->setIndustry( + "10001/20102", "IT科技/IT软件与服务", + "10001/20102", "IT科技/IT软件与服务"); + + if ($result->code == '10000') { + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } else { + $this->assertEquals('40004', $result->code); + $this->assertEquals('Business Failed', $result->msg); + $this->assertEquals('3002', $result->subCode); + $this->assertEquals('模板消息行业一月只能修改一次', $result->subMsg); + } + } + + public function testGetIndustry() + { + $result = Factory::marketing()->openLife()->getIndustry(); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + $this->assertEquals('IT科技/IT软件与服务', $result->primaryCategory); + $this->assertEquals('IT科技/IT软件与服务', $result->secondaryCategory); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/marketing/pass/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/marketing/pass/ClientTest.php new file mode 100644 index 0000000..729991f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/marketing/pass/ClientTest.php @@ -0,0 +1,102 @@ +getTestAccount()); + } + + public function testCreateTemplate() + { + $result = Factory::marketing()->pass()->createTemplate("1234567890", $this->getTplContent()); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testUpdateTemplate() + { + $result = Factory::marketing()->pass()->updateTemplate("2020012014534017917956080", $this->getTplContent()); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testAddInstance() + { + $result = Factory::marketing()->pass()->addInstance("2020012014534017917956080", "{}", + "1", "{\"partner_id\":\"2088102114633762\",\"out_trade_no\":\"1234567\"}"); + $this->assertEquals('40004', $result->code); + $this->assertEquals('Business Failed', $result->msg); + $this->assertEquals('KP.AE_ALIPASS_APPID_NOSUPPORT', $result->subCode); + $this->assertEquals('该AppId不支持', $result->subMsg); + } + + public function testUpdateInstance() + { + $result = Factory::marketing()->pass()->updateInstance("209919213", + "2088918273", "{}", "USED", "8612231273", "wave"); + $this->assertEquals('40004', $result->code); + $this->assertEquals('Business Failed', $result->msg); + $this->assertEquals('KP.AE_ALIPASS_NOTEXIST', $result->subCode); + $this->assertEquals('卡券不存在', $result->subMsg); + } + + private function getTplContent() + { + return '{"logo": "http://img01.taobaocdn.com/top/i1/LB1NDJuQpXXXXbYXFXXXXXXXXXX","strip": null,"icon": null,"content": { + "evoucherInfo": { + "goodsId": "", + "title": "test", + "type": "boardingPass", + "product": "air", + "startDate": "2020-01-20 13:45:56", + "endDate": "2020-01-25 13:45:56", + "operation": [{ + "message": { + "img": "http://img01.taobaocdn.com/top/i1/LB1NDJuQpXXXXbYXFXXXXXXXXXX", + "target": "" + }, + "format": "img", + "messageEncoding": "utf-8", + "altText": "" + }], + "einfo": { + "logoText": "test", + "headFields": [{"key": "test","label": "测试","value": "","type": "text"}], + "primaryFields": [{"key": "from","label": "测试","value": "","type": "text"},{"key": "to","label": "测试","value": "","type": "text"}], + "secondaryFields": [{"key": "fltNo","label": "航班号","value": "CA123","type": "text"}], + "auxiliaryFields": [{"key": "test","label": "测试","value": "","type": "text"}], + "backFields": [] + }, + "locations": [] + }, + "merchant": {"mname": "君泓","mtel": "","minfo": ""}, + "platform": { + "channelID": "2088201564809153", + "webServiceUrl": "https://alipass.alipay.com/builder/syncRecord.htm?tempId=2020012013442621326446216" + }, + "style": {"backgroundColor": "RGB(26,150,219)"}, + "fileInfo": { + "formatVersion": "2", + "canShare": true, + "canBuy": false, + "canPresent": true, + "serialNumber": "2020012013520759738677158", + "supportTaxi": "true", + "taxiSchemaUrl": "" + }, + "appInfo": {"app": {"android_appid": "","ios_appid": "","android_launch": "","ios_launch": "","android_download": "","ios_download": ""},"label": "测试","message": ""}, + "source": "alipassprod", + "alipayVerify": ["qrcode"]}}'; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/marketing/templatemessage/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/marketing/templatemessage/ClientTest.php new file mode 100644 index 0000000..77abaa7 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/marketing/templatemessage/ClientTest.php @@ -0,0 +1,27 @@ +getTestAccount()); + $result = Factory::marketing()->templateMessage()->send("2088102122458832", + "2017010100000000580012345678", + "MDI4YzIxMDE2M2I5YTQzYjUxNWE4MjA4NmU1MTIyYmM=", + "page/component/index", + "{\"keyword1\": {\"value\" : \"12:00\"},\"keyword2\": {\"value\" : \"20180808\"},\"keyword3\": {\"value\" : \"支付宝\"}}"); + $this->assertEquals('40004',$result->code); + $this->assertEquals('Business Failed',$result->msg); + $this->assertEquals('USER_TEMPLATE_ILLEGAL',$result->subCode); + $this->assertEquals('模板非法',$result->subMsg); + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/member/identification/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/member/identification/ClientTest.php new file mode 100644 index 0000000..6c0bd03 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/member/identification/ClientTest.php @@ -0,0 +1,55 @@ +getTestAccount()); + } + + public function testInit() + { + $identityParam = new IdentityParam(); + $identityParam->identityType = "CERT_INFO"; + $identityParam->certType = "IDENTITY_CARD"; + $identityParam->certName = "张三"; + $identityParam->certNo = "5139011988090987631"; + + $merchantConfig = new MerchantConfig(); + $merchantConfig->returnUrl = "www.taobao.com"; + + $result = Factory::member()->identification()->init(microtime(),'FACE',$identityParam,$merchantConfig); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testCertify() + { + $result = Factory::member()->identification()->certify("16cbbf40de9829e337d51818a76eacc2"); + $this->assertEquals(true, strpos($result->body,'sign')>0); + $this->assertEquals(true, strpos($result->body,'gateway.do')>0); + } + + public function testQuery() + { + $result = Factory::member()->identification()->query("16cbbf40de9829e337d51818a76eacc2"); + $this->assertEquals('40004', $result->code); + $this->assertEquals('Business Failed', $result->msg); + $this->assertEquals('CERTIFY_ID_EXPIRED',$result->subCode); + $this->assertEquals('认证已失效',$result->subMsg); + + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/multipleFactory/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/multipleFactory/ClientTest.php new file mode 100644 index 0000000..7b39655 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/multipleFactory/ClientTest.php @@ -0,0 +1,35 @@ + "Iphone6 16G", + "out_trade_no" => "f4833085-0c46-4bb0-8e5f-622a02a4cffc", + "total_amount" => "0.10" + ); + $textParams = array(); + + $account = new TestAccount(); + MultipleFactory::setOptions($account->getTestAccount()); + $result = MultipleFactory::util()->generic()->sdkExecute("alipay.trade.app.pay", $textParams, $bizParams); + $this->assertEquals(true, strpos($result->body, 'alipay_sdk=alipay-easysdk-php') > 0); + $this->assertEquals(true, strpos($result->body, 'app_id=2019022663440152') > 0); + + MultipleFactory::setOptions($account->getTestCertAccount()); + $result2 = MultipleFactory::util()->generic()->sdkExecute("alipay.trade.app.pay", $textParams, $bizParams); + $this->assertEquals(true, strpos($result2->body, 'alipay_sdk=alipay-easysdk-php') > 0); + $this->assertEquals(true, strpos($result2->body, 'app_id=2019051064521003') > 0); + + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/payment/app/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/payment/app/ClientTest.php new file mode 100644 index 0000000..93f7083 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/payment/app/ClientTest.php @@ -0,0 +1,39 @@ +getTestAccount()); + } + + public function testPay() + { + $result = Factory::payment()->app()->pay("Iphone6 16G", "f4833085-0c46-4bb0-8e5f-622a02a4cffc", "0.10"); + $this->assertEquals(true, strpos($result->body, 'alipay_sdk=alipay-easysdk-php') > 0); + $this->assertEquals(true, strpos($result->body, 'sign') > 0); + } + + public function testPayWithOptional() + { + $result = Factory::payment()->app() + ->agent("ca34ea491e7146cc87d25fca24c4cD11") + ->optional("extend_params",$this->getHuabeiParams()) + ->pay("Iphone6 16G", "f4833085-0c46-4bb0-8e5f-622a02a4cffc", "0.10"); + $this->assertEquals(true, strpos($result->body, 'alipay_sdk=alipay-easysdk-php') > 0); + $this->assertEquals(true, strpos($result->body, 'sign') > 0); + } + + private function getHuabeiParams() + { + $extendParams = array("hb_fq_num" => "3", "hb_fq_seller_percent" => "3"); + return $extendParams; + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/payment/common/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/payment/common/ClientTest.php new file mode 100644 index 0000000..8170275 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/payment/common/ClientTest.php @@ -0,0 +1,93 @@ +getTestAccount()); + } + + public function testCrate() + { + $result = Factory::payment()->common()->create("Iphone6 16G", + microtime(), "88.88", "2088002656718920"); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + return $result->outTradeNo; + } + + public function testCreateWithOptional(){ + $result = Factory::payment()->common() + ->optional("goods_detail", $this->getGoodsDetail()) + ->create("Iphone6 16G",microtime(), "0.01", "2088002656718920"); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + private function getGoodsDetail(){ + $goodDetail = array( + "goods_id" => "apple-01", + "goods_name" => "iPhone6 16G", + "quantity" => 1, + "price" => "0.01" + ); + $goodsDetail[0] = $goodDetail; + return $goodsDetail; + } + + public function testQuery() + { + $result = Factory::payment()->common()->query('6f149ddb-ab8c-4546-81fb-5880b4aaa318'); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testCancel() + { + $result = Factory::payment()->common()->cancel($this->testCrate()); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testClose() + { + $result = Factory::payment()->common()->close($this->testCrate()); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testRefund() + { + $result = Factory::payment()->common()->refund($this->testCrate(), '0.01'); + $this->assertEquals('40004', $result->code); + $this->assertEquals('Business Failed', $result->msg); + $this->assertEquals('ACQ.TRADE_STATUS_ERROR', $result->subCode); + $this->assertEquals('交易状态不合法', $result->subMsg); + } + + public function testRefundQuery() + { + $result = Factory::payment()->common()->queryRefund($this->testCrate(), "20200401010101001"); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testDownloadBill() + { + $result = Factory::payment()->common()->downloadBill("trade", "2020-01"); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/payment/facetoface/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/payment/facetoface/ClientTest.php new file mode 100644 index 0000000..0194204 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/payment/facetoface/ClientTest.php @@ -0,0 +1,42 @@ +getTestAccount()); + } + + public function testPay() + { + $create =Factory::payment()->common()->create("Iphone6 16G", + microtime(), "88.88", "2088002656718920"); + + $result = Factory::payment()->faceToFace()->pay("Iphone6 16G", $create->outTradeNo, "0.10", + "1234567890"); + $this->assertEquals('40004', $result->code); + $this->assertEquals('Business Failed', $result->msg); + $this->assertEquals('ACQ.PAYMENT_AUTH_CODE_INVALID', $result->subCode); + $this->assertEquals('支付失败,获取顾客账户信息失败,请顾客刷新付款码后重新收款,如再次收款失败,请联系管理员处理。[SOUNDWAVE_PARSER_FAIL]', $result->subMsg); + } + + public function testPrecreate(){ + $create =Factory::payment()->common()->create("Iphone6 16G", + microtime(), "88.88", "2088002656718920"); + $result = Factory::payment()->faceToFace()->precreate("Iphone6 16G", $create->outTradeNo, "0.10"); + + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/payment/huabei/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/payment/huabei/ClientTest.php new file mode 100644 index 0000000..eff7253 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/payment/huabei/ClientTest.php @@ -0,0 +1,25 @@ +getTestAccount()); + $config = new HuabeiConfig(); + $config->hbFqNum = '3'; + $config->hbFqSellerPercent = '0'; + $result = Factory::payment()->huabei()->create("Iphone6 16G", microtime(), "0.10", "2088002656718920", $config); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/payment/page/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/payment/page/ClientTest.php new file mode 100644 index 0000000..c871144 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/payment/page/ClientTest.php @@ -0,0 +1,36 @@ +getTestAccount()); + } + + public function testPay() + { + $create = Factory::payment()->common()->create("Iphone6 16G", + microtime(), "88.88", "2088002656718920"); + $result = Factory::payment()->page()->pay("Iphone6 16G", $create->outTradeNo, "0.10", "https://www.taobao.com"); + $this->assertEquals(true, strpos($result->body, 'alipay-easysdk-php-') > 0); + $this->assertEquals(true, strpos($result->body, 'sign') > 0); + } + + public function testPayWithOptionalNotify() + { + $create = Factory::payment()->common()->create("Iphone6 16G", + microtime(), "88.88", "2088002656718920"); + $result = Factory::payment()->page() + ->asyncNotify("https://www.test2.com/newCallback") + ->pay("Iphone6 16G", $create->outTradeNo, "0.10", "https://www.taobao.com"); + $this->assertEquals(true, strpos($result->body, 'alipay-easysdk-php-') > 0); + $this->assertEquals(true, strpos($result->body, 'sign') > 0); + } + +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/payment/wap/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/payment/wap/ClientTest.php new file mode 100644 index 0000000..e66053b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/payment/wap/ClientTest.php @@ -0,0 +1,41 @@ +getTestAccount()); + } + public function testPay(){ + $create =Factory::payment()->common()->create("Iphone6 16G", + microtime(), "88.88", "2088002656718920"); + $result = Factory::payment()->wap()->pay("Iphone6 16G",$create->outTradeNo,"0.10","https://www.taobao.com","https://www.taobao.com"); + $this->assertEquals(true, strpos($result->body,'return_url')>0); + $this->assertEquals(true, strpos($result->body,'sign')>0); + } + + public function testPayWithOptional(){ + $create =Factory::payment()->common()->create("Iphone6 16G", + microtime(), "88.88", "2088002656718920"); + $result = Factory::payment()->wap() + ->agent("ca34ea491e7146cc87d25fca24c4cD11") + ->batchOptional($this->getOptionalArgs()) + ->pay("Iphone6 16G",$create->outTradeNo,"0.10","https://www.taobao.com","https://www.taobao.com"); + $this->assertEquals(true, strpos($result->body,'return_url')>0); + $this->assertEquals(true, strpos($result->body,'sign')>0); + } + + private function getOptionalArgs(){ + $optionalArgs = array( + "timeout_express" => "10m", + "body" => "Iphone6 16G" + ); + return $optionalArgs; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/alipayCertPublicKey_RSA2.crt b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/alipayCertPublicKey_RSA2.crt new file mode 100644 index 0000000..fd7c0a0 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/alipayCertPublicKey_RSA2.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIQIBkJAnXy/rwX3BTZaKNEzjANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MTkwNwYDVQQDDDBBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IENs +YXNzIDIgUjEwHhcNMTkwOTAyMTI0NDIyWhcNMjEwOTAxMTI0NDIyWjB0MQswCQYDVQQGEwJDTjEP +MA0GA1UECgwG6ZKf6ZuoMQ8wDQYDVQQLDAZBbGlwYXkxQzBBBgNVBAMMOuaUr+S7mOWunSjkuK3l +m70p572R57uc5oqA5pyv5pyJ6ZmQ5YWs5Y+4LTIwODgwMDI2NTY3MTg5MjAwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDQxh7MsF7bsPyQlToJWOPlmGfqUerZI2o2725LUqrabGYOaAgx +a8OAm6sFXoq6TykRltIBEmAjYjMYudQelwxSv8NhQ1eLEFrY7o2Z3TQ+y8lvlLmvqWnEMzOqq4Fc +UN6gzd1nissGVtzUkmx9ErB+89g6WAKV1bFCZBQHIjzfMIqcZkddUZ4SiksMKB/ncKFOJPJf2CUI +i31URny3WlIoC44jG1SiX2sPKdbkbsSGQcDfGIpNRQBNJxlXX/8Y8D7RrFCWHtjh4ONSMT29+xjS +8HNM0gSR2y4QKXyRupXrNY9yTTtkPhQIEjfSjsQPnuM+3b7VFd3GSDcDbvskNRNLAgMBAAGjEjAQ +MA4GA1UdDwEB/wQEAwID+DANBgkqhkiG9w0BAQsFAAOCAQEAf8Qx2UsLFqPDTxKk9eT0np75NqJ8 +MexTuPJ/gC+Lp20YzEUyYW2rPlDFhDmFztlqk9RdynLRqyjB5dOAdWlxhgDlEqB9E6DvkVKtpIaL +7h7zqJei9gb/STAyf5vTVWR/WTmOhp3vQhaj7+lt14JwK/ELYMdBLD2IdmFis7YdzhCsGo7Y4FPb +BuHCV8Ngfaf2PvDlKaFOVzDg8tGnMBbAOgpe+mhxKUdhNG3eXcO0Z813rNIC15YAvWm68tNAwuZJ +rIVgK+049WUojwUJxOwVyzewob/8Gx7o8ipIV5E/bMrduSvigsj7OmNzwQ5/iSm31dfcXi3fOXXz +BLMb888PlA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE4jCCAsqgAwIBAgIIYsSr5bKAMl8wDQYJKoZIhvcNAQELBQAwejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMjE0MzQxNVoXDTM3MTEyNjE0MzQxNVowgYIxCzAJBgNVBAYTAkNOMRYwFAYDVQQKDA1BbnQgRmluYW5jaWFsMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE5MDcGA1UEAwwwQW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDbGFzcyAyIFIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsLMfYaoRoPRbmDcAfXPCmKf43pWRN5yTXa/KJWO0l+mrgQvs89bANEvbDUxlkGwycwtwi5DgBuBgVhLliXu+R9CYgr2dXs8D8Hx/gsggDcyGPLmVrDOnL+dyeauheARZfA3du60fwEwwbGcVIpIxPa/4n3IS/ElxQa6DNgqxh8J9Xwh7qMGl0JK9+bALuxf7B541Gr4p0WENG8fhgjBV4w4ut9eQLOoa1eddOUSZcy46Z7allwowwgt7b5VFfx/P1iKJ3LzBMgkCK7GZ2kiLrL7RiqV+h482J7hkJD+ardoc6LnrHO/hIZymDxok+VH9fVeUdQa29IZKrIDVj65THQIDAQABo2MwYTAfBgNVHSMEGDAWgBRfdLQEwE8HWurlsdsio4dBspzhATAdBgNVHQ4EFgQUSqHkYINtUSAtDPnS8XoyoP9p7qEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAIQ8TzFy4bVIVb8+WhHKCkKNPcJe2EZuIcqvRoi727lZTJOfYy/JzLtckyZYfEI8J0lasZ29wkTta1IjSo+a6XdhudU4ONVBrL70U8Kzntplw/6TBNbLFpp7taRALjUgbCOk4EoBMbeCL0GiYYsTS0mw7xdySzmGQku4GTyqutIGPQwKxSj9iSFw1FCZqr4VP4tyXzMUgc52SzagA6i7AyLedd3tbS6lnR5BL+W9Kx9hwT8L7WANAxQzv/jGldeuSLN8bsTxlOYlsdjmIGu/C9OWblPYGpjQQIRyvs4Cc/mNhrh+14EQgwuemIIFDLOgcD+iISoN8CqegelNcJndFw1PDN6LkVoiHz9p7jzsge8RKay/QW6C03KNDpWZEUCgCUdfHfo8xKeR+LL1cfn24HKJmZt8L/aeRZwZ1jwePXFRVtiXELvgJuM/tJDIFj2KD337iV64fWcKQ/ydDVGqfDZAdcU4hQdsrPWENwPTQPfVPq2NNLMyIH9+WKx9Ed6/WzeZmIy5ZWpX1TtTolo6OJXQFeItMAjHxW/ZSZTok5IS3FuRhExturaInnzjYpx50a6kS34c5+c8hYq7sAtZ/CNLZmBnBCFDaMQqT8xFZJ5uolUaSeXxg7JFY1QsYp5RKvj4SjFwCGKJ2+hPPe9UyyltxOidNtxjaknOCeBHytOr +-----END CERTIFICATE----- diff --git a/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/alipayRootCert.crt b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/alipayRootCert.crt new file mode 100644 index 0000000..76417c5 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/alipayRootCert.crt @@ -0,0 +1,88 @@ +-----BEGIN CERTIFICATE----- +MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG +EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw +MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO +UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE +MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT +V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti +W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ +MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b +53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI +pDoiVhsLwg== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIF0zCCA7ugAwIBAgIIH8+hjWpIDREwDQYJKoZIhvcNAQELBQAwejELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMTEzNDg0MFoXDTM4MDIyODEzNDg0 +MFowejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNV +BAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAtytTRcBNuur5h8xuxnlKJetT65cHGemGi8oD+beHFPTk +rUTlFt9Xn7fAVGo6QSsPb9uGLpUFGEdGmbsQ2q9cV4P89qkH04VzIPwT7AywJdt2 +xAvMs+MgHFJzOYfL1QkdOOVO7NwKxH8IvlQgFabWomWk2Ei9WfUyxFjVO1LVh0Bp +dRBeWLMkdudx0tl3+21t1apnReFNQ5nfX29xeSxIhesaMHDZFViO/DXDNW2BcTs6 +vSWKyJ4YIIIzStumD8K1xMsoaZBMDxg4itjWFaKRgNuPiIn4kjDY3kC66Sl/6yTl +YUz8AybbEsICZzssdZh7jcNb1VRfk79lgAprm/Ktl+mgrU1gaMGP1OE25JCbqli1 +Pbw/BpPynyP9+XulE+2mxFwTYhKAwpDIDKuYsFUXuo8t261pCovI1CXFzAQM2w7H +DtA2nOXSW6q0jGDJ5+WauH+K8ZSvA6x4sFo4u0KNCx0ROTBpLif6GTngqo3sj+98 +SZiMNLFMQoQkjkdN5Q5g9N6CFZPVZ6QpO0JcIc7S1le/g9z5iBKnifrKxy0TQjtG +PsDwc8ubPnRm/F82RReCoyNyx63indpgFfhN7+KxUIQ9cOwwTvemmor0A+ZQamRe +9LMuiEfEaWUDK+6O0Gl8lO571uI5onYdN1VIgOmwFbe+D8TcuzVjIZ/zvHrAGUcC +AwEAAaNdMFswCwYDVR0PBAQDAgEGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFF90 +tATATwda6uWx2yKjh0GynOEBMB8GA1UdIwQYMBaAFF90tATATwda6uWx2yKjh0Gy +nOEBMA0GCSqGSIb3DQEBCwUAA4ICAQCVYaOtqOLIpsrEikE5lb+UARNSFJg6tpkf +tJ2U8QF/DejemEHx5IClQu6ajxjtu0Aie4/3UnIXop8nH/Q57l+Wyt9T7N2WPiNq +JSlYKYbJpPF8LXbuKYG3BTFTdOVFIeRe2NUyYh/xs6bXGr4WKTXb3qBmzR02FSy3 +IODQw5Q6zpXj8prYqFHYsOvGCEc1CwJaSaYwRhTkFedJUxiyhyB5GQwoFfExCVHW +05ZFCAVYFldCJvUzfzrWubN6wX0DD2dwultgmldOn/W/n8at52mpPNvIdbZb2F41 +T0YZeoWnCJrYXjq/32oc1cmifIHqySnyMnavi75DxPCdZsCOpSAT4j4lAQRGsfgI +kkLPGQieMfNNkMCKh7qjwdXAVtdqhf0RVtFILH3OyEodlk1HYXqX5iE5wlaKzDop +PKwf2Q3BErq1xChYGGVS+dEvyXc/2nIBlt7uLWKp4XFjqekKbaGaLJdjYP5b2s7N +1dM0MXQ/f8XoXKBkJNzEiM3hfsU6DOREgMc1DIsFKxfuMwX3EkVQM1If8ghb6x5Y +jXayv+NLbidOSzk4vl5QwngO/JYFMkoc6i9LNwEaEtR9PhnrdubxmrtM+RjfBm02 +77q3dSWFESFQ4QxYWew4pHE0DpWbWy/iMIKQ6UZ5RLvB8GEcgt8ON7BBJeMc+Dyi +kT9qhqn+lw== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIICiDCCAgygAwIBAgIIQX76UsB/30owDAYIKoZIzj0EAwMFADB6MQswCQYDVQQG +EwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UECwwXQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNpYWwgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgRTEwHhcNMTkwNDI4MTYyMDQ0WhcNNDkwNDIwMTYyMDQ0 +WjB6MQswCQYDVQQGEwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UE +CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNp +YWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRTEwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAASCCRa94QI0vR5Up9Yr9HEupz6hSoyjySYqo7v837KnmjveUIUNiuC9pWAU +WP3jwLX3HkzeiNdeg22a0IZPoSUCpasufiLAnfXh6NInLiWBrjLJXDSGaY7vaokt +rpZvAdmjXTBbMAsGA1UdDwQEAwIBBjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRZ +4ZTgDpksHL2qcpkFkxD2zVd16TAfBgNVHSMEGDAWgBRZ4ZTgDpksHL2qcpkFkxD2 +zVd16TAMBggqhkjOPQQDAwUAA2gAMGUCMQD4IoqT2hTUn0jt7oXLdMJ8q4vLp6sg +wHfPiOr9gxreb+e6Oidwd2LDnC4OUqCWiF8CMAzwKs4SnDJYcMLf2vpkbuVE4dTH +Rglz+HGcTLWsFs4KxLsq7MuU+vJTBUeDJeDjdA== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIUEMdk6dVgOEIS2cCP0Q43P90Ps5YwDQYJKoZIhvcNAQEF +BQAwajELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM +E0NoaW5hIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMMH2lUcnVzQ2hpbmEgQ2xhc3Mg +MiBSb290IENBIC0gRzMwHhcNMTMwNDE4MDkzNjU2WhcNMzMwNDE4MDkzNjU2WjBq +MQswCQYDVQQGEwJDTjETMBEGA1UECgwKaVRydXNDaGluYTEcMBoGA1UECwwTQ2hp +bmEgVHJ1c3QgTmV0d29yazEoMCYGA1UEAwwfaVRydXNDaGluYSBDbGFzcyAyIFJv +b3QgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPPShpV +nJbMqqCw6Bz1kehnoPst9pkr0V9idOwU2oyS47/HjJXk9Rd5a9xfwkPO88trUpz5 +4GmmwspDXjVFu9L0eFaRuH3KMha1Ak01citbF7cQLJlS7XI+tpkTGHEY5pt3EsQg +wykfZl/A1jrnSkspMS997r2Gim54cwz+mTMgDRhZsKK/lbOeBPpWtcFizjXYCqhw +WktvQfZBYi6o4sHCshnOswi4yV1p+LuFcQ2ciYdWvULh1eZhLxHbGXyznYHi0dGN +z+I9H8aXxqAQfHVhbdHNzi77hCxFjOy+hHrGsyzjrd2swVQ2iUWP8BfEQqGLqM1g +KgWKYfcTGdbPB1MCAwEAAaNjMGEwHQYDVR0OBBYEFG/oAMxTVe7y0+408CTAK8hA +uTyRMB8GA1UdIwQYMBaAFG/oAMxTVe7y0+408CTAK8hAuTyRMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBLnUTfW7hp +emMbuUGCk7RBswzOT83bDM6824EkUnf+X0iKS95SUNGeeSWK2o/3ALJo5hi7GZr3 +U8eLaWAcYizfO99UXMRBPw5PRR+gXGEronGUugLpxsjuynoLQu8GQAeysSXKbN1I +UugDo9u8igJORYA+5ms0s5sCUySqbQ2R5z/GoceyI9LdxIVa1RjVX8pYOj8JFwtn +DJN3ftSFvNMYwRuILKuqUYSHc2GPYiHVflDh5nDymCMOQFcFG3WsEuB+EYQPFgIU +1DHmdZcz7Llx8UOZXX2JupWCYzK1XhJb+r4hK5ncf/w8qGtYlmyJpxk3hr1TfUJX +Yf4Zr0fJsGuv +-----END CERTIFICATE----- \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/appCertPublicKey_2019051064521003.crt b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/appCertPublicKey_2019051064521003.crt new file mode 100644 index 0000000..ad22ab9 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/appCertPublicKey_2019051064521003.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIEkzCCA3ugAwIBAgIQICABI1M0G1IN1Hv7M5NTmjANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UE +BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MTkwNwYDVQQDDDBBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IENs +YXNzIDEgUjEwHhcNMjAwMTIzMDc0NTQ3WhcNMjIwMTIyMDc0NTQ3WjBbMQswCQYDVQQGEwJDTjEP +MA0GA1UECgwG6ZKf6ZuoMQ8wDQYDVQQLDAZBbGlwYXkxKjAoBgNVBAMMITIwODgwMDI2NTY3MTg5 +MjAtMjAxOTA1MTA2NDUyMTAwMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIRaW3zN +ZGJY3oOUL41KMZqcoyI9JyDWG/fyb8qShWgH9NGinO6JeGWWX2pU2b5GKCd1CB6imnbD5U3zvErR +Z6h9Kc9pD4M22MNqnpuFontWuFXhq01MIbuolV5zTw94nrMR4aMPgTt7wX6svcQ8cKyg+v7Xz4DH +QCQOPhtFM3aL1UHsEZhLp+F2xNENTGpphmlV7D50ahnAo3A8Jdkt9ZBIzkWk4CoMdeoYk6BlOETG +XZ93Mc1TKR6cLNPj7LIUKb7xUh4ekaRoky2RP7k9NgBLsZLDjMkqZmzvHHhnstddmq5Er49Ger9b +VHnKsWNMWtN0Oi+ZyWTDcwvACdCgLbcCAwEAAaOCASkwggElMB8GA1UdIwQYMBaAFHEH4gRhFuTl +8mXrMQ/J4PQ8mtWRMB0GA1UdDgQWBBSNSXcCsxvjAa3v5QcTyVZ183CMjzBABgNVHSAEOTA3MDUG +B2CBHAFuAQEwKjAoBggrBgEFBQcCARYcaHR0cDovL2NhLmFsaXBheS5jb20vY3BzLnBkZjAOBgNV +HQ8BAf8EBAMCBsAwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2NhLmFsaXBheS5jb20vY3JsMzcu +Y3JsMGAGCCsGAQUFBwEBBFQwUjAoBggrBgEFBQcwAoYcaHR0cDovL2NhLmFsaXBheS5jb20vY2E2 +LmNlcjAmBggrBgEFBQcwAYYaaHR0cDovL2NhLmFsaXBheS5jb206ODM0MC8wDQYJKoZIhvcNAQEL +BQADggEBAA0l9rTtjEl4uqE4RP4Nd+A0KgM8NmWQHLxsubDRMSeYVFMzrpSm8V9zhlxLmKdFxWP/ +OuY4SHRe8eOSA++5yJc3ihg9B7/ddK2kNTsnaB7Xtvex685kvDDR8DMZmQYeirDThGVPhUeBgPdk +wY0R5KU6mEh2FzT3QIxDzP6t4ssSyYHhFPssZ4PXHFQ5eHzmdpJ81/85crfques67JxAm4CCfldb +bX0DH1BUrPxcnvz4Kj5lKv1qIvBR71yUnrGFOKAVCx04VYK4dTNDI70W9lLgX1aTfLGUBTYiJe/J +Zq/XlYhQP/T7t8HOAaCQFf2hM9tRq62EaL1UbExV2hcAP/E= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/privateKey.json b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/privateKey.json new file mode 100644 index 0000000..39daf4d --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/privateKey.json @@ -0,0 +1,4 @@ +{ + "2019022663440152": "<- 已脱敏,如想要执行单元测试,请开发者自行替换TestAccount中的相关账号并在此重新配置新的APPID与私钥的关联 ->", + "2019051064521003": "<- 已脱敏,如想要执行单元测试,请开发者自行替换TestAccount中的相关账号并在此重新配置新的APPID与私钥的关联 ->" +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/sample.mp4 b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/sample.mp4 new file mode 100644 index 0000000..26fb8b2 Binary files /dev/null and b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/sample.mp4 differ diff --git a/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/sample.png b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/sample.png new file mode 100644 index 0000000..066ec3b Binary files /dev/null and b/serve/vendor/alipaysdk/easysdk/php/test/resources/fixture/sample.png differ diff --git a/serve/vendor/alipaysdk/easysdk/php/test/security/textrisk/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/security/textrisk/ClientTest.php new file mode 100644 index 0000000..ca09b49 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/security/textrisk/ClientTest.php @@ -0,0 +1,20 @@ +getTestAccount()); + $result = Factory::security()->textRisk()->detect("test"); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/php/test/util/aes/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/util/aes/ClientTest.php new file mode 100644 index 0000000..816008b --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/util/aes/ClientTest.php @@ -0,0 +1,27 @@ +getTestAccount()); + } + + public function testDecrypt(){ + $result = Factory::util()->aes()->decrypt("ILpoMowjIQjfYMR847rnFQ=="); + $this->assertEquals(true, $result == 'test1234567'); + + } + + public function testEncrypt(){ + $result = Factory::util()->aes()->encrypt("test1234567"); + $this->assertEquals(true, $result == 'ILpoMowjIQjfYMR847rnFQ=='); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/php/test/util/generic/ClientTest.php b/serve/vendor/alipaysdk/easysdk/php/test/util/generic/ClientTest.php new file mode 100644 index 0000000..5854913 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/php/test/util/generic/ClientTest.php @@ -0,0 +1,95 @@ +getTestAccount()); + } + + public function testSDKExecute() + { + $bizParams = array( + "subject" => "Iphone6 16G", + "out_trade_no" => "f4833085-0c46-4bb0-8e5f-622a02a4cffc", + "total_amount" => "0.10" + ); + + $textParams = array(); + + $result = Factory::util()->generic()->sdkExecute("alipay.trade.app.pay", $textParams, $bizParams); + $this->assertEquals(true, strpos($result->body, 'alipay_sdk=alipay-easysdk-php') > 0); + $this->assertEquals(true, strpos($result->body, 'sign') > 0); + } + + public function testFileExecute() + { + $textParams = array( + "image_type" => "png", + "image_name" => "海底捞", + "image_pids" => "22088021822217233" + ); + $account = new TestAccount(); + $filePath = $account->getResourcesPath(). '/resources/fixture/sample.png'; + + $fileParams = array( + "image_content" => $filePath + ); + + $result = Factory::util()->generic()->fileExecute("alipay.offline.material.image.upload", $textParams, null, $fileParams); + $responseChecker = new ResponseChecker(); + $this->assertEquals(true, $responseChecker->success($result)); + $this->assertEquals('Success', $result->msg); + } + + public function testExecuteWithoutAppAuthToken() + { + $result = Factory::util()->generic()->execute("alipay.trade.create", null, $this->getBizParams(microtime())); + $this->assertEquals('10000', $result->code); + $this->assertEquals('Success', $result->msg); + } + + public function testExecuteWithAppAuthToken() + { + $result = Factory::util()->generic()->execute("alipay.trade.create", $this->getTextParams(), $this->getBizParams(microtime())); + $this->assertEquals('20001', $result->code); + $this->assertEquals('Insufficient Token Permissions', $result->msg); + $this->assertEquals('aop.invalid-app-auth-token', $result->subCode); + $this->assertEquals('无效的应用授权令牌', $result->subMsg); + } + + //设置系统参数(OpenAPI中非biz_content里的参数) + private function getTextParams() + { + return array("app_auth_token" => "201712BB_D0804adb2e743078d1822d536956X34"); + } + + private function getBizParams($outTradeNo) + { + $bizParams = array( + "subject" => "Iphone6 16G", + "out_trade_no" => $outTradeNo, + "total_amount" => "0.10", + "buyer_id" => "2088002656718920", + "extend_params" => $this->getHuabeiParams() + ); + return $bizParams; + } + + private function getHuabeiParams() + { + $extendParams = array("hb_fq_num" => "3", "hb_fq_seller_percent" => "3"); + return $extendParams; + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/tea/base/image/Teafile b/serve/vendor/alipaysdk/easysdk/tea/base/image/Teafile new file mode 100644 index 0000000..0999cc4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/base/image/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-base-image", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.base.image", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Base.Image", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Base.Image" + }, + "go": { + "namespace": "base/image" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/base/image/main.tea b/serve/vendor/alipaysdk/easysdk/tea/base/image/main.tea new file mode 100644 index 0000000..d93736f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/base/image/main.tea @@ -0,0 +1,88 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayOfflineMaterialImageUploadResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + imageId: string(name='image_id'), + imageUrl: string(name='image_url') +} + +api upload(imageName: string, imageFilePath: string): AlipayOfflineMaterialImageUploadResponse { + var systemParams: map[string]string = { + method = 'alipay.offline.material.image.upload', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + }; + + var textParams: map[string]string = { + image_type = 'jpg', + image_name = imageName + }; + + var fileParams: map[string]string = { + image_content = imageFilePath + }; + + var boundary = @kernel.getRandomBoundary(); + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = @kernel.concatStr('multipart/form-data;charset=utf-8;boundary=', boundary) + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + }); + + __request.body = @kernel.toMultipartRequestBody(textParams, fileParams, boundary); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.offline.material.image.upload"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 100000, + readTimeout = 100000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/base/oauth/Teafile b/serve/vendor/alipaysdk/easysdk/tea/base/oauth/Teafile new file mode 100644 index 0000000..2d97133 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/base/oauth/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-base-oauth", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.base.oauth", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Base.OAuth", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Base.OAuth" + }, + "go": { + "namespace": "base/oauth" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/base/oauth/main.tea b/serve/vendor/alipaysdk/easysdk/tea/base/oauth/main.tea new file mode 100644 index 0000000..ff28a4f --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/base/oauth/main.tea @@ -0,0 +1,150 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipaySystemOauthTokenResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + userId: string(name='user_id'), + accessToken: string(name='access_token'), + expiresIn: long(name='expires_in'), + refreshToken: string(name='refresh_token'), + reExpiresIn: long(name='re_expires_in') +} + +api getToken(code: string): AlipaySystemOauthTokenResponse { + var systemParams: map[string]string = { + method = 'alipay.system.oauth.token', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + }; + + var textParams: map[string]string = { + grant_type = 'authorization_code', + code = code + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: object = @kernel.readAsJson(__response, "alipay.system.oauth.token"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api refreshToken(refreshToken: string): AlipaySystemOauthTokenResponse { + var systemParams: map[string]string = { + method = 'alipay.system.oauth.token', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + }; + + var textParams: map[string]string = { + grant_type = 'refresh_token', + refresh_token = refreshToken + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: object = @kernel.readAsJson(__response, "alipay.system.oauth.token"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/base/qrcode/Teafile b/serve/vendor/alipaysdk/easysdk/tea/base/qrcode/Teafile new file mode 100644 index 0000000..48b2d40 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/base/qrcode/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-base-qrcode", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.base.qrcode", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Base.Qrcode", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Base.Qrcode" + }, + "go": { + "namespace": "base/qrcode" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/base/qrcode/main.tea b/serve/vendor/alipaysdk/easysdk/tea/base/qrcode/main.tea new file mode 100644 index 0000000..821bf99 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/base/qrcode/main.tea @@ -0,0 +1,83 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayOpenAppQrcodeCreateResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + qrCodeUrl: string(name='qr_code_url') +} + +api create(urlParam: string, queryParam: string, describe: string): AlipayOpenAppQrcodeCreateResponse { + var systemParams: map[string]string = { + method = 'alipay.open.app.qrcode.create', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + url_param = urlParam, + query_param = queryParam, + describe = describe + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: object = @kernel.readAsJson(__response, "alipay.open.app.qrcode.create"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/base/video/Teafile b/serve/vendor/alipaysdk/easysdk/tea/base/video/Teafile new file mode 100644 index 0000000..e504f5e --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/base/video/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-base-video", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.base.video", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Base.Video", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Base.Video" + }, + "go": { + "namespace": "base/video" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/base/video/main.tea b/serve/vendor/alipaysdk/easysdk/tea/base/video/main.tea new file mode 100644 index 0000000..9f58f20 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/base/video/main.tea @@ -0,0 +1,88 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayOfflineMaterialImageUploadResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + imageId: string(name='image_id'), + imageUrl: string(name='image_url') +} + +api upload(videoName: string, videoFilePath: string): AlipayOfflineMaterialImageUploadResponse { + var systemParams: map[string]string = { + method = 'alipay.offline.material.image.upload', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + }; + + var textParams: map[string]string = { + image_type = 'mp4', + image_name = videoName + }; + + var fileParams: map[string]string = { + image_content = videoFilePath + }; + + var boundary = @kernel.getRandomBoundary(); + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = @kernel.concatStr('multipart/form-data;charset=utf-8;boundary=', boundary) + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + }); + + __request.body = @kernel.toMultipartRequestBody(textParams, fileParams, boundary); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.offline.material.image.upload"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 100000, + readTimeout = 100000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/kernel/Teafile b/serve/vendor/alipaysdk/easysdk/tea/kernel/Teafile new file mode 100644 index 0000000..ee192b4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/kernel/Teafile @@ -0,0 +1,22 @@ +{ + "scope": "alipay", + "name": "easysdk-kernel", + "version": "0.0.1", + "main": "./main.tea", + "releases": { + "java": "com.alipay.sdk:easysdk-kernel:1.0.3", + "csharp": "AlipayEasySDK.Kernel:1.0.1" + }, + "java": { + "package": "com.alipay.easysdk.kernel" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Kernel" + }, + "php": { + "namespace": "Alipay.EasySDK.Kernel" + }, + "go": { + "namespace": "alipay/easysdk/kernel" + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/tea/kernel/main.tea b/serve/vendor/alipaysdk/easysdk/tea/kernel/main.tea new file mode 100644 index 0000000..c7d3aa4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/kernel/main.tea @@ -0,0 +1,50 @@ +model Context { + config: map[string]any, + certEnvironment: any +} + +init(context: Context); + +function getTimestamp(): string; + +function getConfig(key: string): string; + +function getSdkVersion(): string; + +function toUrlEncodedRequestBody(bizParams: map[string]any): bytes; + +async function readAsJson(response: $Response, method: string): map[string]any; + +function toRespModel(respMap: map[string]any): map[string]any; + +function getRandomBoundary(): string; + +function toMultipartRequestBody(textParams: map[string]string, fileParams: map[string]string, boundary: string): readable; + +function generatePage(method: string, systemParams: map[string]string, bizParams: map[string]any, textParams: map[string]string, sign: string): string; + +function getMerchantCertSN(): string; + +function getAlipayCertSN(respMap:map[string]any): string; + +function getAlipayRootCertSN(): string; + +function isCertMode(): boolean; + +function extractAlipayPublicKey(alipayCertSN:string): string; + +function verify(respMap: map[string]any, alipayPublicKey: string): boolean; + +function sign(systemParams: map[string]string, bizParams: map[string]any, textParams: map[string]string, merchantPrivateKey: string): string; + +function aesEncrypt(plainText: string, encryptKey: string): string; + +function aesDecrypt(cipherText: string, encryptKey: string): string; + +function generateOrderString(systemParams: map[string]string, bizParams: map[string]any, textParams: map[string]string, sign: string): string; + +function concatStr(a: string, b: string): string; + +function verifyParams(parameters: map[string]string, publicKey: string): boolean; + +function sortMap(randomMap: map[string]string): map[string]string; \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/tea/marketing/openlife/Teafile b/serve/vendor/alipaysdk/easysdk/tea/marketing/openlife/Teafile new file mode 100644 index 0000000..704b255 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/marketing/openlife/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-marketing-openlife", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.marketing.openlife", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Marketing.OpenLife", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Marketing.OpenLife" + }, + "go": { + "namespace": "marketing/openlife" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/marketing/openlife/main.tea b/serve/vendor/alipaysdk/easysdk/tea/marketing/openlife/main.tea new file mode 100644 index 0000000..5482524 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/marketing/openlife/main.tea @@ -0,0 +1,644 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayOpenPublicMessageContentCreateResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + contentId: string(name='content_id'), + contentUrl: string(name='content_url') +} + +model AlipayOpenPublicMessageContentModifyResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + contentId: string(name='content_id'), + contentUrl: string(name='content_url') +} + +model AlipayOpenPublicMessageTotalSendResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + messageId: string(name='message_id') +} + +model Text { + title: string(name='title'), + content: string(name='content') +} + +model Article { + title?: string(name='title'), + desc: string(name='desc'), + imageUrl?: string(name='image_url'), + url: string(name='url'), + actionName?: string(name='action_name') +} + +model Keyword { + color: string(name='color'), + value: string(name='value') +} + +model Context { + headColor: string(name='head_color'), + url: string(name='url'), + actionName: string(name='action_name'), + keyword1?: Keyword(name='keyword1'), + keyword2?: Keyword(name='keyword2'), + first?: Keyword(name='first'), + remark?: Keyword(name='remark') +} + +model Template { + templateId: string(name='template_id'), + context: Context(name='context') +} + +model AlipayOpenPublicMessageSingleSendResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg') +} + +model AlipayOpenPublicLifeMsgRecallResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg') +} + +model AlipayOpenPublicTemplateMessageIndustryModifyResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg') +} + +model AlipayOpenPublicSettingCategoryQueryResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + primaryCategory: string(name='primary_category'), + secondaryCategory: string(name='secondary_category') +} + +api createImageTextContent(title: string, cover: string, content: string, contentComment: string, ctype: string, benefit: string, extTags: string, loginIds: string): AlipayOpenPublicMessageContentCreateResponse { + var systemParams: map[string]string = { + method = 'alipay.open.public.message.content.create', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + title = title, + cover = cover, + content = content, + could_comment = contentComment, + ctype = ctype, + benefit = benefit, + ext_tags = extTags, + login_ids = loginIds + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.open.public.message.content.create"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api modifyImageTextContent(contentId: string, title: string, cover: string, content: string, couldComment: string, ctype: string, benefit: string, extTags: string, loginIds: string): AlipayOpenPublicMessageContentModifyResponse { + var systemParams: map[string]string = { + method = 'alipay.open.public.message.content.modify', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + content_id = contentId, + title = title, + cover = cover, + content = content, + could_comment = couldComment, + ctype = ctype, + benefit = benefit, + ext_tags = extTags, + login_ids = loginIds + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.open.public.message.content.modify"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api sendText(text: string): AlipayOpenPublicMessageTotalSendResponse { + var systemParams: map[string]string = { + method = 'alipay.open.public.message.total.send', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var textObj: Text = new Text { + title = '', + content = text + }; + + var bizParams: map[string]any = { + msg_type = 'text', + text = textObj + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.open.public.message.total.send"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api sendImageText(articles: [ Article ]): AlipayOpenPublicMessageTotalSendResponse { + var systemParams: map[string]string = { + method = 'alipay.open.public.message.total.send', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + msg_type = 'image-text', + articles = articles + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.open.public.message.total.send"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api sendSingleMessage(toUserId: string, template: Template): AlipayOpenPublicMessageSingleSendResponse { + var systemParams: map[string]string = { + method = 'alipay.open.public.message.single.send', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + to_user_id = toUserId, + template = template + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.open.public.message.single.send"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api recallMessage(messageId: string): AlipayOpenPublicLifeMsgRecallResponse { + var systemParams: map[string]string = { + method = 'alipay.open.public.life.msg.recall', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + message_id = messageId + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.open.public.life.msg.recall"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api setIndustry(primaryIndustryCode: string, primaryIndustryName: string, secondaryIndustryCode: string, secondaryIndustryName: string): AlipayOpenPublicTemplateMessageIndustryModifyResponse { + var systemParams: map[string]string = { + method = 'alipay.open.public.template.message.industry.modify', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + primary_industry_code = primaryIndustryCode, + primary_industry_name = primaryIndustryName, + secondary_industry_code = secondaryIndustryCode, + secondary_industry_name = secondaryIndustryName + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.open.public.template.message.industry.modify"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api getIndustry(): AlipayOpenPublicSettingCategoryQueryResponse { + var systemParams: map[string]string = { + method = 'alipay.open.public.setting.category.query', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.open.public.setting.category.query"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/marketing/pass/Teafile b/serve/vendor/alipaysdk/easysdk/tea/marketing/pass/Teafile new file mode 100644 index 0000000..d0e7498 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/marketing/pass/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-marketing-pass", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.marketing.pass", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Marketing.Pass", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Marketing.Pass" + }, + "go": { + "namespace": "marketing/pass" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/marketing/pass/main.tea b/serve/vendor/alipaysdk/easysdk/tea/marketing/pass/main.tea new file mode 100644 index 0000000..85c03be --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/marketing/pass/main.tea @@ -0,0 +1,317 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayPassTemplateAddResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + success: boolean(name='success'), + result: string(name='result') +} + +model AlipayPassTemplateUpdateResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + success: boolean(name='success'), + result: string(name='result') +} + +model AlipayPassInstanceAddResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + success: boolean(name='success'), + result: string(name='result') +} + +model AlipayPassInstanceUpdateResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + success: boolean(name='success'), + result: string(name='result') +} + +api createTemplate(uniqueId: string, tplContent: string): AlipayPassTemplateAddResponse { + var systemParams: map[string]string = { + method = 'alipay.pass.template.add', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + unique_id = uniqueId, + tpl_content = tplContent + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.pass.template.add"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api updateTemplate(tplId: string, tplContent: string): AlipayPassTemplateUpdateResponse { + var systemParams: map[string]string = { + method = 'alipay.pass.template.update', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + tpl_id = tplId, + tpl_content = tplContent + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.pass.template.update"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api addInstance(tplId: string, tplParams: string, recognitionType: string, recognitionInfo: string): AlipayPassInstanceAddResponse { + var systemParams: map[string]string = { + method = 'alipay.pass.instance.add', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + tpl_id = tplId, + tpl_params = tplParams, + recognition_type = recognitionType, + recognition_info = recognitionInfo + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.pass.instance.add"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api updateInstance(serialNumber: string, channelId: string, tplParams: string, status: string, verifyCode: string, verifyType: string): AlipayPassInstanceUpdateResponse { + var systemParams: map[string]string = { + method = 'alipay.pass.instance.update', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + serial_number = serialNumber, + channel_id = channelId, + tpl_params = tplParams, + status = status, + verify_code = verifyCode, + verify_type = verifyType + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.pass.instance.update"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/marketing/templateMessage/Teafile b/serve/vendor/alipaysdk/easysdk/tea/marketing/templateMessage/Teafile new file mode 100644 index 0000000..9ba709a --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/marketing/templateMessage/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-marketing-templatemessage", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.marketing.templatemessage", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Marketing.TemplateMessage", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Marketing.TemplateMessage" + }, + "go": { + "namespace": "marketing/templatemessage" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/marketing/templateMessage/main.tea b/serve/vendor/alipaysdk/easysdk/tea/marketing/templateMessage/main.tea new file mode 100644 index 0000000..48535ee --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/marketing/templateMessage/main.tea @@ -0,0 +1,83 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayOpenAppMiniTemplatemessageSendResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg') +} + +api send(toUserId: string, formId: string, userTemplateId: string, page: string, data: string): AlipayOpenAppMiniTemplatemessageSendResponse { + var systemParams: map[string]string = { + method = 'alipay.open.app.mini.templatemessage.send', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + to_user_id = toUserId, + form_id = formId, + user_template_id = userTemplateId, + page = page, + data = data + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.open.app.mini.templatemessage.send"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/member/identification/Teafile b/serve/vendor/alipaysdk/easysdk/tea/member/identification/Teafile new file mode 100644 index 0000000..9e5cf34 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/member/identification/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-member-identification", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.member.identification", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Member.Identification", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Member.Identification" + }, + "go": { + "namespace": "member/identification" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/member/identification/main.tea b/serve/vendor/alipaysdk/easysdk/tea/member/identification/main.tea new file mode 100644 index 0000000..90096e4 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/member/identification/main.tea @@ -0,0 +1,204 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model IdentityParam { + identityType: string(name='identity_type'), + certType: string(name='cert_type'), + certName: string(name='cert_name'), + certNo: string(name='cert_no') +} + +model MerchantConfig { + returnUrl: string(name='return_url') +} + +model AlipayUserCertifyOpenInitializeResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + certifyId: string(name='certify_id') +} + +model AlipayUserCertifyOpenCertifyResponse { + body: string(name='body', description='认证服务请求地址') +} + +model AlipayUserCertifyOpenQueryResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + passed: string(name='passed'), + identityInfo: string(name='identity_info'), + materialInfo: string(name='material_info') +} + +api init(outerOrderNo: string, bizCode: string, identityParam: IdentityParam, merchantConfig: MerchantConfig): AlipayUserCertifyOpenInitializeResponse { + var systemParams: map[string]string = { + method = 'alipay.user.certify.open.initialize', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + outer_order_no = outerOrderNo, + biz_code = bizCode, + identity_param = identityParam, + merchant_config = merchantConfig + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.user.certify.open.initialize"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +function certify(certifyId: string): AlipayUserCertifyOpenCertifyResponse { + var systemParams: map[string]string = { + method = 'alipay.user.certify.open.certify', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + certify_id = certifyId + }; + + var textParams: map[string]string = { + }; + + var sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig('merchantPrivateKey')); + + var response: map[string]string = { + body = @kernel.generatePage('GET', systemParams, bizParams, textParams, sign) + }; + return response; +} + +api query(certifyId: string): AlipayUserCertifyOpenQueryResponse { + var systemParams: map[string]string = { + method = 'alipay.user.certify.open.query', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + certify_id = certifyId + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.user.certify.open.query"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/app/Teafile b/serve/vendor/alipaysdk/easysdk/tea/payment/app/Teafile new file mode 100644 index 0000000..ce73a53 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/app/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-payment-app", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.payment.app", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Payment.App", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Payment.App" + }, + "go": { + "namespace": "payment/app" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/app/main.tea b/serve/vendor/alipaysdk/easysdk/tea/payment/app/main.tea new file mode 100644 index 0000000..0f35d86 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/app/main.tea @@ -0,0 +1,42 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayTradeAppPayResponse { + body: string(name='body', description='订单信息,字符串形式') +} + +function pay(subject: string, outTradeNo: string, totalAmount: string): AlipayTradeAppPayResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.app.pay', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + subject = subject, + out_trade_no = outTradeNo, + total_amount = totalAmount + }; + + var textParams: map[string]string = { + }; + + var sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig('merchantPrivateKey')); + + var response: map[string]string = { + body = @kernel.generateOrderString(systemParams, bizParams, textParams, sign) + }; + return response; +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/common/Teafile b/serve/vendor/alipaysdk/easysdk/tea/payment/common/Teafile new file mode 100644 index 0000000..5e129c3 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/common/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-payment-common", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.payment.common", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Payment.Common", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Payment.Common" + }, + "go": { + "namespace": "payment/common" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/common/main.tea b/serve/vendor/alipaysdk/easysdk/tea/payment/common/main.tea new file mode 100644 index 0000000..f30c9ac --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/common/main.tea @@ -0,0 +1,650 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model RefundRoyaltyResult{ + refundAmount: string(name='refund_amount'), + royaltyType: string(name='royalty_type'), + resultCode: string(name='result_code'), + transOut: string(name='trans_out'), + transOutEmail: string(name='trans_out_email'), + transIn: string(name='trans_in'), + transInEmail: string(name='trans_in_email'), +} + +model TradeFundBill { + fundChannel: string(name='fund_channel'), + bankCode: string(name='bank_code'), + amount: string(name='amount'), + realAmount: string(name='real_amount'), + fundType: string(name='fund_type') +} + +model TradeSettleDetail { + operationType: string(name='operation_type'), + operationSerial_no: string(name='operation_serial_no'), + operationDt: string(name='operation_dt'), + transOut: string(name='trans_out'), + transIn: string(name='trans_in'), + amount: string(name='amount') +} + +model TradeSettleInfo { + tradeSettleDetailList: [ TradeSettleDetail ](name='trade_settle_detail_list') +} + +model PresetPayToolInfo { + amount: [ string ](name='amount'), + assertTypeCode: string(name='assert_type_code') +} + +model AlipayTradeCreateResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + outTradeNo: string(name='out_trade_no'), + tradeNo: string(name='trade_no') +} + +model AlipayTradeQueryResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + tradeNo: string(name='trade_no'), + outTradeNo: string(name='out_trade_no'), + buyerLogonId: string(name='buyer_logon_id'), + tradeStatus: string(name='trade_status'), + totalAmount: string(name='total_amount'), + transCurrency: string(name='trans_currency'), + settleCurrency: string(name='settle_currency'), + settleAmount: string(name='settle_amount'), + payCurrency: string(name='pay_currency'), + payAmount: string(name='pay_amount'), + settleTransRate: string(name='settle_trans_rate'), + transPayRate: string(name='trans_pay_rate'), + buyerPayAmount: string(name='buyer_pay_amount'), + pointAmount: string(name='point_amount'), + invoiceAmount: string(name='invoice_amount'), + sendPayDate: string(name='send_pay_date'), + receiptAmount: string(name='receipt_amount'), + storeId: string(name='store_id'), + terminalId: string(name='terminal_id'), + fundBillList: [ TradeFundBill ](name='fund_bill_list'), + storeName: string(name='store_name'), + buyerUserId: string(name='buyer_user_id'), + chargeAmount: string(name='charge_amount'), + chargeFlags: string(name='charge_flags'), + settlementId: string(name='settlement_id'), + tradeSettleInfo: [ TradeSettleInfo ](name='trade_settle_info'), + authTradePayMode: string(name='auth_trade_pay_mode'), + buyerUserType: string(name='buyer_user_type'), + mdiscountAmount: string(name='mdiscount_amount'), + discountAmount: string(name='discount_amount'), + buyerUserName: string(name='buyer_user_name'), + subject: string(name='subject'), + body: string(name='body'), + alipaySubMerchantId: string(name='alipay_sub_merchant_id'), + extInfos: string(name='ext_infos') +} + +model AlipayTradeRefundResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + tradeNo: string(name='trade_no'), + outTradeNo: string(name='out_trade_no'), + buyerLogonId: string(name='buyer_logon_id'), + fundChange: string(name='fund_change'), + refundFee: string(name='refund_fee'), + refundCurrency: string(name='refund_currency'), + gmtRefundPay: string(name='gmt_refund_pay'), + refundDetailItemList: [ TradeFundBill ](name='refund_detail_item_list'), + storeName: string(name='store_name'), + buyerUserId: string(name='buyer_user_id'), + refundPresetPaytoolList: [ PresetPayToolInfo ](name='refund_preset_paytool_list'), + refundSettlementId: string(name='refund_settlement_id'), + presentRefundBuyerAmount: string(name='present_refund_buyer_amount'), + presentRefundDiscountAmount: string(name='present_refund_discount_amount'), + presentRefundMdiscountAmount: string(name='present_refund_mdiscount_amount'), +} + +model AlipayTradeCloseResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + tradeNo: string(name='trade_no'), + outTradeNo: string(name='out_trade_no') +} + +model AlipayTradeCancelResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + tradeNo: string(name='trade_no'), + outTradeNo: string(name='out_trade_no'), + retryFlag: string(name='retry_flag'), + action: string(name='action'), + gmtRefundPay: string(name='gmt_refund_pay'), + refundSettlementId: string(name='refund_settlement_id') +} + +model AlipayTradeFastpayRefundQueryResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + errorCode: string(name='error_code'), + gmtRefundPay: string(name='gmt_refund_pay'), + industrySepcDetail: string(name='industry_sepc_detail'), + outRequestNo: string(name='out_request_no'), + outTradeNo: string(name='out_trade_no'), + presentRefundBuyerAmount: string(name='present_refund_buyer_amount'), + presentRefundDiscountAmount: string(name='present_refund_discount_amount'), + presentRefundMdiscountAmount: string(name='present_refund_mdiscount_amount'), + refundAmount: string(name='refund_amount'), + refundChargeAmount: string(name='refund_charge_amount'), + refundDetailItemList: [ TradeFundBill ](name='refund_detail_item_list'), + refundReason: string(name='refund_reason'), + refundRoyaltys: [ RefundRoyaltyResult ](name='refund_royaltys'), + refundSettlementId: string(name='refund_settlement_id'), + refundStatus: string(name='refund_status'), + sendBackFee: string(name='send_back_fee'), + totalAmount: string(name='total_amount'), + tradeNo: string(name='trade_no') +} + +model AlipayDataDataserviceBillDownloadurlQueryResponse{ + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + billDownloadUrl: string(name='bill_download_url'), +} + +api create(subject: string, outTradeNo: string, totalAmount: string, buyerId: string): AlipayTradeCreateResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.create', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + subject = subject, + out_trade_no = outTradeNo, + total_amount = totalAmount, + buyer_id = buyerId + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.trade.create"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api query(outTradeNo: string): AlipayTradeQueryResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.query', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + out_trade_no = outTradeNo + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.trade.query"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api refund(outTradeNo: string, refundAmount: string): AlipayTradeRefundResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.refund', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + out_trade_no = outTradeNo, + refund_amount = refundAmount + }; + + var textParams: map[string]string = { + }; + + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.trade.refund"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api close(outTradeNo: string): AlipayTradeCloseResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.close', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + out_trade_no = outTradeNo + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.trade.close"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api cancel(outTradeNo: string): AlipayTradeCancelResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.cancel', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + out_trade_no = outTradeNo + }; + + var textParams: map[string]string = { + }; + + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.trade.cancel"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api queryRefund(outTradeNo: string, outRequestNo: string): AlipayTradeFastpayRefundQueryResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.fastpay.refund.query', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + out_trade_no = outTradeNo, + out_request_no = outRequestNo + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.trade.fastpay.refund.query"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api downloadBill(billType: string, billDate: string): AlipayDataDataserviceBillDownloadurlQueryResponse { + var systemParams: map[string]string = { + method = 'alipay.data.dataservice.bill.downloadurl.query', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + bill_type = billType, + bill_date = billDate + }; + + var textParams: map[string]string = { + }; + + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.data.dataservice.bill.downloadurl.query"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +function verifyNotify(parameters: map[string]string): boolean { + if (@kernel.isCertMode()) { + return @kernel.verifyParams(parameters, @kernel.extractAlipayPublicKey('')); + } else { + return @kernel.verifyParams(parameters, @kernel.getConfig('alipayPublicKey')); + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/faceToFace/Teafile b/serve/vendor/alipaysdk/easysdk/tea/payment/faceToFace/Teafile new file mode 100644 index 0000000..676d572 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/faceToFace/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-payment-facetoface", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.payment.facetoface", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Payment.FaceToFace", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Payment.FaceToFace" + }, + "go": { + "namespace": "payment/facetoface" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/faceToFace/main.tea b/serve/vendor/alipaysdk/easysdk/tea/payment/faceToFace/main.tea new file mode 100644 index 0000000..47cff15 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/faceToFace/main.tea @@ -0,0 +1,215 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model TradeFundBill { + fundChannel: string(name='fund_channel'), + bankCode: string(name='bank_code'), + amount: string(name='amount'), + realAmount: string(name='real_amount') +} + +model VoucherDetail { + id: string(name='id'), + name: string(name='name'), + type: string(name='type'), + amount: string(name='amount'), + merchantContribute: string(name='merchant_contribute'), + otherContribute: string(name='other_contribute'), + memo: string(name='memo'), + templateId: string(name='template_id'), + purchaseBuyerContribute: string(name='purchase_buyer_contribute'), + purchaseMerchantContribute: string(name='purchase_merchant_contribute'), + purchaseAntContribute: string(name='purchase_ant_contribute') +} + +model AlipayTradePayResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + tradeNo: string(name='trade_no'), + outTradeNo: string(name='out_trade_no'), + buyerLogonId: string(name='buyer_logon_id'), + settleAmount: string(name='settle_amount'), + payCurrency: string(name='pay_currency'), + payAmount: string(name='pay_amount'), + settleTransRate: string(name='settle_trans_rate'), + transPayRate: string(name='trans_pay_rate'), + totalAmount: string(name='total_amount'), + transCurrency: string(name='trans_currency'), + settleCurrency: string(name='settle_currency'), + receiptAmount: string(name='receipt_amount'), + buyerPayAmount: string(name='buyer_pay_amount'), + pointAmount: string(name='point_amount'), + invoiceAmount: string(name='invoice_amount'), + gmtPayment: string(name='gmt_payment'), + fundBillList: [ TradeFundBill ](name='fund_bill_list'), + cardBalance: string(name='card_balance'), + storeName: string(name='store_name'), + buyerUserId: string(name='buyer_user_id'), + discountGoodsDetail: string(name='discount_goods_detail'), + voucherDetailList: [ VoucherDetail ](name='voucher_detail_list'), + advanceAmount: string(name='advance_amount'), + authTradePayMode: string(name='auth_trade_pay_mode'), + chargeAmount: string(name='charge_amount'), + chargeFlags: string(name='charge_flags'), + settlementId: string(name='settlement_id'), + businessParams: string(name='business_params'), + buyerUserType: string(name='buyer_user_type'), + mdiscountAmount: string(name='mdiscount_amount'), + discountAmount: string(name='discount_amount'), + buyerUserName: string(name='buyer_user_name') +} + +model AlipayTradePrecreateResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + outTradeNo: string(name='out_trade_no'), + qrCode: string(name='qr_code'), +} + + +api pay(subject: string, outTradeNo: string, totalAmount: string, authCode: string): AlipayTradePayResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.pay', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + subject = subject, + out_trade_no = outTradeNo, + total_amount = totalAmount, + auth_code = authCode, + scene = 'bar_code' + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.trade.pay"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + +api preCreate(subject: string, outTradeNo: string, totalAmount: string): AlipayTradePrecreateResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.precreate', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + subject = subject, + out_trade_no = outTradeNo, + total_amount = totalAmount + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.trade.precreate"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/huabei/Teafile b/serve/vendor/alipaysdk/easysdk/tea/payment/huabei/Teafile new file mode 100644 index 0000000..907b625 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/huabei/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-payment-huabei", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.payment.huabei", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Payment.Huabei", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Payment.Huabei" + }, + "go": { + "namespace": "payment/huabei" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/huabei/main.tea b/serve/vendor/alipaysdk/easysdk/tea/payment/huabei/main.tea new file mode 100644 index 0000000..710d019 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/huabei/main.tea @@ -0,0 +1,91 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model HuabeiConfig { + hbFqNum: string(name='hb_fq_num'), + hbFqSellerPercent: string(name='hb_fq_seller_percent') +} + +model AlipayTradeCreateResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + outTradeNo: string(name='out_trade_no'), + tradeNo: string(name='trade_no') +} + +api create(subject: string, outTradeNo: string, totalAmount: string, buyerId: string, extendParams: HuabeiConfig): AlipayTradeCreateResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.create', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + subject = subject, + out_trade_no = outTradeNo, + total_amount = totalAmount, + buyer_id = buyerId, + extend_params = extendParams + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.trade.create"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/page/Teafile b/serve/vendor/alipaysdk/easysdk/tea/payment/page/Teafile new file mode 100644 index 0000000..28803ac --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/page/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-payment-page", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.payment.page", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Payment.Page", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Payment.Page" + }, + "go": { + "namespace": "payment/page" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/page/main.tea b/serve/vendor/alipaysdk/easysdk/tea/payment/page/main.tea new file mode 100644 index 0000000..84616c8 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/page/main.tea @@ -0,0 +1,44 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayTradePagePayResponse { + body: string(name='body', description='订单信息,Form表单形式') +} + +function pay(subject: string, outTradeNo: string, totalAmount: string, returnUrl: string): AlipayTradePagePayResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.page.pay', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + subject = subject, + out_trade_no = outTradeNo, + total_amount = totalAmount, + product_code = 'FAST_INSTANT_TRADE_PAY' + }; + + var textParams: map[string]string = { + return_url = returnUrl + }; + + var sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig('merchantPrivateKey')); + + var response: map[string]string = { + body = @kernel.generatePage('POST', systemParams, bizParams, textParams, sign) + }; + return response; +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/wap/Teafile b/serve/vendor/alipaysdk/easysdk/tea/payment/wap/Teafile new file mode 100644 index 0000000..90a1963 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/wap/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-payment-wap", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.payment.wap", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Payment.Wap", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Payment.Wap" + }, + "go": { + "namespace": "payment/wap" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/payment/wap/main.tea b/serve/vendor/alipaysdk/easysdk/tea/payment/wap/main.tea new file mode 100644 index 0000000..c819dca --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/payment/wap/main.tea @@ -0,0 +1,45 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayTradeWapPayResponse { + body: string(name='body', description='订单信息,Form表单形式') +} + +function pay(subject: string, outTradeNo: string, totalAmount: string, quitUrl: string, returnUrl: string): AlipayTradeWapPayResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.wap.pay', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + subject = subject, + out_trade_no = outTradeNo, + total_amount = totalAmount, + quit_url = quitUrl, + product_code = 'QUICK_WAP_WAY' + }; + + var textParams: map[string]string = { + return_url = returnUrl + }; + + var sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig('merchantPrivateKey')); + + var response: map[string]string = { + body = @kernel.generatePage('POST', systemParams, bizParams, textParams, sign) + }; + return response; +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/security/textRisk/Teafile b/serve/vendor/alipaysdk/easysdk/tea/security/textRisk/Teafile new file mode 100644 index 0000000..f396ccb --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/security/textRisk/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-security-textrisk", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.security.textrisk", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Security.TextRisk", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Security.TextRisk" + }, + "go": { + "namespace": "security/textRisk" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} \ No newline at end of file diff --git a/serve/vendor/alipaysdk/easysdk/tea/security/textRisk/main.tea b/serve/vendor/alipaysdk/easysdk/tea/security/textRisk/main.tea new file mode 100644 index 0000000..91fb193 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/security/textRisk/main.tea @@ -0,0 +1,82 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipaySecurityRiskContentDetectResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + action: string(name='action'), + keywords: [ string ](name='keywords'), + uniqueId: string(name='unique_id') +} + +api detect(content: string): AlipaySecurityRiskContentDetectResponse { + var systemParams: map[string]string = { + method = 'alipay.security.risk.content.detect', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + content = content + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.security.risk.content.detect"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/trans/Teafile b/serve/vendor/alipaysdk/easysdk/tea/trans/Teafile new file mode 100644 index 0000000..907b625 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/trans/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-payment-huabei", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.payment.huabei", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Payment.Huabei", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Payment.Huabei" + }, + "go": { + "namespace": "payment/huabei" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/trans/main.tea b/serve/vendor/alipaysdk/easysdk/tea/trans/main.tea new file mode 100644 index 0000000..685dc81 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/trans/main.tea @@ -0,0 +1,94 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model PayeeInfo { + identity: string(name='identity'), + identityType: string(name='identity_type'), + name: string(name='identity_type') +} + +model AlipayFundTransUniTransferResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg'), + + outBizNo: string(name='out_biz_no'), + orderId: string(name='order_id'), + payFundOrderId: string(name='pay_fund_order_id'), + status: string(name='status'), + transDate: string(name='trans_date') +} + +api transfer(outBizNo: string, transAmount: string, productCode: string, payeeInfo: PayeeInfo): AlipayFundTransUniTransferResponse { + var systemParams: map[string]string = { + method = 'alipay.trade.create', + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var bizParams: map[string]any = { + out_biz_no = outBizNo, + trans_amount = transAmount, + product_code = productCode, + payee_info = payeeInfo + }; + + var textParams: map[string]string = { + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, "alipay.fund.trans.uni.transfer"); + + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/util/aes/Teafile b/serve/vendor/alipaysdk/easysdk/tea/util/aes/Teafile new file mode 100644 index 0000000..f2031ca --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/util/aes/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-util-aes", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.util.aes", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Util.AES", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Util.AES" + }, + "go": { + "baseClient": "util/aes" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/util/aes/main.tea b/serve/vendor/alipaysdk/easysdk/tea/util/aes/main.tea new file mode 100644 index 0000000..b07a420 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/util/aes/main.tea @@ -0,0 +1,15 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +function decrypt(cipherText: string): string { + return @kernel.aesDecrypt(cipherText, @kernel.getConfig('encryptKey')); +} + +function encrypt(plainText: string): string { + return @kernel.aesEncrypt(plainText, @kernel.getConfig('encryptKey')); +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/util/generic/Teafile b/serve/vendor/alipaysdk/easysdk/tea/util/generic/Teafile new file mode 100644 index 0000000..f692d20 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/util/generic/Teafile @@ -0,0 +1,26 @@ +{ + "scope": "alipay", + "name": "easysdk-system-generic", + "version": "0.0.1", + "main": "./main.tea", + "java": { + "package": "com.alipay.easysdk.util.generic", + "baseClient": "com.alipay.easysdk.kernel.BaseClient" + }, + "csharp": { + "namespace": "Alipay.EasySDK.Util.Generic", + "baseClient": "Alipay.EasySDK.Kernel:BaseClient" + }, + "typescript": { + "baseClient": "@alipay/easysdk-baseclient" + }, + "php": { + "package": "Alipay.EasySDK.Util.Generic" + }, + "go": { + "baseClient": "util/generic" + }, + "libraries": { + "EasySDKKernel": "alipay:easysdk-kernel:*" + } +} diff --git a/serve/vendor/alipaysdk/easysdk/tea/util/generic/main.tea b/serve/vendor/alipaysdk/easysdk/tea/util/generic/main.tea new file mode 100644 index 0000000..e1703b1 --- /dev/null +++ b/serve/vendor/alipaysdk/easysdk/tea/util/generic/main.tea @@ -0,0 +1,157 @@ +import EasySDKKernel; + +type @kernel = EasySDKKernel + +init(kernel: EasySDKKernel) { + @kernel = kernel; +} + +model AlipayOpenApiGenericResponse { + httpBody: string(name='http_body', description='响应原始字符串'), + code: string(name='code'), + msg: string(name='msg'), + subCode: string(name='sub_code'), + subMsg: string(name='sub_msg') +} + +model AlipayOpenApiGenericSDKResponse { + body: string(name='body', description='订单信息,字符串形式') +} + +api execute(method: string, textParams: map[string]string, bizParams: map[string]any): AlipayOpenApiGenericResponse { + var systemParams: map[string]string = { + method = method, + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = 'application/x-www-form-urlencoded;charset=utf-8' + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toUrlEncodedRequestBody(bizParams); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, method); + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 15000, + readTimeout = 15000, + retry = { + maxAttempts = 0 + } +} + + +api fileExecute(method: string, textParams: map[string]string, bizParams: map[string]any, fileParams: map[string]string): AlipayOpenApiGenericResponse { + var systemParams: map[string]string = { + method = method, + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var boundary = @kernel.getRandomBoundary(); + + __request.protocol = @kernel.getConfig("protocol"); + __request.method = 'POST'; + __request.pathname = '/gateway.do'; + + __request.headers = { + host = @kernel.getConfig("gatewayHost"), + content-type = @kernel.concatStr('multipart/form-data;charset=utf-8;boundary=', boundary) + }; + + __request.query = @kernel.sortMap({ + sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig("merchantPrivateKey")), + ... systemParams, + ... textParams + }); + + __request.body = @kernel.toMultipartRequestBody(textParams, fileParams, boundary); +} returns { + var respMap: map[string]any = @kernel.readAsJson(__response, method); + if (@kernel.isCertMode()) { + if (@kernel.verify(respMap, @kernel.extractAlipayPublicKey(@kernel.getAlipayCertSN(respMap)))) { + return @kernel.toRespModel(respMap); + } + } else { + if (@kernel.verify(respMap, @kernel.getConfig("alipayPublicKey"))) { + return @kernel.toRespModel(respMap); + } + } + + throw { + message = '验签失败,请检查支付宝公钥设置是否正确。' + } + +} runtime { + ignoreSSL = @kernel.getConfig("ignoreSSL"), + httpProxy = @kernel.getConfig("httpProxy"), + connectTimeout = 100000, + readTimeout = 100000, + retry = { + maxAttempts = 0 + } +} + +api sdkExecute(method: string, textParams: map[string]string, bizParams: map[string]any): AlipayOpenApiGenericSDKResponse { + var systemParams: map[string]string = { + method = method, + app_id = @kernel.getConfig("appId"), + timestamp = @kernel.getTimestamp(), + format = 'json', + version = '1.0', + alipay_sdk = @kernel.getSdkVersion(), + charset = 'UTF-8', + sign_type = @kernel.getConfig("signType"), + app_cert_sn = @kernel.getMerchantCertSN(), + alipay_root_cert_sn = @kernel.getAlipayRootCertSN() + }; + + var sign = @kernel.sign(systemParams, bizParams, textParams, @kernel.getConfig('merchantPrivateKey')); + + var response: map[string]string = { + body = @kernel.generateOrderString(systemParams, bizParams, textParams, sign) + }; + return response; +} + diff --git a/serve/vendor/autoload.php b/serve/vendor/autoload.php new file mode 100644 index 0000000..9428aab --- /dev/null +++ b/serve/vendor/autoload.php @@ -0,0 +1,7 @@ +writeFile('Hello World!', 'qrcode.png'); +``` + +## Available image renderer back ends +BaconQrCode comes with multiple back ends for rendering images. Currently included are the following: + +- `ImagickImageBackEnd`: renders raster images using the Imagick library +- `SvgImageBackEnd`: renders SVG files using XMLWriter +- `EpsImageBackEnd`: renders EPS files diff --git a/serve/vendor/bacon/bacon-qr-code/composer.json b/serve/vendor/bacon/bacon-qr-code/composer.json new file mode 100644 index 0000000..b240199 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/composer.json @@ -0,0 +1,32 @@ +{ + "name": "bacon/bacon-qr-code", + "description": "BaconQrCode is a QR code generator for PHP.", + "license" : "BSD-2-Clause", + "homepage": "https://github.com/Bacon/BaconQrCode", + "require": { + "php": "^7.1 || ^8.0", + "ext-iconv": "*", + "dasprid/enum": "^1.0.3" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "require-dev": { + "phpunit/phpunit": "^7 | ^8 | ^9", + "squizlabs/php_codesniffer": "^3.4", + "phly/keep-a-changelog": "^1.4" + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/phpunit.xml.dist b/serve/vendor/bacon/bacon-qr-code/phpunit.xml.dist new file mode 100644 index 0000000..4d2f9cf --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/phpunit.xml.dist @@ -0,0 +1,17 @@ + + + + + ./test + + + + + + src + + + diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/BitArray.php b/serve/vendor/bacon/bacon-qr-code/src/Common/BitArray.php new file mode 100644 index 0000000..158384f --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/BitArray.php @@ -0,0 +1,372 @@ + + */ + private $bits; + + /** + * Size of the bit array in bits. + * + * @var int + */ + private $size; + + /** + * Creates a new bit array with a given size. + */ + public function __construct(int $size = 0) + { + $this->size = $size; + $this->bits = SplFixedArray::fromArray(array_fill(0, ($this->size + 31) >> 3, 0)); + } + + /** + * Gets the size in bits. + */ + public function getSize() : int + { + return $this->size; + } + + /** + * Gets the size in bytes. + */ + public function getSizeInBytes() : int + { + return ($this->size + 7) >> 3; + } + + /** + * Ensures that the array has a minimum capacity. + */ + public function ensureCapacity(int $size) : void + { + if ($size > count($this->bits) << 5) { + $this->bits->setSize(($size + 31) >> 5); + } + } + + /** + * Gets a specific bit. + */ + public function get(int $i) : bool + { + return 0 !== ($this->bits[$i >> 5] & (1 << ($i & 0x1f))); + } + + /** + * Sets a specific bit. + */ + public function set(int $i) : void + { + $this->bits[$i >> 5] = $this->bits[$i >> 5] | 1 << ($i & 0x1f); + } + + /** + * Flips a specific bit. + */ + public function flip(int $i) : void + { + $this->bits[$i >> 5] ^= 1 << ($i & 0x1f); + } + + /** + * Gets the next set bit position from a given position. + */ + public function getNextSet(int $from) : int + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = $this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while (0 === $currentBits) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = $this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + return $result > $this->size ? $this->size : $result; + } + + /** + * Gets the next unset bit position from a given position. + */ + public function getNextUnset(int $from) : int + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = ~$this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while (0 === $currentBits) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = ~$this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + return $result > $this->size ? $this->size : $result; + } + + /** + * Sets a bulk of bits. + */ + public function setBulk(int $i, int $newBits) : void + { + $this->bits[$i >> 5] = $newBits; + } + + /** + * Sets a range of bits. + * + * @throws InvalidArgumentException if end is smaller than start + */ + public function setRange(int $start, int $end) : void + { + if ($end < $start) { + throw new InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return; + } + + --$end; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; ++$i) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if (0 === $firstBit && 31 === $lastBit) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j < $lastBit; ++$j) { + $mask |= 1 << $j; + } + } + + $this->bits[$i] = $this->bits[$i] | $mask; + } + } + + /** + * Clears the bit array, unsetting every bit. + */ + public function clear() : void + { + $bitsLength = count($this->bits); + + for ($i = 0; $i < $bitsLength; ++$i) { + $this->bits[$i] = 0; + } + } + + /** + * Checks if a range of bits is set or not set. + + * @throws InvalidArgumentException if end is smaller than start + */ + public function isRange(int $start, int $end, bool $value) : bool + { + if ($end < $start) { + throw new InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return true; + } + + --$end; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; ++$i) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if (0 === $firstBit && 31 === $lastBit) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j <= $lastBit; ++$j) { + $mask |= 1 << $j; + } + } + + if (($this->bits[$i] & $mask) !== ($value ? $mask : 0)) { + return false; + } + } + + return true; + } + + /** + * Appends a bit to the array. + */ + public function appendBit(bool $bit) : void + { + $this->ensureCapacity($this->size + 1); + + if ($bit) { + $this->bits[$this->size >> 5] = $this->bits[$this->size >> 5] | (1 << ($this->size & 0x1f)); + } + + ++$this->size; + } + + /** + * Appends a number of bits (up to 32) to the array. + + * @throws InvalidArgumentException if num bits is not between 0 and 32 + */ + public function appendBits(int $value, int $numBits) : void + { + if ($numBits < 0 || $numBits > 32) { + throw new InvalidArgumentException('Num bits must be between 0 and 32'); + } + + $this->ensureCapacity($this->size + $numBits); + + for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) { + $this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) === 1); + } + } + + /** + * Appends another bit array to this array. + */ + public function appendBitArray(self $other) : void + { + $otherSize = $other->getSize(); + $this->ensureCapacity($this->size + $other->getSize()); + + for ($i = 0; $i < $otherSize; ++$i) { + $this->appendBit($other->get($i)); + } + } + + /** + * Makes an exclusive-or comparision on the current bit array. + * + * @throws InvalidArgumentException if sizes don't match + */ + public function xorBits(self $other) : void + { + $bitsLength = count($this->bits); + $otherBits = $other->getBitArray(); + + if ($bitsLength !== count($otherBits)) { + throw new InvalidArgumentException('Sizes don\'t match'); + } + + for ($i = 0; $i < $bitsLength; ++$i) { + $this->bits[$i] = $this->bits[$i] ^ $otherBits[$i]; + } + } + + /** + * Converts the bit array to a byte array. + * + * @return SplFixedArray + */ + public function toBytes(int $bitOffset, int $numBytes) : SplFixedArray + { + $bytes = new SplFixedArray($numBytes); + + for ($i = 0; $i < $numBytes; ++$i) { + $byte = 0; + + for ($j = 0; $j < 8; ++$j) { + if ($this->get($bitOffset)) { + $byte |= 1 << (7 - $j); + } + + ++$bitOffset; + } + + $bytes[$i] = $byte; + } + + return $bytes; + } + + /** + * Gets the internal bit array. + * + * @return SplFixedArray + */ + public function getBitArray() : SplFixedArray + { + return $this->bits; + } + + /** + * Reverses the array. + */ + public function reverse() : void + { + $newBits = new SplFixedArray(count($this->bits)); + + for ($i = 0; $i < $this->size; ++$i) { + if ($this->get($this->size - $i - 1)) { + $newBits[$i >> 5] = $newBits[$i >> 5] | (1 << ($i & 0x1f)); + } + } + + $this->bits = $newBits; + } + + /** + * Returns a string representation of the bit array. + */ + public function __toString() : string + { + $result = ''; + + for ($i = 0; $i < $this->size; ++$i) { + if (0 === ($i & 0x07)) { + $result .= ' '; + } + + $result .= $this->get($i) ? 'X' : '.'; + } + + return $result; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php b/serve/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php new file mode 100644 index 0000000..10bf8fe --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php @@ -0,0 +1,313 @@ + + */ + private $bits; + + /** + * @throws InvalidArgumentException if a dimension is smaller than zero + */ + public function __construct(int $width, int $height = null) + { + if (null === $height) { + $height = $width; + } + + if ($width < 1 || $height < 1) { + throw new InvalidArgumentException('Both dimensions must be greater than zero'); + } + + $this->width = $width; + $this->height = $height; + $this->rowSize = ($width + 31) >> 5; + $this->bits = SplFixedArray::fromArray(array_fill(0, $this->rowSize * $height, 0)); + } + + /** + * Gets the requested bit, where true means black. + */ + public function get(int $x, int $y) : bool + { + $offset = $y * $this->rowSize + ($x >> 5); + return 0 !== (BitUtils::unsignedRightShift($this->bits[$offset], ($x & 0x1f)) & 1); + } + + /** + * Sets the given bit to true. + */ + public function set(int $x, int $y) : void + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] | (1 << ($x & 0x1f)); + } + + /** + * Flips the given bit. + */ + public function flip(int $x, int $y) : void + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] ^ (1 << ($x & 0x1f)); + } + + /** + * Clears all bits (set to false). + */ + public function clear() : void + { + $max = count($this->bits); + + for ($i = 0; $i < $max; ++$i) { + $this->bits[$i] = 0; + } + } + + /** + * Sets a square region of the bit matrix to true. + * + * @throws InvalidArgumentException if left or top are negative + * @throws InvalidArgumentException if width or height are smaller than 1 + * @throws InvalidArgumentException if region does not fit into the matix + */ + public function setRegion(int $left, int $top, int $width, int $height) : void + { + if ($top < 0 || $left < 0) { + throw new InvalidArgumentException('Left and top must be non-negative'); + } + + if ($height < 1 || $width < 1) { + throw new InvalidArgumentException('Width and height must be at least 1'); + } + + $right = $left + $width; + $bottom = $top + $height; + + if ($bottom > $this->height || $right > $this->width) { + throw new InvalidArgumentException('The region must fit inside the matrix'); + } + + for ($y = $top; $y < $bottom; ++$y) { + $offset = $y * $this->rowSize; + + for ($x = $left; $x < $right; ++$x) { + $index = $offset + ($x >> 5); + $this->bits[$index] = $this->bits[$index] | (1 << ($x & 0x1f)); + } + } + } + + /** + * A fast method to retrieve one row of data from the matrix as a BitArray. + */ + public function getRow(int $y, BitArray $row = null) : BitArray + { + if (null === $row || $row->getSize() < $this->width) { + $row = new BitArray($this->width); + } + + $offset = $y * $this->rowSize; + + for ($x = 0; $x < $this->rowSize; ++$x) { + $row->setBulk($x << 5, $this->bits[$offset + $x]); + } + + return $row; + } + + /** + * Sets a row of data from a BitArray. + */ + public function setRow(int $y, BitArray $row) : void + { + $bits = $row->getBitArray(); + + for ($i = 0; $i < $this->rowSize; ++$i) { + $this->bits[$y * $this->rowSize + $i] = $bits[$i]; + } + } + + /** + * This is useful in detecting the enclosing rectangle of a 'pure' barcode. + * + * @return int[]|null + */ + public function getEnclosingRectangle() : ?array + { + $left = $this->width; + $top = $this->height; + $right = -1; + $bottom = -1; + + for ($y = 0; $y < $this->height; ++$y) { + for ($x32 = 0; $x32 < $this->rowSize; ++$x32) { + $bits = $this->bits[$y * $this->rowSize + $x32]; + + if (0 !== $bits) { + if ($y < $top) { + $top = $y; + } + + if ($y > $bottom) { + $bottom = $y; + } + + if ($x32 * 32 < $left) { + $bit = 0; + + while (($bits << (31 - $bit)) === 0) { + $bit++; + } + + if (($x32 * 32 + $bit) < $left) { + $left = $x32 * 32 + $bit; + } + } + } + + if ($x32 * 32 + 31 > $right) { + $bit = 31; + + while (0 === BitUtils::unsignedRightShift($bits, $bit)) { + --$bit; + } + + if (($x32 * 32 + $bit) > $right) { + $right = $x32 * 32 + $bit; + } + } + } + } + + $width = $right - $left; + $height = $bottom - $top; + + if ($width < 0 || $height < 0) { + return null; + } + + return [$left, $top, $width, $height]; + } + + /** + * Gets the most top left set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return int[]|null + */ + public function getTopLeftOnBit() : ?array + { + $bitsOffset = 0; + + while ($bitsOffset < count($this->bits) && 0 === $this->bits[$bitsOffset]) { + ++$bitsOffset; + } + + if (count($this->bits) === $bitsOffset) { + return null; + } + + $x = intdiv($bitsOffset, $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (0 === ($bits << (31 - $bit))) { + ++$bit; + } + + $x += $bit; + + return [$x, $y]; + } + + /** + * Gets the most bottom right set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return int[]|null + */ + public function getBottomRightOnBit() : ?array + { + $bitsOffset = count($this->bits) - 1; + + while ($bitsOffset >= 0 && 0 === $this->bits[$bitsOffset]) { + --$bitsOffset; + } + + if ($bitsOffset < 0) { + return null; + } + + $x = intdiv($bitsOffset, $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (0 === BitUtils::unsignedRightShift($bits, $bit)) { + --$bit; + } + + $x += $bit; + + return [$x, $y]; + } + + /** + * Gets the width of the matrix, + */ + public function getWidth() : int + { + return $this->width; + } + + /** + * Gets the height of the matrix. + */ + public function getHeight() : int + { + return $this->height; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php b/serve/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php new file mode 100644 index 0000000..0c575b4 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php @@ -0,0 +1,41 @@ +>>" in other + * languages. + */ + public static function unsignedRightShift(int $a, int $b) : int + { + return ( + $a >= 0 + ? $a >> $b + : (($a & 0x7fffffff) >> $b) | (0x40000000 >> ($b - 1)) + ); + } + + /** + * Gets the number of trailing zeros. + */ + public static function numberOfTrailingZeros(int $i) : int + { + $lastPos = strrpos(str_pad(decbin($i), 32, '0', STR_PAD_LEFT), '1'); + return $lastPos === false ? 32 : 31 - $lastPos; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php b/serve/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php new file mode 100644 index 0000000..6dfff17 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php @@ -0,0 +1,180 @@ +|null + */ + private static $valueToEci; + + /** + * @var array|null + */ + private static $nameToEci; + + public function __construct(array $values, string ...$otherEncodingNames) + { + $this->values = $values; + $this->otherEncodingNames = $otherEncodingNames; + } + + /** + * Returns the primary value. + */ + public function getValue() : int + { + return $this->values[0]; + } + + /** + * Gets character set ECI by value. + * + * Returns the representing ECI of a given value, or null if it is legal but unsupported. + * + * @throws InvalidArgumentException if value is not between 0 and 900 + */ + public static function getCharacterSetEciByValue(int $value) : ?self + { + if ($value < 0 || $value >= 900) { + throw new InvalidArgumentException('Value must be between 0 and 900'); + } + + $valueToEci = self::valueToEci(); + + if (! array_key_exists($value, $valueToEci)) { + return null; + } + + return $valueToEci[$value]; + } + + /** + * Returns character set ECI by name. + * + * Returns the representing ECI of a given name, or null if it is legal but unsupported + */ + public static function getCharacterSetEciByName(string $name) : ?self + { + $nameToEci = self::nameToEci(); + $name = strtolower($name); + + if (! array_key_exists($name, $nameToEci)) { + return null; + } + + return $nameToEci[$name]; + } + + private static function valueToEci() : array + { + if (null !== self::$valueToEci) { + return self::$valueToEci; + } + + self::$valueToEci = []; + + foreach (self::values() as $eci) { + foreach ($eci->values as $value) { + self::$valueToEci[$value] = $eci; + } + } + + return self::$valueToEci; + } + + private static function nameToEci() : array + { + if (null !== self::$nameToEci) { + return self::$nameToEci; + } + + self::$nameToEci = []; + + foreach (self::values() as $eci) { + self::$nameToEci[strtolower($eci->name())] = $eci; + + foreach ($eci->otherEncodingNames as $name) { + self::$nameToEci[strtolower($name)] = $eci; + } + } + + return self::$nameToEci; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php b/serve/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php new file mode 100644 index 0000000..a9a1d07 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php @@ -0,0 +1,49 @@ +count = $count; + $this->dataCodewords = $dataCodewords; + } + + /** + * Returns how many times the block is used. + */ + public function getCount() : int + { + return $this->count; + } + + /** + * Returns the number of data codewords. + */ + public function getDataCodewords() : int + { + return $this->dataCodewords; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php b/serve/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php new file mode 100644 index 0000000..172b5f2 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php @@ -0,0 +1,74 @@ +ecCodewordsPerBlock = $ecCodewordsPerBlock; + $this->ecBlocks = $ecBlocks; + } + + /** + * Returns the number of EC codewords per block. + */ + public function getEcCodewordsPerBlock() : int + { + return $this->ecCodewordsPerBlock; + } + + /** + * Returns the total number of EC block appearances. + */ + public function getNumBlocks() : int + { + $total = 0; + + foreach ($this->ecBlocks as $ecBlock) { + $total += $ecBlock->getCount(); + } + + return $total; + } + + /** + * Returns the total count of EC codewords. + */ + public function getTotalEcCodewords() : int + { + return $this->ecCodewordsPerBlock * $this->getNumBlocks(); + } + + /** + * Returns the EC blocks included in this collection. + * + * @return EcBlock[] + */ + public function getEcBlocks() : array + { + return $this->ecBlocks; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php b/serve/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php new file mode 100644 index 0000000..9bbf440 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php @@ -0,0 +1,63 @@ +bits = $bits; + } + + /** + * @throws OutOfBoundsException if number of bits is invalid + */ + public static function forBits(int $bits) : self + { + switch ($bits) { + case 0: + return self::M(); + + case 1: + return self::L(); + + case 2: + return self::H(); + + case 3: + return self::Q(); + } + + throw new OutOfBoundsException('Invalid number of bits'); + } + + /** + * Returns the two bits used to encode this error correction level. + */ + public function getBits() : int + { + return $this->bits; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php b/serve/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php new file mode 100644 index 0000000..53e3541 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php @@ -0,0 +1,203 @@ +ecLevel = ErrorCorrectionLevel::forBits(($formatInfo >> 3) & 0x3); + $this->dataMask = $formatInfo & 0x7; + } + + /** + * Checks how many bits are different between two integers. + */ + public static function numBitsDiffering(int $a, int $b) : int + { + $a ^= $b; + + return ( + self::BITS_SET_IN_HALF_BYTE[$a & 0xf] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 4) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 8) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 12) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 16) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 20) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 24) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 28) & 0xf)] + ); + } + + /** + * Decodes format information. + */ + public static function decodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self + { + $formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2); + + if (null !== $formatInfo) { + return $formatInfo; + } + + // Should return null, but, some QR codes apparently do not mask this info. Try again by actually masking the + // pattern first. + return self::doDecodeFormatInformation( + $maskedFormatInfo1 ^ self::FORMAT_INFO_MASK_QR, + $maskedFormatInfo2 ^ self::FORMAT_INFO_MASK_QR + ); + } + + /** + * Internal method for decoding format information. + */ + private static function doDecodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self + { + $bestDifference = PHP_INT_MAX; + $bestFormatInfo = 0; + + foreach (self::FORMAT_INFO_DECODE_LOOKUP as $decodeInfo) { + $targetInfo = $decodeInfo[0]; + + if ($targetInfo === $maskedFormatInfo1 || $targetInfo === $maskedFormatInfo2) { + // Found an exact match + return new self($decodeInfo[1]); + } + + $bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + + if ($maskedFormatInfo1 !== $maskedFormatInfo2) { + // Also try the other option + $bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + } + } + + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match. + if ($bestDifference <= 3) { + return new self($bestFormatInfo); + } + + return null; + } + + /** + * Returns the error correction level. + */ + public function getErrorCorrectionLevel() : ErrorCorrectionLevel + { + return $this->ecLevel; + } + + /** + * Returns the data mask. + */ + public function getDataMask() : int + { + return $this->dataMask; + } + + /** + * Hashes the code of the EC level. + */ + public function hashCode() : int + { + return ($this->ecLevel->getBits() << 3) | $this->dataMask; + } + + /** + * Verifies if this instance equals another one. + */ + public function equals(self $other) : bool + { + return ( + $this->ecLevel === $other->ecLevel + && $this->dataMask === $other->dataMask + ); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/Mode.php b/serve/vendor/bacon/bacon-qr-code/src/Common/Mode.php new file mode 100644 index 0000000..51e6c9a --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/Mode.php @@ -0,0 +1,76 @@ +characterCountBitsForVersions = $characterCountBitsForVersions; + $this->bits = $bits; + } + + /** + * Returns the number of bits used in a specific QR code version. + */ + public function getCharacterCountBits(Version $version) : int + { + $number = $version->getVersionNumber(); + + if ($number <= 9) { + $offset = 0; + } elseif ($number <= 26) { + $offset = 1; + } else { + $offset = 2; + } + + return $this->characterCountBitsForVersions[$offset]; + } + + /** + * Returns the four bits used to encode this mode. + */ + public function getBits() : int + { + return $this->bits; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php b/serve/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php new file mode 100644 index 0000000..a5aad0b --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php @@ -0,0 +1,468 @@ + 8) { + throw new InvalidArgumentException('Symbol size must be between 0 and 8'); + } + + if ($firstRoot < 0 || $firstRoot >= (1 << $symbolSize)) { + throw new InvalidArgumentException('First root must be between 0 and ' . (1 << $symbolSize)); + } + + if ($numRoots < 0 || $numRoots >= (1 << $symbolSize)) { + throw new InvalidArgumentException('Num roots must be between 0 and ' . (1 << $symbolSize)); + } + + if ($padding < 0 || $padding >= ((1 << $symbolSize) - 1 - $numRoots)) { + throw new InvalidArgumentException( + 'Padding must be between 0 and ' . ((1 << $symbolSize) - 1 - $numRoots) + ); + } + + $this->symbolSize = $symbolSize; + $this->blockSize = (1 << $symbolSize) - 1; + $this->padding = $padding; + $this->alphaTo = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + $this->indexOf = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + + // Generate galous field lookup table + $this->indexOf[0] = $this->blockSize; + $this->alphaTo[$this->blockSize] = 0; + + $sr = 1; + + for ($i = 0; $i < $this->blockSize; ++$i) { + $this->indexOf[$sr] = $i; + $this->alphaTo[$i] = $sr; + + $sr <<= 1; + + if ($sr & (1 << $symbolSize)) { + $sr ^= $gfPoly; + } + + $sr &= $this->blockSize; + } + + if (1 !== $sr) { + throw new RuntimeException('Field generator polynomial is not primitive'); + } + + // Form RS code generator polynomial from its roots + $this->generatorPoly = SplFixedArray::fromArray(array_fill(0, $numRoots + 1, 0), false); + $this->firstRoot = $firstRoot; + $this->primitive = $primitive; + $this->numRoots = $numRoots; + + // Find prim-th root of 1, used in decoding + for ($iPrimitive = 1; ($iPrimitive % $primitive) !== 0; $iPrimitive += $this->blockSize) { + } + + $this->iPrimitive = intdiv($iPrimitive, $primitive); + + $this->generatorPoly[0] = 1; + + for ($i = 0, $root = $firstRoot * $primitive; $i < $numRoots; ++$i, $root += $primitive) { + $this->generatorPoly[$i + 1] = 1; + + for ($j = $i; $j > 0; $j--) { + if ($this->generatorPoly[$j] !== 0) { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1] ^ $this->alphaTo[ + $this->modNn($this->indexOf[$this->generatorPoly[$j]] + $root) + ]; + } else { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1]; + } + } + + $this->generatorPoly[$j] = $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[0]] + $root)]; + } + + // Convert generator poly to index form for quicker encoding + for ($i = 0; $i <= $numRoots; ++$i) { + $this->generatorPoly[$i] = $this->indexOf[$this->generatorPoly[$i]]; + } + } + + /** + * Encodes data and writes result back into parity array. + */ + public function encode(SplFixedArray $data, SplFixedArray $parity) : void + { + for ($i = 0; $i < $this->numRoots; ++$i) { + $parity[$i] = 0; + } + + $iterations = $this->blockSize - $this->numRoots - $this->padding; + + for ($i = 0; $i < $iterations; ++$i) { + $feedback = $this->indexOf[$data[$i] ^ $parity[0]]; + + if ($feedback !== $this->blockSize) { + // Feedback term is non-zero + $feedback = $this->modNn($this->blockSize - $this->generatorPoly[$this->numRoots] + $feedback); + + for ($j = 1; $j < $this->numRoots; ++$j) { + $parity[$j] = $parity[$j] ^ $this->alphaTo[ + $this->modNn($feedback + $this->generatorPoly[$this->numRoots - $j]) + ]; + } + } + + for ($j = 0; $j < $this->numRoots - 1; ++$j) { + $parity[$j] = $parity[$j + 1]; + } + + if ($feedback !== $this->blockSize) { + $parity[$this->numRoots - 1] = $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[0])]; + } else { + $parity[$this->numRoots - 1] = 0; + } + } + } + + /** + * Decodes received data. + */ + public function decode(SplFixedArray $data, SplFixedArray $erasures = null) : ?int + { + // This speeds up the initialization a bit. + $numRootsPlusOne = SplFixedArray::fromArray(array_fill(0, $this->numRoots + 1, 0), false); + $numRoots = SplFixedArray::fromArray(array_fill(0, $this->numRoots, 0), false); + + $lambda = clone $numRootsPlusOne; + $b = clone $numRootsPlusOne; + $t = clone $numRootsPlusOne; + $omega = clone $numRootsPlusOne; + $root = clone $numRoots; + $loc = clone $numRoots; + + $numErasures = (null !== $erasures ? count($erasures) : 0); + + // Form the Syndromes; i.e., evaluate data(x) at roots of g(x) + $syndromes = SplFixedArray::fromArray(array_fill(0, $this->numRoots, $data[0]), false); + + for ($i = 1; $i < $this->blockSize - $this->padding; ++$i) { + for ($j = 0; $j < $this->numRoots; ++$j) { + if ($syndromes[$j] === 0) { + $syndromes[$j] = $data[$i]; + } else { + $syndromes[$j] = $data[$i] ^ $this->alphaTo[ + $this->modNn($this->indexOf[$syndromes[$j]] + ($this->firstRoot + $j) * $this->primitive) + ]; + } + } + } + + // Convert syndromes to index form, checking for nonzero conditions + $syndromeError = 0; + + for ($i = 0; $i < $this->numRoots; ++$i) { + $syndromeError |= $syndromes[$i]; + $syndromes[$i] = $this->indexOf[$syndromes[$i]]; + } + + if (! $syndromeError) { + // If syndrome is zero, data[] is a codeword and there are no errors to correct, so return data[] + // unmodified. + return 0; + } + + $lambda[0] = 1; + + if ($numErasures > 0) { + // Init lambda to be the erasure locator polynomial + $lambda[1] = $this->alphaTo[$this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[0]))]; + + for ($i = 1; $i < $numErasures; ++$i) { + $u = $this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[$i])); + + for ($j = $i + 1; $j > 0; --$j) { + $tmp = $this->indexOf[$lambda[$j - 1]]; + + if ($tmp !== $this->blockSize) { + $lambda[$j] = $lambda[$j] ^ $this->alphaTo[$this->modNn($u + $tmp)]; + } + } + } + } + + for ($i = 0; $i <= $this->numRoots; ++$i) { + $b[$i] = $this->indexOf[$lambda[$i]]; + } + + // Begin Berlekamp-Massey algorithm to determine error+erasure locator polynomial + $r = $numErasures; + $el = $numErasures; + + while (++$r <= $this->numRoots) { + // Compute discrepancy at the r-th step in poly form + $discrepancyR = 0; + + for ($i = 0; $i < $r; ++$i) { + if ($lambda[$i] !== 0 && $syndromes[$r - $i - 1] !== $this->blockSize) { + $discrepancyR ^= $this->alphaTo[ + $this->modNn($this->indexOf[$lambda[$i]] + $syndromes[$r - $i - 1]) + ]; + } + } + + $discrepancyR = $this->indexOf[$discrepancyR]; + + if ($discrepancyR === $this->blockSize) { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + continue; + } + + $t[0] = $lambda[0]; + + for ($i = 0; $i < $this->numRoots; ++$i) { + if ($b[$i] !== $this->blockSize) { + $t[$i + 1] = $lambda[$i + 1] ^ $this->alphaTo[$this->modNn($discrepancyR + $b[$i])]; + } else { + $t[$i + 1] = $lambda[$i + 1]; + } + } + + if (2 * $el <= $r + $numErasures - 1) { + $el = $r + $numErasures - $el; + + for ($i = 0; $i <= $this->numRoots; ++$i) { + $b[$i] = ( + $lambda[$i] === 0 + ? $this->blockSize + : $this->modNn($this->indexOf[$lambda[$i]] - $discrepancyR + $this->blockSize) + ); + } + } else { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + } + + $lambda = clone $t; + } + + // Convert lambda to index form and compute deg(lambda(x)) + $degLambda = 0; + + for ($i = 0; $i <= $this->numRoots; ++$i) { + $lambda[$i] = $this->indexOf[$lambda[$i]]; + + if ($lambda[$i] !== $this->blockSize) { + $degLambda = $i; + } + } + + // Find roots of the error+erasure locator polynomial by Chien search. + $reg = clone $lambda; + $reg[0] = 0; + $count = 0; + $i = 1; + + for ($k = $this->iPrimitive - 1; $i <= $this->blockSize; ++$i, $k = $this->modNn($k + $this->iPrimitive)) { + $q = 1; + + for ($j = $degLambda; $j > 0; $j--) { + if ($reg[$j] !== $this->blockSize) { + $reg[$j] = $this->modNn($reg[$j] + $j); + $q ^= $this->alphaTo[$reg[$j]]; + } + } + + if ($q !== 0) { + // Not a root + continue; + } + + // Store root (index-form) and error location number + $root[$count] = $i; + $loc[$count] = $k; + + if (++$count === $degLambda) { + break; + } + } + + if ($degLambda !== $count) { + // deg(lambda) unequal to number of roots: uncorrectable error detected + return null; + } + + // Compute err+eras evaluate poly omega(x) = s(x)*lambda(x) (modulo x**numRoots). In index form. Also find + // deg(omega). + $degOmega = $degLambda - 1; + + for ($i = 0; $i <= $degOmega; ++$i) { + $tmp = 0; + + for ($j = $i; $j >= 0; --$j) { + if ($syndromes[$i - $j] !== $this->blockSize && $lambda[$j] !== $this->blockSize) { + $tmp ^= $this->alphaTo[$this->modNn($syndromes[$i - $j] + $lambda[$j])]; + } + } + + $omega[$i] = $this->indexOf[$tmp]; + } + + // Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = inv(X(l))**(firstRoot-1) and + // den = lambda_pr(inv(X(l))) all in poly form. + for ($j = $count - 1; $j >= 0; --$j) { + $num1 = 0; + + for ($i = $degOmega; $i >= 0; $i--) { + if ($omega[$i] !== $this->blockSize) { + $num1 ^= $this->alphaTo[$this->modNn($omega[$i] + $i * $root[$j])]; + } + } + + $num2 = $this->alphaTo[$this->modNn($root[$j] * ($this->firstRoot - 1) + $this->blockSize)]; + $den = 0; + + // lambda[i+1] for i even is the formal derivativelambda_pr of lambda[i] + for ($i = min($degLambda, $this->numRoots - 1) & ~1; $i >= 0; $i -= 2) { + if ($lambda[$i + 1] !== $this->blockSize) { + $den ^= $this->alphaTo[$this->modNn($lambda[$i + 1] + $i * $root[$j])]; + } + } + + // Apply error to data + if ($num1 !== 0 && $loc[$j] >= $this->padding) { + $data[$loc[$j] - $this->padding] = $data[$loc[$j] - $this->padding] ^ ( + $this->alphaTo[ + $this->modNn( + $this->indexOf[$num1] + $this->indexOf[$num2] + $this->blockSize - $this->indexOf[$den] + ) + ] + ); + } + } + + if (null !== $erasures) { + if (count($erasures) < $count) { + $erasures->setSize($count); + } + + for ($i = 0; $i < $count; $i++) { + $erasures[$i] = $loc[$i]; + } + } + + return $count; + } + + /** + * Computes $x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, without a slow divide. + */ + private function modNn(int $x) : int + { + while ($x >= $this->blockSize) { + $x -= $this->blockSize; + $x = ($x >> $this->symbolSize) + ($x & $this->blockSize); + } + + return $x; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Common/Version.php b/serve/vendor/bacon/bacon-qr-code/src/Common/Version.php new file mode 100644 index 0000000..917d048 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Common/Version.php @@ -0,0 +1,596 @@ +|null + */ + private static $versions; + + /** + * @param int[] $alignmentPatternCenters + */ + private function __construct( + int $versionNumber, + array $alignmentPatternCenters, + EcBlocks ...$ecBlocks + ) { + $this->versionNumber = $versionNumber; + $this->alignmentPatternCenters = $alignmentPatternCenters; + $this->ecBlocks = $ecBlocks; + + $totalCodewords = 0; + $ecCodewords = $ecBlocks[0]->getEcCodewordsPerBlock(); + + foreach ($ecBlocks[0]->getEcBlocks() as $ecBlock) { + $totalCodewords += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords); + } + + $this->totalCodewords = $totalCodewords; + } + + /** + * Returns the version number. + */ + public function getVersionNumber() : int + { + return $this->versionNumber; + } + + /** + * Returns the alignment pattern centers. + * + * @return int[] + */ + public function getAlignmentPatternCenters() : array + { + return $this->alignmentPatternCenters; + } + + /** + * Returns the total number of codewords. + */ + public function getTotalCodewords() : int + { + return $this->totalCodewords; + } + + /** + * Calculates the dimension for the current version. + */ + public function getDimensionForVersion() : int + { + return 17 + 4 * $this->versionNumber; + } + + /** + * Returns the number of EC blocks for a specific EC level. + */ + public function getEcBlocksForLevel(ErrorCorrectionLevel $ecLevel) : EcBlocks + { + return $this->ecBlocks[$ecLevel->ordinal()]; + } + + /** + * Gets a provisional version number for a specific dimension. + * + * @throws InvalidArgumentException if dimension is not 1 mod 4 + */ + public static function getProvisionalVersionForDimension(int $dimension) : self + { + if (1 !== $dimension % 4) { + throw new InvalidArgumentException('Dimension is not 1 mod 4'); + } + + return self::getVersionForNumber(intdiv($dimension - 17, 4)); + } + + /** + * Gets a version instance for a specific version number. + * + * @throws InvalidArgumentException if version number is out of range + */ + public static function getVersionForNumber(int $versionNumber) : self + { + if ($versionNumber < 1 || $versionNumber > 40) { + throw new InvalidArgumentException('Version number must be between 1 and 40'); + } + + return self::versions()[$versionNumber - 1]; + } + + /** + * Decodes version information from an integer and returns the version. + */ + public static function decodeVersionInformation(int $versionBits) : ?self + { + $bestDifference = PHP_INT_MAX; + $bestVersion = 0; + + foreach (self::VERSION_DECODE_INFO as $i => $targetVersion) { + if ($targetVersion === $versionBits) { + return self::getVersionForNumber($i + 7); + } + + $bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion); + + if ($bitsDifference < $bestDifference) { + $bestVersion = $i + 7; + $bestDifference = $bitsDifference; + } + } + + if ($bestDifference <= 3) { + return self::getVersionForNumber($bestVersion); + } + + return null; + } + + /** + * Builds the function pattern for the current version. + */ + public function buildFunctionPattern() : BitMatrix + { + $dimension = $this->getDimensionForVersion(); + $bitMatrix = new BitMatrix($dimension); + + // Top left finder pattern + separator + format + $bitMatrix->setRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + $bitMatrix->setRegion($dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + $bitMatrix->setRegion(0, $dimension - 8, 9, 8); + + // Alignment patterns + $max = count($this->alignmentPatternCenters); + + for ($x = 0; $x < $max; ++$x) { + $i = $this->alignmentPatternCenters[$x] - 2; + + for ($y = 0; $y < $max; ++$y) { + if (($x === 0 && ($y === 0 || $y === $max - 1)) || ($x === $max - 1 && $y === 0)) { + // No alignment patterns near the three finder paterns + continue; + } + + $bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5); + } + } + + // Vertical timing pattern + $bitMatrix->setRegion(6, 9, 1, $dimension - 17); + // Horizontal timing pattern + $bitMatrix->setRegion(9, 6, $dimension - 17, 1); + + if ($this->versionNumber > 6) { + // Version info, top right + $bitMatrix->setRegion($dimension - 11, 0, 3, 6); + // Version info, bottom left + $bitMatrix->setRegion(0, $dimension - 11, 6, 3); + } + + return $bitMatrix; + } + + /** + * Returns a string representation for the version. + */ + public function __toString() : string + { + return (string) $this->versionNumber; + } + + /** + * Build and cache a specific version. + * + * See ISO 18004:2006 6.5.1 Table 9. + * + * @return array + */ + private static function versions() : array + { + if (null !== self::$versions) { + return self::$versions; + } + + return self::$versions = [ + new self( + 1, + [], + new EcBlocks(7, new EcBlock(1, 19)), + new EcBlocks(10, new EcBlock(1, 16)), + new EcBlocks(13, new EcBlock(1, 13)), + new EcBlocks(17, new EcBlock(1, 9)) + ), + new self( + 2, + [6, 18], + new EcBlocks(10, new EcBlock(1, 34)), + new EcBlocks(16, new EcBlock(1, 28)), + new EcBlocks(22, new EcBlock(1, 22)), + new EcBlocks(28, new EcBlock(1, 16)) + ), + new self( + 3, + [6, 22], + new EcBlocks(15, new EcBlock(1, 55)), + new EcBlocks(26, new EcBlock(1, 44)), + new EcBlocks(18, new EcBlock(2, 17)), + new EcBlocks(22, new EcBlock(2, 13)) + ), + new self( + 4, + [6, 26], + new EcBlocks(20, new EcBlock(1, 80)), + new EcBlocks(18, new EcBlock(2, 32)), + new EcBlocks(26, new EcBlock(3, 24)), + new EcBlocks(16, new EcBlock(4, 9)) + ), + new self( + 5, + [6, 30], + new EcBlocks(26, new EcBlock(1, 108)), + new EcBlocks(24, new EcBlock(2, 43)), + new EcBlocks(18, new EcBlock(2, 15), new EcBlock(2, 16)), + new EcBlocks(22, new EcBlock(2, 11), new EcBlock(2, 12)) + ), + new self( + 6, + [6, 34], + new EcBlocks(18, new EcBlock(2, 68)), + new EcBlocks(16, new EcBlock(4, 27)), + new EcBlocks(24, new EcBlock(4, 19)), + new EcBlocks(28, new EcBlock(4, 15)) + ), + new self( + 7, + [6, 22, 38], + new EcBlocks(20, new EcBlock(2, 78)), + new EcBlocks(18, new EcBlock(4, 31)), + new EcBlocks(18, new EcBlock(2, 14), new EcBlock(4, 15)), + new EcBlocks(26, new EcBlock(4, 13), new EcBlock(1, 14)) + ), + new self( + 8, + [6, 24, 42], + new EcBlocks(24, new EcBlock(2, 97)), + new EcBlocks(22, new EcBlock(2, 38), new EcBlock(2, 39)), + new EcBlocks(22, new EcBlock(4, 18), new EcBlock(2, 19)), + new EcBlocks(26, new EcBlock(4, 14), new EcBlock(2, 15)) + ), + new self( + 9, + [6, 26, 46], + new EcBlocks(30, new EcBlock(2, 116)), + new EcBlocks(22, new EcBlock(3, 36), new EcBlock(2, 37)), + new EcBlocks(20, new EcBlock(4, 16), new EcBlock(4, 17)), + new EcBlocks(24, new EcBlock(4, 12), new EcBlock(4, 13)) + ), + new self( + 10, + [6, 28, 50], + new EcBlocks(18, new EcBlock(2, 68), new EcBlock(2, 69)), + new EcBlocks(26, new EcBlock(4, 43), new EcBlock(1, 44)), + new EcBlocks(24, new EcBlock(6, 19), new EcBlock(2, 20)), + new EcBlocks(28, new EcBlock(6, 15), new EcBlock(2, 16)) + ), + new self( + 11, + [6, 30, 54], + new EcBlocks(20, new EcBlock(4, 81)), + new EcBlocks(30, new EcBlock(1, 50), new EcBlock(4, 51)), + new EcBlocks(28, new EcBlock(4, 22), new EcBlock(4, 23)), + new EcBlocks(24, new EcBlock(3, 12), new EcBlock(8, 13)) + ), + new self( + 12, + [6, 32, 58], + new EcBlocks(24, new EcBlock(2, 92), new EcBlock(2, 93)), + new EcBlocks(22, new EcBlock(6, 36), new EcBlock(2, 37)), + new EcBlocks(26, new EcBlock(4, 20), new EcBlock(6, 21)), + new EcBlocks(28, new EcBlock(7, 14), new EcBlock(4, 15)) + ), + new self( + 13, + [6, 34, 62], + new EcBlocks(26, new EcBlock(4, 107)), + new EcBlocks(22, new EcBlock(8, 37), new EcBlock(1, 38)), + new EcBlocks(24, new EcBlock(8, 20), new EcBlock(4, 21)), + new EcBlocks(22, new EcBlock(12, 11), new EcBlock(4, 12)) + ), + new self( + 14, + [6, 26, 46, 66], + new EcBlocks(30, new EcBlock(3, 115), new EcBlock(1, 116)), + new EcBlocks(24, new EcBlock(4, 40), new EcBlock(5, 41)), + new EcBlocks(20, new EcBlock(11, 16), new EcBlock(5, 17)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(5, 13)) + ), + new self( + 15, + [6, 26, 48, 70], + new EcBlocks(22, new EcBlock(5, 87), new EcBlock(1, 88)), + new EcBlocks(24, new EcBlock(5, 41), new EcBlock(5, 42)), + new EcBlocks(30, new EcBlock(5, 24), new EcBlock(7, 25)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(7, 13)) + ), + new self( + 16, + [6, 26, 50, 74], + new EcBlocks(24, new EcBlock(5, 98), new EcBlock(1, 99)), + new EcBlocks(28, new EcBlock(7, 45), new EcBlock(3, 46)), + new EcBlocks(24, new EcBlock(15, 19), new EcBlock(2, 20)), + new EcBlocks(30, new EcBlock(3, 15), new EcBlock(13, 16)) + ), + new self( + 17, + [6, 30, 54, 78], + new EcBlocks(28, new EcBlock(1, 107), new EcBlock(5, 108)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(1, 47)), + new EcBlocks(28, new EcBlock(1, 22), new EcBlock(15, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(17, 15)) + ), + new self( + 18, + [6, 30, 56, 82], + new EcBlocks(30, new EcBlock(5, 120), new EcBlock(1, 121)), + new EcBlocks(26, new EcBlock(9, 43), new EcBlock(4, 44)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(1, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(19, 15)) + ), + new self( + 19, + [6, 30, 58, 86], + new EcBlocks(28, new EcBlock(3, 113), new EcBlock(4, 114)), + new EcBlocks(26, new EcBlock(3, 44), new EcBlock(11, 45)), + new EcBlocks(26, new EcBlock(17, 21), new EcBlock(4, 22)), + new EcBlocks(26, new EcBlock(9, 13), new EcBlock(16, 14)) + ), + new self( + 20, + [6, 34, 62, 90], + new EcBlocks(28, new EcBlock(3, 107), new EcBlock(5, 108)), + new EcBlocks(26, new EcBlock(3, 41), new EcBlock(13, 42)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(5, 25)), + new EcBlocks(28, new EcBlock(15, 15), new EcBlock(10, 16)) + ), + new self( + 21, + [6, 28, 50, 72, 94], + new EcBlocks(28, new EcBlock(4, 116), new EcBlock(4, 117)), + new EcBlocks(26, new EcBlock(17, 42)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(19, 16), new EcBlock(6, 17)) + ), + new self( + 22, + [6, 26, 50, 74, 98], + new EcBlocks(28, new EcBlock(2, 111), new EcBlock(7, 112)), + new EcBlocks(28, new EcBlock(17, 46)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(16, 25)), + new EcBlocks(24, new EcBlock(34, 13)) + ), + new self( + 23, + [6, 30, 54, 78, 102], + new EcBlocks(30, new EcBlock(4, 121), new EcBlock(5, 122)), + new EcBlocks(28, new EcBlock(4, 47), new EcBlock(14, 48)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(16, 15), new EcBlock(14, 16)) + ), + new self( + 24, + [6, 28, 54, 80, 106], + new EcBlocks(30, new EcBlock(6, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(6, 45), new EcBlock(14, 46)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(16, 25)), + new EcBlocks(30, new EcBlock(30, 16), new EcBlock(2, 17)) + ), + new self( + 25, + [6, 32, 58, 84, 110], + new EcBlocks(26, new EcBlock(8, 106), new EcBlock(4, 107)), + new EcBlocks(28, new EcBlock(8, 47), new EcBlock(13, 48)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(13, 16)) + ), + new self( + 26, + [6, 30, 58, 86, 114], + new EcBlocks(28, new EcBlock(10, 114), new EcBlock(2, 115)), + new EcBlocks(28, new EcBlock(19, 46), new EcBlock(4, 47)), + new EcBlocks(28, new EcBlock(28, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(33, 16), new EcBlock(4, 17)) + ), + new self( + 27, + [6, 34, 62, 90, 118], + new EcBlocks(30, new EcBlock(8, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(22, 45), new EcBlock(3, 46)), + new EcBlocks(30, new EcBlock(8, 23), new EcBlock(26, 24)), + new EcBlocks(30, new EcBlock(12, 15), new EcBlock(28, 16)) + ), + new self( + 28, + [6, 26, 50, 74, 98, 122], + new EcBlocks(30, new EcBlock(3, 117), new EcBlock(10, 118)), + new EcBlocks(28, new EcBlock(3, 45), new EcBlock(23, 46)), + new EcBlocks(30, new EcBlock(4, 24), new EcBlock(31, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(31, 16)) + ), + new self( + 29, + [6, 30, 54, 78, 102, 126], + new EcBlocks(30, new EcBlock(7, 116), new EcBlock(7, 117)), + new EcBlocks(28, new EcBlock(21, 45), new EcBlock(7, 46)), + new EcBlocks(30, new EcBlock(1, 23), new EcBlock(37, 24)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(26, 16)) + ), + new self( + 30, + [6, 26, 52, 78, 104, 130], + new EcBlocks(30, new EcBlock(5, 115), new EcBlock(10, 116)), + new EcBlocks(28, new EcBlock(19, 47), new EcBlock(10, 48)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(25, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(25, 16)) + ), + new self( + 31, + [6, 30, 56, 82, 108, 134], + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(3, 116)), + new EcBlocks(28, new EcBlock(2, 46), new EcBlock(29, 47)), + new EcBlocks(30, new EcBlock(42, 24), new EcBlock(1, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(28, 16)) + ), + new self( + 32, + [6, 34, 60, 86, 112, 138], + new EcBlocks(30, new EcBlock(17, 115)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(10, 24), new EcBlock(35, 25)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(35, 16)) + ), + new self( + 33, + [6, 30, 58, 86, 114, 142], + new EcBlocks(30, new EcBlock(17, 115), new EcBlock(1, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(21, 47)), + new EcBlocks(30, new EcBlock(29, 24), new EcBlock(19, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(46, 16)) + ), + new self( + 34, + [6, 34, 62, 90, 118, 146], + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(6, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(44, 24), new EcBlock(7, 25)), + new EcBlocks(30, new EcBlock(59, 16), new EcBlock(1, 17)) + ), + new self( + 35, + [6, 30, 54, 78, 102, 126, 150], + new EcBlocks(30, new EcBlock(12, 121), new EcBlock(7, 122)), + new EcBlocks(28, new EcBlock(12, 47), new EcBlock(26, 48)), + new EcBlocks(30, new EcBlock(39, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(41, 16)) + ), + new self( + 36, + [6, 24, 50, 76, 102, 128, 154], + new EcBlocks(30, new EcBlock(6, 121), new EcBlock(14, 122)), + new EcBlocks(28, new EcBlock(6, 47), new EcBlock(34, 48)), + new EcBlocks(30, new EcBlock(46, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(2, 15), new EcBlock(64, 16)) + ), + new self( + 37, + [6, 28, 54, 80, 106, 132, 158], + new EcBlocks(30, new EcBlock(17, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(29, 46), new EcBlock(14, 47)), + new EcBlocks(30, new EcBlock(49, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(24, 15), new EcBlock(46, 16)) + ), + new self( + 38, + [6, 32, 58, 84, 110, 136, 162], + new EcBlocks(30, new EcBlock(4, 122), new EcBlock(18, 123)), + new EcBlocks(28, new EcBlock(13, 46), new EcBlock(32, 47)), + new EcBlocks(30, new EcBlock(48, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(42, 15), new EcBlock(32, 16)) + ), + new self( + 39, + [6, 26, 54, 82, 110, 138, 166], + new EcBlocks(30, new EcBlock(20, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(40, 47), new EcBlock(7, 48)), + new EcBlocks(30, new EcBlock(43, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(10, 15), new EcBlock(67, 16)) + ), + new self( + 40, + [6, 30, 58, 86, 114, 142, 170], + new EcBlocks(30, new EcBlock(19, 118), new EcBlock(6, 119)), + new EcBlocks(28, new EcBlock(18, 47), new EcBlock(31, 48)), + new EcBlocks(30, new EcBlock(34, 24), new EcBlock(34, 25)), + new EcBlocks(30, new EcBlock(20, 15), new EcBlock(61, 16)) + ), + ]; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php b/serve/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php new file mode 100644 index 0000000..be54afa --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php @@ -0,0 +1,58 @@ + + */ + private $dataBytes; + + /** + * Error correction bytes in the block. + * + * @var SplFixedArray + */ + private $errorCorrectionBytes; + + /** + * Creates a new block pair. + * + * @param SplFixedArray $data + * @param SplFixedArray $errorCorrection + */ + public function __construct(SplFixedArray $data, SplFixedArray $errorCorrection) + { + $this->dataBytes = $data; + $this->errorCorrectionBytes = $errorCorrection; + } + + /** + * Gets the data bytes. + * + * @return SplFixedArray + */ + public function getDataBytes() : SplFixedArray + { + return $this->dataBytes; + } + + /** + * Gets the error correction bytes. + * + * @return SplFixedArray + */ + public function getErrorCorrectionBytes() : SplFixedArray + { + return $this->errorCorrectionBytes; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php b/serve/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php new file mode 100644 index 0000000..b58cc0a --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php @@ -0,0 +1,150 @@ +> + */ + private $bytes; + + /** + * Width of the matrix. + * + * @var int + */ + private $width; + + /** + * Height of the matrix. + * + * @var int + */ + private $height; + + public function __construct(int $width, int $height) + { + $this->height = $height; + $this->width = $width; + $this->bytes = new SplFixedArray($height); + + for ($y = 0; $y < $height; ++$y) { + $this->bytes[$y] = SplFixedArray::fromArray(array_fill(0, $width, 0)); + } + } + + /** + * Gets the width of the matrix. + */ + public function getWidth() : int + { + return $this->width; + } + + /** + * Gets the height of the matrix. + */ + public function getHeight() : int + { + return $this->height; + } + + /** + * Gets the internal representation of the matrix. + * + * @return SplFixedArray> + */ + public function getArray() : SplFixedArray + { + return $this->bytes; + } + + /** + * @return Traversable + */ + public function getBytes() : Traversable + { + foreach ($this->bytes as $row) { + foreach ($row as $byte) { + yield $byte; + } + } + } + + /** + * Gets the byte for a specific position. + */ + public function get(int $x, int $y) : int + { + return $this->bytes[$y][$x]; + } + + /** + * Sets the byte for a specific position. + */ + public function set(int $x, int $y, int $value) : void + { + $this->bytes[$y][$x] = $value; + } + + /** + * Clears the matrix with a specific value. + */ + public function clear(int $value) : void + { + for ($y = 0; $y < $this->height; ++$y) { + for ($x = 0; $x < $this->width; ++$x) { + $this->bytes[$y][$x] = $value; + } + } + } + + public function __clone() + { + $this->bytes = clone $this->bytes; + + foreach ($this->bytes as $index => $row) { + $this->bytes[$index] = clone $row; + } + } + + /** + * Returns a string representation of the matrix. + */ + public function __toString() : string + { + $result = ''; + + for ($y = 0; $y < $this->height; $y++) { + for ($x = 0; $x < $this->width; $x++) { + switch ($this->bytes[$y][$x]) { + case 0: + $result .= ' 0'; + break; + + case 1: + $result .= ' 1'; + break; + + default: + $result .= ' '; + break; + } + } + + $result .= "\n"; + } + + return $result; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php b/serve/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php new file mode 100644 index 0000000..4345f57 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php @@ -0,0 +1,652 @@ +getSize() + + $mode->getCharacterCountBits(Version::getVersionForNumber(1)) + + $dataBits->getSize(); + $provisionalVersion = self::chooseVersion($provisionalBitsNeeded, $ecLevel); + + // Use that guess to calculate the right version. I am still not sure + // this works in 100% of cases. + $bitsNeeded = $headerBits->getSize() + + $mode->getCharacterCountBits($provisionalVersion) + + $dataBits->getSize(); + $version = self::chooseVersion($bitsNeeded, $ecLevel); + + $headerAndDataBits = new BitArray(); + $headerAndDataBits->appendBitArray($headerBits); + + // Find "length" of main segment and write it. + $numLetters = (Mode::BYTE() === $mode ? $dataBits->getSizeInBytes() : strlen($content)); + self::appendLengthInfo($numLetters, $version, $mode, $headerAndDataBits); + + // Put data together into the overall payload. + $headerAndDataBits->appendBitArray($dataBits); + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numDataBytes = $version->getTotalCodewords() - $ecBlocks->getTotalEcCodewords(); + + // Terminate the bits properly. + self::terminateBits($numDataBytes, $headerAndDataBits); + + // Interleave data bits with error correction code. + $finalBits = self::interleaveWithEcBytes( + $headerAndDataBits, + $version->getTotalCodewords(), + $numDataBytes, + $ecBlocks->getNumBlocks() + ); + + // Choose the mask pattern. + $dimension = $version->getDimensionForVersion(); + $matrix = new ByteMatrix($dimension, $dimension); + $maskPattern = self::chooseMaskPattern($finalBits, $ecLevel, $version, $matrix); + + // Build the matrix. + MatrixUtil::buildMatrix($finalBits, $ecLevel, $version, $maskPattern, $matrix); + + return new QrCode($mode, $ecLevel, $version, $maskPattern, $matrix); + } + + /** + * Gets the alphanumeric code for a byte. + */ + private static function getAlphanumericCode(int $code) : int + { + if (isset(self::ALPHANUMERIC_TABLE[$code])) { + return self::ALPHANUMERIC_TABLE[$code]; + } + + return -1; + } + + /** + * Chooses the best mode for a given content. + */ + private static function chooseMode(string $content, string $encoding = null) : Mode + { + if (null !== $encoding && 0 === strcasecmp($encoding, 'SHIFT-JIS')) { + return self::isOnlyDoubleByteKanji($content) ? Mode::KANJI() : Mode::BYTE(); + } + + $hasNumeric = false; + $hasAlphanumeric = false; + $contentLength = strlen($content); + + for ($i = 0; $i < $contentLength; ++$i) { + $char = $content[$i]; + + if (ctype_digit($char)) { + $hasNumeric = true; + } elseif (-1 !== self::getAlphanumericCode(ord($char))) { + $hasAlphanumeric = true; + } else { + return Mode::BYTE(); + } + } + + if ($hasAlphanumeric) { + return Mode::ALPHANUMERIC(); + } elseif ($hasNumeric) { + return Mode::NUMERIC(); + } + + return Mode::BYTE(); + } + + /** + * Calculates the mask penalty for a matrix. + */ + private static function calculateMaskPenalty(ByteMatrix $matrix) : int + { + return ( + MaskUtil::applyMaskPenaltyRule1($matrix) + + MaskUtil::applyMaskPenaltyRule2($matrix) + + MaskUtil::applyMaskPenaltyRule3($matrix) + + MaskUtil::applyMaskPenaltyRule4($matrix) + ); + } + + /** + * Checks if content only consists of double-byte kanji characters. + */ + private static function isOnlyDoubleByteKanji(string $content) : bool + { + $bytes = @iconv('utf-8', 'SHIFT-JIS', $content); + + if (false === $bytes) { + return false; + } + + $length = strlen($bytes); + + if (0 !== $length % 2) { + return false; + } + + for ($i = 0; $i < $length; $i += 2) { + $byte = $bytes[$i] & 0xff; + + if (($byte < 0x81 || $byte > 0x9f) && $byte < 0xe0 || $byte > 0xeb) { + return false; + } + } + + return true; + } + + /** + * Chooses the best mask pattern for a matrix. + */ + private static function chooseMaskPattern( + BitArray $bits, + ErrorCorrectionLevel $ecLevel, + Version $version, + ByteMatrix $matrix + ) : int { + $minPenalty = PHP_INT_MAX; + $bestMaskPattern = -1; + + for ($maskPattern = 0; $maskPattern < QrCode::NUM_MASK_PATTERNS; ++$maskPattern) { + MatrixUtil::buildMatrix($bits, $ecLevel, $version, $maskPattern, $matrix); + $penalty = self::calculateMaskPenalty($matrix); + + if ($penalty < $minPenalty) { + $minPenalty = $penalty; + $bestMaskPattern = $maskPattern; + } + } + + return $bestMaskPattern; + } + + /** + * Chooses the best version for the input. + * + * @throws WriterException if data is too big + */ + private static function chooseVersion(int $numInputBits, ErrorCorrectionLevel $ecLevel) : Version + { + for ($versionNum = 1; $versionNum <= 40; ++$versionNum) { + $version = Version::getVersionForNumber($versionNum); + $numBytes = $version->getTotalCodewords(); + + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numEcBytes = $ecBlocks->getTotalEcCodewords(); + + $numDataBytes = $numBytes - $numEcBytes; + $totalInputBytes = intdiv($numInputBits + 8, 8); + + if ($numDataBytes >= $totalInputBytes) { + return $version; + } + } + + throw new WriterException('Data too big'); + } + + /** + * Terminates the bits in a bit array. + * + * @throws WriterException if data bits cannot fit in the QR code + * @throws WriterException if bits size does not equal the capacity + */ + private static function terminateBits(int $numDataBytes, BitArray $bits) : void + { + $capacity = $numDataBytes << 3; + + if ($bits->getSize() > $capacity) { + throw new WriterException('Data bits cannot fit in the QR code'); + } + + for ($i = 0; $i < 4 && $bits->getSize() < $capacity; ++$i) { + $bits->appendBit(false); + } + + $numBitsInLastByte = $bits->getSize() & 0x7; + + if ($numBitsInLastByte > 0) { + for ($i = $numBitsInLastByte; $i < 8; ++$i) { + $bits->appendBit(false); + } + } + + $numPaddingBytes = $numDataBytes - $bits->getSizeInBytes(); + + for ($i = 0; $i < $numPaddingBytes; ++$i) { + $bits->appendBits(0 === ($i & 0x1) ? 0xec : 0x11, 8); + } + + if ($bits->getSize() !== $capacity) { + throw new WriterException('Bits size does not equal capacity'); + } + } + + /** + * Gets number of data- and EC bytes for a block ID. + * + * @return int[] + * @throws WriterException if block ID is too large + * @throws WriterException if EC bytes mismatch + * @throws WriterException if RS blocks mismatch + * @throws WriterException if total bytes mismatch + */ + private static function getNumDataBytesAndNumEcBytesForBlockId( + int $numTotalBytes, + int $numDataBytes, + int $numRsBlocks, + int $blockId + ) : array { + if ($blockId >= $numRsBlocks) { + throw new WriterException('Block ID too large'); + } + + $numRsBlocksInGroup2 = $numTotalBytes % $numRsBlocks; + $numRsBlocksInGroup1 = $numRsBlocks - $numRsBlocksInGroup2; + $numTotalBytesInGroup1 = intdiv($numTotalBytes, $numRsBlocks); + $numTotalBytesInGroup2 = $numTotalBytesInGroup1 + 1; + $numDataBytesInGroup1 = intdiv($numDataBytes, $numRsBlocks); + $numDataBytesInGroup2 = $numDataBytesInGroup1 + 1; + $numEcBytesInGroup1 = $numTotalBytesInGroup1 - $numDataBytesInGroup1; + $numEcBytesInGroup2 = $numTotalBytesInGroup2 - $numDataBytesInGroup2; + + if ($numEcBytesInGroup1 !== $numEcBytesInGroup2) { + throw new WriterException('EC bytes mismatch'); + } + + if ($numRsBlocks !== $numRsBlocksInGroup1 + $numRsBlocksInGroup2) { + throw new WriterException('RS blocks mismatch'); + } + + if ($numTotalBytes !== + (($numDataBytesInGroup1 + $numEcBytesInGroup1) * $numRsBlocksInGroup1) + + (($numDataBytesInGroup2 + $numEcBytesInGroup2) * $numRsBlocksInGroup2) + ) { + throw new WriterException('Total bytes mismatch'); + } + + if ($blockId < $numRsBlocksInGroup1) { + return [$numDataBytesInGroup1, $numEcBytesInGroup1]; + } else { + return [$numDataBytesInGroup2, $numEcBytesInGroup2]; + } + } + + /** + * Interleaves data with EC bytes. + * + * @throws WriterException if number of bits and data bytes does not match + * @throws WriterException if data bytes does not match offset + * @throws WriterException if an interleaving error occurs + */ + private static function interleaveWithEcBytes( + BitArray $bits, + int $numTotalBytes, + int $numDataBytes, + int $numRsBlocks + ) : BitArray { + if ($bits->getSizeInBytes() !== $numDataBytes) { + throw new WriterException('Number of bits and data bytes does not match'); + } + + $dataBytesOffset = 0; + $maxNumDataBytes = 0; + $maxNumEcBytes = 0; + + $blocks = new SplFixedArray($numRsBlocks); + + for ($i = 0; $i < $numRsBlocks; ++$i) { + list($numDataBytesInBlock, $numEcBytesInBlock) = self::getNumDataBytesAndNumEcBytesForBlockId( + $numTotalBytes, + $numDataBytes, + $numRsBlocks, + $i + ); + + $size = $numDataBytesInBlock; + $dataBytes = $bits->toBytes(8 * $dataBytesOffset, $size); + $ecBytes = self::generateEcBytes($dataBytes, $numEcBytesInBlock); + $blocks[$i] = new BlockPair($dataBytes, $ecBytes); + + $maxNumDataBytes = max($maxNumDataBytes, $size); + $maxNumEcBytes = max($maxNumEcBytes, count($ecBytes)); + $dataBytesOffset += $numDataBytesInBlock; + } + + if ($numDataBytes !== $dataBytesOffset) { + throw new WriterException('Data bytes does not match offset'); + } + + $result = new BitArray(); + + for ($i = 0; $i < $maxNumDataBytes; ++$i) { + foreach ($blocks as $block) { + $dataBytes = $block->getDataBytes(); + + if ($i < count($dataBytes)) { + $result->appendBits($dataBytes[$i], 8); + } + } + } + + for ($i = 0; $i < $maxNumEcBytes; ++$i) { + foreach ($blocks as $block) { + $ecBytes = $block->getErrorCorrectionBytes(); + + if ($i < count($ecBytes)) { + $result->appendBits($ecBytes[$i], 8); + } + } + } + + if ($numTotalBytes !== $result->getSizeInBytes()) { + throw new WriterException( + 'Interleaving error: ' . $numTotalBytes . ' and ' . $result->getSizeInBytes() . ' differ' + ); + } + + return $result; + } + + /** + * Generates EC bytes for given data. + * + * @param SplFixedArray $dataBytes + * @return SplFixedArray + */ + private static function generateEcBytes(SplFixedArray $dataBytes, int $numEcBytesInBlock) : SplFixedArray + { + $numDataBytes = count($dataBytes); + $toEncode = new SplFixedArray($numDataBytes + $numEcBytesInBlock); + + for ($i = 0; $i < $numDataBytes; $i++) { + $toEncode[$i] = $dataBytes[$i] & 0xff; + } + + $ecBytes = new SplFixedArray($numEcBytesInBlock); + $codec = self::getCodec($numDataBytes, $numEcBytesInBlock); + $codec->encode($toEncode, $ecBytes); + + return $ecBytes; + } + + /** + * Gets an RS codec and caches it. + */ + private static function getCodec(int $numDataBytes, int $numEcBytesInBlock) : ReedSolomonCodec + { + $cacheId = $numDataBytes . '-' . $numEcBytesInBlock; + + if (isset(self::$codecs[$cacheId])) { + return self::$codecs[$cacheId]; + } + + return self::$codecs[$cacheId] = new ReedSolomonCodec( + 8, + 0x11d, + 0, + 1, + $numEcBytesInBlock, + 255 - $numDataBytes - $numEcBytesInBlock + ); + } + + /** + * Appends mode information to a bit array. + */ + private static function appendModeInfo(Mode $mode, BitArray $bits) : void + { + $bits->appendBits($mode->getBits(), 4); + } + + /** + * Appends length information to a bit array. + * + * @throws WriterException if num letters is bigger than expected + */ + private static function appendLengthInfo(int $numLetters, Version $version, Mode $mode, BitArray $bits) : void + { + $numBits = $mode->getCharacterCountBits($version); + + if ($numLetters >= (1 << $numBits)) { + throw new WriterException($numLetters . ' is bigger than ' . ((1 << $numBits) - 1)); + } + + $bits->appendBits($numLetters, $numBits); + } + + /** + * Appends bytes to a bit array in a specific mode. + * + * @throws WriterException if an invalid mode was supplied + */ + private static function appendBytes(string $content, Mode $mode, BitArray $bits, string $encoding) : void + { + switch ($mode) { + case Mode::NUMERIC(): + self::appendNumericBytes($content, $bits); + break; + + case Mode::ALPHANUMERIC(): + self::appendAlphanumericBytes($content, $bits); + break; + + case Mode::BYTE(): + self::append8BitBytes($content, $bits, $encoding); + break; + + case Mode::KANJI(): + self::appendKanjiBytes($content, $bits); + break; + + default: + throw new WriterException('Invalid mode: ' . $mode); + } + } + + /** + * Appends numeric bytes to a bit array. + */ + private static function appendNumericBytes(string $content, BitArray $bits) : void + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + $num1 = (int) $content[$i]; + + if ($i + 2 < $length) { + // Encode three numeric letters in ten bits. + $num2 = (int) $content[$i + 1]; + $num3 = (int) $content[$i + 2]; + $bits->appendBits($num1 * 100 + $num2 * 10 + $num3, 10); + $i += 3; + } elseif ($i + 1 < $length) { + // Encode two numeric letters in seven bits. + $num2 = (int) $content[$i + 1]; + $bits->appendBits($num1 * 10 + $num2, 7); + $i += 2; + } else { + // Encode one numeric letter in four bits. + $bits->appendBits($num1, 4); + ++$i; + } + } + } + + /** + * Appends alpha-numeric bytes to a bit array. + * + * @throws WriterException if an invalid alphanumeric code was found + */ + private static function appendAlphanumericBytes(string $content, BitArray $bits) : void + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + $code1 = self::getAlphanumericCode(ord($content[$i])); + + if (-1 === $code1) { + throw new WriterException('Invalid alphanumeric code'); + } + + if ($i + 1 < $length) { + $code2 = self::getAlphanumericCode(ord($content[$i + 1])); + + if (-1 === $code2) { + throw new WriterException('Invalid alphanumeric code'); + } + + // Encode two alphanumeric letters in 11 bits. + $bits->appendBits($code1 * 45 + $code2, 11); + $i += 2; + } else { + // Encode one alphanumeric letter in six bits. + $bits->appendBits($code1, 6); + ++$i; + } + } + } + + /** + * Appends regular 8-bit bytes to a bit array. + * + * @throws WriterException if content cannot be encoded to target encoding + */ + private static function append8BitBytes(string $content, BitArray $bits, string $encoding) : void + { + $bytes = @iconv('utf-8', $encoding, $content); + + if (false === $bytes) { + throw new WriterException('Could not encode content to ' . $encoding); + } + + $length = strlen($bytes); + + for ($i = 0; $i < $length; $i++) { + $bits->appendBits(ord($bytes[$i]), 8); + } + } + + /** + * Appends KANJI bytes to a bit array. + * + * @throws WriterException if content does not seem to be encoded in SHIFT-JIS + * @throws WriterException if an invalid byte sequence occurs + */ + private static function appendKanjiBytes(string $content, BitArray $bits) : void + { + if (strlen($content) % 2 > 0) { + // We just do a simple length check here. The for loop will check + // individual characters. + throw new WriterException('Content does not seem to be encoded in SHIFT-JIS'); + } + + $length = strlen($content); + + for ($i = 0; $i < $length; $i += 2) { + $byte1 = ord($content[$i]) & 0xff; + $byte2 = ord($content[$i + 1]) & 0xff; + $code = ($byte1 << 8) | $byte2; + + if ($code >= 0x8140 && $code <= 0x9ffc) { + $subtracted = $code - 0x8140; + } elseif ($code >= 0xe040 && $code <= 0xebbf) { + $subtracted = $code - 0xc140; + } else { + throw new WriterException('Invalid byte sequence'); + } + + $encoded = (($subtracted >> 8) * 0xc0) + ($subtracted & 0xff); + + $bits->appendBits($encoded, 13); + } + } + + /** + * Appends ECI information to a bit array. + */ + private static function appendEci(CharacterSetEci $eci, BitArray $bits) : void + { + $mode = Mode::ECI(); + $bits->appendBits($mode->getBits(), 4); + $bits->appendBits($eci->getValue(), 8); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php b/serve/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php new file mode 100644 index 0000000..3baddbd --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php @@ -0,0 +1,271 @@ +getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height - 1; ++$y) { + for ($x = 0; $x < $width - 1; ++$x) { + $value = $array[$y][$x]; + + if ($value === $array[$y][$x + 1] + && $value === $array[$y + 1][$x] + && $value === $array[$y + 1][$x + 1] + ) { + ++$penalty; + } + } + } + + return self::N2 * $penalty; + } + + /** + * Applies mask penalty rule 3 and returns the penalty. + * + * Finds consecutive cells of 00001011101 or 10111010000, and gives penalty + * to them. If we find patterns like 000010111010000, we give penalties + * twice (i.e. 40 * 2). + */ + public static function applyMaskPenaltyRule3(ByteMatrix $matrix) : int + { + $penalty = 0; + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; ++$y) { + for ($x = 0; $x < $width; ++$x) { + if ($x + 6 < $width + && 1 === $array[$y][$x] + && 0 === $array[$y][$x + 1] + && 1 === $array[$y][$x + 2] + && 1 === $array[$y][$x + 3] + && 1 === $array[$y][$x + 4] + && 0 === $array[$y][$x + 5] + && 1 === $array[$y][$x + 6] + && ( + ( + $x + 10 < $width + && 0 === $array[$y][$x + 7] + && 0 === $array[$y][$x + 8] + && 0 === $array[$y][$x + 9] + && 0 === $array[$y][$x + 10] + ) + || ( + $x - 4 >= 0 + && 0 === $array[$y][$x - 1] + && 0 === $array[$y][$x - 2] + && 0 === $array[$y][$x - 3] + && 0 === $array[$y][$x - 4] + ) + ) + ) { + $penalty += self::N3; + } + + if ($y + 6 < $height + && 1 === $array[$y][$x] + && 0 === $array[$y + 1][$x] + && 1 === $array[$y + 2][$x] + && 1 === $array[$y + 3][$x] + && 1 === $array[$y + 4][$x] + && 0 === $array[$y + 5][$x] + && 1 === $array[$y + 6][$x] + && ( + ( + $y + 10 < $height + && 0 === $array[$y + 7][$x] + && 0 === $array[$y + 8][$x] + && 0 === $array[$y + 9][$x] + && 0 === $array[$y + 10][$x] + ) + || ( + $y - 4 >= 0 + && 0 === $array[$y - 1][$x] + && 0 === $array[$y - 2][$x] + && 0 === $array[$y - 3][$x] + && 0 === $array[$y - 4][$x] + ) + ) + ) { + $penalty += self::N3; + } + } + } + + return $penalty; + } + + /** + * Applies mask penalty rule 4 and returns the penalty. + * + * Calculates the ratio of dark cells and gives penalty if the ratio is far + * from 50%. It gives 10 penalty for 5% distance. + */ + public static function applyMaskPenaltyRule4(ByteMatrix $matrix) : int + { + $numDarkCells = 0; + + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; ++$y) { + $arrayY = $array[$y]; + + for ($x = 0; $x < $width; ++$x) { + if (1 === $arrayY[$x]) { + ++$numDarkCells; + } + } + } + + $numTotalCells = $height * $width; + $darkRatio = $numDarkCells / $numTotalCells; + $fixedPercentVariances = (int) (abs($darkRatio - 0.5) * 20); + + return $fixedPercentVariances * self::N4; + } + + /** + * Returns the mask bit for "getMaskPattern" at "x" and "y". + * + * See 8.8 of JISX0510:2004 for mask pattern conditions. + * + * @throws InvalidArgumentException if an invalid mask pattern was supplied + */ + public static function getDataMaskBit(int $maskPattern, int $x, int $y) : bool + { + switch ($maskPattern) { + case 0: + $intermediate = ($y + $x) & 0x1; + break; + + case 1: + $intermediate = $y & 0x1; + break; + + case 2: + $intermediate = $x % 3; + break; + + case 3: + $intermediate = ($y + $x) % 3; + break; + + case 4: + $intermediate = (BitUtils::unsignedRightShift($y, 1) + ($x / 3)) & 0x1; + break; + + case 5: + $temp = $y * $x; + $intermediate = ($temp & 0x1) + ($temp % 3); + break; + + case 6: + $temp = $y * $x; + $intermediate = (($temp & 0x1) + ($temp % 3)) & 0x1; + break; + + case 7: + $temp = $y * $x; + $intermediate = (($temp % 3) + (($y + $x) & 0x1)) & 0x1; + break; + + default: + throw new InvalidArgumentException('Invalid mask pattern: ' . $maskPattern); + } + + return 0 == $intermediate; + } + + /** + * Helper function for applyMaskPenaltyRule1. + * + * We need this for doing this calculation in both vertical and horizontal + * orders respectively. + */ + private static function applyMaskPenaltyRule1Internal(ByteMatrix $matrix, bool $isHorizontal) : int + { + $penalty = 0; + $iLimit = $isHorizontal ? $matrix->getHeight() : $matrix->getWidth(); + $jLimit = $isHorizontal ? $matrix->getWidth() : $matrix->getHeight(); + $array = $matrix->getArray(); + + for ($i = 0; $i < $iLimit; ++$i) { + $numSameBitCells = 0; + $prevBit = -1; + + for ($j = 0; $j < $jLimit; $j++) { + $bit = $isHorizontal ? $array[$i][$j] : $array[$j][$i]; + + if ($bit === $prevBit) { + ++$numSameBitCells; + } else { + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + + $numSameBitCells = 1; + $prevBit = $bit; + } + } + + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + } + + return $penalty; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php b/serve/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php new file mode 100644 index 0000000..0967e29 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php @@ -0,0 +1,513 @@ +clear(-1); + } + + /** + * Builds a complete matrix. + */ + public static function buildMatrix( + BitArray $dataBits, + ErrorCorrectionLevel $level, + Version $version, + int $maskPattern, + ByteMatrix $matrix + ) : void { + self::clearMatrix($matrix); + self::embedBasicPatterns($version, $matrix); + self::embedTypeInfo($level, $maskPattern, $matrix); + self::maybeEmbedVersionInfo($version, $matrix); + self::embedDataBits($dataBits, $maskPattern, $matrix); + } + + /** + * Removes the position detection patterns from a matrix. + * + * This can be useful if you need to render those patterns separately. + */ + public static function removePositionDetectionPatterns(ByteMatrix $matrix) : void + { + $pdpWidth = count(self::POSITION_DETECTION_PATTERN[0]); + + self::removePositionDetectionPattern(0, 0, $matrix); + self::removePositionDetectionPattern($matrix->getWidth() - $pdpWidth, 0, $matrix); + self::removePositionDetectionPattern(0, $matrix->getWidth() - $pdpWidth, $matrix); + } + + /** + * Embeds type information into a matrix. + */ + private static function embedTypeInfo(ErrorCorrectionLevel $level, int $maskPattern, ByteMatrix $matrix) : void + { + $typeInfoBits = new BitArray(); + self::makeTypeInfoBits($level, $maskPattern, $typeInfoBits); + + $typeInfoBitsSize = $typeInfoBits->getSize(); + + for ($i = 0; $i < $typeInfoBitsSize; ++$i) { + $bit = $typeInfoBits->get($typeInfoBitsSize - 1 - $i); + + $x1 = self::TYPE_INFO_COORDINATES[$i][0]; + $y1 = self::TYPE_INFO_COORDINATES[$i][1]; + + $matrix->set($x1, $y1, (int) $bit); + + if ($i < 8) { + $x2 = $matrix->getWidth() - $i - 1; + $y2 = 8; + } else { + $x2 = 8; + $y2 = $matrix->getHeight() - 7 + ($i - 8); + } + + $matrix->set($x2, $y2, (int) $bit); + } + } + + /** + * Generates type information bits and appends them to a bit array. + * + * @throws RuntimeException if bit array resulted in invalid size + */ + private static function makeTypeInfoBits(ErrorCorrectionLevel $level, int $maskPattern, BitArray $bits) : void + { + $typeInfo = ($level->getBits() << 3) | $maskPattern; + $bits->appendBits($typeInfo, 5); + + $bchCode = self::calculateBchCode($typeInfo, self::TYPE_INFO_POLY); + $bits->appendBits($bchCode, 10); + + $maskBits = new BitArray(); + $maskBits->appendBits(self::TYPE_INFO_MASK_PATTERN, 15); + $bits->xorBits($maskBits); + + if (15 !== $bits->getSize()) { + throw new RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Embeds version information if required. + */ + private static function maybeEmbedVersionInfo(Version $version, ByteMatrix $matrix) : void + { + if ($version->getVersionNumber() < 7) { + return; + } + + $versionInfoBits = new BitArray(); + self::makeVersionInfoBits($version, $versionInfoBits); + + $bitIndex = 6 * 3 - 1; + + for ($i = 0; $i < 6; ++$i) { + for ($j = 0; $j < 3; ++$j) { + $bit = $versionInfoBits->get($bitIndex); + --$bitIndex; + + $matrix->set($i, $matrix->getHeight() - 11 + $j, (int) $bit); + $matrix->set($matrix->getHeight() - 11 + $j, $i, (int) $bit); + } + } + } + + /** + * Generates version information bits and appends them to a bit array. + * + * @throws RuntimeException if bit array resulted in invalid size + */ + private static function makeVersionInfoBits(Version $version, BitArray $bits) : void + { + $bits->appendBits($version->getVersionNumber(), 6); + + $bchCode = self::calculateBchCode($version->getVersionNumber(), self::VERSION_INFO_POLY); + $bits->appendBits($bchCode, 12); + + if (18 !== $bits->getSize()) { + throw new RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Calculates the BCH code for a value and a polynomial. + */ + private static function calculateBchCode(int $value, int $poly) : int + { + $msbSetInPoly = self::findMsbSet($poly); + $value <<= $msbSetInPoly - 1; + + while (self::findMsbSet($value) >= $msbSetInPoly) { + $value ^= $poly << (self::findMsbSet($value) - $msbSetInPoly); + } + + return $value; + } + + /** + * Finds and MSB set. + */ + private static function findMsbSet(int $value) : int + { + $numDigits = 0; + + while (0 !== $value) { + $value >>= 1; + ++$numDigits; + } + + return $numDigits; + } + + /** + * Embeds basic patterns into a matrix. + */ + private static function embedBasicPatterns(Version $version, ByteMatrix $matrix) : void + { + self::embedPositionDetectionPatternsAndSeparators($matrix); + self::embedDarkDotAtLeftBottomCorner($matrix); + self::maybeEmbedPositionAdjustmentPatterns($version, $matrix); + self::embedTimingPatterns($matrix); + } + + /** + * Embeds position detection patterns and separators into a byte matrix. + */ + private static function embedPositionDetectionPatternsAndSeparators(ByteMatrix $matrix) : void + { + $pdpWidth = count(self::POSITION_DETECTION_PATTERN[0]); + + self::embedPositionDetectionPattern(0, 0, $matrix); + self::embedPositionDetectionPattern($matrix->getWidth() - $pdpWidth, 0, $matrix); + self::embedPositionDetectionPattern(0, $matrix->getWidth() - $pdpWidth, $matrix); + + $hspWidth = 8; + + self::embedHorizontalSeparationPattern(0, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern($matrix->getWidth() - $hspWidth, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern(0, $matrix->getWidth() - $hspWidth, $matrix); + + $vspSize = 7; + + self::embedVerticalSeparationPattern($vspSize, 0, $matrix); + self::embedVerticalSeparationPattern($matrix->getHeight() - $vspSize - 1, 0, $matrix); + self::embedVerticalSeparationPattern($vspSize, $matrix->getHeight() - $vspSize, $matrix); + } + + /** + * Embeds a single position detection pattern into a byte matrix. + */ + private static function embedPositionDetectionPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 7; ++$y) { + for ($x = 0; $x < 7; ++$x) { + $matrix->set($xStart + $x, $yStart + $y, self::POSITION_DETECTION_PATTERN[$y][$x]); + } + } + } + + private static function removePositionDetectionPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 7; ++$y) { + for ($x = 0; $x < 7; ++$x) { + $matrix->set($xStart + $x, $yStart + $y, 0); + } + } + } + + /** + * Embeds a single horizontal separation pattern. + * + * @throws RuntimeException if a byte was already set + */ + private static function embedHorizontalSeparationPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($x = 0; $x < 8; $x++) { + if (-1 !== $matrix->get($xStart + $x, $yStart)) { + throw new RuntimeException('Byte already set'); + } + + $matrix->set($xStart + $x, $yStart, 0); + } + } + + /** + * Embeds a single vertical separation pattern. + * + * @throws RuntimeException if a byte was already set + */ + private static function embedVerticalSeparationPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 7; $y++) { + if (-1 !== $matrix->get($xStart, $yStart + $y)) { + throw new RuntimeException('Byte already set'); + } + + $matrix->set($xStart, $yStart + $y, 0); + } + } + + /** + * Embeds a dot at the left bottom corner. + * + * @throws RuntimeException if a byte was already set to 0 + */ + private static function embedDarkDotAtLeftBottomCorner(ByteMatrix $matrix) : void + { + if (0 === $matrix->get(8, $matrix->getHeight() - 8)) { + throw new RuntimeException('Byte already set to 0'); + } + + $matrix->set(8, $matrix->getHeight() - 8, 1); + } + + /** + * Embeds position adjustment patterns if required. + */ + private static function maybeEmbedPositionAdjustmentPatterns(Version $version, ByteMatrix $matrix) : void + { + if ($version->getVersionNumber() < 2) { + return; + } + + $index = $version->getVersionNumber() - 1; + + $coordinates = self::POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[$index]; + $numCoordinates = count($coordinates); + + for ($i = 0; $i < $numCoordinates; ++$i) { + for ($j = 0; $j < $numCoordinates; ++$j) { + $y = $coordinates[$i]; + $x = $coordinates[$j]; + + if (null === $x || null === $y) { + continue; + } + + if (-1 === $matrix->get($x, $y)) { + self::embedPositionAdjustmentPattern($x - 2, $y - 2, $matrix); + } + } + } + } + + /** + * Embeds a single position adjustment pattern. + */ + private static function embedPositionAdjustmentPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 5; $y++) { + for ($x = 0; $x < 5; $x++) { + $matrix->set($xStart + $x, $yStart + $y, self::POSITION_ADJUSTMENT_PATTERN[$y][$x]); + } + } + } + + /** + * Embeds timing patterns into a matrix. + */ + private static function embedTimingPatterns(ByteMatrix $matrix) : void + { + $matrixWidth = $matrix->getWidth(); + + for ($i = 8; $i < $matrixWidth - 8; ++$i) { + $bit = ($i + 1) % 2; + + if (-1 === $matrix->get($i, 6)) { + $matrix->set($i, 6, $bit); + } + + if (-1 === $matrix->get(6, $i)) { + $matrix->set(6, $i, $bit); + } + } + } + + /** + * Embeds "dataBits" using "getMaskPattern". + * + * For debugging purposes, it skips masking process if "getMaskPattern" is -1. See 8.7 of JISX0510:2004 (p.38) for + * how to embed data bits. + * + * @throws WriterException if not all bits could be consumed + */ + private static function embedDataBits(BitArray $dataBits, int $maskPattern, ByteMatrix $matrix) : void + { + $bitIndex = 0; + $direction = -1; + + // Start from the right bottom cell. + $x = $matrix->getWidth() - 1; + $y = $matrix->getHeight() - 1; + + while ($x > 0) { + // Skip vertical timing pattern. + if (6 === $x) { + --$x; + } + + while ($y >= 0 && $y < $matrix->getHeight()) { + for ($i = 0; $i < 2; $i++) { + $xx = $x - $i; + + // Skip the cell if it's not empty. + if (-1 !== $matrix->get($xx, $y)) { + continue; + } + + if ($bitIndex < $dataBits->getSize()) { + $bit = $dataBits->get($bitIndex); + ++$bitIndex; + } else { + // Padding bit. If there is no bit left, we'll fill the + // left cells with 0, as described in 8.4.9 of + // JISX0510:2004 (p. 24). + $bit = false; + } + + // Skip masking if maskPattern is -1. + if (-1 !== $maskPattern && MaskUtil::getDataMaskBit($maskPattern, $xx, $y)) { + $bit = ! $bit; + } + + $matrix->set($xx, $y, (int) $bit); + } + + $y += $direction; + } + + $direction = -$direction; + $y += $direction; + $x -= 2; + } + + // All bits should be consumed + if ($dataBits->getSize() !== $bitIndex) { + throw new WriterException('Not all bits consumed (' . $bitIndex . ' out of ' . $dataBits->getSize() .')'); + } + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php b/serve/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php new file mode 100644 index 0000000..f568e88 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php @@ -0,0 +1,141 @@ +mode = $mode; + $this->errorCorrectionLevel = $errorCorrectionLevel; + $this->version = $version; + $this->maskPattern = $maskPattern; + $this->matrix = $matrix; + } + + /** + * Gets the mode. + */ + public function getMode() : Mode + { + return $this->mode; + } + + /** + * Gets the EC level. + */ + public function getErrorCorrectionLevel() : ErrorCorrectionLevel + { + return $this->errorCorrectionLevel; + } + + /** + * Gets the version. + */ + public function getVersion() : Version + { + return $this->version; + } + + /** + * Gets the mask pattern. + */ + public function getMaskPattern() : int + { + return $this->maskPattern; + } + + /** + * Gets the matrix. + * + * @return ByteMatrix + */ + public function getMatrix() + { + return $this->matrix; + } + + /** + * Validates whether a mask pattern is valid. + */ + public static function isValidMaskPattern(int $maskPattern) : bool + { + return $maskPattern > 0 && $maskPattern < self::NUM_MASK_PATTERNS; + } + + /** + * Returns a string representation of the QR code. + */ + public function __toString() : string + { + $result = "<<\n" + . ' mode: ' . $this->mode . "\n" + . ' ecLevel: ' . $this->errorCorrectionLevel . "\n" + . ' version: ' . $this->version . "\n" + . ' maskPattern: ' . $this->maskPattern . "\n"; + + if ($this->matrix === null) { + $result .= " matrix: null\n"; + } else { + $result .= " matrix:\n"; + $result .= $this->matrix; + } + + $result .= ">>\n"; + + return $result; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php b/serve/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php new file mode 100644 index 0000000..6f70c20 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php @@ -0,0 +1,10 @@ + 100) { + throw new Exception\InvalidArgumentException('Alpha must be between 0 and 100'); + } + + $this->alpha = $alpha; + $this->baseColor = $baseColor; + } + + public function getAlpha() : int + { + return $this->alpha; + } + + public function getBaseColor() : ColorInterface + { + return $this->baseColor; + } + + public function toRgb() : Rgb + { + return $this->baseColor->toRgb(); + } + + public function toCmyk() : Cmyk + { + return $this->baseColor->toCmyk(); + } + + public function toGray() : Gray + { + return $this->baseColor->toGray(); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php new file mode 100644 index 0000000..d6de390 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php @@ -0,0 +1,103 @@ + 100) { + throw new Exception\InvalidArgumentException('Cyan must be between 0 and 100'); + } + + if ($magenta < 0 || $magenta > 100) { + throw new Exception\InvalidArgumentException('Magenta must be between 0 and 100'); + } + + if ($yellow < 0 || $yellow > 100) { + throw new Exception\InvalidArgumentException('Yellow must be between 0 and 100'); + } + + if ($black < 0 || $black > 100) { + throw new Exception\InvalidArgumentException('Black must be between 0 and 100'); + } + + $this->cyan = $cyan; + $this->magenta = $magenta; + $this->yellow = $yellow; + $this->black = $black; + } + + public function getCyan() : int + { + return $this->cyan; + } + + public function getMagenta() : int + { + return $this->magenta; + } + + public function getYellow() : int + { + return $this->yellow; + } + + public function getBlack() : int + { + return $this->black; + } + + public function toRgb() : Rgb + { + $k = $this->black / 100; + $c = (-$k * $this->cyan + $k * 100 + $this->cyan) / 100; + $m = (-$k * $this->magenta + $k * 100 + $this->magenta) / 100; + $y = (-$k * $this->yellow + $k * 100 + $this->yellow) / 100; + + return new Rgb( + (int) (-$c * 255 + 255), + (int) (-$m * 255 + 255), + (int) (-$y * 255 + 255) + ); + } + + public function toCmyk() : Cmyk + { + return $this; + } + + public function toGray() : Gray + { + return $this->toRgb()->toGray(); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php new file mode 100644 index 0000000..b50d1ca --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php @@ -0,0 +1,22 @@ + 100) { + throw new Exception\InvalidArgumentException('Gray must be between 0 and 100'); + } + + $this->gray = (int) $gray; + } + + public function getGray() : int + { + return $this->gray; + } + + public function toRgb() : Rgb + { + return new Rgb((int) ($this->gray * 2.55), (int) ($this->gray * 2.55), (int) ($this->gray * 2.55)); + } + + public function toCmyk() : Cmyk + { + return new Cmyk(0, 0, 0, 100 - $this->gray); + } + + public function toGray() : Gray + { + return $this; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php new file mode 100644 index 0000000..7935406 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php @@ -0,0 +1,88 @@ + 255) { + throw new Exception\InvalidArgumentException('Red must be between 0 and 255'); + } + + if ($green < 0 || $green > 255) { + throw new Exception\InvalidArgumentException('Green must be between 0 and 255'); + } + + if ($blue < 0 || $blue > 255) { + throw new Exception\InvalidArgumentException('Blue must be between 0 and 255'); + } + + $this->red = $red; + $this->green = $green; + $this->blue = $blue; + } + + public function getRed() : int + { + return $this->red; + } + + public function getGreen() : int + { + return $this->green; + } + + public function getBlue() : int + { + return $this->blue; + } + + public function toRgb() : Rgb + { + return $this; + } + + public function toCmyk() : Cmyk + { + $c = 1 - ($this->red / 255); + $m = 1 - ($this->green / 255); + $y = 1 - ($this->blue / 255); + $k = min($c, $m, $y); + + return new Cmyk( + (int) (100 * ($c - $k) / (1 - $k)), + (int) (100 * ($m - $k) / (1 - $k)), + (int) (100 * ($y - $k) / (1 - $k)), + (int) (100 * $k) + ); + } + + public function toGray() : Gray + { + return new Gray((int) (($this->red * 0.21 + $this->green * 0.71 + $this->blue * 0.07) / 2.55)); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php new file mode 100644 index 0000000..a3e1909 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php @@ -0,0 +1,38 @@ +externalEye = $externalEye; + $this->internalEye = $internalEye; + } + + public function getExternalPath() : Path + { + return $this->externalEye->getExternalPath(); + } + + public function getInternalPath() : Path + { + return $this->externalEye->getInternalPath(); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php new file mode 100644 index 0000000..ab68f3c --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php @@ -0,0 +1,26 @@ +module = $module; + } + + public function getExternalPath() : Path + { + $matrix = new ByteMatrix(7, 7); + + for ($x = 0; $x < 7; ++$x) { + $matrix->set($x, 0, 1); + $matrix->set($x, 6, 1); + } + + for ($y = 1; $y < 6; ++$y) { + $matrix->set(0, $y, 1); + $matrix->set(6, $y, 1); + } + + return $this->module->createPath($matrix)->translate(-3.5, -3.5); + } + + public function getInternalPath() : Path + { + $matrix = new ByteMatrix(3, 3); + + for ($x = 0; $x < 3; ++$x) { + for ($y = 0; $y < 3; ++$y) { + $matrix->set($x, $y, 1); + } + } + + return $this->module->createPath($matrix)->translate(-1.5, -1.5); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php new file mode 100644 index 0000000..64d54ee --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php @@ -0,0 +1,54 @@ +move(-3.5, -3.5) + ->line(3.5, -3.5) + ->line(3.5, 3.5) + ->line(-3.5, 3.5) + ->close() + ->move(-2.5, -2.5) + ->line(-2.5, 2.5) + ->line(2.5, 2.5) + ->line(2.5, -2.5) + ->close() + ; + } + + public function getInternalPath() : Path + { + return (new Path()) + ->move(1.5, 0) + ->ellipticArc(1.5, 1.5, 0., false, true, 0., 1.5) + ->ellipticArc(1.5, 1.5, 0., false, true, -1.5, 0.) + ->ellipticArc(1.5, 1.5, 0., false, true, 0., -1.5) + ->ellipticArc(1.5, 1.5, 0., false, true, 1.5, 0.) + ->close() + ; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php new file mode 100644 index 0000000..a3892b4 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php @@ -0,0 +1,53 @@ +move(-3.5, -3.5) + ->line(3.5, -3.5) + ->line(3.5, 3.5) + ->line(-3.5, 3.5) + ->close() + ->move(-2.5, -2.5) + ->line(-2.5, 2.5) + ->line(2.5, 2.5) + ->line(2.5, -2.5) + ->close() + ; + } + + public function getInternalPath() : Path + { + return (new Path()) + ->move(-1.5, -1.5) + ->line(1.5, -1.5) + ->line(1.5, 1.5) + ->line(-1.5, 1.5) + ->close() + ; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php new file mode 100644 index 0000000..b581b54 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php @@ -0,0 +1,376 @@ +eps = "%!PS-Adobe-3.0 EPSF-3.0\n" + . "%%Creator: BaconQrCode\n" + . sprintf("%%%%BoundingBox: 0 0 %d %d \n", $size, $size) + . "%%BeginProlog\n" + . "save\n" + . "50 dict begin\n" + . "/q { gsave } bind def\n" + . "/Q { grestore } bind def\n" + . "/s { scale } bind def\n" + . "/t { translate } bind def\n" + . "/r { rotate } bind def\n" + . "/n { newpath } bind def\n" + . "/m { moveto } bind def\n" + . "/l { lineto } bind def\n" + . "/c { curveto } bind def\n" + . "/z { closepath } bind def\n" + . "/f { eofill } bind def\n" + . "/rgb { setrgbcolor } bind def\n" + . "/cmyk { setcmykcolor } bind def\n" + . "/gray { setgray } bind def\n" + . "%%EndProlog\n" + . "1 -1 s\n" + . sprintf("0 -%d t\n", $size); + + if ($backgroundColor instanceof Alpha && 0 === $backgroundColor->getAlpha()) { + return; + } + + $this->eps .= wordwrap( + '0 0 m' + . sprintf(' %s 0 l', (string) $size) + . sprintf(' %s %s l', (string) $size, (string) $size) + . sprintf(' 0 %s l', (string) $size) + . ' z' + . ' ' .$this->getColorSetString($backgroundColor) . " f\n", + 75, + "\n " + ); + } + + public function scale(float $size) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= sprintf("%1\$s %1\$s s\n", round($size, self::PRECISION)); + } + + public function translate(float $x, float $y) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= sprintf("%s %s t\n", round($x, self::PRECISION), round($y, self::PRECISION)); + } + + public function rotate(int $degrees) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= sprintf("%d r\n", $degrees); + } + + public function push() : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= "q\n"; + } + + public function pop() : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= "Q\n"; + } + + public function drawPathWithColor(Path $path, ColorInterface $color) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $fromX = 0; + $fromY = 0; + $this->eps .= wordwrap( + 'n ' + . $this->drawPathOperations($path, $fromX, $fromY) + . ' ' . $this->getColorSetString($color) . " f\n", + 75, + "\n " + ); + } + + public function drawPathWithGradient( + Path $path, + Gradient $gradient, + float $x, + float $y, + float $width, + float $height + ) : void { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $fromX = 0; + $fromY = 0; + $this->eps .= wordwrap( + 'q n ' . $this->drawPathOperations($path, $fromX, $fromY) . "\n", + 75, + "\n " + ); + + $this->createGradientFill($gradient, $x, $y, $width, $height); + } + + public function done() : string + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= "%%TRAILER\nend restore\n%%EOF"; + $blob = $this->eps; + $this->eps = null; + + return $blob; + } + + private function drawPathOperations(Iterable $ops, &$fromX, &$fromY) : string + { + $pathData = []; + + foreach ($ops as $op) { + switch (true) { + case $op instanceof Move: + $fromX = $toX = round($op->getX(), self::PRECISION); + $fromY = $toY = round($op->getY(), self::PRECISION); + $pathData[] = sprintf('%s %s m', $toX, $toY); + break; + + case $op instanceof Line: + $fromX = $toX = round($op->getX(), self::PRECISION); + $fromY = $toY = round($op->getY(), self::PRECISION); + $pathData[] = sprintf('%s %s l', $toX, $toY); + break; + + case $op instanceof EllipticArc: + $pathData[] = $this->drawPathOperations($op->toCurves($fromX, $fromY), $fromX, $fromY); + break; + + case $op instanceof Curve: + $x1 = round($op->getX1(), self::PRECISION); + $y1 = round($op->getY1(), self::PRECISION); + $x2 = round($op->getX2(), self::PRECISION); + $y2 = round($op->getY2(), self::PRECISION); + $fromX = $x3 = round($op->getX3(), self::PRECISION); + $fromY = $y3 = round($op->getY3(), self::PRECISION); + $pathData[] = sprintf('%s %s %s %s %s %s c', $x1, $y1, $x2, $y2, $x3, $y3); + break; + + case $op instanceof Close: + $pathData[] = 'z'; + break; + + default: + throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); + } + } + + return implode(' ', $pathData); + } + + private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : void + { + $startColor = $gradient->getStartColor(); + $endColor = $gradient->getEndColor(); + + if ($startColor instanceof Alpha) { + $startColor = $startColor->getBaseColor(); + } + + $startColorType = get_class($startColor); + + if (! in_array($startColorType, [Rgb::class, Cmyk::class, Gray::class])) { + $startColorType = Cmyk::class; + $startColor = $startColor->toCmyk(); + } + + if (get_class($endColor) !== $startColorType) { + switch ($startColorType) { + case Cmyk::class: + $endColor = $endColor->toCmyk(); + break; + + case Rgb::class: + $endColor = $endColor->toRgb(); + break; + + case Gray::class: + $endColor = $endColor->toGray(); + break; + } + } + + $this->eps .= "eoclip\n<<\n"; + + if ($gradient->getType() === GradientType::RADIAL()) { + $this->eps .= " /ShadingType 3\n"; + } else { + $this->eps .= " /ShadingType 2\n"; + } + + $this->eps .= " /Extend [ true true ]\n" + . " /AntiAlias true\n"; + + switch ($startColorType) { + case Cmyk::class: + $this->eps .= " /ColorSpace /DeviceCMYK\n"; + break; + + case Rgb::class: + $this->eps .= " /ColorSpace /DeviceRGB\n"; + break; + + case Gray::class: + $this->eps .= " /ColorSpace /DeviceGray\n"; + break; + } + + switch ($gradient->getType()) { + case GradientType::HORIZONTAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y, self::PRECISION), + round($x + $width, self::PRECISION), + round($y, self::PRECISION) + ); + break; + + case GradientType::VERTICAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y, self::PRECISION), + round($x, self::PRECISION), + round($y + $height, self::PRECISION) + ); + break; + + case GradientType::DIAGONAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y, self::PRECISION), + round($x + $width, self::PRECISION), + round($y + $height, self::PRECISION) + ); + break; + + case GradientType::INVERSE_DIAGONAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y + $height, self::PRECISION), + round($x + $width, self::PRECISION), + round($y, self::PRECISION) + ); + break; + + case GradientType::RADIAL(): + $centerX = ($x + $width) / 2; + $centerY = ($y + $height) / 2; + + $this->eps .= sprintf( + " /Coords [ %s %s 0 %s %s %s ]\n", + round($centerX, self::PRECISION), + round($centerY, self::PRECISION), + round($centerX, self::PRECISION), + round($centerY, self::PRECISION), + round(max($width, $height) / 2, self::PRECISION) + ); + break; + } + + $this->eps .= " /Function\n" + . " <<\n" + . " /FunctionType 2\n" + . " /Domain [ 0 1 ]\n" + . sprintf(" /C0 [ %s ]\n", $this->getColorString($startColor)) + . sprintf(" /C1 [ %s ]\n", $this->getColorString($endColor)) + . " /N 1\n" + . " >>\n>>\nshfill\nQ\n"; + } + + private function getColorSetString(ColorInterface $color) : string + { + if ($color instanceof Rgb) { + return $this->getColorString($color) . ' rgb'; + } + + if ($color instanceof Cmyk) { + return $this->getColorString($color) . ' cmyk'; + } + + if ($color instanceof Gray) { + return $this->getColorString($color) . ' gray'; + } + + return $this->getColorSetString($color->toCmyk()); + } + + private function getColorString(ColorInterface $color) : string + { + if ($color instanceof Rgb) { + return sprintf('%s %s %s', $color->getRed() / 255, $color->getGreen() / 255, $color->getBlue() / 255); + } + + if ($color instanceof Cmyk) { + return sprintf( + '%s %s %s %s', + $color->getCyan() / 100, + $color->getMagenta() / 100, + $color->getYellow() / 100, + $color->getBlack() / 100 + ); + } + + if ($color instanceof Gray) { + return sprintf('%s', $color->getGray() / 100); + } + + return $this->getColorString($color->toCmyk()); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php new file mode 100644 index 0000000..0935819 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php @@ -0,0 +1,87 @@ +imageFormat = $imageFormat; + $this->compressionQuality = $compressionQuality; + } + + public function new(int $size, ColorInterface $backgroundColor) : void + { + $this->image = new Imagick(); + $this->image->newImage($size, $size, $this->getColorPixel($backgroundColor)); + $this->image->setImageFormat($this->imageFormat); + $this->image->setCompressionQuality($this->compressionQuality); + $this->draw = new ImagickDraw(); + $this->gradientCount = 0; + $this->matrices = [new TransformationMatrix()]; + $this->matrixIndex = 0; + } + + public function scale(float $size) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->scale($size, $size); + $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex] + ->multiply(TransformationMatrix::scale($size)); + } + + public function translate(float $x, float $y) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->translate($x, $y); + $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex] + ->multiply(TransformationMatrix::translate($x, $y)); + } + + public function rotate(int $degrees) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->rotate($degrees); + $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex] + ->multiply(TransformationMatrix::rotate($degrees)); + } + + public function push() : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->push(); + $this->matrices[++$this->matrixIndex] = $this->matrices[$this->matrixIndex - 1]; + } + + public function pop() : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->pop(); + unset($this->matrices[$this->matrixIndex--]); + } + + public function drawPathWithColor(Path $path, ColorInterface $color) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->setFillColor($this->getColorPixel($color)); + $this->drawPath($path); + } + + public function drawPathWithGradient( + Path $path, + Gradient $gradient, + float $x, + float $y, + float $width, + float $height + ) : void { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->setFillPatternURL('#' . $this->createGradientFill($gradient, $x, $y, $width, $height)); + $this->drawPath($path); + } + + public function done() : string + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->image->drawImage($this->draw); + $blob = $this->image->getImageBlob(); + $this->draw->clear(); + $this->image->clear(); + $this->draw = null; + $this->image = null; + $this->gradientCount = null; + + return $blob; + } + + private function drawPath(Path $path) : void + { + $this->draw->pathStart(); + + foreach ($path as $op) { + switch (true) { + case $op instanceof Move: + $this->draw->pathMoveToAbsolute($op->getX(), $op->getY()); + break; + + case $op instanceof Line: + $this->draw->pathLineToAbsolute($op->getX(), $op->getY()); + break; + + case $op instanceof EllipticArc: + $this->draw->pathEllipticArcAbsolute( + $op->getXRadius(), + $op->getYRadius(), + $op->getXAxisAngle(), + $op->isLargeArc(), + $op->isSweep(), + $op->getX(), + $op->getY() + ); + break; + + case $op instanceof Curve: + $this->draw->pathCurveToAbsolute( + $op->getX1(), + $op->getY1(), + $op->getX2(), + $op->getY2(), + $op->getX3(), + $op->getY3() + ); + break; + + case $op instanceof Close: + $this->draw->pathClose(); + break; + + default: + throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); + } + } + + $this->draw->pathFinish(); + } + + private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string + { + list($width, $height) = $this->matrices[$this->matrixIndex]->apply($x + $width, $y + $height); + list($x, $y) = $this->matrices[$this->matrixIndex]->apply($x, $y); + $width -= $x; + $height -= $y; + + $startColor = $this->getColorPixel($gradient->getStartColor())->getColorAsString(); + $endColor = $this->getColorPixel($gradient->getEndColor())->getColorAsString(); + $gradientImage = new Imagick(); + + switch ($gradient->getType()) { + case GradientType::HORIZONTAL(): + $gradientImage->newPseudoImage((int) $height, (int) $width, sprintf( + 'gradient:%s-%s', + $startColor, + $endColor + )); + $gradientImage->rotateImage('transparent', -90); + break; + + case GradientType::VERTICAL(): + $gradientImage->newPseudoImage((int) $width, (int) $height, sprintf( + 'gradient:%s-%s', + $startColor, + $endColor + )); + break; + + case GradientType::DIAGONAL(): + case GradientType::INVERSE_DIAGONAL(): + $gradientImage->newPseudoImage((int) ($width * sqrt(2)), (int) ($height * sqrt(2)), sprintf( + 'gradient:%s-%s', + $startColor, + $endColor + )); + + if (GradientType::DIAGONAL() === $gradient->getType()) { + $gradientImage->rotateImage('transparent', -45); + } else { + $gradientImage->rotateImage('transparent', -135); + } + + $rotatedWidth = $gradientImage->getImageWidth(); + $rotatedHeight = $gradientImage->getImageHeight(); + + $gradientImage->setImagePage($rotatedWidth, $rotatedHeight, 0, 0); + $gradientImage->cropImage( + intdiv($rotatedWidth, 2) - 2, + intdiv($rotatedHeight, 2) - 2, + intdiv($rotatedWidth, 4) + 1, + intdiv($rotatedWidth, 4) + 1 + ); + break; + + case GradientType::RADIAL(): + $gradientImage->newPseudoImage((int) $width, (int) $height, sprintf( + 'radial-gradient:%s-%s', + $startColor, + $endColor + )); + break; + } + + $id = sprintf('g%d', ++$this->gradientCount); + $this->draw->pushPattern($id, 0, 0, $x + $width, $y + $height); + $this->draw->composite(Imagick::COMPOSITE_COPY, $x, $y, $width, $height, $gradientImage); + $this->draw->popPattern(); + return $id; + } + + private function getColorPixel(ColorInterface $color) : ImagickPixel + { + $alpha = 100; + + if ($color instanceof Alpha) { + $alpha = $color->getAlpha(); + $color = $color->getBaseColor(); + } + + if ($color instanceof Rgb) { + return new ImagickPixel(sprintf( + 'rgba(%d, %d, %d, %F)', + $color->getRed(), + $color->getGreen(), + $color->getBlue(), + $alpha / 100 + )); + } + + if ($color instanceof Cmyk) { + return new ImagickPixel(sprintf( + 'cmyka(%d, %d, %d, %d, %F)', + $color->getCyan(), + $color->getMagenta(), + $color->getYellow(), + $color->getBlack(), + $alpha / 100 + )); + } + + if ($color instanceof Gray) { + return new ImagickPixel(sprintf( + 'graya(%d%%, %F)', + $color->getGray(), + $alpha / 100 + )); + } + + return $this->getColorPixel(new Alpha($alpha, $color->toRgb())); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php new file mode 100644 index 0000000..714da6e --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php @@ -0,0 +1,369 @@ +xmlWriter = new XMLWriter(); + $this->xmlWriter->openMemory(); + + $this->xmlWriter->startDocument('1.0', 'UTF-8'); + $this->xmlWriter->startElement('svg'); + $this->xmlWriter->writeAttribute('xmlns', 'http://www.w3.org/2000/svg'); + $this->xmlWriter->writeAttribute('version', '1.1'); + $this->xmlWriter->writeAttribute('width', (string) $size); + $this->xmlWriter->writeAttribute('height', (string) $size); + $this->xmlWriter->writeAttribute('viewBox', '0 0 '. $size . ' ' . $size); + + $this->gradientCount = 0; + $this->currentStack = 0; + $this->stack[0] = 0; + + $alpha = 1; + + if ($backgroundColor instanceof Alpha) { + $alpha = $backgroundColor->getAlpha() / 100; + } + + if (0 === $alpha) { + return; + } + + $this->xmlWriter->startElement('rect'); + $this->xmlWriter->writeAttribute('x', '0'); + $this->xmlWriter->writeAttribute('y', '0'); + $this->xmlWriter->writeAttribute('width', (string) $size); + $this->xmlWriter->writeAttribute('height', (string) $size); + $this->xmlWriter->writeAttribute('fill', $this->getColorString($backgroundColor)); + + if ($alpha < 1) { + $this->xmlWriter->writeAttribute('fill-opacity', (string) $alpha); + } + + $this->xmlWriter->endElement(); + } + + public function scale(float $size) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->xmlWriter->writeAttribute( + 'transform', + sprintf('scale(%s)', round($size, self::PRECISION)) + ); + ++$this->stack[$this->currentStack]; + } + + public function translate(float $x, float $y) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->xmlWriter->writeAttribute( + 'transform', + sprintf('translate(%s,%s)', round($x, self::PRECISION), round($y, self::PRECISION)) + ); + ++$this->stack[$this->currentStack]; + } + + public function rotate(int $degrees) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->xmlWriter->writeAttribute('transform', sprintf('rotate(%d)', $degrees)); + ++$this->stack[$this->currentStack]; + } + + public function push() : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->stack[] = 1; + ++$this->currentStack; + } + + public function pop() : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + for ($i = 0; $i < $this->stack[$this->currentStack]; ++$i) { + $this->xmlWriter->endElement(); + } + + array_pop($this->stack); + --$this->currentStack; + } + + public function drawPathWithColor(Path $path, ColorInterface $color) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $alpha = 1; + + if ($color instanceof Alpha) { + $alpha = $color->getAlpha() / 100; + } + + $this->startPathElement($path); + $this->xmlWriter->writeAttribute('fill', $this->getColorString($color)); + + if ($alpha < 1) { + $this->xmlWriter->writeAttribute('fill-opacity', (string) $alpha); + } + + $this->xmlWriter->endElement(); + } + + public function drawPathWithGradient( + Path $path, + Gradient $gradient, + float $x, + float $y, + float $width, + float $height + ) : void { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $gradientId = $this->createGradientFill($gradient, $x, $y, $width, $height); + $this->startPathElement($path); + $this->xmlWriter->writeAttribute('fill', 'url(#' . $gradientId . ')'); + $this->xmlWriter->endElement(); + } + + public function done() : string + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + foreach ($this->stack as $openElements) { + for ($i = $openElements; $i > 0; --$i) { + $this->xmlWriter->endElement(); + } + } + + $this->xmlWriter->endDocument(); + $blob = $this->xmlWriter->outputMemory(true); + $this->xmlWriter = null; + $this->stack = null; + $this->currentStack = null; + $this->gradientCount = null; + + return $blob; + } + + private function startPathElement(Path $path) : void + { + $pathData = []; + + foreach ($path as $op) { + switch (true) { + case $op instanceof Move: + $pathData[] = sprintf( + 'M%s %s', + round($op->getX(), self::PRECISION), + round($op->getY(), self::PRECISION) + ); + break; + + case $op instanceof Line: + $pathData[] = sprintf( + 'L%s %s', + round($op->getX(), self::PRECISION), + round($op->getY(), self::PRECISION) + ); + break; + + case $op instanceof EllipticArc: + $pathData[] = sprintf( + 'A%s %s %s %u %u %s %s', + round($op->getXRadius(), self::PRECISION), + round($op->getYRadius(), self::PRECISION), + round($op->getXAxisAngle(), self::PRECISION), + $op->isLargeArc(), + $op->isSweep(), + round($op->getX(), self::PRECISION), + round($op->getY(), self::PRECISION) + ); + break; + + case $op instanceof Curve: + $pathData[] = sprintf( + 'C%s %s %s %s %s %s', + round($op->getX1(), self::PRECISION), + round($op->getY1(), self::PRECISION), + round($op->getX2(), self::PRECISION), + round($op->getY2(), self::PRECISION), + round($op->getX3(), self::PRECISION), + round($op->getY3(), self::PRECISION) + ); + break; + + case $op instanceof Close: + $pathData[] = 'Z'; + break; + + default: + throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); + } + } + + $this->xmlWriter->startElement('path'); + $this->xmlWriter->writeAttribute('fill-rule', 'evenodd'); + $this->xmlWriter->writeAttribute('d', implode('', $pathData)); + } + + private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string + { + $this->xmlWriter->startElement('defs'); + + $startColor = $gradient->getStartColor(); + $endColor = $gradient->getEndColor(); + + if ($gradient->getType() === GradientType::RADIAL()) { + $this->xmlWriter->startElement('radialGradient'); + } else { + $this->xmlWriter->startElement('linearGradient'); + } + + $this->xmlWriter->writeAttribute('gradientUnits', 'userSpaceOnUse'); + + switch ($gradient->getType()) { + case GradientType::HORIZONTAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y, self::PRECISION)); + break; + + case GradientType::VERTICAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y + $height, self::PRECISION)); + break; + + case GradientType::DIAGONAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y + $height, self::PRECISION)); + break; + + case GradientType::INVERSE_DIAGONAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y + $height, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y, self::PRECISION)); + break; + + case GradientType::RADIAL(): + $this->xmlWriter->writeAttribute('cx', (string) round(($x + $width) / 2, self::PRECISION)); + $this->xmlWriter->writeAttribute('cy', (string) round(($y + $height) / 2, self::PRECISION)); + $this->xmlWriter->writeAttribute('r', (string) round(max($width, $height) / 2, self::PRECISION)); + break; + } + + $id = sprintf('g%d', ++$this->gradientCount); + $this->xmlWriter->writeAttribute('id', $id); + + $this->xmlWriter->startElement('stop'); + $this->xmlWriter->writeAttribute('offset', '0%'); + $this->xmlWriter->writeAttribute('stop-color', $this->getColorString($startColor)); + + if ($startColor instanceof Alpha) { + $this->xmlWriter->writeAttribute('stop-opacity', $startColor->getAlpha()); + } + + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('stop'); + $this->xmlWriter->writeAttribute('offset', '100%'); + $this->xmlWriter->writeAttribute('stop-color', $this->getColorString($endColor)); + + if ($endColor instanceof Alpha) { + $this->xmlWriter->writeAttribute('stop-opacity', $endColor->getAlpha()); + } + + $this->xmlWriter->endElement(); + + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + return $id; + } + + private function getColorString(ColorInterface $color) : string + { + $color = $color->toRgb(); + + return sprintf( + '#%02x%02x%02x', + $color->getRed(), + $color->getGreen(), + $color->getBlue() + ); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php new file mode 100644 index 0000000..7e88da6 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php @@ -0,0 +1,68 @@ +values = [1, 0, 0, 1, 0, 0]; + } + + public function multiply(self $other) : self + { + $matrix = new self(); + $matrix->values[0] = $this->values[0] * $other->values[0] + $this->values[2] * $other->values[1]; + $matrix->values[1] = $this->values[1] * $other->values[0] + $this->values[3] * $other->values[1]; + $matrix->values[2] = $this->values[0] * $other->values[2] + $this->values[2] * $other->values[3]; + $matrix->values[3] = $this->values[1] * $other->values[2] + $this->values[3] * $other->values[3]; + $matrix->values[4] = $this->values[0] * $other->values[4] + $this->values[2] * $other->values[5] + + $this->values[4]; + $matrix->values[5] = $this->values[1] * $other->values[4] + $this->values[3] * $other->values[5] + + $this->values[5]; + + return $matrix; + } + + public static function scale(float $size) : self + { + $matrix = new self(); + $matrix->values = [$size, 0, 0, $size, 0, 0]; + return $matrix; + } + + public static function translate(float $x, float $y) : self + { + $matrix = new self(); + $matrix->values = [1, 0, 0, 1, $x, $y]; + return $matrix; + } + + public static function rotate(int $degrees) : self + { + $matrix = new self(); + $rad = deg2rad($degrees); + $matrix->values = [cos($rad), sin($rad), -sin($rad), cos($rad), 0, 0]; + return $matrix; + } + + + /** + * Applies this matrix onto a point and returns the resulting viewport point. + * + * @return float[] + */ + public function apply(float $x, float $y) : array + { + return [ + $x * $this->values[0] + $y * $this->values[2] + $this->values[4], + $x * $this->values[1] + $y * $this->values[3] + $this->values[5], + ]; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php new file mode 100644 index 0000000..ab16276 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php @@ -0,0 +1,152 @@ +rendererStyle = $rendererStyle; + $this->imageBackEnd = $imageBackEnd; + } + + /** + * @throws InvalidArgumentException if matrix width doesn't match height + */ + public function render(QrCode $qrCode) : string + { + $size = $this->rendererStyle->getSize(); + $margin = $this->rendererStyle->getMargin(); + $matrix = $qrCode->getMatrix(); + $matrixSize = $matrix->getWidth(); + + if ($matrixSize !== $matrix->getHeight()) { + throw new InvalidArgumentException('Matrix must have the same width and height'); + } + + $totalSize = $matrixSize + ($margin * 2); + $moduleSize = $size / $totalSize; + $fill = $this->rendererStyle->getFill(); + + $this->imageBackEnd->new($size, $fill->getBackgroundColor()); + $this->imageBackEnd->scale((float) $moduleSize); + $this->imageBackEnd->translate((float) $margin, (float) $margin); + + $module = $this->rendererStyle->getModule(); + $moduleMatrix = clone $matrix; + MatrixUtil::removePositionDetectionPatterns($moduleMatrix); + $modulePath = $this->drawEyes($matrixSize, $module->createPath($moduleMatrix)); + + if ($fill->hasGradientFill()) { + $this->imageBackEnd->drawPathWithGradient( + $modulePath, + $fill->getForegroundGradient(), + 0, + 0, + $matrixSize, + $matrixSize + ); + } else { + $this->imageBackEnd->drawPathWithColor($modulePath, $fill->getForegroundColor()); + } + + return $this->imageBackEnd->done(); + } + + private function drawEyes(int $matrixSize, Path $modulePath) : Path + { + $fill = $this->rendererStyle->getFill(); + + $eye = $this->rendererStyle->getEye(); + $externalPath = $eye->getExternalPath(); + $internalPath = $eye->getInternalPath(); + + $modulePath = $this->drawEye( + $externalPath, + $internalPath, + $fill->getTopLeftEyeFill(), + 3.5, + 3.5, + 0, + $modulePath + ); + $modulePath = $this->drawEye( + $externalPath, + $internalPath, + $fill->getTopRightEyeFill(), + $matrixSize - 3.5, + 3.5, + 90, + $modulePath + ); + $modulePath = $this->drawEye( + $externalPath, + $internalPath, + $fill->getBottomLeftEyeFill(), + 3.5, + $matrixSize - 3.5, + -90, + $modulePath + ); + + return $modulePath; + } + + private function drawEye( + Path $externalPath, + Path $internalPath, + EyeFill $fill, + float $xTranslation, + float $yTranslation, + int $rotation, + Path $modulePath + ) : Path { + if ($fill->inheritsBothColors()) { + return $modulePath + ->append($externalPath->translate($xTranslation, $yTranslation)) + ->append($internalPath->translate($xTranslation, $yTranslation)); + } + + $this->imageBackEnd->push(); + $this->imageBackEnd->translate($xTranslation, $yTranslation); + + if (0 !== $rotation) { + $this->imageBackEnd->rotate($rotation); + } + + if ($fill->inheritsExternalColor()) { + $modulePath = $modulePath->append($externalPath->translate($xTranslation, $yTranslation)); + } else { + $this->imageBackEnd->drawPathWithColor($externalPath, $fill->getExternalColor()); + } + + if ($fill->inheritsInternalColor()) { + $modulePath = $modulePath->append($internalPath->translate($xTranslation, $yTranslation)); + } else { + $this->imageBackEnd->drawPathWithColor($internalPath, $fill->getInternalColor()); + } + + $this->imageBackEnd->pop(); + + return $modulePath; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php new file mode 100644 index 0000000..f536e5a --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php @@ -0,0 +1,63 @@ + 1) { + throw new InvalidArgumentException('Size must between 0 (exclusive) and 1 (inclusive)'); + } + + $this->size = $size; + } + + public function createPath(ByteMatrix $matrix) : Path + { + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + $path = new Path(); + $halfSize = $this->size / 2; + $margin = (1 - $this->size) / 2; + + for ($y = 0; $y < $height; ++$y) { + for ($x = 0; $x < $width; ++$x) { + if (! $matrix->get($x, $y)) { + continue; + } + + $pathX = $x + $margin; + $pathY = $y + $margin; + + $path = $path + ->move($pathX + $this->size, $pathY + $halfSize) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $halfSize, $pathY + $this->size) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX, $pathY + $halfSize) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $halfSize, $pathY) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $this->size, $pathY + $halfSize) + ->close() + ; + } + } + + return $path; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php new file mode 100644 index 0000000..90482f2 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php @@ -0,0 +1,100 @@ + + */ + private $points = []; + + /** + * @var array|null + */ + private $simplifiedPoints; + + /** + * @var int + */ + private $minX = PHP_INT_MAX; + + /** + * @var int + */ + private $minY = PHP_INT_MAX; + + /** + * @var int + */ + private $maxX = -1; + + /** + * @var int + */ + private $maxY = -1; + + public function __construct(bool $positive) + { + $this->positive = $positive; + } + + public function addPoint(int $x, int $y) : void + { + $this->points[] = [$x, $y]; + $this->minX = min($this->minX, $x); + $this->minY = min($this->minY, $y); + $this->maxX = max($this->maxX, $x); + $this->maxY = max($this->maxY, $y); + } + + public function isPositive() : bool + { + return $this->positive; + } + + /** + * @return array + */ + public function getPoints() : array + { + return $this->points; + } + + public function getMaxX() : int + { + return $this->maxX; + } + + public function getSimplifiedPoints() : array + { + if (null !== $this->simplifiedPoints) { + return $this->simplifiedPoints; + } + + $points = []; + $length = count($this->points); + + for ($i = 0; $i < $length; ++$i) { + $previousPoint = $this->points[(0 === $i ? $length : $i) - 1]; + $nextPoint = $this->points[($length - 1 === $i ? -1 : $i) + 1]; + $currentPoint = $this->points[$i]; + + if (($previousPoint[0] === $currentPoint[0] && $currentPoint[0] === $nextPoint[0]) + || ($previousPoint[1] === $currentPoint[1] && $currentPoint[1] === $nextPoint[1]) + ) { + continue; + } + + $points[] = $currentPoint; + } + + return $this->simplifiedPoints = $points; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php new file mode 100644 index 0000000..af52d52 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php @@ -0,0 +1,169 @@ +bytes = iterator_to_array($matrix->getBytes()); + $this->size = count($this->bytes); + $this->width = $matrix->getWidth(); + $this->height = $matrix->getHeight(); + } + + /** + * @return Edge[] + */ + public function getIterator() : Traversable + { + $originalBytes = $this->bytes; + $point = $this->findNext(0, 0); + + while (null !== $point) { + $edge = $this->findEdge($point[0], $point[1]); + $this->xorEdge($edge); + + yield $edge; + + $point = $this->findNext($point[0], $point[1]); + } + + $this->bytes = $originalBytes; + } + + /** + * @return int[]|null + */ + private function findNext(int $x, int $y) : ?array + { + $i = $this->width * $y + $x; + + while ($i < $this->size && 1 !== $this->bytes[$i]) { + ++$i; + } + + if ($i < $this->size) { + return $this->pointOf($i); + } + + return null; + } + + private function findEdge(int $x, int $y) : Edge + { + $edge = new Edge($this->isSet($x, $y)); + $startX = $x; + $startY = $y; + $dirX = 0; + $dirY = 1; + + while (true) { + $edge->addPoint($x, $y); + $x += $dirX; + $y += $dirY; + + if ($x === $startX && $y === $startY) { + break; + } + + $left = $this->isSet($x + ($dirX + $dirY - 1 ) / 2, $y + ($dirY - $dirX - 1) / 2); + $right = $this->isSet($x + ($dirX - $dirY - 1) / 2, $y + ($dirY + $dirX - 1) / 2); + + if ($right && ! $left) { + $tmp = $dirX; + $dirX = -$dirY; + $dirY = $tmp; + } elseif ($right) { + $tmp = $dirX; + $dirX = -$dirY; + $dirY = $tmp; + } elseif (! $left) { + $tmp = $dirX; + $dirX = $dirY; + $dirY = -$tmp; + } + } + + return $edge; + } + + private function xorEdge(Edge $path) : void + { + $points = $path->getPoints(); + $y1 = $points[0][1]; + $length = count($points); + $maxX = $path->getMaxX(); + + for ($i = 1; $i < $length; ++$i) { + $y = $points[$i][1]; + + if ($y === $y1) { + continue; + } + + $x = $points[$i][0]; + $minY = min($y1, $y); + + for ($j = $x; $j < $maxX; ++$j) { + $this->flip($j, $minY); + } + + $y1 = $y; + } + } + + private function isSet(int $x, int $y) : bool + { + return ( + $x >= 0 + && $x < $this->width + && $y >= 0 + && $y < $this->height + ) && 1 === $this->bytes[$this->width * $y + $x]; + } + + /** + * @return int[] + */ + private function pointOf(int $i) : array + { + $y = intdiv($i, $this->width); + return [$i - $y * $this->width, $y]; + } + + private function flip(int $x, int $y) : void + { + $this->bytes[$this->width * $y + $x] = ( + $this->isSet($x, $y) ? 0 : 1 + ); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php new file mode 100644 index 0000000..0ccb0e0 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php @@ -0,0 +1,18 @@ + 1) { + throw new InvalidArgumentException('Intensity must between 0 (exclusive) and 1 (inclusive)'); + } + + $this->intensity = $intensity / 2; + } + + public function createPath(ByteMatrix $matrix) : Path + { + $path = new Path(); + + foreach (new EdgeIterator($matrix) as $edge) { + $points = $edge->getSimplifiedPoints(); + $length = count($points); + + $currentPoint = $points[0]; + $nextPoint = $points[1]; + $horizontal = ($currentPoint[1] === $nextPoint[1]); + + if ($horizontal) { + $right = $nextPoint[0] > $currentPoint[0]; + $path = $path->move( + $currentPoint[0] + ($right ? $this->intensity : -$this->intensity), + $currentPoint[1] + ); + } else { + $up = $nextPoint[0] < $currentPoint[0]; + $path = $path->move( + $currentPoint[0], + $currentPoint[1] + ($up ? -$this->intensity : $this->intensity) + ); + } + + for ($i = 1; $i <= $length; ++$i) { + if ($i === $length) { + $previousPoint = $points[$length - 1]; + $currentPoint = $points[0]; + $nextPoint = $points[1]; + } else { + $previousPoint = $points[(0 === $i ? $length : $i) - 1]; + $currentPoint = $points[$i]; + $nextPoint = $points[($length - 1 === $i ? -1 : $i) + 1]; + } + + $horizontal = ($previousPoint[1] === $currentPoint[1]); + + if ($horizontal) { + $right = $previousPoint[0] < $currentPoint[0]; + $up = $nextPoint[1] < $currentPoint[1]; + $sweep = ($up xor $right); + + if ($this->intensity < 0.5 + || ($right && $previousPoint[0] !== $currentPoint[0] - 1) + || (! $right && $previousPoint[0] - 1 !== $currentPoint[0]) + ) { + $path = $path->line( + $currentPoint[0] + ($right ? -$this->intensity : $this->intensity), + $currentPoint[1] + ); + } + + $path = $path->ellipticArc( + $this->intensity, + $this->intensity, + 0, + false, + $sweep, + $currentPoint[0], + $currentPoint[1] + ($up ? -$this->intensity : $this->intensity) + ); + } else { + $up = $previousPoint[1] > $currentPoint[1]; + $right = $nextPoint[0] > $currentPoint[0]; + $sweep = ! ($up xor $right); + + if ($this->intensity < 0.5 + || ($up && $previousPoint[1] !== $currentPoint[1] + 1) + || (! $up && $previousPoint[0] + 1 !== $currentPoint[0]) + ) { + $path = $path->line( + $currentPoint[0], + $currentPoint[1] + ($up ? $this->intensity : -$this->intensity) + ); + } + + $path = $path->ellipticArc( + $this->intensity, + $this->intensity, + 0, + false, + $sweep, + $currentPoint[0] + ($right ? $this->intensity : -$this->intensity), + $currentPoint[1] + ); + } + } + + $path = $path->close(); + } + + return $path; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php new file mode 100644 index 0000000..9ab4607 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php @@ -0,0 +1,47 @@ +getSimplifiedPoints(); + $length = count($points); + $path = $path->move($points[0][0], $points[0][1]); + + for ($i = 1; $i < $length; ++$i) { + $path = $path->line($points[$i][0], $points[$i][1]); + } + + $path = $path->close(); + } + + return $path; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php new file mode 100644 index 0000000..b07feb0 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php @@ -0,0 +1,29 @@ +x1 = $x1; + $this->y1 = $y1; + $this->x2 = $x2; + $this->y2 = $y2; + $this->x3 = $x3; + $this->y3 = $y3; + } + + public function getX1() : float + { + return $this->x1; + } + + public function getY1() : float + { + return $this->y1; + } + + public function getX2() : float + { + return $this->x2; + } + + public function getY2() : float + { + return $this->y2; + } + + public function getX3() : float + { + return $this->x3; + } + + public function getY3() : float + { + return $this->y3; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self( + $this->x1 + $x, + $this->y1 + $y, + $this->x2 + $x, + $this->y2 + $y, + $this->x3 + $x, + $this->y3 + $y + ); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php new file mode 100644 index 0000000..eff7deb --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php @@ -0,0 +1,278 @@ +xRadius = abs($xRadius); + $this->yRadius = abs($yRadius); + $this->xAxisAngle = $xAxisAngle % 360; + $this->largeArc = $largeArc; + $this->sweep = $sweep; + $this->x = $x; + $this->y = $y; + } + + public function getXRadius() : float + { + return $this->xRadius; + } + + public function getYRadius() : float + { + return $this->yRadius; + } + + public function getXAxisAngle() : float + { + return $this->xAxisAngle; + } + + public function isLargeArc() : bool + { + return $this->largeArc; + } + + public function isSweep() : bool + { + return $this->sweep; + } + + public function getX() : float + { + return $this->x; + } + + public function getY() : float + { + return $this->y; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self( + $this->xRadius, + $this->yRadius, + $this->xAxisAngle, + $this->largeArc, + $this->sweep, + $this->x + $x, + $this->y + $y + ); + } + + /** + * Converts the elliptic arc to multiple curves. + * + * Since not all image back ends support elliptic arcs, this method allows to convert the arc into multiple curves + * resembling the same result. + * + * @see https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/ + * @return array + */ + public function toCurves(float $fromX, float $fromY) : array + { + if (sqrt(($fromX - $this->x) ** 2 + ($fromY - $this->y) ** 2) < self::ZERO_TOLERANCE) { + return []; + } + + if ($this->xRadius < self::ZERO_TOLERANCE || $this->yRadius < self::ZERO_TOLERANCE) { + return [new Line($this->x, $this->y)]; + } + + return $this->createCurves($fromX, $fromY); + } + + /** + * @return Curve[] + */ + private function createCurves(float $fromX, $fromY) : array + { + $xAngle = deg2rad($this->xAxisAngle); + list($centerX, $centerY, $radiusX, $radiusY, $startAngle, $deltaAngle) = + $this->calculateCenterPointParameters($fromX, $fromY, $xAngle); + + $s = $startAngle; + $e = $s + $deltaAngle; + $sign = ($e < $s) ? -1 : 1; + $remain = abs($e - $s); + $p1 = self::point($centerX, $centerY, $radiusX, $radiusY, $xAngle, $s); + $curves = []; + + while ($remain > self::ZERO_TOLERANCE) { + $step = min($remain, pi() / 2); + $signStep = $step * $sign; + $p2 = self::point($centerX, $centerY, $radiusX, $radiusY, $xAngle, $s + $signStep); + + $alphaT = tan($signStep / 2); + $alpha = sin($signStep) * (sqrt(4 + 3 * $alphaT ** 2) - 1) / 3; + $d1 = self::derivative($radiusX, $radiusY, $xAngle, $s); + $d2 = self::derivative($radiusX, $radiusY, $xAngle, $s + $signStep); + + $curves[] = new Curve( + $p1[0] + $alpha * $d1[0], + $p1[1] + $alpha * $d1[1], + $p2[0] - $alpha * $d2[0], + $p2[1] - $alpha * $d2[1], + $p2[0], + $p2[1] + ); + + $s += $signStep; + $remain -= $step; + $p1 = $p2; + } + + return $curves; + } + + /** + * @return float[] + */ + private function calculateCenterPointParameters(float $fromX, float $fromY, float $xAngle) + { + $rX = $this->xRadius; + $rY = $this->yRadius; + + // F.6.5.1 + $dx2 = ($fromX - $this->x) / 2; + $dy2 = ($fromY - $this->y) / 2; + $x1p = cos($xAngle) * $dx2 + sin($xAngle) * $dy2; + $y1p = -sin($xAngle) * $dx2 + cos($xAngle) * $dy2; + + // F.6.5.2 + $rxs = $rX ** 2; + $rys = $rY ** 2; + $x1ps = $x1p ** 2; + $y1ps = $y1p ** 2; + $cr = $x1ps / $rxs + $y1ps / $rys; + + if ($cr > 1) { + $s = sqrt($cr); + $rX *= $s; + $rY *= $s; + $rxs = $rX ** 2; + $rys = $rY ** 2; + } + + $dq = ($rxs * $y1ps + $rys * $x1ps); + $pq = ($rxs * $rys - $dq) / $dq; + $q = sqrt(max(0, $pq)); + + if ($this->largeArc === $this->sweep) { + $q = -$q; + } + + $cxp = $q * $rX * $y1p / $rY; + $cyp = -$q * $rY * $x1p / $rX; + + // F.6.5.3 + $cx = cos($xAngle) * $cxp - sin($xAngle) * $cyp + ($fromX + $this->x) / 2; + $cy = sin($xAngle) * $cxp + cos($xAngle) * $cyp + ($fromY + $this->y) / 2; + + // F.6.5.5 + $theta = self::angle(1, 0, ($x1p - $cxp) / $rX, ($y1p - $cyp) / $rY); + + // F.6.5.6 + $delta = self::angle(($x1p - $cxp) / $rX, ($y1p - $cyp) / $rY, (-$x1p - $cxp) / $rX, (-$y1p - $cyp) / $rY); + $delta = fmod($delta, pi() * 2); + + if (! $this->sweep) { + $delta -= 2 * pi(); + } + + return [$cx, $cy, $rX, $rY, $theta, $delta]; + } + + private static function angle(float $ux, float $uy, float $vx, float $vy) : float + { + // F.6.5.4 + $dot = $ux * $vx + $uy * $vy; + $length = sqrt($ux ** 2 + $uy ** 2) * sqrt($vx ** 2 + $vy ** 2); + $angle = acos(min(1, max(-1, $dot / $length))); + + if (($ux * $vy - $uy * $vx) < 0) { + return -$angle; + } + + return $angle; + } + + /** + * @return float[] + */ + private static function point( + float $centerX, + float $centerY, + float $radiusX, + float $radiusY, + float $xAngle, + float $angle + ) : array { + return [ + $centerX + $radiusX * cos($xAngle) * cos($angle) - $radiusY * sin($xAngle) * sin($angle), + $centerY + $radiusX * sin($xAngle) * cos($angle) + $radiusY * cos($xAngle) * sin($angle), + ]; + } + + /** + * @return float[] + */ + private static function derivative(float $radiusX, float $radiusY, float $xAngle, float $angle) : array + { + return [ + -$radiusX * cos($xAngle) * sin($angle) - $radiusY * sin($xAngle) * cos($angle), + -$radiusX * sin($xAngle) * sin($angle) + $radiusY * cos($xAngle) * cos($angle), + ]; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php new file mode 100644 index 0000000..3149a39 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php @@ -0,0 +1,41 @@ +x = $x; + $this->y = $y; + } + + public function getX() : float + { + return $this->x; + } + + public function getY() : float + { + return $this->y; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self($this->x + $x, $this->y + $y); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php new file mode 100644 index 0000000..481d0dd --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php @@ -0,0 +1,41 @@ +x = $x; + $this->y = $y; + } + + public function getX() : float + { + return $this->x; + } + + public function getY() : float + { + return $this->y; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self($this->x + $x, $this->y + $y); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php new file mode 100644 index 0000000..a5fa0ed --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php @@ -0,0 +1,12 @@ +operations[] = new Move($x, $y); + return $path; + } + + /** + * Draws a line from the current position to another position. + */ + public function line(float $x, float $y) : self + { + $path = clone $this; + $path->operations[] = new Line($x, $y); + return $path; + } + + /** + * Draws an elliptic arc from the current position to another position. + */ + public function ellipticArc( + float $xRadius, + float $yRadius, + float $xAxisRotation, + bool $largeArc, + bool $sweep, + float $x, + float $y + ) : self { + $path = clone $this; + $path->operations[] = new EllipticArc($xRadius, $yRadius, $xAxisRotation, $largeArc, $sweep, $x, $y); + return $path; + } + + /** + * Draws a curve from the current position to another position. + */ + public function curve(float $x1, float $y1, float $x2, float $y2, float $x3, float $y3) : self + { + $path = clone $this; + $path->operations[] = new Curve($x1, $y1, $x2, $y2, $x3, $y3); + return $path; + } + + /** + * Closes a sub-path. + */ + public function close() : self + { + $path = clone $this; + $path->operations[] = Close::instance(); + return $path; + } + + /** + * Appends another path to this one. + */ + public function append(self $other) : self + { + $path = clone $this; + $path->operations = array_merge($this->operations, $other->operations); + return $path; + } + + public function translate(float $x, float $y) : self + { + $path = new self(); + + foreach ($this->operations as $operation) { + $path->operations[] = $operation->translate($x, $y); + } + + return $path; + } + + /** + * @return OperationInterface[]|Traversable + */ + public function getIterator() : Traversable + { + foreach ($this->operations as $operation) { + yield $operation; + } + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php new file mode 100644 index 0000000..8aa7652 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php @@ -0,0 +1,86 @@ +margin = $margin; + } + + /** + * @throws InvalidArgumentException if matrix width doesn't match height + */ + public function render(QrCode $qrCode) : string + { + $matrix = $qrCode->getMatrix(); + $matrixSize = $matrix->getWidth(); + + if ($matrixSize !== $matrix->getHeight()) { + throw new InvalidArgumentException('Matrix must have the same width and height'); + } + + $rows = $matrix->getArray()->toArray(); + + if (0 !== $matrixSize % 2) { + $rows[] = array_fill(0, $matrixSize, 0); + } + + $horizontalMargin = str_repeat(self::EMPTY_BLOCK, $this->margin); + $result = str_repeat("\n", (int) ceil($this->margin / 2)); + + for ($i = 0; $i < $matrixSize; $i += 2) { + $result .= $horizontalMargin; + + $upperRow = $rows[$i]; + $lowerRow = $rows[$i + 1]; + + for ($j = 0; $j < $matrixSize; ++$j) { + $upperBit = $upperRow[$j]; + $lowerBit = $lowerRow[$j]; + + if ($upperBit) { + $result .= $lowerBit ? self::FULL_BLOCK : self::UPPER_HALF_BLOCK; + } else { + $result .= $lowerBit ? self::LOWER_HALF_BLOCK : self::EMPTY_BLOCK; + } + } + + $result .= $horizontalMargin . "\n"; + } + + $result .= str_repeat("\n", (int) ceil($this->margin / 2)); + + return $result; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php new file mode 100644 index 0000000..b0aae39 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php @@ -0,0 +1,11 @@ +externalColor = $externalColor; + $this->internalColor = $internalColor; + } + + public static function uniform(ColorInterface $color) : self + { + return new self($color, $color); + } + + public static function inherit() : self + { + return self::$inherit ?: self::$inherit = new self(null, null); + } + + public function inheritsBothColors() : bool + { + return null === $this->externalColor && null === $this->internalColor; + } + + public function inheritsExternalColor() : bool + { + return null === $this->externalColor; + } + + public function inheritsInternalColor() : bool + { + return null === $this->internalColor; + } + + public function getExternalColor() : ColorInterface + { + if (null === $this->externalColor) { + throw new RuntimeException('External eye color inherits foreground color'); + } + + return $this->externalColor; + } + + public function getInternalColor() : ColorInterface + { + if (null === $this->internalColor) { + throw new RuntimeException('Internal eye color inherits foreground color'); + } + + return $this->internalColor; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php new file mode 100644 index 0000000..d54268e --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php @@ -0,0 +1,168 @@ +backgroundColor = $backgroundColor; + $this->foregroundColor = $foregroundColor; + $this->foregroundGradient = $foregroundGradient; + $this->topLeftEyeFill = $topLeftEyeFill; + $this->topRightEyeFill = $topRightEyeFill; + $this->bottomLeftEyeFill = $bottomLeftEyeFill; + } + + public static function default() : self + { + return self::$default ?: self::$default = self::uniformColor(new Gray(100), new Gray(0)); + } + + public static function withForegroundColor( + ColorInterface $backgroundColor, + ColorInterface $foregroundColor, + EyeFill $topLeftEyeFill, + EyeFill $topRightEyeFill, + EyeFill $bottomLeftEyeFill + ) : self { + return new self( + $backgroundColor, + $foregroundColor, + null, + $topLeftEyeFill, + $topRightEyeFill, + $bottomLeftEyeFill + ); + } + + public static function withForegroundGradient( + ColorInterface $backgroundColor, + Gradient $foregroundGradient, + EyeFill $topLeftEyeFill, + EyeFill $topRightEyeFill, + EyeFill $bottomLeftEyeFill + ) : self { + return new self( + $backgroundColor, + null, + $foregroundGradient, + $topLeftEyeFill, + $topRightEyeFill, + $bottomLeftEyeFill + ); + } + + public static function uniformColor(ColorInterface $backgroundColor, ColorInterface $foregroundColor) : self + { + return new self( + $backgroundColor, + $foregroundColor, + null, + EyeFill::inherit(), + EyeFill::inherit(), + EyeFill::inherit() + ); + } + + public static function uniformGradient(ColorInterface $backgroundColor, Gradient $foregroundGradient) : self + { + return new self( + $backgroundColor, + null, + $foregroundGradient, + EyeFill::inherit(), + EyeFill::inherit(), + EyeFill::inherit() + ); + } + + public function hasGradientFill() : bool + { + return null !== $this->foregroundGradient; + } + + public function getBackgroundColor() : ColorInterface + { + return $this->backgroundColor; + } + + public function getForegroundColor() : ColorInterface + { + if (null === $this->foregroundColor) { + throw new RuntimeException('Fill uses a gradient, thus no foreground color is available'); + } + + return $this->foregroundColor; + } + + public function getForegroundGradient() : Gradient + { + if (null === $this->foregroundGradient) { + throw new RuntimeException('Fill uses a single color, thus no foreground gradient is available'); + } + + return $this->foregroundGradient; + } + + public function getTopLeftEyeFill() : EyeFill + { + return $this->topLeftEyeFill; + } + + public function getTopRightEyeFill() : EyeFill + { + return $this->topRightEyeFill; + } + + public function getBottomLeftEyeFill() : EyeFill + { + return $this->bottomLeftEyeFill; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php new file mode 100644 index 0000000..3813dfd --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php @@ -0,0 +1,46 @@ +startColor = $startColor; + $this->endColor = $endColor; + $this->type = $type; + } + + public function getStartColor() : ColorInterface + { + return $this->startColor; + } + + public function getEndColor() : ColorInterface + { + return $this->endColor; + } + + public function getType() : GradientType + { + return $this->type; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php b/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php new file mode 100644 index 0000000..c1ca754 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php @@ -0,0 +1,22 @@ +margin = $margin; + $this->size = $size; + $this->module = $module ?: SquareModule::instance(); + $this->eye = $eye ?: new ModuleEye($this->module); + $this->fill = $fill ?: Fill::default(); + } + + public function withSize(int $size) : self + { + $style = clone $this; + $style->size = $size; + return $style; + } + + public function withMargin(int $margin) : self + { + $style = clone $this; + $style->margin = $margin; + return $style; + } + + public function getSize() : int + { + return $this->size; + } + + public function getMargin() : int + { + return $this->margin; + } + + public function getModule() : ModuleInterface + { + return $this->module; + } + + public function getEye() : EyeInterface + { + return $this->eye; + } + + public function getFill() : Fill + { + return $this->fill; + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/src/Writer.php b/serve/vendor/bacon/bacon-qr-code/src/Writer.php new file mode 100644 index 0000000..6688901 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/src/Writer.php @@ -0,0 +1,68 @@ +renderer = $renderer; + } + + /** + * Writes QR code and returns it as string. + * + * Content is a string which *should* be encoded in UTF-8, in case there are + * non ASCII-characters present. + * + * @throws InvalidArgumentException if the content is empty + */ + public function writeString( + string $content, + string $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + ?ErrorCorrectionLevel $ecLevel = null + ) : string { + if (strlen($content) === 0) { + throw new InvalidArgumentException('Found empty contents'); + } + + if (null === $ecLevel) { + $ecLevel = ErrorCorrectionLevel::L(); + } + + return $this->renderer->render(Encoder::encode($content, $ecLevel, $encoding)); + } + + /** + * Writes QR code to a file. + * + * @see Writer::writeString() + */ + public function writeFile( + string $content, + string $filename, + string $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + ?ErrorCorrectionLevel $ecLevel = null + ) : void { + file_put_contents($filename, $this->writeString($content, $encoding, $ecLevel)); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php b/serve/vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php new file mode 100644 index 0000000..add798b --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php @@ -0,0 +1,222 @@ +assertFalse($array->get($i)); + $array->set($i); + $this->assertTrue($array->get($i)); + } + } + + public function testGetNextSet1() : void + { + $array = new BitArray(32); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, 32, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, 32, $array->getNextSet($i)); + } + } + + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, 33, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, 33, $array->getNextSet($i)); + } + } + } + + public function testGetNextSet2() : void + { + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, $i <= 31 ? 31 : 33, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, $i <= 31 ? 31 : 33, $array->getNextSet($i)); + } + } + + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, 32, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, 32, $array->getNextSet($i)); + } + } + } + + public function testGetNextSet3() : void + { + $array = new BitArray(63); + $array->set(31); + $array->set(32); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($i <= 31) { + $expected = 31; + } elseif ($i <= 32) { + $expected = 32; + } else { + $expected = 63; + } + + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, $expected, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, $expected, $array->getNextSet($i)); + } + } + } + + public function testGetNextSet4() : void + { + $array = new BitArray(63); + $array->set(33); + $array->set(40); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($i <= 33) { + $expected = 33; + } elseif ($i <= 40) { + $expected = 40; + } else { + $expected = 63; + } + + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, $expected, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, $expected, $array->getNextSet($i)); + } + } + } + + public function testGetNextSet5() : void + { + mt_srand(0xdeadbeef, MT_RAND_PHP); + + for ($i = 0; $i < 10; ++$i) { + $array = new BitArray(mt_rand(1, 100)); + $numSet = mt_rand(0, 19); + + for ($j = 0; $j < $numSet; ++$j) { + $array->set(mt_rand(0, $array->getSize() - 1)); + } + + $numQueries = mt_rand(0, 19); + + for ($j = 0; $j < $numQueries; ++$j) { + $query = mt_rand(0, $array->getSize() - 1); + $expected = $query; + + while ($expected < $array->getSize() && ! $array->get($expected)) { + ++$expected; + } + + $actual = $array->getNextSet($query); + + if ($actual !== $expected) { + $array->getNextSet($query); + } + + $this->assertEquals($expected, $actual); + } + } + } + + public function testSetBulk() : void + { + $array = new BitArray(64); + $array->setBulk(32, 0xFFFF0000); + + for ($i = 0; $i < 48; ++$i) { + $this->assertFalse($array->get($i)); + } + + for ($i = 48; $i < 64; ++$i) { + $this->assertTrue($array->get($i)); + } + } + + public function testClear() : void + { + $array = new BitArray(32); + + for ($i = 0; $i < 32; ++$i) { + $array->set($i); + } + + $array->clear(); + + for ($i = 0; $i < 32; ++$i) { + $this->assertFalse($array->get($i)); + } + } + + public function testGetArray() : void + { + $array = new BitArray(64); + $array->set(0); + $array->set(63); + + $ints = $array->getBitArray(); + + $this->assertSame(1, $ints[0]); + $this->assertSame(0x80000000, $ints[1]); + } + + public function testIsRange() : void + { + $array = new BitArray(64); + $this->assertTrue($array->isRange(0, 64, false)); + $this->assertFalse($array->isRange(0, 64, true)); + + $array->set(32); + $this->assertTrue($array->isRange(32, 33, true)); + + $array->set(31); + $this->assertTrue($array->isRange(31, 33, true)); + + $array->set(34); + $this->assertFalse($array->isRange(31, 35, true)); + + for ($i = 0; $i < 31; ++$i) { + $array->set($i); + } + + $this->assertTrue($array->isRange(0, 33, true)); + + for ($i = 33; $i < 64; ++$i) { + $array->set($i); + } + + $this->assertTrue($array->isRange(0, 64, true)); + $this->assertFalse($array->isRange(0, 64, false)); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Common/BitMatrixTest.php b/serve/vendor/bacon/bacon-qr-code/test/Common/BitMatrixTest.php new file mode 100644 index 0000000..8ad86d4 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Common/BitMatrixTest.php @@ -0,0 +1,115 @@ +assertEquals(33, $matrix->getHeight()); + + for ($y = 0; $y < 33; ++$y) { + for ($x = 0; $x < 33; ++$x) { + if ($y * $x % 3 === 0) { + $matrix->set($x, $y); + } + } + } + + for ($y = 0; $y < 33; $y++) { + for ($x = 0; $x < 33; ++$x) { + $this->assertSame(0 === $x * $y % 3, $matrix->get($x, $y)); + } + } + } + + public function testSetRegion() : void + { + $matrix = new BitMatrix(5); + $matrix->setRegion(1, 1, 3, 3); + + for ($y = 0; $y < 5; ++$y) { + for ($x = 0; $x < 5; ++$x) { + $this->assertSame($y >= 1 && $y <= 3 && $x >= 1 && $x <= 3, $matrix->get($x, $y)); + } + } + } + + public function testRectangularMatrix() : void + { + $matrix = new BitMatrix(75, 20); + $this->assertSame(75, $matrix->getWidth()); + $this->assertSame(20, $matrix->getHeight()); + + $matrix->set(10, 0); + $matrix->set(11, 1); + $matrix->set(50, 2); + $matrix->set(51, 3); + $matrix->flip(74, 4); + $matrix->flip(0, 5); + + $this->assertTrue($matrix->get(10, 0)); + $this->assertTrue($matrix->get(11, 1)); + $this->assertTrue($matrix->get(50, 2)); + $this->assertTrue($matrix->get(51, 3)); + $this->assertTrue($matrix->get(74, 4)); + $this->assertTrue($matrix->get(0, 5)); + + $matrix->flip(50, 2); + $matrix->flip(51, 3); + + $this->assertFalse($matrix->get(50, 2)); + $this->assertFalse($matrix->get(51, 3)); + } + + public function testRectangularSetRegion() : void + { + $matrix = new BitMatrix(320, 240); + $this->assertSame(320, $matrix->getWidth()); + $this->assertSame(240, $matrix->getHeight()); + + $matrix->setRegion(105, 22, 80, 12); + + for ($y = 0; $y < 240; ++$y) { + for ($x = 0; $x < 320; ++$x) { + $this->assertEquals($y >= 22 && $y < 34 && $x >= 105 && $x < 185, $matrix->get($x, $y)); + } + } + } + + public function testGetRow() : void + { + $matrix = new BitMatrix(102, 5); + + for ($x = 0; $x < 102; ++$x) { + if (0 === ($x & 3)) { + $matrix->set($x, 2); + } + } + + $array1 = $matrix->getRow(2, null); + $this->assertSame(102, $array1->getSize()); + + $array2 = new BitArray(60); + $array2 = $matrix->getRow(2, $array2); + $this->assertSame(102, $array2->getSize()); + + $array3 = new BitArray(200); + $array3 = $matrix->getRow(2, $array3); + $this->assertSame(200, $array3->getSize()); + + for ($x = 0; $x < 102; ++$x) { + $on = (0 === ($x & 3)); + + $this->assertSame($on, $array1->get($x)); + $this->assertSame($on, $array2->get($x)); + $this->assertSame($on, $array3->get($x)); + } + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php b/serve/vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php new file mode 100644 index 0000000..2904d31 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php @@ -0,0 +1,25 @@ +assertSame(1, BitUtils::unsignedRightShift(1, 0)); + $this->assertSame(1, BitUtils::unsignedRightShift(10, 3)); + $this->assertSame(536870910, BitUtils::unsignedRightShift(-10, 3)); + } + + public function testNumberOfTrailingZeros() : void + { + $this->assertSame(32, BitUtils::numberOfTrailingZeros(0)); + $this->assertSame(1, BitUtils::numberOfTrailingZeros(10)); + $this->assertSame(0, BitUtils::numberOfTrailingZeros(15)); + $this->assertSame(2, BitUtils::numberOfTrailingZeros(20)); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php b/serve/vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php new file mode 100644 index 0000000..369b5d9 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php @@ -0,0 +1,25 @@ +assertSame(0x0, ErrorCorrectionLevel::M()->getBits()); + $this->assertSame(0x1, ErrorCorrectionLevel::L()->getBits()); + $this->assertSame(0x2, ErrorCorrectionLevel::H()->getBits()); + $this->assertSame(0x3, ErrorCorrectionLevel::Q()->getBits()); + } + + public function testInvalidErrorCorrectionLevelThrowsException() : void + { + $this->expectException(OutOfBoundsException::class); + ErrorCorrectionLevel::forBits(4); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php b/serve/vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php new file mode 100644 index 0000000..39534a2 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php @@ -0,0 +1,94 @@ +assertSame(0, FormatInformation::numBitsDiffering(1, 1)); + $this->assertSame(1, FormatInformation::numBitsDiffering(0, 2)); + $this->assertSame(2, FormatInformation::numBitsDiffering(1, 2)); + $this->assertEquals(32, FormatInformation::numBitsDiffering(-1, 0)); + } + + public function testDecode() : void + { + $expected = FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO, + self::MASKED_TEST_FORMAT_INFO + ); + + $this->assertNotNull($expected); + $this->assertSame(7, $expected->getDataMask()); + $this->assertSame(ErrorCorrectionLevel::Q(), $expected->getErrorCorrectionLevel()); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::UNMAKSED_TEST_FORMAT_INFO, + self::MASKED_TEST_FORMAT_INFO + ) + ); + } + + public function testDecodeWithBitDifference() : void + { + $expected = FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO, + self::MASKED_TEST_FORMAT_INFO + ); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0x1, + self::MASKED_TEST_FORMAT_INFO ^ 0x1 + ) + ); + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0x3, + self::MASKED_TEST_FORMAT_INFO ^ 0x3 + ) + ); + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0x7, + self::MASKED_TEST_FORMAT_INFO ^ 0x7 + ) + ); + $this->assertNull( + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0xf, + self::MASKED_TEST_FORMAT_INFO ^ 0xf + ) + ); + } + + public function testDecodeWithMisRead() : void + { + $expected = FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO, + self::MASKED_TEST_FORMAT_INFO + ); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0x3, + self::MASKED_TEST_FORMAT_INFO ^ 0xf + ) + ); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Common/ModeTest.php b/serve/vendor/bacon/bacon-qr-code/test/Common/ModeTest.php new file mode 100644 index 0000000..51fcb3e --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Common/ModeTest.php @@ -0,0 +1,19 @@ +assertSame(0x0, Mode::TERMINATOR()->getBits()); + $this->assertSame(0x1, Mode::NUMERIC()->getBits()); + $this->assertSame(0x2, Mode::ALPHANUMERIC()->getBits()); + $this->assertSame(0x4, Mode::BYTE()->getBits()); + $this->assertSame(0x8, Mode::KANJI()->getBits()); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php b/serve/vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php new file mode 100644 index 0000000..47975b5 --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php @@ -0,0 +1,96 @@ +encode($block, $parity); + + // Copy parity into test blocks + for ($i = 0; $i < $numRoots; ++$i) { + $block[$i + $dataSize] = $parity[$i]; + $tBlock[$i + $dataSize] = $parity[$i]; + } + + // Seed with errors + for ($i = 0; $i < $errors; ++$i) { + $errorValue = mt_rand(1, $blockSize); + + do { + $errorLocation = mt_rand(0, $blockSize); + } while (0 !== $errorLocations[$errorLocation]); + + $errorLocations[$errorLocation] = 1; + + if (mt_rand(0, 1)) { + $erasures[] = $errorLocation; + } + + $tBlock[$errorLocation] ^= $errorValue; + } + + $erasures = SplFixedArray::fromArray($erasures, false); + + // Decode the errored block + $foundErrors = $codec->decode($tBlock, $erasures); + + if ($errors > 0 && null === $foundErrors) { + $this->assertSame($block, $tBlock, 'Decoder failed to correct errors'); + } + + $this->assertSame($errors, $foundErrors, 'Found errors do not equal expected errors'); + + for ($i = 0; $i < $foundErrors; ++$i) { + if (0 === $errorLocations[$erasures[$i]]) { + $this->fail(sprintf('Decoder indicates error in location %d without error', $erasures[$i])); + } + } + + $this->assertEquals($block, $tBlock, 'Decoder did not correct errors'); + } + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Common/VersionTest.php b/serve/vendor/bacon/bacon-qr-code/test/Common/VersionTest.php new file mode 100644 index 0000000..f6f038b --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Common/VersionTest.php @@ -0,0 +1,78 @@ +assertNotNull($version); + $this->assertEquals($versionNumber, $version->getVersionNumber()); + $this->assertNotNull($version->getAlignmentPatternCenters()); + + if ($versionNumber > 1) { + $this->assertTrue(count($version->getAlignmentPatternCenters()) > 0); + } + + $this->assertEquals($dimension, $version->getDimensionForVersion()); + $this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::H())); + $this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::L())); + $this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::M())); + $this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::Q())); + $this->assertNotNull($version->buildFunctionPattern()); + } + + /** + * @dataProvider versions + */ + public function testGetProvisionalVersionForDimension(int $versionNumber, int $dimension) : void + { + $this->assertSame( + $versionNumber, + Version::getProvisionalVersionForDimension($dimension)->getVersionNumber() + ); + } + + /** + * @dataProvider decodeInformation + */ + public function testDecodeVersionInformation(int $expectedVersion, int $mask) : void + { + $version = Version::decodeVersionInformation($mask); + $this->assertNotNull($version); + $this->assertSame($expectedVersion, $version->getVersionNumber()); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php b/serve/vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php new file mode 100644 index 0000000..9baa66b --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php @@ -0,0 +1,487 @@ +getMethods(ReflectionMethod::IS_STATIC) as $method) { + $method->setAccessible(true); + $this->methods[$method->getName()] = $method; + } + } + + public function testGetAlphanumericCode() : void + { + // The first ten code points are numbers. + for ($i = 0; $i < 10; ++$i) { + $this->assertSame($i, $this->methods['getAlphanumericCode']->invoke(null, ord('0') + $i)); + } + + // The next 26 code points are capital alphabet letters. + for ($i = 10; $i < 36; ++$i) { + // The first ten code points are numbers + $this->assertSame($i, $this->methods['getAlphanumericCode']->invoke(null, ord('A') + $i - 10)); + } + + // Others are symbol letters. + $this->assertSame(36, $this->methods['getAlphanumericCode']->invoke(null, ord(' '))); + $this->assertSame(37, $this->methods['getAlphanumericCode']->invoke(null, ord('$'))); + $this->assertSame(38, $this->methods['getAlphanumericCode']->invoke(null, ord('%'))); + $this->assertSame(39, $this->methods['getAlphanumericCode']->invoke(null, ord('*'))); + $this->assertSame(40, $this->methods['getAlphanumericCode']->invoke(null, ord('+'))); + $this->assertSame(41, $this->methods['getAlphanumericCode']->invoke(null, ord('-'))); + $this->assertSame(42, $this->methods['getAlphanumericCode']->invoke(null, ord('.'))); + $this->assertSame(43, $this->methods['getAlphanumericCode']->invoke(null, ord('/'))); + $this->assertSame(44, $this->methods['getAlphanumericCode']->invoke(null, ord(':'))); + + // Should return -1 for other letters. + $this->assertSame(-1, $this->methods['getAlphanumericCode']->invoke(null, ord('a'))); + $this->assertSame(-1, $this->methods['getAlphanumericCode']->invoke(null, ord('#'))); + $this->assertSame(-1, $this->methods['getAlphanumericCode']->invoke(null, ord("\0"))); + } + + public function testChooseMode() : void + { + // Numeric mode + $this->assertSame(Mode::NUMERIC(), $this->methods['chooseMode']->invoke(null, '0')); + $this->assertSame(Mode::NUMERIC(), $this->methods['chooseMode']->invoke(null, '0123456789')); + + // Alphanumeric mode + $this->assertSame(Mode::ALPHANUMERIC(), $this->methods['chooseMode']->invoke(null, 'A')); + $this->assertSame( + Mode::ALPHANUMERIC(), + $this->methods['chooseMode']->invoke(null, '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:') + ); + + // 8-bit byte mode + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, 'a')); + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, '#')); + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, '')); + + // AIUE in Hiragana in SHIFT-JIS + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\x8\xa\x8\xa\x8\xa\x8\xa6")); + + // Nihon in Kanji in SHIFT-JIS + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\x9\xf\x9\x7b")); + + // Sou-Utso-Byou in Kanji in SHIFT-JIS + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\xe\x4\x9\x5\x9\x61")); + } + + public function testEncode() : void + { + $qrCode = Encoder::encode('ABCDEF', ErrorCorrectionLevel::H()); + $expected = "<<\n" + . " mode: ALPHANUMERIC\n" + . " ecLevel: H\n" + . " version: 1\n" + . " maskPattern: 0\n" + . " matrix:\n" + . " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n" + . " 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n" + . " 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n" + . " 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n" + . " 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n" + . " 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n" + . " 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n" + . " 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n" + . ">>\n"; + + $this->assertSame($expected, (string) $qrCode); + } + + public function testSimpleUtf8Eci() : void + { + $qrCode = Encoder::encode('hello', ErrorCorrectionLevel::H(), 'utf-8'); + $expected = "<<\n" + . " mode: BYTE\n" + . " ecLevel: H\n" + . " version: 1\n" + . " maskPattern: 3\n" + . " matrix:\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 1 1 1 0 0 0 1 1 0 1 0 0 0 0\n" + . " 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 0\n" + . " 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 1 1 1\n" + . " 1 1 0 0 1 0 0 1 1 0 0 1 1 1 1 0 1 0 1 1 0\n" + . " 0 0 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 0 1 0 0\n" + . " 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 0 0 1 1 0 0 0\n" + . " 1 0 1 1 1 0 1 0 1 1 0 0 0 1 0 0 1 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 1 1 0\n" + . " 1 1 1 1 1 1 1 0 0 1 0 1 1 1 0 1 1 0 0 0 0\n" + . ">>\n"; + + $this->assertSame($expected, (string) $qrCode); + } + + public function testAppendModeInfo() : void + { + $bits = new BitArray(); + $this->methods['appendModeInfo']->invoke(null, Mode::NUMERIC(), $bits); + $this->assertSame(' ...X', (string) $bits); + } + + public function testAppendLengthInfo() : void + { + // 1 letter (1/1), 10 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 1, + Version::getVersionForNumber(1), + Mode::NUMERIC(), + $bits + ); + $this->assertSame(' ........ .X', (string) $bits); + + // 2 letters (2/1), 11 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 2, + Version::getVersionForNumber(10), + Mode::ALPHANUMERIC(), + $bits + ); + $this->assertSame(' ........ .X.', (string) $bits); + + // 255 letters (255/1), 16 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 255, + Version::getVersionForNumber(27), + Mode::BYTE(), + $bits + ); + $this->assertSame(' ........ XXXXXXXX', (string) $bits); + + // 512 letters (1024/2), 12 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 512, + Version::getVersionForNumber(40), + Mode::KANJI(), + $bits + ); + $this->assertSame(' ..X..... ....', (string) $bits); + } + + public function testAppendBytes() : void + { + // Should use appendNumericBytes. + // 1 = 01 = 0001 in 4 bits. + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + '1', + Mode::NUMERIC(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertSame(' ...X', (string) $bits); + + // Should use appendAlphaNumericBytes. + // A = 10 = 0xa = 001010 in 6 bits. + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + 'A', + Mode::ALPHANUMERIC(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertSame(' ..X.X.', (string) $bits); + + // Should use append8BitBytes. + // 0x61, 0x62, 0x63 + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + 'abc', + Mode::BYTE(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertSame(' .XX....X .XX...X. .XX...XX', (string) $bits); + + // Should use appendKanjiBytes. + // 0x93, 0x5f + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + "\x93\x5f", + Mode::KANJI(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertSame(' .XX.XX.. XXXXX', (string) $bits); + + // Lower letters such as 'a' cannot be encoded in alphanumeric mode. + $this->expectException(WriterException::class); + $this->methods['appendBytes']->invoke( + null, + 'a', + Mode::ALPHANUMERIC(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + } + + public function testTerminateBits() : void + { + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 0, $bits); + $this->assertSame('', (string) $bits); + + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertSame(' ........', (string) $bits); + + $bits = new BitArray(); + $bits->appendBits(0, 3); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertSame(' ........', (string) $bits); + + $bits = new BitArray(); + $bits->appendBits(0, 5); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertSame(' ........', (string) $bits); + + $bits = new BitArray(); + $bits->appendBits(0, 8); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertSame(' ........', (string) $bits); + + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 2, $bits); + $this->assertSame(' ........ XXX.XX..', (string) $bits); + + $bits = new BitArray(); + $bits->appendBits(0, 1); + $this->methods['terminateBits']->invoke(null, 3, $bits); + $this->assertSame(' ........ XXX.XX.. ...X...X', (string) $bits); + } + + public function testGetNumDataBytesAndNumEcBytesForBlockId() : void + { + // Version 1-H. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 26, 9, 1, 0); + $this->assertSame(9, $numDataBytes); + $this->assertSame(17, $numEcBytes); + + // Version 3-H. 2 blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 70, 26, 2, 0); + $this->assertSame(13, $numDataBytes); + $this->assertSame(22, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 70, 26, 2, 1); + $this->assertSame(13, $numDataBytes); + $this->assertSame(22, $numEcBytes); + + // Version 7-H. (4 + 1) blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 196, 66, 5, 0); + $this->assertSame(13, $numDataBytes); + $this->assertSame(26, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 196, 66, 5, 4); + $this->assertSame(14, $numDataBytes); + $this->assertSame(26, $numEcBytes); + + // Version 40-H. (20 + 61) blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 3706, 1276, 81, 0); + $this->assertSame(15, $numDataBytes); + $this->assertSame(30, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 3706, 1276, 81, 20); + $this->assertSame(16, $numDataBytes); + $this->assertSame(30, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 3706, 1276, 81, 80); + $this->assertSame(16, $numDataBytes); + $this->assertSame(30, $numEcBytes); + } + + public function testInterleaveWithEcBytes() : void + { + $dataBytes = SplFixedArray::fromArray([32, 65, 205, 69, 41, 220, 46, 128, 236], false); + $in = new BitArray(); + + foreach ($dataBytes as $dataByte) { + $in->appendBits($dataByte, 8); + } + + $outBits = $this->methods['interleaveWithEcBytes']->invoke(null, $in, 26, 9, 1); + $expected = SplFixedArray::fromArray([ + // Data bytes. + 32, 65, 205, 69, 41, 220, 46, 128, 236, + // Error correction bytes. + 42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61, + ], false); + + $out = $outBits->toBytes(0, count($expected)); + + $this->assertEquals($expected, $out); + } + + public function testAppendNumericBytes() : void + { + // 1 = 01 = 0001 in 4 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '1', $bits); + $this->assertSame(' ...X', (string) $bits); + + // 12 = 0xc = 0001100 in 7 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '12', $bits); + $this->assertSame(' ...XX..', (string) $bits); + + // 123 = 0x7b = 0001111011 in 10 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '123', $bits); + $this->assertSame(' ...XXXX. XX', (string) $bits); + + // 1234 = "123" + "4" = 0001111011 + 0100 in 14 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '1234', $bits); + $this->assertSame(' ...XXXX. XX.X..', (string) $bits); + + // Empty + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '', $bits); + $this->assertSame('', (string) $bits); + } + + public function testAppendAlphanumericBytes() : void + { + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'A', $bits); + $this->assertSame(' ..X.X.', (string) $bits); + + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'AB', $bits); + $this->assertSame(' ..XXX..X X.X', (string) $bits); + + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'ABC', $bits); + $this->assertSame(' ..XXX..X X.X..XX. .', (string) $bits); + + // Empty + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, '', $bits); + $this->assertSame('', (string) $bits); + + // Invalid data + $this->expectException(WriterException::class); + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'abc', $bits); + } + + public function testAppend8BitBytes() : void + { + // 0x61, 0x62, 0x63 + $bits = new BitArray(); + $this->methods['append8BitBytes']->invoke(null, 'abc', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING); + $this->assertSame(' .XX....X .XX...X. .XX...XX', (string) $bits); + + // Empty + $bits = new BitArray(); + $this->methods['append8BitBytes']->invoke(null, '', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING); + $this->assertSame('', (string) $bits); + } + + public function testAppendKanjiBytes() : void + { + // Numbers are from page 21 of JISX0510:2004 + $bits = new BitArray(); + $this->methods['appendKanjiBytes']->invoke(null, "\x93\x5f", $bits); + $this->assertSame(' .XX.XX.. XXXXX', (string) $bits); + + $this->methods['appendKanjiBytes']->invoke(null, "\xe4\xaa", $bits); + $this->assertSame(' .XX.XX.. XXXXXXX. X.X.X.X. X.', (string) $bits); + } + + public function testGenerateEcBytes() : void + { + // Numbers are from http://www.swetake.com/qr/qr3.html and + // http://www.swetake.com/qr/qr9.html + $dataBytes = SplFixedArray::fromArray([32, 65, 205, 69, 41, 220, 46, 128, 236], false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17); + $expected = SplFixedArray::fromArray( + [42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61], + false + ); + $this->assertEquals($expected, $ecBytes); + + $dataBytes = SplFixedArray::fromArray( + [67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214], + false + ); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 18); + $expected = SplFixedArray::fromArray( + [175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187], + false + ); + $this->assertEquals($expected, $ecBytes); + + // High-order zero coefficient case. + $dataBytes = SplFixedArray::fromArray([32, 49, 205, 69, 42, 20, 0, 236, 17], false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17); + $expected = SplFixedArray::fromArray( + [0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213], + false + ); + $this->assertEquals($expected, $ecBytes); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php b/serve/vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php new file mode 100644 index 0000000..46670fc --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php @@ -0,0 +1,251 @@ +assertSame( + 1 === $expected[$y][$x], + MaskUtil::getDataMaskBit($maskPattern, $x, $y) + ); + } + } + } + + public function testApplyMaskPenaltyRule1() : void + { + $matrix = new ByteMatrix(4, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + + $this->assertSame(0, MaskUtil::applyMaskPenaltyRule1($matrix)); + + // Horizontal + $matrix = new ByteMatrix(6, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + $matrix->set(4, 0, 0); + $matrix->set(5, 0, 1); + $this->assertSame(3, MaskUtil::applyMaskPenaltyRule1($matrix)); + $matrix->set(5, 0, 0); + $this->assertSame(4, MaskUtil::applyMaskPenaltyRule1($matrix)); + + // Vertical + $matrix = new ByteMatrix(1, 6); + $matrix->set(0, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(0, 3, 0); + $matrix->set(0, 4, 0); + $matrix->set(0, 5, 1); + $this->assertSame(3, MaskUtil::applyMaskPenaltyRule1($matrix)); + $matrix->set(0, 5, 0); + $this->assertSame(4, MaskUtil::applyMaskPenaltyRule1($matrix)); + } + + public function testApplyMaskPenaltyRule2() : void + { + $matrix = new ByteMatrix(1, 1); + $matrix->set(0, 0, 0); + $this->assertSame(0, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(2, 2); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 1); + $this->assertSame(0, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(2, 2); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 0); + $this->assertSame(3, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(3, 3); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 0); + $matrix->set(2, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(1, 2, 0); + $matrix->set(2, 2, 0); + $this->assertSame(3 * 4, MaskUtil::applyMaskPenaltyRule2($matrix)); + } + + public function testApplyMaskPenalty3() : void + { + // Horizontal 00001011101 + $matrix = new ByteMatrix(11, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $matrix->set(6, 0, 1); + $matrix->set(7, 0, 1); + $matrix->set(8, 0, 1); + $matrix->set(9, 0, 0); + $matrix->set(10, 0, 1); + $this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Horizontal 10111010000 + $matrix = new ByteMatrix(11, 1); + $matrix->set(0, 0, 1); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 1); + $matrix->set(3, 0, 1); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $matrix->set(6, 0, 1); + $matrix->set(7, 0, 0); + $matrix->set(8, 0, 0); + $matrix->set(9, 0, 0); + $matrix->set(10, 0, 0); + $this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Vertical 00001011101 + $matrix = new ByteMatrix(1, 11); + $matrix->set(0, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(0, 3, 0); + $matrix->set(0, 4, 1); + $matrix->set(0, 5, 0); + $matrix->set(0, 6, 1); + $matrix->set(0, 7, 1); + $matrix->set(0, 8, 1); + $matrix->set(0, 9, 0); + $matrix->set(0, 10, 1); + $this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Vertical 10111010000 + $matrix = new ByteMatrix(1, 11); + $matrix->set(0, 0, 1); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 1); + $matrix->set(0, 3, 1); + $matrix->set(0, 4, 1); + $matrix->set(0, 5, 0); + $matrix->set(0, 6, 1); + $matrix->set(0, 7, 0); + $matrix->set(0, 8, 0); + $matrix->set(0, 9, 0); + $matrix->set(0, 10, 0); + $this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + } + + public function testApplyMaskPenaltyRule4() : void + { + // Dark cell ratio = 0% + $matrix = new ByteMatrix(1, 1); + $matrix->set(0, 0, 0); + $this->assertSame(100, MaskUtil::applyMaskPenaltyRule4($matrix)); + + // Dark cell ratio = 5% + $matrix = new ByteMatrix(2, 1); + $matrix->set(0, 0, 0); + $matrix->set(0, 0, 1); + $this->assertSame(0, MaskUtil::applyMaskPenaltyRule4($matrix)); + + // Dark cell ratio = 66.67% + $matrix = new ByteMatrix(6, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 1); + $matrix->set(2, 0, 1); + $matrix->set(3, 0, 1); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $this->assertSame(30, MaskUtil::applyMaskPenaltyRule4($matrix)); + } +} diff --git a/serve/vendor/bacon/bacon-qr-code/test/Encoder/MatrixUtilTest.php b/serve/vendor/bacon/bacon-qr-code/test/Encoder/MatrixUtilTest.php new file mode 100644 index 0000000..106ceaa --- /dev/null +++ b/serve/vendor/bacon/bacon-qr-code/test/Encoder/MatrixUtilTest.php @@ -0,0 +1,335 @@ +getMethods(ReflectionMethod::IS_STATIC) as $method) { + $method->setAccessible(true); + $this->methods[$method->getName()] = $method; + } + } + + public function testToString() : void + { + $matrix = new ByteMatrix(3, 3); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 1); + $matrix->set(2, 0, 0); + $matrix->set(0, 1, 1); + $matrix->set(1, 1, 0); + $matrix->set(2, 1, 1); + $matrix->set(0, 2, -1); + $matrix->set(1, 2, -1); + $matrix->set(2, 2, -1); + + $expected = " 0 1 0\n 1 0 1\n \n"; + $this->assertSame($expected, (string) $matrix); + } + + public function testClearMatrix() : void + { + $matrix = new ByteMatrix(2, 2); + MatrixUtil::clearMatrix($matrix); + + $this->assertSame(-1, $matrix->get(0, 0)); + $this->assertSame(-1, $matrix->get(1, 0)); + $this->assertSame(-1, $matrix->get(0, 1)); + $this->assertSame(-1, $matrix->get(1, 1)); + } + + public function testEmbedBasicPatterns1() : void + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(1), + $matrix + ); + $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 0 0 0 0 0 0 0 1 \n" + . " 1 1 1 1 1 1 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 1 1 1 1 1 1 0 \n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testEmbedBasicPatterns2() : void + { + $matrix = new ByteMatrix(25, 25); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(2), + $matrix + ); + $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 1 1 1 1 1 \n" + . " 0 0 0 0 0 0 0 0 1 1 0 0 0 1 \n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 \n" + . " 1 0 0 0 0 0 1 0 1 0 0 0 1 \n" + . " 1 0 1 1 1 0 1 0 1 1 1 1 1 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 1 1 1 1 1 1 0 \n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testEmbedTypeInfo() : void + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedTypeInfo']->invoke( + null, + ErrorCorrectionLevel::M(), + 5, + $matrix + ); + $expected = " 0 \n" + . " 1 \n" + . " 1 \n" + . " 1 \n" + . " 0 \n" + . " 0 \n" + . " \n" + . " 1 \n" + . " 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0\n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 1 \n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testEmbedVersionInfo() : void + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['maybeEmbedVersionInfo']->invoke( + null, + Version::getVersionForNumber(7), + $matrix + ); + $expected = " 0 0 1 \n" + . " 0 1 0 \n" + . " 0 1 0 \n" + . " 0 1 1 \n" + . " 1 1 1 \n" + . " 0 0 0 \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " 0 0 0 0 1 0 \n" + . " 0 1 1 1 1 0 \n" + . " 1 0 0 1 1 0 \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testEmbedDataBits() : void + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(1), + $matrix + ); + + $bits = new BitArray(); + $this->methods['embedDataBits']->invoke( + null, + $bits, + -1, + $matrix + ); + + $expected = " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testBuildMatrix() : void + { + $bytes = [ + 32, 65, 205, 69, 41, 220, 46, 128, 236, 42, 159, 74, 221, 244, 169, + 239, 150, 138, 70, 237, 85, 224, 96, 74, 219 , 61 + ]; + $bits = new BitArray(); + + foreach ($bytes as $byte) { + $bits->appendBits($byte, 8); + } + + $matrix = new ByteMatrix(21, 21); + MatrixUtil::buildMatrix( + $bits, + ErrorCorrectionLevel::H(), + Version::getVersionForNumber(1), + 3, + $matrix + ); + + $expected = " 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n" + . " 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n" + . " 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n" + . " 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n" + . " 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n" + . " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n" + . " 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n" + . " 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testFindMsbSet() : void + { + $this->assertSame(0, $this->methods['findMsbSet']->invoke(null, 0)); + $this->assertSame(1, $this->methods['findMsbSet']->invoke(null, 1)); + $this->assertSame(8, $this->methods['findMsbSet']->invoke(null, 0x80)); + $this->assertSame(32, $this->methods['findMsbSet']->invoke(null, 0x80000000)); + } + + public function testCalculateBchCode() : void + { + // Encoding of type information. + // From Appendix C in JISX0510:2004 (p 65) + $this->assertSame(0xdc, $this->methods['calculateBchCode']->invoke(null, 5, 0x537)); + // From http://www.swetake.com/qr/qr6.html + $this->assertSame(0x1c2, $this->methods['calculateBchCode']->invoke(null, 0x13, 0x537)); + // From http://www.swetake.com/qr/qr11.html + $this->assertSame(0x214, $this->methods['calculateBchCode']->invoke(null, 0x1b, 0x537)); + + // Encoding of version information. + // From Appendix D in JISX0510:2004 (p 68) + $this->assertSame(0xc94, $this->methods['calculateBchCode']->invoke(null, 7, 0x1f25)); + $this->assertSame(0x5bc, $this->methods['calculateBchCode']->invoke(null, 8, 0x1f25)); + $this->assertSame(0xa99, $this->methods['calculateBchCode']->invoke(null, 9, 0x1f25)); + $this->assertSame(0x4d3, $this->methods['calculateBchCode']->invoke(null, 10, 0x1f25)); + $this->assertSame(0x9a6, $this->methods['calculateBchCode']->invoke(null, 20, 0x1f25)); + $this->assertSame(0xd75, $this->methods['calculateBchCode']->invoke(null, 30, 0x1f25)); + $this->assertSame(0xc69, $this->methods['calculateBchCode']->invoke(null, 40, 0x1f25)); + } + + public function testMakeVersionInfoBits() : void + { + // From Appendix D in JISX0510:2004 (p 68) + $bits = new BitArray(); + $this->methods['makeVersionInfoBits']->invoke(null, Version::getVersionForNumber(7), $bits); + $this->assertSame(' ...XXXXX ..X..X.X ..', (string) $bits); + } + + public function testMakeTypeInfoBits() : void + { + // From Appendix D in JISX0510:2004 (p 68) + $bits = new BitArray(); + $this->methods['makeTypeInfoBits']->invoke(null, ErrorCorrectionLevel::M(), 5, $bits); + $this->assertSame(' X......X X..XXX.', (string) $bits); + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/composer.json b/serve/vendor/barcode-bakery/barcode-1d/composer.json new file mode 100644 index 0000000..e4d9d74 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/composer.json @@ -0,0 +1,53 @@ +{ + "name": "barcode-bakery/barcode-1d", + "version": "6.0.0", + "license": [ + "Commercial", + "CC-BY-NC-ND-4.0" + ], + "support": { + "email": "contact@barcodebakery.com", + "docs": "http://www.barcodebakery.com" + }, + "type": "library", + "homepage": "http://www.barcodebakery.com", + "authors": [ + { + "name": "Jean-Sébastien Goupil", + "email": "contact@barcodebakery.com" + } + ], + "description": "Generates 1D barcodes from a PHP server to a file or HTML document.", + "autoload": { + "psr-4": { + "BarcodeBakery\\Barcode\\": "src" + } + }, + "keywords": [ + "barcode", + "generator", + "bakery", + "codabar", + "code11", + "code39", + "code39extended", + "code93", + "code128", + "ean-8", + "ean-13", + "ean8", + "ean13", + "isbn", + "i25", + "s25", + "msi", + "upc-a", + "upc-e", + "upcext2", + "upcext5" + ], + "require": { + "php": ">=5.6", + "ext-gd": "*" + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGcodabar.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcodabar.php new file mode 100644 index 0000000..ed5512f --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcodabar.php @@ -0,0 +1,131 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '$', ':', '/', '.', '+', 'A', 'B', 'C', 'D'); + $this->code = array( // 0 added to add an extra space + '00000110', /* 0 */ + '00001100', /* 1 */ + '00010010', /* 2 */ + '11000000', /* 3 */ + '00100100', /* 4 */ + '10000100', /* 5 */ + '01000010', /* 6 */ + '01001000', /* 7 */ + '01100000', /* 8 */ + '10010000', /* 9 */ + '00011000', /* - */ + '00110000', /* $ */ + '10001010', /* : */ + '10100010', /* / */ + '10101000', /* . */ + '00111110', /* + */ + '00110100', /* A */ + '01010010', /* B */ + '00010110', /* C */ + '00011100' /* D */ + ); + } + + /** + * Parses the text before displaying it. + * + * @param mixed $text + */ + public function parse($text) + { + parent::parse(strtoupper($text)); // Only Capital Letters are Allowed + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->findCode($this->text[$i]), true); + } + + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $textLength = 0; + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $index = $this->findIndex($this->text[$i]); + if ($index !== false) { + $textLength += 8; + $textLength += substr_count($this->code[$index], '1'); + } + } + + $w += $textLength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('codabar', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('codabar', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + // Must start by A, B, C or D + if ($c == 0 || ($this->text[0] !== 'A' && $this->text[0] !== 'B' && $this->text[0] !== 'C' && $this->text[0] !== 'D')) { + throw new BCGParseException('codabar', 'The text must start by the character A, B, C, or D.'); + } + + // Must end by A, B, C or D + $c2 = $c - 1; + if ($c2 === 0 || ($this->text[$c2] !== 'A' && $this->text[$c2] !== 'B' && $this->text[$c2] !== 'C' && $this->text[$c2] !== 'D')) { + throw new BCGParseException('codabar', 'The text must end by the character A, B, C, or D.'); + } + + parent::validate(); + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode11.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode11.php new file mode 100644 index 0000000..12b8098 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode11.php @@ -0,0 +1,196 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-'); + $this->code = array( // 0 added to add an extra space + '000010', /* 0 */ + '100010', /* 1 */ + '010010', /* 2 */ + '110000', /* 3 */ + '001010', /* 4 */ + '101000', /* 5 */ + '011000', /* 6 */ + '000110', /* 7 */ + '100100', /* 8 */ + '100000', /* 9 */ + '001000' /* - */ + ); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + // Starting Code + $this->drawChar($im, '001100', true); + + // Chars + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->findCode($this->text[$i]), true); + } + + // Checksum + $this->calculateChecksum(); + $c = count($this->checksumValue); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->code[$this->checksumValue[$i]], true); + } + + // Ending Code + $this->drawChar($im, '00110', true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $startlength = 8; + + $textlength = 0; + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $textlength += $this->getIndexLength($this->findIndex($this->text[$i])); + } + + $checksumlength = 0; + $this->calculateChecksum(); + $c = count($this->checksumValue); + for ($i = 0; $i < $c; $i++) { + $checksumlength += $this->getIndexLength($this->checksumValue[$i]); + } + + $endlength = 7; + + $w += $startlength + $textlength + $checksumlength + $endlength; + $h += $this->thickness; + + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('code11', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('code11', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Checksum + // First CheckSUM "C" + // The "C" checksum character is the modulo 11 remainder of the sum of the weighted + // value of the data characters. The weighting value starts at "1" for the right-most + // data character, 2 for the second to last, 3 for the third-to-last, and so on up to 20. + // After 10, the sequence wraps around back to 1. + + // Second CheckSUM "K" + // Same as CheckSUM "C" but we count the CheckSum "C" at the end + // After 9, the sequence wraps around back to 1. + $sequence_multiplier = array(10, 9); + $temp_text = $this->text; + $this->checksumValue = array(); + for ($z = 0; $z < 2; $z++) { + $c = strlen($temp_text); + + // We don't display the K CheckSum if the original text had a length less than 10 + if ($c <= 10 && $z === 1) { + break; + } + + $checksum = 0; + for ($i = $c, $j = 0; $i > 0; $i--, $j++) { + $multiplier = $i % $sequence_multiplier[$z]; + if ($multiplier === 0) { + $multiplier = $sequence_multiplier[$z]; + } + + $checksum += $this->findIndex($temp_text[$j]) * $multiplier; + } + + $this->checksumValue[$z] = $checksum % 11; + $temp_text .= $this->keys[$this->checksumValue[$z]]; + } + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + $ret = ''; + $c = count($this->checksumValue); + for ($i = 0; $i < $c; $i++) { + $ret .= $this->keys[$this->checksumValue[$i]]; + } + + return $ret; + } + + return false; + } + + private function getIndexLength($index) + { + $length = 0; + if ($index !== false) { + $length += 6; + $length += substr_count($this->code[$index], '1'); + } + + return $length; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode128.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode128.php new file mode 100644 index 0000000..a46e4b9 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode128.php @@ -0,0 +1,932 @@ +keysA = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'; + for ($i = 0; $i < 32; $i++) { + $this->keysA .= chr($i); + } + + /* CODE 128 B */ + $this->keysB = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' . chr(127); + + /* CODE 128 C */ + $this->keysC = '0123456789'; + + $this->code = array( + '101111', /* 00 */ + '111011', /* 01 */ + '111110', /* 02 */ + '010112', /* 03 */ + '010211', /* 04 */ + '020111', /* 05 */ + '011102', /* 06 */ + '011201', /* 07 */ + '021101', /* 08 */ + '110102', /* 09 */ + '110201', /* 10 */ + '120101', /* 11 */ + '001121', /* 12 */ + '011021', /* 13 */ + '011120', /* 14 */ + '002111', /* 15 */ + '012011', /* 16 */ + '012110', /* 17 */ + '112100', /* 18 */ + '110021', /* 19 */ + '110120', /* 20 */ + '102101', /* 21 */ + '112001', /* 22 */ + '201020', /* 23 */ + '200111', /* 24 */ + '210011', /* 25 */ + '210110', /* 26 */ + '201101', /* 27 */ + '211001', /* 28 */ + '211100', /* 29 */ + '101012', /* 30 */ + '101210', /* 31 */ + '121010', /* 32 */ + '000212', /* 33 */ + '020012', /* 34 */ + '020210', /* 35 */ + '001202', /* 36 */ + '021002', /* 37 */ + '021200', /* 38 */ + '100202', /* 39 */ + '120002', /* 40 */ + '120200', /* 41 */ + '001022', /* 42 */ + '001220', /* 43 */ + '021020', /* 44 */ + '002012', /* 45 */ + '002210', /* 46 */ + '022010', /* 47 */ + '202010', /* 48 */ + '100220', /* 49 */ + '120020', /* 50 */ + '102002', /* 51 */ + '102200', /* 52 */ + '102020', /* 53 */ + '200012', /* 54 */ + '200210', /* 55 */ + '220010', /* 56 */ + '201002', /* 57 */ + '201200', /* 58 */ + '221000', /* 59 */ + '203000', /* 60 */ + '110300', /* 61 */ + '320000', /* 62 */ + '000113', /* 63 */ + '000311', /* 64 */ + '010013', /* 65 */ + '010310', /* 66 */ + '030011', /* 67 */ + '030110', /* 68 */ + '001103', /* 69 */ + '001301', /* 70 */ + '011003', /* 71 */ + '011300', /* 72 */ + '031001', /* 73 */ + '031100', /* 74 */ + '130100', /* 75 */ + '110003', /* 76 */ + '302000', /* 77 */ + '130001', /* 78 */ + '023000', /* 79 */ + '000131', /* 80 */ + '010031', /* 81 */ + '010130', /* 82 */ + '003101', /* 83 */ + '013001', /* 84 */ + '013100', /* 85 */ + '300101', /* 86 */ + '310001', /* 87 */ + '310100', /* 88 */ + '101030', /* 89 */ + '103010', /* 90 */ + '301010', /* 91 */ + '000032', /* 92 */ + '000230', /* 93 */ + '020030', /* 94 */ + '003002', /* 95 */ + '003200', /* 96 */ + '300002', /* 97 */ + '300200', /* 98 */ + '002030', /* 99 */ + '003020', /* 100*/ + '200030', /* 101*/ + '300020', /* 102*/ + '100301', /* 103*/ + '100103', /* 104*/ + '100121', /* 105*/ + '122000' /*STOP*/ + ); + $this->setStart($start); + $this->setTilde(true); + + // Latches and Shifts + $this->latch = array( + array(null, self::KEYA_CODEB, self::KEYA_CODEC), + array(self::KEYB_CODEA, null, self::KEYB_CODEC), + array(self::KEYC_CODEA, self::KEYC_CODEB, null) + ); + $this->shift = array( + array(null, self::KEYA_SHIFT), + array(self::KEYB_SHIFT, null) + ); + $this->fnc = array( + array(self::KEYA_FNC1, self::KEYA_FNC2, self::KEYA_FNC3, self::KEYA_FNC4), + array(self::KEYB_FNC1, self::KEYB_FNC2, self::KEYB_FNC3, self::KEYB_FNC4), + array(self::KEYC_FNC1, null, null, null) + ); + + // Method available + $this->METHOD = array(CODE128_A => 'A', CODE128_B => 'B', CODE128_C => 'C'); + } + + /** + * Specifies the start code. Can be 'A', 'B', 'C', or null + * - Table A: Capitals + ASCII 0-31 + punct + * - Table B: Capitals + LowerCase + punct + * - Table C: Numbers + * + * If null is specified, the table selection is automatically made. + * The default is null. + * + * @param string $table + */ + public function setStart($table) + { + if ($table !== 'A' && $table !== 'B' && $table !== 'C' && $table !== null) { + throw new BCGArgumentException('The starting table must be A, B, C or null.', 'table'); + } + + $this->starting_text = $table; + } + + /** + * Gets the tilde. + * + * @return bool + */ + public function getTilde() + { + return $this->tilde; + } + + /** + * Accepts tilde to be process as a special character. + * If true, you can do this: + * - ~~ : to make ONE tilde + * - ~Fx : to insert FCNx. x is equal from 1 to 4. + * + * @param boolean $accept + */ + public function setTilde($accept) + { + $this->tilde = (bool)$accept; + } + + /** + * Parses the text before displaying it. + * + * @param mixed $text + */ + public function parse($text) + { + $this->setStartFromText($text); + + $this->text = ''; + $seq = ''; + + $currentMode = $this->starting_text; + + // Here, we format correctly what the user gives. + if (!is_array($text)) { + $seq = $this->getSequence($text, $currentMode); + $this->text = $text; + } else { + // This loop checks for UnknownText AND raises an exception if a character is not allowed in a table + $ao = new \ArrayObject($text); + $it = $ao->getIterator(); + while ($it->valid()) { // We take each value + $val1 = $it->current(); + if (!is_array($val1)) { // This is not a table + if (is_string($val1)) { // If it's a string, parse as unknown + $seq .= $this->getSequence($val1, $currentMode); + $this->text .= $val1; + } else { + // it's the case of "array(ENCODING, 'text')" + // We got ENCODING in $val1, getting the next in $val2 + $it->next(); + $val2 = $it->current(); + $seq .= $this->{'setParse' . $this->METHOD[$val1]}($val2, $currentMode); + $this->text .= $val2; + } + } else { // The method is specified + // $val1[0] = ENCODING + // $val1[1] = 'text' + $value = isset($val1[1]) ? $val1[1] : ''; // If data available + $seq .= $this->{'setParse' . $this->METHOD[$val1[0]]}($value, $currentMode); + $this->text .= $value; + } + + $it->next(); + } + } + + if ($seq !== '') { + $bitstream = $this->createBinaryStream($this->text, $seq); + $this->setData($bitstream); + } + + $this->addDefaultLabel(); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + $c = count($this->data); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->data[$i], true); + } + + $this->drawChar($im, '1', true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + // Contains start + text + checksum + stop + $textlength = count($this->data) * 11; + $endlength = 2; // + final bar + + $w += $textlength + $endlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = count($this->data); + if ($c === 0) { + throw new BCGParseException('code128', 'No data has been entered.'); + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Checksum + // First Char (START) + // + Starting with the first data character following the start character, + // take the value of the character (between 0 and 102, inclusive) multiply + // it by its character position (1) and add that to the running checksum. + // Modulated 103 + $this->checksumValue = $this->indcheck[0]; + $c = count($this->indcheck); + for ($i = 1; $i < $c; $i++) { + $this->checksumValue += $this->indcheck[$i] * $i; + } + + $this->checksumValue = $this->checksumValue % 103; + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + if ($this->lastTable === 'C') { + return (string)$this->checksumValue; + } + + return $this->{'keys' . $this->lastTable}[$this->checksumValue]; + } + + return false; + } + + /** + * Specifies the starting_text table if none has been specified earlier. + * + * @param string $text + */ + private function setStartFromText($text) + { + if ($this->starting_text === null) { + // If we have a forced table at the start, we get that one... + if (is_array($text)) { + if (is_array($text[0])) { + // Code like array(array(ENCODING, '')) + $this->starting_text = $this->METHOD[$text[0][0]]; + return; + } else { + if (is_string($text[0])) { + // Code like array('test') (Automatic text) + $text = $text[0]; + } else { + // Code like array(ENCODING, '') + $this->starting_text = $this->METHOD[$text[0]]; + return; + } + } + } + + // At this point, we had an "automatic" table selection... + // If we can get at least 4 numbers, go in C; otherwise go in B. + $tmp = preg_quote($this->keysC, '/'); + $length = strlen($text); + if ($length >= 4 && preg_match('/[' . $tmp . ']/', substr($text, 0, 4))) { + $this->starting_text = 'C'; + } else { + if ($length > 0 && strpos($this->keysB, $text[0]) !== false) { + $this->starting_text = 'B'; + } else { + $this->starting_text = 'A'; + } + } + } + } + + /** + * Extracts the ~ value from the $text at the $pos. + * If the tilde is not ~~, ~F1, ~F2, ~F3, ~F4; an error is raised. + * + * @param string $text + * @param int $pos + * @return string + */ + private static function extractTilde($text, $pos) + { + if ($text[$pos] === '~') { + if (isset($text[$pos + 1])) { + // Do we have a tilde? + if ($text[$pos + 1] === '~') { + return '~~'; + } elseif ($text[$pos + 1] === 'F') { + // Do we have a number after? + if (isset($text[$pos + 2])) { + $v = intval($text[$pos + 2]); + if ($v >= 1 && $v <= 4) { + return '~F' . $v; + } else { + throw new BCGParseException('code128', 'Bad ~F. You must provide a number from 1 to 4.'); + } + } else { + throw new BCGParseException('code128', 'Bad ~F. You must provide a number from 1 to 4.'); + } + } else { + throw new BCGParseException('code128', 'Wrong code after the ~.'); + } + } else { + throw new BCGParseException('code128', 'Wrong code after the ~.'); + } + } else { + throw new BCGParseException('code128', 'There is no ~ at this location.'); + } + } + + /** + * Gets the "dotted" sequence for the $text based on the $currentMode. + * There is also a check if we use the special tilde ~ + * + * @param string $text + * @param string $currentMode + * @return string + */ + private function getSequenceParsed($text, $currentMode) + { + if ($this->tilde) { + $sequence = ''; + $previousPos = 0; + while (($pos = strpos($text, '~', $previousPos)) !== false) { + $tildeData = self::extractTilde($text, $pos); + + $simpleTilde = ($tildeData === '~~'); + if ($simpleTilde && $currentMode !== 'B') { + throw new BCGParseException('code128', 'The Table ' . $currentMode . ' doesn\'t contain the character ~.'); + } + + // At this point, we know we have ~Fx + if ($tildeData !== '~F1' && $currentMode === 'C') { + // The mode C doesn't support ~F2, ~F3, ~F4 + throw new BCGParseException('code128', 'The Table C doesn\'t contain the function ' . $tildeData . '.'); + } + + $length = $pos - $previousPos; + if ($currentMode === 'C') { + if ($length % 2 === 1) { + throw new BCGParseException('code128', 'The text "' . $text . '" must have an even number of character to be encoded in Table C.'); + } + } + + $sequence .= str_repeat('.', $length); + $sequence .= '.'; + $sequence .= (!$simpleTilde) ? 'F' : ''; + $previousPos = $pos + strlen($tildeData); + } + + // Flushing + $length = strlen($text) - $previousPos; + if ($currentMode === 'C') { + if ($length % 2 === 1) { + throw new BCGParseException('code128', 'The text "' . $text . '" must have an even number of character to be encoded in Table C.'); + } + } + + $sequence .= str_repeat('.', $length); + + return $sequence; + } else { + return str_repeat('.', strlen($text)); + } + } + + /** + * Parses the text and returns the appropriate sequence for the Table A. + * + * @param string $text + * @param string $currentMode + * @return string + */ + private function setParseA($text, &$currentMode) + { + $tmp = preg_quote($this->keysA, '/'); + + // If we accept the ~ for special character, we must allow it. + if ($this->tilde) { + $tmp .= '~'; + } + + $match = array(); + if (preg_match('/[^' . $tmp . ']/', $text, $match) === 1) { + // We found something not allowed + throw new BCGParseException('code128', 'The text "' . $text . '" can\'t be parsed with the Table A. The character "' . $match[0] . '" is not allowed.'); + } else { + $latch = ($currentMode === 'A') ? '' : '0'; + $currentMode = 'A'; + + return $latch . $this->getSequenceParsed($text, $currentMode); + } + } + + /** + * Parses the text and returns the appropriate sequence for the Table B. + * + * @param string $text + * @param string $currentMode + * @return string + */ + private function setParseB($text, &$currentMode) + { + $tmp = preg_quote($this->keysB, '/'); + + $match = array(); + if (preg_match('/[^' . $tmp . ']/', $text, $match) === 1) { + // We found something not allowed + throw new BCGParseException('code128', 'The text "' . $text . '" can\'t be parsed with the Table B. The character "' . $match[0] . '" is not allowed.'); + } else { + $latch = ($currentMode === 'B') ? '' : '1'; + $currentMode = 'B'; + + return $latch . $this->getSequenceParsed($text, $currentMode); + } + } + + /** + * Parses the text and returns the appropriate sequence for the Table C. + * + * @param string $text + * @param string $currentMode + * @return string + */ + private function setParseC($text, &$currentMode) + { + $tmp = preg_quote($this->keysC, '/'); + + // If we accept the ~ for special character, we must allow it. + if ($this->tilde) { + $tmp .= '~F'; + } + + $match = array(); + if (preg_match('/[^' . $tmp . ']/', $text, $match) === 1) { + // We found something not allowed + throw new BCGParseException('code128', 'The text "' . $text . '" can\'t be parsed with the Table C. The character "' . $match[0] . '" is not allowed.'); + } else { + $latch = ($currentMode === 'C') ? '' : '2'; + $currentMode = 'C'; + + return $latch . $this->getSequenceParsed($text, $currentMode); + } + } + + /** + * Depending on the $text, it will return the correct + * sequence to encode the text. + * + * @param string $text + * @param string $starting_text + * @return string + */ + private function getSequence($text, &$starting_text) + { + $e = 10000; + $latLen = array( + array(0, 1, 1), + array(1, 0, 1), + array(1, 1, 0) + ); + $shftLen = array( + array($e, 1, $e), + array(1, $e, $e), + array($e, $e, $e) + ); + $charSiz = array(2, 2, 1); + + $startA = $e; + $startB = $e; + $startC = $e; + if ($starting_text === 'A') { + $startA = 0; + } + if ($starting_text === 'B') { + $startB = 0; + } + if ($starting_text === 'C') { + $startC = 0; + } + + $curLen = array($startA, $startB, $startC); + $curSeq = array(null, null, null); + + $nextNumber = false; + + $x = 0; + $xLen = strlen($text); + for ($x = 0; $x < $xLen; $x++) { + $input = $text[$x]; + + // 1. + for ($i = 0; $i < 3; $i++) { + for ($j = 0; $j < 3; $j++) { + if (($curLen[$i] + $latLen[$i][$j]) < $curLen[$j]) { + $curLen[$j] = $curLen[$i] + $latLen[$i][$j]; + $curSeq[$j] = $curSeq[$i] . $j; + } + } + } + + // 2. + $nxtLen = array($e, $e, $e); + $nxtSeq = array(); + + // 3. + $flag = false; + $posArray = array(); + + // Special case, we do have a tilde and we process them + if ($this->tilde && $input === '~') { + $tildeData = self::extractTilde($text, $x); + + if ($tildeData === '~~') { + // We simply skip a tilde + $posArray[] = 1; + $x++; + } elseif (substr($tildeData, 0, 2) === '~F') { + $v = intval($tildeData[2]); + $posArray[] = 0; + $posArray[] = 1; + if ($v === 1) { + $posArray[] = 2; + } + + $x += 2; + $flag = true; + } + } else { + $pos = strpos($this->keysA, $input); + if ($pos !== false) { + $posArray[] = 0; + } + + $pos = strpos($this->keysB, $input); + if ($pos !== false) { + $posArray[] = 1; + } + + // Do we have the next char a number?? OR a ~F1 + $pos = strpos($this->keysC, $input); + if ($nextNumber || ($pos !== false && isset($text[$x + 1]) && strpos($this->keysC, $text[$x + 1]) !== false)) { + $nextNumber = !$nextNumber; + $posArray[] = 2; + } + } + + $c = count($posArray); + for ($i = 0; $i < $c; $i++) { + if (($curLen[$posArray[$i]] + $charSiz[$posArray[$i]]) < $nxtLen[$posArray[$i]]) { + $nxtLen[$posArray[$i]] = $curLen[$posArray[$i]] + $charSiz[$posArray[$i]]; + $nxtSeq[$posArray[$i]] = $curSeq[$posArray[$i]] . '.'; + } + + for ($j = 0; $j < 2; $j++) { + if ($j === $posArray[$i]) { + continue; + } + if (($curLen[$j] + $shftLen[$j][$posArray[$i]] + $charSiz[$posArray[$i]]) < $nxtLen[$j]) { + $nxtLen[$j] = $curLen[$j] + $shftLen[$j][$posArray[$i]] + $charSiz[$posArray[$i]]; + $nxtSeq[$j] = $curSeq[$j] . chr($posArray[$i] + 65) . '.'; + } + } + } + + if ($c === 0) { + // We found an unsuported character + throw new BCGParseException('code128', 'Character ' . $input . ' not supported.'); + } + + if ($flag) { + for ($i = 0; $i < 5; $i++) { + if (isset($nxtSeq[$i])) { + $nxtSeq[$i] .= 'F'; + } + } + } + + // 4. + for ($i = 0; $i < 3; $i++) { + $curLen[$i] = $nxtLen[$i]; + if (isset($nxtSeq[$i])) { + $curSeq[$i] = $nxtSeq[$i]; + } + } + } + + // Every curLen under $e is possible but we take the smallest + $m = $e; + $k = -1; + for ($i = 0; $i < 3; $i++) { + if ($curLen[$i] < $m) { + $k = $i; + $m = $curLen[$i]; + } + } + + if ($k === -1) { + return ''; + } + + return $curSeq[$k]; + } + + /** + * Depending on the sequence $seq given (returned from getSequence()), + * this method will return the code stream in an array. Each char will be a + * string of bit based on the Code 128. + * + * Each letter from the sequence represents bits. + * + * 0 to 2 are latches + * A to B are Shift + Letter + * . is a char in the current encoding + * + * @param string $text + * @param string $seq + * @return string[][] + */ + private function createBinaryStream($text, $seq) + { + $c = strlen($seq); + + $data = array(); // code stream + $indcheck = array(); // index for checksum + + $currentEncoding = 0; + if ($this->starting_text === 'A') { + $currentEncoding = 0; + $indcheck[] = self::KEY_STARTA; + $this->lastTable = 'A'; + } elseif ($this->starting_text === 'B') { + $currentEncoding = 1; + $indcheck[] = self::KEY_STARTB; + $this->lastTable = 'B'; + } elseif ($this->starting_text === 'C') { + $currentEncoding = 2; + $indcheck[] = self::KEY_STARTC; + $this->lastTable = 'C'; + } + + $data[] = $this->code[103 + $currentEncoding]; + + $temporaryEncoding = -1; + for ($i = 0, $counter = 0; $i < $c; $i++) { + $input = $seq[$i]; + $inputI = intval($input); + if ($input === '.') { + $this->encodeChar($data, $currentEncoding, $seq, $text, $i, $counter, $indcheck); + if ($temporaryEncoding !== -1) { + $currentEncoding = $temporaryEncoding; + $temporaryEncoding = -1; + } + } elseif ($input >= 'A' && $input <= 'B') { + // We shift + $encoding = ord($input) - 65; + $shift = $this->shift[$currentEncoding][$encoding]; + $indcheck[] = $shift; + $data[] = $this->code[$shift]; + if ($temporaryEncoding === -1) { + $temporaryEncoding = $currentEncoding; + } + + $currentEncoding = $encoding; + } elseif ($inputI >= 0 && $inputI < 3) { + $temporaryEncoding = -1; + + // We latch + $latch = $this->latch[$currentEncoding][$inputI]; + if ($latch !== null) { + $indcheck[] = $latch; + $this->lastTable = chr(65 + $inputI); + $data[] = $this->code[$latch]; + $currentEncoding = $inputI; + } + } + } + + return array($indcheck, $data); + } + + /** + * Encodes characters, base on its encoding and sequence + * + * @param int[] $data + * @param int $encoding + * @param string $seq + * @param string $text + * @param int $i + * @param int $counter + * @param int[] $indcheck + */ + private function encodeChar(&$data, $encoding, $seq, $text, &$i, &$counter, &$indcheck) + { + if (isset($seq[$i + 1]) && $seq[$i + 1] === 'F') { + // We have a flag !! + if ($text[$counter + 1] === 'F') { + $number = $text[$counter + 2]; + $fnc = $this->fnc[$encoding][$number - 1]; + $indcheck[] = $fnc; + $data[] = $this->code[$fnc]; + + // Skip F + number + $counter += 2; + } else { + // Not supposed + } + + $i++; + } else { + if ($encoding === 2) { + // We take 2 numbers in the same time + $code = (int)substr($text, $counter, 2); + $indcheck[] = $code; + $data[] = $this->code[$code]; + $counter++; + $i++; + } else { + $keys = ($encoding === 0) ? $this->keysA : $this->keysB; + $pos = strpos($keys, $text[$counter]); + $indcheck[] = $pos; + $data[] = $this->code[$pos]; + } + } + + $counter++; + } + + /** + * Saves data into the classes. + * + * This method will save data, calculate real column number + * (if -1 was selected), the real error level (if -1 was + * selected)... It will add Padding to the end and generate + * the error codes. + * + * @param array $data + */ + private function setData($data) + { + $this->indcheck = $data[0]; + $this->data = $data[1]; + $this->calculateChecksum(); + $this->data[] = $this->code[$this->checksumValue]; + $this->data[] = $this->code[self::KEY_STOP]; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode39.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode39.php new file mode 100644 index 0000000..a53a931 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode39.php @@ -0,0 +1,206 @@ +starting = $this->ending = 43; + $this->keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', '*'); + $this->code = array( // 0 added to add an extra space + '0001101000', /* 0 */ + '1001000010', /* 1 */ + '0011000010', /* 2 */ + '1011000000', /* 3 */ + '0001100010', /* 4 */ + '1001100000', /* 5 */ + '0011100000', /* 6 */ + '0001001010', /* 7 */ + '1001001000', /* 8 */ + '0011001000', /* 9 */ + '1000010010', /* A */ + '0010010010', /* B */ + '1010010000', /* C */ + '0000110010', /* D */ + '1000110000', /* E */ + '0010110000', /* F */ + '0000011010', /* G */ + '1000011000', /* H */ + '0010011000', /* I */ + '0000111000', /* J */ + '1000000110', /* K */ + '0010000110', /* L */ + '1010000100', /* M */ + '0000100110', /* N */ + '1000100100', /* O */ + '0010100100', /* P */ + '0000001110', /* Q */ + '1000001100', /* R */ + '0010001100', /* S */ + '0000101100', /* T */ + '1100000010', /* U */ + '0110000010', /* V */ + '1110000000', /* W */ + '0100100010', /* X */ + '1100100000', /* Y */ + '0110100000', /* Z */ + '0100001010', /* - */ + '1100001000', /* . */ + '0110001000', /* */ + '0101010000', /* $ */ + '0101000100', /* / */ + '0100010100', /* + */ + '0001010100', /* % */ + '0100101000' /* * */ + ); + + $this->setChecksum(false); + } + + /** + * Sets if we display the checksum. + * + * @param bool $checksum + */ + public function setChecksum($checksum) + { + $this->checksum = (bool)$checksum; + } + + /** + * Parses the text before displaying it. + * + * @param mixed $text + */ + public function parse($text) + { + parent::parse(strtoupper($text)); // Only Capital Letters are Allowed + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + // Starting * + $this->drawChar($im, $this->code[$this->starting], true); + + // Chars + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->findCode($this->text[$i]), true); + } + + // Checksum (rarely used) + if ($this->checksum === true) { + $this->calculateChecksum(); + $this->drawChar($im, $this->code[$this->checksumValue % 43], true); + } + + // Ending * + $this->drawChar($im, $this->code[$this->ending], true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $textlength = 13 * strlen($this->text); + $startlength = 13; + $checksumlength = 0; + if ($this->checksum === true) { + $checksumlength = 13; + } + + $endlength = 13; + + $w += $startlength + $textlength + $checksumlength + $endlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('code39', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('code39', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + if (strpos($this->text, '*') !== false) { + throw new BCGParseException('code39', 'The character \'*\' is not allowed.'); + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + $this->checksumValue = 0; + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $this->checksumValue += $this->findIndex($this->text[$i]); + } + + $this->checksumValue = $this->checksumValue % 43; + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + return $this->keys[$this->checksumValue]; + } + + return false; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode39extended.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode39extended.php new file mode 100644 index 0000000..bd46d59 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode39extended.php @@ -0,0 +1,221 @@ +keys[self::EXTENDED_1] = '($)'; + $this->keys[self::EXTENDED_2] = '(/)'; + $this->keys[self::EXTENDED_3] = '(+)'; + $this->keys[self::EXTENDED_4] = '(%)'; + } + + /** + * Parses the text before displaying it. + * + * @param mixed $text + */ + public function parse($text) + { + $this->text = $text; + + $data = array(); + $indcheck = array(); + + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $pos = array_search($this->text[$i], $this->keys); + if ($pos === false) { + // Search in extended? + $extended = self::getExtendedVersion($this->text[$i]); + if ($extended === false) { + throw new BCGParseException('code39extended', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } else { + $extc = strlen($extended); + for ($j = 0; $j < $extc; $j++) { + $v = $extended[$j]; + if ($v === '$') { + $indcheck[] = self::EXTENDED_1; + $data[] = $this->code[self::EXTENDED_1]; + } elseif ($v === '%') { + $indcheck[] = self::EXTENDED_2; + $data[] = $this->code[self::EXTENDED_2]; + } elseif ($v === '/') { + $indcheck[] = self::EXTENDED_3; + $data[] = $this->code[self::EXTENDED_3]; + } elseif ($v === '+') { + $indcheck[] = self::EXTENDED_4; + $data[] = $this->code[self::EXTENDED_4]; + } else { + $pos2 = array_search($v, $this->keys); + $indcheck[] = $pos2; + $data[] = $this->code[$pos2]; + } + } + } + } else { + $indcheck[] = $pos; + $data[] = $this->code[$pos]; + } + } + + $this->setData(array($indcheck, $data)); + $this->addDefaultLabel(); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + // Starting * + $this->drawChar($im, $this->code[$this->starting], true); + $c = count($this->data); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->data[$i], true); + } + + // Checksum (rarely used) + if ($this->checksum === true) { + $this->drawChar($im, $this->code[$this->checksumValue % 43], true); + } + + // Ending * + $this->drawChar($im, $this->code[$this->ending], true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $textlength = 13 * count($this->data); + $startlength = 13; + $checksumlength = 0; + if ($this->checksum === true) { + $checksumlength = 13; + } + + $endlength = 13; + + $w += $startlength + $textlength + $checksumlength + $endlength; + $h += $this->thickness; + return BCGBarcode1D::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = count($this->data); + if ($c === 0) { + throw new BCGParseException('code39extended', 'No data has been entered.'); + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + $this->checksumValue = 0; + $c = count($this->indcheck); + for ($i = 0; $i < $c; $i++) { + $this->checksumValue += $this->indcheck[$i]; + } + + $this->checksumValue = $this->checksumValue % 43; + } + + /** + * Saves data into the classes. + * + * This method will save data, calculate real column number + * (if -1 was selected), the real error level (if -1 was + * selected)... It will add Padding to the end and generate + * the error codes. + * + * @param array $data + */ + private function setData($data) + { + $this->indcheck = $data[0]; + $this->data = $data[1]; + $this->calculateChecksum(); + } + + /** + * Returns the extended reprensentation of the character. + * + * @param string $char + * @return string + */ + private static function getExtendedVersion($char) + { + $o = ord($char); + if ($o === 0) { + return '%U'; + } elseif ($o >= 1 && $o <= 26) { + return '$' . chr($o + 64); + } elseif (($o >= 33 && $o <= 44) || $o === 47 || $o === 48) { + return '/' . chr($o + 32); + } elseif ($o >= 97 && $o <= 122) { + return '+' . chr($o - 32); + } elseif ($o >= 27 && $o <= 31) { + return '%' . chr($o + 38); + } elseif ($o >= 59 && $o <= 63) { + return '%' . chr($o + 11); + } elseif ($o >= 91 && $o <= 95) { + return '%' . chr($o - 16); + } elseif ($o >= 123 && $o <= 127) { + return '%' . chr($o - 43); + } elseif ($o === 64) { + return '%V'; + } elseif ($o === 96) { + return '%W'; + } elseif ($o > 127) { + return false; + } else { + return $char; + } + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode93.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode93.php new file mode 100644 index 0000000..cba2ccf --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGcode93.php @@ -0,0 +1,316 @@ +starting = $this->ending = 47; /* * */ + $this->keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', '($)', '(%)', '(/)', '(+)', '(*)'); + $this->code = array( + '020001', /* 0 */ + '000102', /* 1 */ + '000201', /* 2 */ + '000300', /* 3 */ + '010002', /* 4 */ + '010101', /* 5 */ + '010200', /* 6 */ + '000003', /* 7 */ + '020100', /* 8 */ + '030000', /* 9 */ + '100002', /* A */ + '100101', /* B */ + '100200', /* C */ + '110001', /* D */ + '110100', /* E */ + '120000', /* F */ + '001002', /* G */ + '001101', /* H */ + '001200', /* I */ + '011001', /* J */ + '021000', /* K */ + '000012', /* L */ + '000111', /* M */ + '000210', /* N */ + '010011', /* O */ + '020010', /* P */ + '101001', /* Q */ + '101100', /* R */ + '100011', /* S */ + '100110', /* T */ + '110010', /* U */ + '111000', /* V */ + '001011', /* W */ + '001110', /* X */ + '011010', /* Y */ + '012000', /* Z */ + '010020', /* - */ + '200001', /* . */ + '200100', /* */ + '210000', /* $ */ + '001020', /* / */ + '002010', /* + */ + '100020', /* % */ + '010110', /*($)*/ + '201000', /*(%)*/ + '200010', /*(/)*/ + '011100', /*(+)*/ + '000030' /*(*)*/ + ); + } + + /** + * Parses the text before displaying it. + * + * @param mixed $text + */ + public function parse($text) + { + $this->text = $text; + + $data = array(); + $indcheck = array(); + + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $pos = array_search($this->text[$i], $this->keys); + if ($pos === false) { + // Search in extended? + $extended = self::getExtendedVersion($this->text[$i]); + if ($extended === false) { + throw new BCGParseException('code93', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } else { + $extc = strlen($extended); + for ($j = 0; $j < $extc; $j++) { + $v = $extended[$j]; + if ($v === '$') { + $indcheck[] = self::EXTENDED_1; + $data[] = $this->code[self::EXTENDED_1]; + } elseif ($v === '%') { + $indcheck[] = self::EXTENDED_2; + $data[] = $this->code[self::EXTENDED_2]; + } elseif ($v === '/') { + $indcheck[] = self::EXTENDED_3; + $data[] = $this->code[self::EXTENDED_3]; + } elseif ($v === '+') { + $indcheck[] = self::EXTENDED_4; + $data[] = $this->code[self::EXTENDED_4]; + } else { + $pos2 = array_search($v, $this->keys); + $indcheck[] = $pos2; + $data[] = $this->code[$pos2]; + } + } + } + } else { + $indcheck[] = $pos; + $data[] = $this->code[$pos]; + } + } + + $this->setData(array($indcheck, $data)); + $this->addDefaultLabel(); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + // Starting * + $this->drawChar($im, $this->code[$this->starting], true); + $c = count($this->data); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->data[$i], true); + } + + // Checksum + $c = count($this->checksumValue); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->code[$this->checksumValue[$i]], true); + } + + // Ending * + $this->drawChar($im, $this->code[$this->ending], true); + + // Draw a Final Bar + $this->drawChar($im, '0', true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $startlength = 9; + $textlength = 9 * count($this->data); + $checksumlength = 2 * 9; + $endlength = 9 + 1; // + final bar + + $w += $startlength + $textlength + $checksumlength + $endlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = count($this->data); + if ($c === 0) { + throw new BCGParseException('code93', 'No data has been entered.'); + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Checksum + // First CheckSUM "C" + // The "C" checksum character is the modulo 47 remainder of the sum of the weighted + // value of the data characters. The weighting value starts at "1" for the right-most + // data character, 2 for the second to last, 3 for the third-to-last, and so on up to 20. + // After 20, the sequence wraps around back to 1. + + // Second CheckSUM "K" + // Same as CheckSUM "C" but we count the CheckSum "C" at the end + // After 15, the sequence wraps around back to 1. + $sequence_multiplier = array(20, 15); + $this->checksumValue = array(); + $indcheck = $this->indcheck; + for ($z = 0; $z < 2; $z++) { + $checksum = 0; + for ($i = count($indcheck), $j = 0; $i > 0; $i--, $j++) { + $multiplier = $i % $sequence_multiplier[$z]; + if ($multiplier === 0) { + $multiplier = $sequence_multiplier[$z]; + } + + $checksum += $indcheck[$j] * $multiplier; + } + + $this->checksumValue[$z] = $checksum % 47; + $indcheck[] = $this->checksumValue[$z]; + } + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + $ret = ''; + $c = count($this->checksumValue); + for ($i = 0; $i < $c; $i++) { + $ret .= $this->keys[$this->checksumValue[$i]]; + } + + return $ret; + } + + return false; + } + + /** + * Saves data into the classes. + * + * This method will save data, calculate real column number + * (if -1 was selected), the real error level (if -1 was + * selected)... It will add Padding to the end and generate + * the error codes. + * + * @param array $data + */ + private function setData($data) + { + $this->indcheck = $data[0]; + $this->data = $data[1]; + $this->calculateChecksum(); + } + + /** + * Returns the extended reprensentation of the character. + * + * @param string $char + * @return string + */ + private static function getExtendedVersion($char) + { + $o = ord($char); + if ($o === 0) { + return '%U'; + } elseif ($o >= 1 && $o <= 26) { + return '$' . chr($o + 64); + } elseif (($o >= 33 && $o <= 44) || $o === 47 || $o === 48) { + return '/' . chr($o + 32); + } elseif ($o >= 97 && $o <= 122) { + return '+' . chr($o - 32); + } elseif ($o >= 27 && $o <= 31) { + return '%' . chr($o + 38); + } elseif ($o >= 59 && $o <= 63) { + return '%' . chr($o + 11); + } elseif ($o >= 91 && $o <= 95) { + return '%' . chr($o - 16); + } elseif ($o >= 123 && $o <= 127) { + return '%' . chr($o - 43); + } elseif ($o === 64) { + return '%V'; + } elseif ($o === 96) { + return '%W'; + } elseif ($o > 127) { + return false; + } else { + return $char; + } + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGean13.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGean13.php new file mode 100644 index 0000000..9748703 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGean13.php @@ -0,0 +1,340 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + // Left-Hand Odd Parity starting with a space + // Left-Hand Even Parity is the inverse (0=0012) starting with a space + // Right-Hand is the same of Left-Hand starting with a bar + $this->code = array( + '2100', /* 0 */ + '1110', /* 1 */ + '1011', /* 2 */ + '0300', /* 3 */ + '0021', /* 4 */ + '0120', /* 5 */ + '0003', /* 6 */ + '0201', /* 7 */ + '0102', /* 8 */ + '2001' /* 9 */ + ); + + // Parity, 0=Odd, 1=Even for manufacturer code. Depending on 1st System Digit + $this->codeParity = array( + array(0, 0, 0, 0, 0), /* 0 */ + array(0, 1, 0, 1, 1), /* 1 */ + array(0, 1, 1, 0, 1), /* 2 */ + array(0, 1, 1, 1, 0), /* 3 */ + array(1, 0, 0, 1, 1), /* 4 */ + array(1, 1, 0, 0, 1), /* 5 */ + array(1, 1, 1, 0, 0), /* 6 */ + array(1, 0, 1, 0, 1), /* 7 */ + array(1, 0, 1, 1, 0), /* 8 */ + array(1, 1, 0, 1, 0) /* 9 */ + ); + + $this->alignDefaultLabel(true); + } + + public function alignDefaultLabel($align) + { + $this->alignLabel = (bool)$align; + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + $this->drawBars($im); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + + if ($this->isDefaultEanLabelEnabled()) { + $dimension = $this->labelCenter1->getDimension(); + $this->drawExtendedBars($im, $dimension[1] - 2); + } + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $startlength = 3; + $centerlength = 5; + $textlength = 12 * 7; + $endlength = 3; + + $w += $startlength + $centerlength + $textlength + $endlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Adds the default label. + */ + protected function addDefaultLabel() + { + if ($this->isDefaultEanLabelEnabled()) { + $this->processChecksum(); + $label = $this->getLabel(); + $font = $this->font; + + $this->labelLeft = new BCGLabel(substr($label, 0, 1), $font, BCGLabel::POSITION_LEFT, BCGLabel::ALIGN_BOTTOM); + $this->labelLeft->setSpacing(4 * $this->scale); + + $this->labelCenter1 = new BCGLabel(substr($label, 1, 6), $font, BCGLabel::POSITION_BOTTOM, BCGLabel::ALIGN_LEFT); + $labelCenter1Dimension = $this->labelCenter1->getDimension(); + $this->labelCenter1->setOffset(($this->scale * 44 - $labelCenter1Dimension[0]) / 2 + $this->scale * 2); + + $this->labelCenter2 = new BCGLabel(substr($label, 7, 5) . $this->keys[$this->checksumValue], $font, BCGLabel::POSITION_BOTTOM, BCGLabel::ALIGN_LEFT); + $this->labelCenter2->setOffset(($this->scale * 44 - $labelCenter1Dimension[0]) / 2 + $this->scale * 48); + + if ($this->alignLabel) { + $labelDimension = $this->labelCenter1->getDimension(); + $this->labelLeft->setOffset($labelDimension[1]); + } else { + $labelDimension = $this->labelLeft->getDimension(); + $this->labelLeft->setOffset($labelDimension[1] / 2); + } + + $this->addLabel($this->labelLeft); + $this->addLabel($this->labelCenter1); + $this->addLabel($this->labelCenter2); + } + } + + /** + * Checks if the default ean label is enabled. + * + * @return bool + */ + protected function isDefaultEanLabelEnabled() + { + $label = $this->getLabel(); + $font = $this->font; + return $label !== null && $label !== '' && $font !== null && $this->defaultLabel !== null; + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('ean13', 'No data has been entered.'); + } + + $this->checkCharsAllowed(); + $this->checkCorrectLength(); + + parent::validate(); + } + + /** + * Check chars allowed. + */ + protected function checkCharsAllowed() + { + // Checking if all chars are allowed + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('ean13', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + } + + /** + * Check correct length. + */ + protected function checkCorrectLength() + { + // If we have 13 chars, just flush the last one without throwing anything + $c = strlen($this->text); + if ($c === 13) { + $this->text = substr($this->text, 0, 12); + } elseif ($c !== 12) { + throw new BCGParseException('ean13', 'Must contain 12 digits, the 13th digit is automatically added.'); + } + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Calculating Checksum + // Consider the right-most digit of the message to be in an "odd" position, + // and assign odd/even to each character moving from right to left + // Odd Position = 3, Even Position = 1 + // Multiply it by the number + // Add all of that and do 10-(?mod10) + $odd = true; + $this->checksumValue = 0; + $c = strlen($this->text); + for ($i = $c; $i > 0; $i--) { + if ($odd === true) { + $multiplier = 3; + $odd = false; + } else { + $multiplier = 1; + $odd = true; + } + + if (!isset($this->keys[$this->text[$i - 1]])) { + return; + } + + $this->checksumValue += $this->keys[$this->text[$i - 1]] * $multiplier; + } + + $this->checksumValue = (10 - $this->checksumValue % 10) % 10; + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + return $this->keys[$this->checksumValue]; + } + + return false; + } + + /** + * Draws the bars + * + * @param resource $im + */ + protected function drawBars($im) + { + // Checksum + $this->calculateChecksum(); + $temp_text = $this->text . $this->keys[$this->checksumValue]; + + // Starting Code + $this->drawChar($im, '000', true); + + // Draw Second Code + $this->drawChar($im, $this->findCode($temp_text[1]), false); + + // Draw Manufacturer Code + for ($i = 0; $i < 5; $i++) { + $this->drawChar($im, self::inverse($this->findCode($temp_text[$i + 2]), $this->codeParity[(int)$temp_text[0]][$i]), false); + } + + // Draw Center Guard Bar + $this->drawChar($im, '00000', false); + + // Draw Product Code + for ($i = 7; $i < 13; $i++) { + $this->drawChar($im, $this->findCode($temp_text[$i]), true); + } + + // Draw Right Guard Bar + $this->drawChar($im, '000', true); + } + + /** + * Draws the extended bars on the image. + * + * @param resource $im + * @param int $plus + */ + protected function drawExtendedBars($im, $plus) + { + $rememberX = $this->positionX; + $rememberH = $this->thickness; + + // We increase the bars + $this->thickness = $this->thickness + intval($plus / $this->scale); + $this->positionX = 0; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + // Center Guard Bar + $this->positionX += 44; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + // Last Bars + $this->positionX += 44; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + $this->positionX = $rememberX; + $this->thickness = $rememberH; + } + + /** + * Inverses the string when the $inverse parameter is equal to 1. + * + * @param string $text + * @param int $inverse + * @return string + */ + private static function inverse($text, $inverse = 1) + { + if ($inverse === 1) { + $text = strrev($text); + } + + return $text; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGean8.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGean8.php new file mode 100644 index 0000000..9cae012 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGean8.php @@ -0,0 +1,257 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + // Left-Hand Odd Parity starting with a space + // Right-Hand is the same of Left-Hand starting with a bar + $this->code = array( + '2100', /* 0 */ + '1110', /* 1 */ + '1011', /* 2 */ + '0300', /* 3 */ + '0021', /* 4 */ + '0120', /* 5 */ + '0003', /* 6 */ + '0201', /* 7 */ + '0102', /* 8 */ + '2001' /* 9 */ + ); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + // Checksum + $this->calculateChecksum(); + $temp_text = $this->text . $this->keys[$this->checksumValue]; + + // Starting Code + $this->drawChar($im, '000', true); + + // Draw First 4 Chars (Left-Hand) + for ($i = 0; $i < 4; $i++) { + $this->drawChar($im, $this->findCode($temp_text[$i]), false); + } + + // Draw Center Guard Bar + $this->drawChar($im, '00000', false); + + // Draw Last 4 Chars (Right-Hand) + for ($i = 4; $i < 8; $i++) { + $this->drawChar($im, $this->findCode($temp_text[$i]), true); + } + + // Draw Right Guard Bar + $this->drawChar($im, '000', true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + + if ($this->isDefaultEanLabelEnabled()) { + $dimension = $this->labelRight->getDimension(); + $this->drawExtendedBars($im, $dimension[1] - 2); + } + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $startlength = 3; + $centerlength = 5; + $textlength = 8 * 7; + $endlength = 3; + + $w += $startlength + $centerlength + $textlength + $endlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Adds the default label. + */ + protected function addDefaultLabel() + { + if ($this->isDefaultEanLabelEnabled()) { + $this->processChecksum(); + $label = $this->getLabel(); + $font = $this->font; + + $this->labelLeft = new BCGLabel(substr($label, 0, 4), $font, BCGLabel::POSITION_BOTTOM, BCGLabel::ALIGN_LEFT); + $labelLeftDimension = $this->labelLeft->getDimension(); + $this->labelLeft->setOffset(($this->scale * 30 - $labelLeftDimension[0]) / 2 + $this->scale * 2); + + $this->labelRight = new BCGLabel(substr($label, 4, 3) . $this->keys[$this->checksumValue], $font, BCGLabel::POSITION_BOTTOM, BCGLabel::ALIGN_LEFT); + $labelRightDimension = $this->labelRight->getDimension(); + $this->labelRight->setOffset(($this->scale * 30 - $labelRightDimension[0]) / 2 + $this->scale * 34); + + $this->addLabel($this->labelLeft); + $this->addLabel($this->labelRight); + } + } + + /** + * Checks if the default ean label is enabled. + * + * @return bool + */ + protected function isDefaultEanLabelEnabled() + { + $label = $this->getLabel(); + $font = $this->font; + return $label !== null && $label !== '' && $font !== null && $this->defaultLabel !== null; + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('ean8', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('ean8', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + // If we have 8 chars just flush the last one + if ($c === 8) { + $this->text = substr($this->text, 0, 7); + } elseif ($c !== 7) { + throw new BCGParseException('ean8', 'Must contain 7 digits, the 8th digit is automatically added.'); + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Calculating Checksum + // Consider the right-most digit of the message to be in an "odd" position, + // and assign odd/even to each character moving from right to left + // Odd Position = 3, Even Position = 1 + // Multiply it by the number + // Add all of that and do 10-(?mod10) + $odd = true; + $this->checksumValue = 0; + $c = strlen($this->text); + for ($i = $c; $i > 0; $i--) { + if ($odd === true) { + $multiplier = 3; + $odd = false; + } else { + $multiplier = 1; + $odd = true; + } + + if (!isset($this->keys[$this->text[$i - 1]])) { + return; + } + + $this->checksumValue += $this->keys[$this->text[$i - 1]] * $multiplier; + } + + $this->checksumValue = (10 - $this->checksumValue % 10) % 10; + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + return $this->keys[$this->checksumValue]; + } + + return false; + } + + /** + * Draws the extended bars on the image. + * + * @param resource $im + * @param int $plus + */ + private function drawExtendedBars($im, $plus) + { + $rememberX = $this->positionX; + $rememberH = $this->thickness; + + // We increase the bars + $this->thickness = $this->thickness + intval($plus / $this->scale); + $this->positionX = 0; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + // Center Guard Bar + $this->positionX += 30; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + // Last Bars + $this->positionX += 30; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + $this->positionX = $rememberX; + $this->thickness = $rememberH; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGgs1128.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGgs1128.php new file mode 100644 index 0000000..0b6330c --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGgs1128.php @@ -0,0 +1,746 @@ +identifiersAi = array( + '00' => array(self::NUMERIC, 18, 18, true), + '01' => array(self::NUMERIC, 14, 14, true), + '02' => array(self::NUMERIC, 14, 14, true), + '10' => array(self::ALPHA_NUMERIC, 1, 20, false), + '11' => array(self::DATE_YYMMDD, 6, 6, false), + '12' => array(self::DATE_YYMMDD, 6, 6, false), + '13' => array(self::DATE_YYMMDD, 6, 6, false), + '15' => array(self::DATE_YYMMDD, 6, 6, false), + '16' => array(self::DATE_YYMMDD, 6, 6, false), + '17' => array(self::DATE_YYMMDD, 6, 6, false), + '20' => array(self::NUMERIC, 2, 2, false), + '21' => array(self::ALPHA_NUMERIC, 1, 20, false), + '22' => array(self::ALPHA_NUMERIC, 1, 20, false), + '240' => array(self::ALPHA_NUMERIC, 1, 30, false), + '241' => array(self::ALPHA_NUMERIC, 1, 30, false), + '242' => array(self::ALPHA_NUMERIC, 1, 6, false), + '243' => array(self::ALPHA_NUMERIC, 1, 20, false), + '250' => array(self::ALPHA_NUMERIC, 1, 30, false), + '251' => array(self::ALPHA_NUMERIC, 1, 30, false), + '253' => array(self::NUMERIC, 14, 30, false), + '254' => array(self::NUMERIC, 1, 20, false), + '255' => array(self::NUMERIC, 14, 25, false), + '30' => array(self::NUMERIC, 1, 8, false), + '310y' => array(self::NUMERIC, 6, 6, false), + '311y' => array(self::NUMERIC, 6, 6, false), + '312y' => array(self::NUMERIC, 6, 6, false), + '313y' => array(self::NUMERIC, 6, 6, false), + '314y' => array(self::NUMERIC, 6, 6, false), + '315y' => array(self::NUMERIC, 6, 6, false), + '316y' => array(self::NUMERIC, 6, 6, false), + '320y' => array(self::NUMERIC, 6, 6, false), + '321y' => array(self::NUMERIC, 6, 6, false), + '322y' => array(self::NUMERIC, 6, 6, false), + '323y' => array(self::NUMERIC, 6, 6, false), + '324y' => array(self::NUMERIC, 6, 6, false), + '325y' => array(self::NUMERIC, 6, 6, false), + '326y' => array(self::NUMERIC, 6, 6, false), + '327y' => array(self::NUMERIC, 6, 6, false), + '328y' => array(self::NUMERIC, 6, 6, false), + '329y' => array(self::NUMERIC, 6, 6, false), + '330y' => array(self::NUMERIC, 6, 6, false), + '331y' => array(self::NUMERIC, 6, 6, false), + '332y' => array(self::NUMERIC, 6, 6, false), + '333y' => array(self::NUMERIC, 6, 6, false), + '334y' => array(self::NUMERIC, 6, 6, false), + '335y' => array(self::NUMERIC, 6, 6, false), + '336y' => array(self::NUMERIC, 6, 6, false), + '337y' => array(self::NUMERIC, 6, 6, false), + '340y' => array(self::NUMERIC, 6, 6, false), + '341y' => array(self::NUMERIC, 6, 6, false), + '342y' => array(self::NUMERIC, 6, 6, false), + '343y' => array(self::NUMERIC, 6, 6, false), + '344y' => array(self::NUMERIC, 6, 6, false), + '345y' => array(self::NUMERIC, 6, 6, false), + '346y' => array(self::NUMERIC, 6, 6, false), + '347y' => array(self::NUMERIC, 6, 6, false), + '348y' => array(self::NUMERIC, 6, 6, false), + '349y' => array(self::NUMERIC, 6, 6, false), + '350y' => array(self::NUMERIC, 6, 6, false), + '351y' => array(self::NUMERIC, 6, 6, false), + '352y' => array(self::NUMERIC, 6, 6, false), + '353y' => array(self::NUMERIC, 6, 6, false), + '354y' => array(self::NUMERIC, 6, 6, false), + '355y' => array(self::NUMERIC, 6, 6, false), + '356y' => array(self::NUMERIC, 6, 6, false), + '357y' => array(self::NUMERIC, 6, 6, false), + '360y' => array(self::NUMERIC, 6, 6, false), + '361y' => array(self::NUMERIC, 6, 6, false), + '362y' => array(self::NUMERIC, 6, 6, false), + '363y' => array(self::NUMERIC, 6, 6, false), + '364y' => array(self::NUMERIC, 6, 6, false), + '365y' => array(self::NUMERIC, 6, 6, false), + '366y' => array(self::NUMERIC, 6, 6, false), + '367y' => array(self::NUMERIC, 6, 6, false), + '368y' => array(self::NUMERIC, 6, 6, false), + '369y' => array(self::NUMERIC, 6, 6, false), + '37' => array(self::NUMERIC, 1, 8, false), + '390y' => array(self::NUMERIC, 1, 15, false), + '391y' => array(self::NUMERIC, 4, 18, false), + '392y' => array(self::NUMERIC, 1, 15, false), + '393y' => array(self::NUMERIC, 4, 18, false), + '394y' => array(self::NUMERIC, 4, 4, false), + '400' => array(self::ALPHA_NUMERIC, 1, 30, false), + '401' => array(self::ALPHA_NUMERIC, 1, 30, false), + '402' => array(self::NUMERIC, 17, 17, false), + '403' => array(self::ALPHA_NUMERIC, 1, 30, false), + '410' => array(self::NUMERIC, 13, 13, true), + '411' => array(self::NUMERIC, 13, 13, true), + '412' => array(self::NUMERIC, 13, 13, true), + '413' => array(self::NUMERIC, 13, 13, true), + '414' => array(self::NUMERIC, 13, 13, true), + '415' => array(self::NUMERIC, 13, 13, true), + '416' => array(self::NUMERIC, 13, 13, true), + '420' => array(self::ALPHA_NUMERIC, 1, 20, false), + '421' => array(self::ALPHA_NUMERIC, 4, 12, false), + '422' => array(self::NUMERIC, 3, 3, false), + '423' => array(self::NUMERIC, 3, 15, false), + '424' => array(self::NUMERIC, 3, 3, false), + '425' => array(self::NUMERIC, 3, 3, false), + '426' => array(self::NUMERIC, 3, 3, false), + '427' => array(self::ALPHA_NUMERIC, 1, 3, false), + '7001' => array(self::NUMERIC, 13, 13, false), + '7002' => array(self::ALPHA_NUMERIC, 1, 30, false), + '7003' => array(self::NUMERIC, 10, 10, false), + '7004' => array(self::NUMERIC, 1, 4, false), + '7005' => array(self::ALPHA_NUMERIC, 1, 12, false), + '7006' => array(self::DATE_YYMMDD, 6, 6, false), + '7007' => array(self::NUMERIC, 6, 12, false), + '7008' => array(self::ALPHA_NUMERIC, 1, 3, false), + '7009' => array(self::ALPHA_NUMERIC, 1, 10, false), + '7010' => array(self::ALPHA_NUMERIC, 1, 2, false), + '7020' => array(self::ALPHA_NUMERIC, 1, 20, false), + '7021' => array(self::ALPHA_NUMERIC, 1, 20, false), + '7022' => array(self::ALPHA_NUMERIC, 1, 20, false), + '7023' => array(self::ALPHA_NUMERIC, 1, 30, false), + '703y' => array(self::ALPHA_NUMERIC, 3, 30, false), + '710' => array(self::ALPHA_NUMERIC, 1, 20, false), + '711' => array(self::ALPHA_NUMERIC, 1, 20, false), + '712' => array(self::ALPHA_NUMERIC, 1, 20, false), + '8001' => array(self::NUMERIC, 14, 14, false), + '8002' => array(self::ALPHA_NUMERIC, 1, 20, false), + '8003' => array(self::ALPHA_NUMERIC, 15, 30, false), + '8004' => array(self::ALPHA_NUMERIC, 1, 30, false), + '8005' => array(self::NUMERIC, 6, 6, false), + '8006' => array(self::NUMERIC, 18, 18, false), + '8007' => array(self::ALPHA_NUMERIC, 1, 34, false), + '8008' => array(self::NUMERIC, 8, 12, false), + '8010' => array(self::ALPHA_NUMERIC, 1, 30, false), + '8011' => array(self::NUMERIC, 1, 12, false), + '8012' => array(self::ALPHA_NUMERIC, 1, 20, false), + '8017' => array(self::NUMERIC, 18, 18, false), + '8018' => array(self::NUMERIC, 18, 18, false), + '8019' => array(self::NUMERIC, 1, 10, false), + '8020' => array(self::ALPHA_NUMERIC, 1, 25, false), + '8110' => array(self::ALPHA_NUMERIC, 1, 70, false), + '8111' => array(self::NUMERIC, 4, 4, false), + '8112' => array(self::ALPHA_NUMERIC, 1, 70, false), + '8200' => array(self::ALPHA_NUMERIC, 1, 70, false), + '90' => array(self::ALPHA_NUMERIC, 1, 90, false), + '91' => array(self::ALPHA_NUMERIC, 1, 90, false), + '92' => array(self::ALPHA_NUMERIC, 1, 90, false), + '93' => array(self::ALPHA_NUMERIC, 1, 90, false), + '94' => array(self::ALPHA_NUMERIC, 1, 90, false), + '95' => array(self::ALPHA_NUMERIC, 1, 90, false), + '96' => array(self::ALPHA_NUMERIC, 1, 90, false), + '97' => array(self::ALPHA_NUMERIC, 1, 90, false), + '98' => array(self::ALPHA_NUMERIC, 1, 90, false), + '99' => array(self::ALPHA_NUMERIC, 1, 90, false) + ); + + $this->setStrictMode(true); + $this->setTilde(true); + $this->setAllowsUnknownIdentifier(false); + $this->setNoLengthLimit(false); + } + + /** + * Gets the content checksum for an identifier. + * Do not pass the identifier code. + * + * @param string $content + * @return int + */ + public static function getAiContentChecksum($content) + { + return self::calculateChecksumMod10($content); + } + + /** + * Enables or disables the strict mode. + * + * @param bool $strictMode + */ + public function setStrictMode($strictMode) + { + $this->strictMode = $strictMode; + } + + /** + * Gets if the strict mode is activated. + * + * @return bool + */ + public function getStrictMode() + { + return $this->strictMode; + } + + /** + * Allows unknown identifiers. + * + * @param bool $allow + */ + public function setAllowsUnknownIdentifier($allow) + { + $this->allowsUnknownIdentifier = (bool)$allow; + } + + /** + * Gets if unkmown identifiers are allowed. + * + * @return bool + */ + public function getAllowsUnknownIdentifier() + { + return $this->allowsUnknownIdentifier; + } + + /** + * Removes the limit of 48 characters. + * + * @param bool $noLengthLimit + */ + public function setNoLengthLimit($noLengthLimit) + { + $this->noLengthLimit = (bool)$noLengthLimit; + } + + /** + * Gets if the limit of 48 characters is removed. + * + * @return bool + */ + public function getNoLengthLimit() + { + return $this->noLengthLimit; + } + + /** + * Parses Text. + * + * @param string $text + */ + public function parse($text) + { + parent::parse($this->parseGs1128($text)); + } + + /** + * Formats data for gs1-128. + * + * @return string + */ + private function formatGs1128() + { + $formatedText = '~F1'; + $formatedLabel = ''; + $c = count($this->identifiersId); + + for ($i = 0; $i < $c; $i++) { + if ($i > 0) { + $formatedLabel .= ' '; + } + + if ($this->identifiersId[$i] !== null) { + $formatedLabel .= '(' . $this->identifiersId[$i] . ')'; + } + + $formatedText .= $this->identifiersId[$i]; + + $formatedLabel .= $this->identifiersContent[$i]; + $formatedText .= $this->identifiersContent[$i]; + + if (isset($this->identifiersAi[$this->identifiersId[$i]])) { + $ai_data = $this->identifiersAi[$this->identifiersId[$i]]; + } elseif (isset($this->identifiersId[$i][3])) { + $identifierWithVar = substr($this->identifiersId[$i], 0, -1) . 'y'; + $ai_data = isset($this->identifiersAi[$identifierWithVar]) ? $this->identifiersAi[$identifierWithVar] : null; + } else { + $ai_data = null; + } + + /* We'll check if we need to add a ~F1 () char */ + /* If we use the legacy mode, we always add a ~F1 () char between AIs */ + if ($ai_data !== null) { + if ((strlen($this->identifiersContent[$i]) < $ai_data[self::MAXLENGTH] && ($i + 1) !== $c) || (!$this->strictMode && ($i + 1) !== $c)) { + $formatedText .= '~F1'; + } + } elseif ($this->allowsUnknownIdentifier && $this->identifiersId[$i] === null && ($i + 1) !== $c) { + /* If this id is unknown, we add a ~F1 () char */ + $formatedText .= '~F1'; + } + } + + if ($this->noLengthLimit === false) { + $calculableCharacters = str_replace('~F1', chr(29), $formatedText); + $calculableCharacters = str_replace('(', '', $calculableCharacters); + $calculableCharacters = str_replace(')', '', $calculableCharacters); + + if (strlen($calculableCharacters) - 1 > self::MAX_GS1128_CHARS) { + throw new BCGParseException('gs1128', 'The barcode can\'t contain more than ' . self::MAX_GS1128_CHARS . ' characters.'); + } + } + + $this->label = $formatedLabel; + return $formatedText; + } + + /** + * Parses the text to gs1-128. + * + * @param mixed $text + * @return mixed + */ + private function parseGs1128($text) + { + /* We format correctly what the user gives */ + if (is_array($text)) { + $formatArray = array(); + foreach ($text as $content) { + if (is_array($content)) { /* double array */ + if (count($content) === 2) { + if (is_array($content[self::ID]) || is_array($content[self::CONTENT])) { + throw new BCGParseException('gs1128', 'Double arrays can\'t contain arrays.'); + } else { + $formatArray[] = '(' . $content[self::ID] . ')' . $content[self::CONTENT]; + } + } else { + throw new BCGParseException('gs1128', 'Double arrays must contain 2 values.'); + } + } else { /* simple array */ + $formatArray[] = $content; + } + } + + unset($text); + $text = $formatArray; + } else { /* string */ + $text = array($text); + } + + $textCount = count($text); + for ($cmpt = 0; $cmpt < $textCount; $cmpt++) { + /* We parse the content of the array */ + if (!$this->parseContent($text[$cmpt])) { + return; + } + } + + return $this->formatGs1128(); + } + + /** + * Splits the id and the content for each application identifiers (AIs). + * + * @param string $text + * @param int $cmpt + * @return bool + */ + private function parseContent($text) + { + /* $yAlreadySet has 3 states: */ + /* null: There is no variable in the ID; true: the variable is already set; false: the variable is not set yet; */ + $content = null; + $yAlreadySet = null; + $realNameId = null; + $separatorsFound = 0; + $checksumAdded = 0; + $decimalPointRemoved = 0; + $toParse = str_replace('~F1', chr(29), $text); + $nbCharToParse = strlen($toParse); + $nbCharId = 0; + $isFormated = $toParse[0] === '(' ? true : false; + $maxCharId = $isFormated ? self::MAX_ID_FORMATED : self::MAX_ID_NOT_FORMATED; + $id = strtolower(substr($toParse, 0, min($maxCharId, $nbCharToParse))); + $id = $isFormated ? $this->findIdFormated($id, $yAlreadySet, $realNameId) : $this->findIdNotFormated($id, $yAlreadySet, $realNameId); + + if ($id === false) { + if ($this->allowsUnknownIdentifier === false) { + return false; + } + + $id = null; + $nbCharId = 0; + $content = $toParse; + } else { + $nbCharId = strlen($id) + ($isFormated ? 2 : 0); + $n = min($this->identifiersAi[$realNameId][self::MAXLENGTH], $nbCharToParse); + $content = substr($toParse, $nbCharId, $n); + } + + if ($id !== null) { + /* If we have an AI with an "y" var, we check if there is a decimal point in the next *MAXLENGTH* characters */ + /* if there is one, we take an extra character */ + if ($yAlreadySet !== null) { + if (strpos($content, '.') !== false || strpos($content, ',') !== false) { + $n++; + if ($n <= $nbCharToParse) { + /* We take an extra char */ + $content = substr($toParse, $nbCharId, $n); + } + } + } + } + + /* We check for separator */ + $separator = strpos($content, chr(29)); + if ($separator !== false) { + $content = substr($content, 0, $separator); + $separatorsFound++; + } + + if ($id !== null) { + /* We check the conformity */ + if (!$this->checkConformity($content, $id, $realNameId)) { + return false; + } + + /* We check the checksum */ + if (!$this->checkChecksum($content, $id, $realNameId, $checksumAdded)) { + return false; + } + + /* We check the vars */ + if (!$this->checkVars($content, $id, $yAlreadySet, $decimalPointRemoved)) { + return false; + } + } + + $this->identifiersId[] = $id; + $this->identifiersContent[] = $content; + + $nbCharLastContent = (((strlen($content) + $nbCharId) - $checksumAdded) + $decimalPointRemoved) + $separatorsFound; + if ($nbCharToParse - $nbCharLastContent > 0) { + /* If there is more than one content in this array, we parse again */ + $otherContent = substr($toParse, $nbCharLastContent, $nbCharToParse); + $nbCharOtherContent = strlen($otherContent); + + if ($otherContent[0] === chr(29)) { + $otherContent = substr($otherContent, 1); + $nbCharOtherContent--; + } + + if ($nbCharOtherContent > 0) { + $text = $otherContent; + return $this->parseContent($text); + } + } + + return true; + } + + /** + * Checks if an id exists. + * + * @param string $id + * @param bool $yAlreadySet + * @param string $realNameId + * @return bool + */ + private function idExists($id, &$yAlreadySet, &$realNameId) + { + $yFound = isset($id[3]) && $id[3] === 'y'; + $idVarAdded = substr($id, 0, -1) . 'y'; + + if (isset($this->identifiersAi[$id])) { + if ($yFound) { + $yAlreadySet = false; + } + + $realNameId = $id; + return true; + } elseif (!$yFound && isset($this->identifiersAi[$idVarAdded])) { + /* if the id don't exist, we try to find this id with "y" at the last char */ + $yAlreadySet = true; + $realNameId = $idVarAdded; + return true; + } + + return false; + } + + /** + * Finds ID with formated content. + * + * @param string $id + * @param bool $yAlreadySet + * @param string $realNameId + * @return mixed + */ + private function findIdFormated($id, &$yAlreadySet, &$realNameId) + { + $pos = strpos($id, ')'); + if ($pos === false) { + throw new BCGParseException('gs1128', 'Identifiers must have no more than 4 characters.'); + } else { + if ($pos < 3) { + throw new BCGParseException('gs1128', 'Identifiers must have at least 2 characters.'); + } + + $id = substr($id, 1, $pos - 1); + if ($this->idExists($id, $yAlreadySet, $realNameId)) { + return $id; + } + + if ($this->allowsUnknownIdentifier === false) { + throw new BCGParseException('gs1128', 'The identifier ' . $id . ' doesn\'t exist.'); + } + + return false; + } + } + + /** + * Finds ID with non-formated content. + * + * @param string $id + * @param bool $yAlreadySet + * @param string $realNameId + * @return mixed + */ + private function findIdNotFormated($id, &$yAlreadySet, &$realNameId) + { + $tofind = $id; + + while (strlen($tofind) >= 2) { + if ($this->idExists($tofind, $yAlreadySet, $realNameId)) { + return $tofind; + } else { + $tofind = substr($tofind, 0, -1); + } + } + + if ($this->allowsUnknownIdentifier === false) { + throw new BCGParseException('gs1128', 'Error in formatting, can\'t find an identifier.'); + } + + return false; + } + + /** + * Checks confirmity of the content. + * + * @param string $content + * @param string $id + * @param string $realNameId + * @return bool + */ + private function checkConformity(&$content, $id, $realNameId) + { + switch ($this->identifiersAi[$realNameId][self::KIND_OF_DATA]) { + case self::NUMERIC: + $content = str_replace(',', '.', $content); + if (!preg_match("/^[0-9.]+$/", $content)) { + throw new BCGParseException('gs1128', 'The value of "' . $id . '" must be numerical.'); + } + + break; + case self::DATE_YYMMDD: + $valid_date = true; + if (preg_match("/^[0-9]{6}$/", $content)) { + $year = substr($content, 0, 2); + $month = substr($content, 2, 2); + $day = substr($content, 4, 2); + + /* day can be 00 if we only need month and year */ + if (intval($month) < 1 || intval($month) > 12 || intval($day) < 0 || intval($day) > 31) { + $valid_date = false; + } + } else { + $valid_date = false; + } + + if (!$valid_date) { + throw new BCGParseException('gs1128', 'The value of "' . $id . '" must be in YYMMDD format.'); + } + + break; + } + + // We check the length of the content + $nbCharContent = strlen($content); + $checksumChar = 0; + $minlengthContent = $this->identifiersAi[$realNameId][self::MINLENGTH]; + $maxlengthContent = $this->identifiersAi[$realNameId][self::MAXLENGTH]; + + if ($this->identifiersAi[$realNameId][self::CHECKSUM]) { + $checksumChar++; + } + + if ($nbCharContent < ($minlengthContent - $checksumChar)) { + if ($minlengthContent === $maxlengthContent) { + throw new BCGParseException('gs1128', 'The value of "' . $id . '" must contain ' . $minlengthContent . ' character(s).'); + } else { + throw new BCGParseException('gs1128', 'The value of "' . $id . '" must contain between ' . $minlengthContent . ' and ' . $maxlengthContent . ' character(s).'); + } + } + + return true; + } + + /** + * Verifies the checksum. + * + * @param string $content + * @param string $id + * @param int $realNameId + * @param int $checksumAdded + * @return bool + */ + private function checkChecksum(&$content, $id, $realNameId, &$checksumAdded) + { + if ($this->identifiersAi[$realNameId][self::CHECKSUM]) { + $nbCharContent = strlen($content); + $minlengthContent = $this->identifiersAi[$realNameId][self::MINLENGTH]; + if ($nbCharContent === ($minlengthContent - 1)) { + /* we need to calculate the checksum */ + $content .= self::getAiContentChecksum($content); + $checksumAdded++; + } elseif ($nbCharContent === $minlengthContent) { + /* we need to check the checksum */ + $checksum = self::getAiContentChecksum(substr($content, 0, -1)); + if (intval($content[$nbCharContent - 1]) !== $checksum) { + throw new BCGParseException('gs1128', 'The checksum of "(' . $id . ') ' . $content . '" must be: ' . $checksum); + } + } + } + + return true; + } + + /** + * Checks vars "y". + * + * @param string $content + * @param string $id + * @param bool $yAlreadySet + * @param int $decimalPointRemoved + * @return bool + */ + private function checkVars(&$content, &$id, $yAlreadySet, &$decimalPointRemoved) + { + $nbCharContent = strlen($content); + /* We check for "y" var in AI */ + if ($yAlreadySet) { + /* We'll check if we have a decimal point */ + if (strpos($content, '.') !== false) { + throw new BCGParseException('gs1128', 'If you do not use any "y" variable, you have to insert a whole number.'); + } + } elseif ($yAlreadySet !== null) { + /* We need to replace the "y" var with the position of the decimal point */ + $pos = strpos($content, '.'); + if ($pos === false) { + $pos = $nbCharContent - 1; + } + + $id = str_replace('y', $nbCharContent - ($pos + 1), strtolower($id)); + $content = str_replace('.', '', $content); + $decimalPointRemoved++; + } + + return true; + } + + /** + * Checksum Mod10. + * + * @param int $content + * @return int + */ + private static function calculateChecksumMod10($content) + { + // Calculating Checksum + // Consider the right-most digit of the message to be in an "odd" position, + // and assign odd/even to each character moving from right to left + // Odd Position = 3, Even Position = 1 + // Multiply it by the number + // Add all of that and do 10-(?mod10) + $odd = true; + $checksumValue = 0; + $c = strlen($content); + + for ($i = $c; $i > 0; $i--) { + if ($odd === true) { + $multiplier = 3; + $odd = false; + } else { + $multiplier = 1; + $odd = true; + } + + $checksumValue += ($content[$i - 1] * $multiplier); + } + + return (10 - $checksumValue % 10) % 10; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGi25.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGi25.php new file mode 100644 index 0000000..b6cd191 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGi25.php @@ -0,0 +1,216 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + $this->code = array( + '00110', /* 0 */ + '10001', /* 1 */ + '01001', /* 2 */ + '11000', /* 3 */ + '00101', /* 4 */ + '10100', /* 5 */ + '01100', /* 6 */ + '00011', /* 7 */ + '10010', /* 8 */ + '01010' /* 9 */ + ); + + $this->setChecksum(false); + $this->setRatio(2); + } + + /** + * Sets the checksum. + * + * @param bool $checksum + */ + public function setChecksum($checksum) + { + $this->checksum = (bool)$checksum; + } + + /** + * Sets the ratio of the black bar compared to the white bars. + * + * @param int $ratio + */ + public function setRatio($ratio) + { + $this->ratio = $ratio; + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + $temp_text = $this->text; + + // Checksum + if ($this->checksum === true) { + $this->calculateChecksum(); + $temp_text .= $this->keys[$this->checksumValue]; + } + + // Starting Code + $this->drawChar($im, '0000', true); + + // Chars + $c = strlen($temp_text); + for ($i = 0; $i < $c; $i += 2) { + $temp_bar = ''; + $c2 = strlen($this->findCode($temp_text[$i])); + for ($j = 0; $j < $c2; $j++) { + $temp_bar .= substr($this->findCode($temp_text[$i]), $j, 1); + $temp_bar .= substr($this->findCode($temp_text[$i + 1]), $j, 1); + } + + $this->drawChar($im, $this->changeBars($temp_bar), true); + } + + // Ending Code + $this->drawChar($im, $this->changeBars('100'), true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $textlength = (3 + ($this->ratio + 1) * 2) * strlen($this->text); + $startlength = 4; + $checksumlength = 0; + if ($this->checksum === true) { + $checksumlength = (3 + ($this->ratio + 1) * 2); + } + + $endlength = 2 + ($this->ratio + 1); + + $w += $startlength + $textlength + $checksumlength + $endlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('i25', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('i25', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + // Must be even + if ($c % 2 !== 0 && $this->checksum === false) { + throw new BCGParseException('i25', 'i25 must contain an even amount of digits if checksum is false.'); + } elseif ($c % 2 === 0 && $this->checksum === true) { + throw new BCGParseException('i25', 'i25 must contain an odd amount of digits if checksum is true.'); + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Calculating Checksum + // Consider the right-most digit of the message to be in an "even" position, + // and assign odd/even to each character moving from right to left + // Even Position = 3, Odd Position = 1 + // Multiply it by the number + // Add all of that and do 10-(?mod10) + $even = true; + $this->checksumValue = 0; + $c = strlen($this->text); + for ($i = $c; $i > 0; $i--) { + if ($even === true) { + $multiplier = 3; + $even = false; + } else { + $multiplier = 1; + $even = true; + } + + $this->checksumValue += $this->keys[$this->text[$i - 1]] * $multiplier; + } + + $this->checksumValue = (10 - $this->checksumValue % 10) % 10; + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + return $this->keys[$this->checksumValue]; + } + + return false; + } + + /** + * Changes the size of the bars based on the ratio + * + * @param string $in + * @return string + */ + private function changeBars($in) + { + if ($this->ratio > 1) { + $c = strlen($in); + for ($i = 0; $i < $c; $i++) { + $in[$i] = $in[$i] === '1' ? $this->ratio : $in[$i]; + } + } + + return $in; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGintelligentmail.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGintelligentmail.php new file mode 100644 index 0000000..7969c7f --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGintelligentmail.php @@ -0,0 +1,674 @@ +setQuietZone(true); + $this->setThickness(9); + } + + /** + * Gets the Quiet zone. + * + * @return bool + */ + public function getQuietZone() + { + return $this->quietZone; + } + + /** + * Sets the Quiet zone. + * + * @param bool $quietZone + */ + public function setQuietZone($quietZone) + { + $this->quietZone = (bool)$quietZone; + } + + /** + * Sets the tracking code. + * + * @param int $barcodeIdentifier 2-digit number. 2nd digit must be 0-4 + * @param int $serviceTypeIdentifier 3 digits + * @param int $mailerIdentifier 6 or 9 digits + * @param int $serialNumber 9 (if mailerId is 6) or 6 digits (if mailerId is 9) + */ + public function setTrackingCode($barcodeIdentifier, $serviceTypeIdentifier, $mailerIdentifier, $serialNumber) + { + $barcodeIdentifier = (string)(int)$barcodeIdentifier; + $serviceTypeIdentifier = (string)(int)$serviceTypeIdentifier; + $mailerIdentifier = (string)(int)$mailerIdentifier; + $serialNumber = (string)(int)$serialNumber; + + $barcodeIdentifier = str_pad($barcodeIdentifier, 2, '0', STR_PAD_LEFT); + + if (strlen($barcodeIdentifier) !== 2) { + throw new BCGArgumentException('Barcode Identifier must contain 2 digits.', 'barcodeIdentifier'); + } + + $barcodeIdentifierSecondNumber = $barcodeIdentifier[1]; + if ($barcodeIdentifierSecondNumber !== '0' && $barcodeIdentifierSecondNumber !== '1' && $barcodeIdentifierSecondNumber !== '2' && $barcodeIdentifierSecondNumber !== '3' && $barcodeIdentifierSecondNumber !== '4') { + throw new BCGArgumentException('Barcode Identifier second digit must be a number between 0 and 4.', 'barcodeIdentifier'); + } + + if ($serviceTypeIdentifier < 0 || $serviceTypeIdentifier > 999) { + throw new BCGArgumentException('Service Type Identifier must be between 0 and 999.', 'serviceTypeIdentifier'); + } + + $mailerIdentifierLength = 6; + if ($mailerIdentifier > 899999) { + $mailerIdentifierLength = 9; + } + + if ($mailerIdentifierLength === 9 && strlen($serialNumber) > 6) { + throw new BCGArgumentException('If the Serial Number has more than 6 digits, the Mailer Identifier must be lower than 900000.', 'mailerIdentifier'); + } + + if ($mailerIdentifierLength === 9) { + if ($mailerIdentifierLength < 0 || $mailerIdentifier > 999999999) { + throw new BCGArgumentException('Mailer Identifier must be between 0 and 999999999.', 'mailerIdentifier'); + } + } + + $this->barcodeIdentifier = $barcodeIdentifier; + $this->serviceTypeIdentifier = str_pad($serviceTypeIdentifier, 3, '0', STR_PAD_LEFT); + $this->mailerIdentifier = str_pad($mailerIdentifier, $mailerIdentifierLength, '0', STR_PAD_LEFT); + $this->serialNumber = str_pad($serialNumber, $mailerIdentifierLength === 6 ? 9 : 6, '0', STR_PAD_LEFT); + } + + /** + * Parses the text before displaying it. + * + * @param mixed $text + */ + public function parse($text) + { + parent::parse($text); + + $number = self::executeStep1($this->text, $this->barcodeIdentifier, $this->serviceTypeIdentifier, $this->mailerIdentifier, $this->serialNumber); + $crc = self::executeStep2($number); + $codewords = self::executeStep3($number); + $codewords = self::executeStep4($codewords, $crc); + $characters = self::executeStep5($codewords, $crc); + $this->data = self::executeStep6($characters); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + if ($this->quietZone) { + $this->positionX += 9; + } + + $c = strlen($this->data); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->data[$i]); + } + + $this->drawText($im, 0, 0, $this->positionX, $this->thickness + ($this->quietZone ? 4 : 0)); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $w += 65 * 3; + $h += $this->thickness; + + // We remove the white on the right + $w -= 1.56; + + if ($this->quietZone) { + $w += 18; + $h += 4; + } + + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + // Tracking must have been entered + if ($this->barcodeIdentifier === null || $this->serviceTypeIdentifier === null || $this->mailerIdentifier === null || $this->serialNumber === null) { + throw new BCGParseException('intelligentmail', 'The tracking code must be set before calling the parse method.'); + } + + // Checking if all chars are allowed + $match = array(); + if (preg_match('/[^0-9]/', $this->text, $match)) { + throw new BCGParseException('intelligentmail', 'The character \'' . $match[0] . '\' is not allowed.'); + } + + // Must contain 0, 5, 9 or 11 chars + $c = strlen($this->text); + if ($c !== 0 && $c !== 5 && $c !== 9 && $c !== 11) { + throw new BCGParseException('intelligentmail', 'Must contain 0, 5, 9, or 11 characters.'); + } + + parent::validate(); + } + + /** + * Overloaded method for drawing special barcode. + * + * @param resource $im + * @param string $code + * @param boolean $startBar + */ + protected function drawChar($im, $code, $startBar = true) + { + $y1 = 0; + $y2 = 0; + switch ($code) { + case 'A': + $y1 = 0; + $y2 = $this->thickness - ($this->thickness / 2.5); + break; + case 'D': + $y1 = 3.096; + $y2 = $this->thickness - 1; + break; + case 'F': + $y1 = 0; + $y2 = $this->thickness - 1; + break; + case 'T': + $y1 = 3.096; + $y2 = $this->thickness - ($this->thickness / 2.5); + break; + } + + if ($this->quietZone) { + $y1 += 2; + $y2 += 2; + } + + $this->drawFilledRectangle($im, $this->positionX, intval($y1), intval($this->positionX + 0.44), intval($y2), BCGBarcode::COLOR_FG); + $this->positionX += 3; + } + + /** + * Executes Step 1: Conversion of Data Fields into Binary Data + * + * @param string $text + * @param string $barcodeIdentifier + * @param string $serviceTypeIdentifier + * @param string $mailerIdentifier + * @param string $serialNumber + * @return string BCNumber + */ + private static function executeStep1($text, $barcodeIdentifier, $serviceTypeIdentifier, $mailerIdentifier, $serialNumber) + { + $number = self::conversionRoutingCode($text); + $number = self::conversionTrackingCode($number, $barcodeIdentifier, $serviceTypeIdentifier, $mailerIdentifier, $serialNumber); + + return $number; + } + + /** + * Executes Step 2: Generation of 11-Bit CRC on Binary Data + * + * @param $number BCNumber + * @return int + */ + private static function executeStep2($number) + { + $byteArray = str_pad(self::bcdecuc($number), 13, chr(0), STR_PAD_LEFT); + + $generatorPolynomial = 0x0f35; + $frameCheckSequence = 0x07ff; + $data = 0; + $byteIndex = 0; + $bit = 0; + + $data = (ord($byteArray[$byteIndex]) << 5) & 0xffff; + for ($bit = 2; $bit < 8; $bit++) { + if (($frameCheckSequence ^ $data) & 0x400) { + $frameCheckSequence = ($frameCheckSequence << 1) ^ $generatorPolynomial; + } else { + $frameCheckSequence = ($frameCheckSequence << 1); + } + + $frameCheckSequence &= 0x7ff; + $data <<= 1; + $data &= 0xffff; + } + + for ($byteIndex = 1; $byteIndex < 13; $byteIndex++) { + $data = (ord($byteArray[$byteIndex]) << 3) & 0xffff; + for ($bit = 0; $bit < 8; $bit++) { + if (($frameCheckSequence ^ $data) & 0x0400) { + $frameCheckSequence = ($frameCheckSequence << 1) ^ $generatorPolynomial; + } else { + $frameCheckSequence = ($frameCheckSequence << 1); + } + + $frameCheckSequence &= 0x7ff; + $data <<= 1; + $data &= 0xffff; + } + } + + return $frameCheckSequence; + } + + /** + * Executes Step 3: Conversion from Binary Data to Codewords + * + * @param string $number BCNumber + * @return int[] + */ + private static function executeStep3($number) + { + $codewords = array(); + $codewords[9] = (int)bcmod($number, '636'); + $number = bcdiv($number, '636', 0); + + for ($i = 8; $i >= 0; $i--) { + $codewords[$i] = (int)bcmod($number, '1365'); + $number = bcdiv($number, '1365', 0); + } + + return $codewords; + } + + /** + * Executes Step 4: Inserting Additional Information into Codewords + * + * @param int[] $codewords + * @param int $crc + * @return int[] + */ + private static function executeStep4($codewords, $crc) + { + $codewords[9] *= 2; + if ($crc & 0x400) { + $codewords[0] += 659; + } + + return $codewords; + } + + /** + * Executes Step 5: Conversion from Codewords to Characters + * + * @param int[] $codewords + * @param int $crc + * @return int[] + */ + private static function executeStep5($codewords, $crc) + { + $characters = array(); + for ($i = 0; $i < 10; $i++) { + if ($codewords[$i] <= 1286) { + $characters[$i] = self::$characterTable1[$codewords[$i]]; + } else { + $characters[$i] = self::$characterTable2[$codewords[$i] - 1287]; + } + } + + for ($i = 0; $i < 10; $i++) { + $mask = 1 << $i; + if ($crc & $mask) { + $characters[$i] ^= 0x1fff; + } + } + + return $characters; + } + + /** + * Executes Step 6: Conversion from Characters to the Intelligent Mail Barcode + * + * @param int[] $characters + * @return string + */ + private static function executeStep6($characters) + { + $bars = ''; + for ($i = 0; $i < 65; $i++) { + $barPosition = self::$barPositions[$i]; + $descender = $barPosition[0]; + $ascender = $barPosition[1]; + $extenderDescender = !!($characters[$descender[0]] & (1 << $descender[1])); + $extenderAscender = !!($characters[$ascender[0]] & (1 << $ascender[1])); + + if ($extenderDescender && $extenderAscender) { + $bars .= 'F'; + } elseif ($extenderDescender) { + $bars .= 'D'; + } elseif ($extenderAscender) { + $bars .= 'A'; + } else { + $bars .= 'T'; + } + } + + return $bars; + } + + /** + * Converts the routing code zipcode. + * + * @param string $zipcode + * @return string BCNumber + */ + private static function conversionRoutingCode($zipcode) + { + $number = $zipcode; + switch (strlen($zipcode)) { + case 11: + $number = bcadd($number, '1000000000', 0); + // no break + case 9: + $number = bcadd($number, '100000', 0); + // no break + case 5: + $number = bcadd($number, '1', 0); + // no break + default: + return $number; + } + } + + /** + * Converts the tracking code number. + * + * @param string $number BCNumber + * @param string $barcodeIdentifier + * @param string $serviceTypeIdentifier + * @param string $mailerIdentifier + * @param string $serialNumber + * @return string BCNumber + */ + private static function conversionTrackingCode($number, $barcodeIdentifier, $serviceTypeIdentifier, $mailerIdentifier, $serialNumber) + { + $number = bcmul($number, '10', 0); + $number = bcadd($number, $barcodeIdentifier[0], 0); + $number = bcmul($number, '5', 0); + $number = bcadd($number, $barcodeIdentifier[1], 0); + + $temp = $serviceTypeIdentifier . $mailerIdentifier . $serialNumber; + for ($i = 0; $i < 18; $i++) { + $number = bcmul($number, '10', 0); + $number = bcadd($number, $temp[$i], 0); + } + + return $number; + } + + /** + * Transforms a BCNumber into unsigned char*. + * + * @param string $dec BCNumber + * @param string + */ + private static function bcdecuc($dec) + { + $last = bcmod($dec, '256'); + $remain = bcdiv(bcsub($dec, $last), '256', 0); + + if ($remain == 0) { + return pack('C', $last); + } else { + return self::bcdecuc($remain) . pack('C', $last); + } + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGisbn.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGisbn.php new file mode 100644 index 0000000..7beac0c --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGisbn.php @@ -0,0 +1,175 @@ +setGS1($gs1); + } + + /** + * Adds the default label. + */ + protected function addDefaultLabel() + { + if ($this->isDefaultEanLabelEnabled()) { + $isbn = $this->createISBNText(); + $font = $this->font; + + $topLabel = new BCGLabel($isbn, $font, BCGLabel::POSITION_TOP, BCGLabel::ALIGN_CENTER); + + $this->addLabel($topLabel); + } + + parent::addDefaultLabel(); + } + + /** + * Sets the first numbers of the barcode. + * - GS1_AUTO: Adds 978 before the code + * - GS1_PREFIX978: Adds 978 before the code + * - GS1_PREFIX979: Adds 979 before the code + * + * @param int $gs1 + */ + public function setGS1($gs1) + { + $gs1 = (int)$gs1; + if ($gs1 !== self::GS1_AUTO && $gs1 !== self::GS1_PREFIX978 && $gs1 !== self::GS1_PREFIX979) { + throw new BCGArgumentException('The GS1 argument must be BCGisbn::GS1_AUTO, BCGisbn::GS1_PREFIX978, or BCGisbn::GS1_PREFIX979', 'gs1'); + } + + $this->gs1 = $gs1; + } + + /** + * Check chars allowed. + */ + protected function checkCharsAllowed() + { + $c = strlen($this->text); + + // Special case, if we have 10 digits, the last one can be X + if ($c === 10) { + if (array_search($this->text[9], $this->keys) === false && $this->text[9] !== 'X') { + throw new BCGParseException('isbn', 'The character \'' . $this->text[9] . '\' is not allowed.'); + } + + // Drop the last char + $this->text = substr($this->text, 0, 9); + } + + return parent::checkCharsAllowed(); + } + + /** + * Check correct length. + */ + protected function checkCorrectLength() + { + $c = strlen($this->text); + + // If we have 13 chars just flush the last one + if ($c === 13) { + $this->text = substr($this->text, 0, 12); + } elseif ($c === 9 || $c === 10) { + if ($c === 10) { + // Before dropping it, we check if it's legal + if (array_search($this->text[9], $this->keys) === false && $this->text[9] !== 'X') { + throw new BCGParseException('isbn', 'The character \'' . $this->text[9] . '\' is not allowed.'); + } + + $this->text = substr($this->text, 0, 9); + } + + if ($this->gs1 === self::GS1_AUTO || $this->gs1 === self::GS1_PREFIX978) { + $this->text = '978' . $this->text; + } elseif ($this->gs1 === self::GS1_PREFIX979) { + $this->text = '979' . $this->text; + } + } elseif ($c !== 12) { + throw new BCGParseException('isbn', 'The code parsed must be 9, 10, 12, or 13 digits long.'); + } + } + + /** + * Creates the ISBN text. + * + * @return string + */ + private function createISBNText() + { + $isbn = ''; + if (!empty($this->text)) { + // We try to create the ISBN Text... the hyphen really depends the ISBN agency. + // We just put one before the checksum and one after the GS1 if present. + $c = strlen($this->text); + if ($c === 12 || $c === 13) { + // If we have 13 characters now, just transform it temporarily to find the checksum... + // Further in the code we take care of that anyway. + $lastCharacter = ''; + if ($c === 13) { + $lastCharacter = $this->text[12]; + $this->text = substr($this->text, 0, 12); + } + + $checksum = $this->processChecksum(); + $isbn = 'ISBN ' . substr($this->text, 0, 3) . '-' . substr($this->text, 3, 9) . '-' . $checksum; + + // Put the last character back + if ($c === 13) { + $this->text .= $lastCharacter; + } + } elseif ($c === 9 || $c === 10) { + $checksum = 0; + for ($i = 10; $i >= 2; $i--) { + $checksum += $this->text[10 - $i] * $i; + } + + $checksum = 11 - $checksum % 11; + if ($checksum === 10) { + $checksum = 'X'; // Changing type + } + + $isbn = 'ISBN ' . substr($this->text, 0, 9) . '-' . $checksum; + } + } + + return $isbn; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGmsi.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGmsi.php new file mode 100644 index 0000000..c2f02fb --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGmsi.php @@ -0,0 +1,195 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + $this->code = array( + '01010101', /* 0 */ + '01010110', /* 1 */ + '01011001', /* 2 */ + '01011010', /* 3 */ + '01100101', /* 4 */ + '01100110', /* 5 */ + '01101001', /* 6 */ + '01101010', /* 7 */ + '10010101', /* 8 */ + '10010110' /* 9 */ + ); + + $this->setChecksum(0); + } + + /** + * Sets how many checksums we display. 0 to 2. + * + * @param int $checksum + */ + public function setChecksum($checksum) + { + $checksum = intval($checksum); + if ($checksum < 0 && $checksum > 2) { + throw new BCGArgumentException('The checksum must be between 0 and 2 included.', 'checksum'); + } + + $this->checksum = $checksum; + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + // Checksum + $this->calculateChecksum(); + + // Starting Code + $this->drawChar($im, '10', true); + + // Chars + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->findCode($this->text[$i]), true); + } + + $c = count($this->checksumValue); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->findCode($this->checksumValue[$i]), true); + } + + // Ending Code + $this->drawChar($im, '010', true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $textlength = 12 * strlen($this->text); + $startlength = 3; + $checksumlength = $this->checksum * 12; + $endlength = 4; + + $w += $startlength + $textlength + $checksumlength + $endlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('msi', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('msi', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Forming a new number + // If the original number is even, we take all even position + // If the original number is odd, we take all odd position + // 123456 = 246 + // 12345 = 135 + // Multiply by 2 + // Add up all the digit in the result (270 : 2+7+0) + // Add up other digit not used. + // 10 - (? Modulo 10). If result = 10, change to 0 + $last_text = $this->text; + $this->checksumValue = array(); + for ($i = 0; $i < $this->checksum; $i++) { + $new_text = ''; + $new_number = 0; + $c = strlen($last_text); + if ($c % 2 === 0) { // Even + $starting = 1; + } else { + $starting = 0; + } + + for ($j = $starting; $j < $c; $j += 2) { + $new_text .= $last_text[$j]; + } + + $new_text = strval(intval($new_text) * 2); + $c2 = strlen($new_text); + for ($j = 0; $j < $c2; $j++) { + $new_number += intval($new_text[$j]); + } + + for ($j = ($starting === 0) ? 1 : 0; $j < $c; $j += 2) { + $new_number += intval($last_text[$j]); + } + + $new_number = (10 - $new_number % 10) % 10; + $this->checksumValue[] = $new_number; + $last_text .= $new_number; + } + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + $ret = ''; + $c = count($this->checksumValue); + for ($i = 0; $i < $c; $i++) { + $ret .= $this->keys[$this->checksumValue[$i]]; + } + + return $ret; + } + + return false; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGothercode.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGothercode.php new file mode 100644 index 0000000..5e0fc98 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGothercode.php @@ -0,0 +1,97 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + $this->drawChar($im, $this->text, true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Gets the label. + * If the label was set to BCGBarcode1D::AUTO_LABEL, the label will display the value from the text parsed. + * + * @return string + */ + public function getLabel() + { + $label = $this->label; + if ($this->label === BCGBarcode1D::AUTO_LABEL) { + $label = ''; + } + + return $label; + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $array = str_split($this->text, 1); + $textlength = array_sum($array) + count($array); + + $w += $textlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('othercode', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('othercode', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + parent::validate(); + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGpostnet.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGpostnet.php new file mode 100644 index 0000000..8b7d628 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGpostnet.php @@ -0,0 +1,148 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + $this->code = array( + '11000', /* 0 */ + '00011', /* 1 */ + '00101', /* 2 */ + '00110', /* 3 */ + '01001', /* 4 */ + '01010', /* 5 */ + '01100', /* 6 */ + '10001', /* 7 */ + '10010', /* 8 */ + '10100' /* 9 */ + ); + + $this->setThickness(9); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + // Checksum + $checksum = 0; + $c = strlen($this->text); + for ($i = 0; $i < $c; $i++) { + $checksum += intval($this->text[$i]); + } + + $checksum = 10 - ($checksum % 10); + + // Starting Code + $this->drawChar($im, '1'); + + // Code + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->findCode($this->text[$i])); + } + + // Checksum + $this->drawChar($im, $this->findCode($checksum)); + + // Ending Code + $this->drawChar($im, '1'); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $c = strlen($this->text); + $startlength = 3; + $textlength = $c * 5 * 3; + $checksumlength = 5 * 3; + $endlength = 3; + + // We remove the white on the right + $removelength = -1.56; + + $w += $startlength + $textlength + $checksumlength + $endlength + $removelength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('postnet', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('postnet', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + // Must contain 5, 9 or 11 chars + if ($c !== 5 && $c !== 9 && $c !== 11) { + throw new BCGParseException('postnet', 'Must contain 5, 9, or 11 characters.'); + } + + parent::validate(); + } + + /** + * Overloaded method for drawing special barcode. + * + * @param resource $im + * @param string $code + * @param boolean $startBar + */ + protected function drawChar($im, $code, $startBar = true) + { + $c = strlen($code); + for ($i = 0; $i < $c; $i++) { + if ($code[$i] === '0') { + $posY = $this->thickness - ($this->thickness / 2.5); + } else { + $posY = 0; + } + + $this->drawFilledRectangle($im, intval($this->positionX), intval($posY), intval($this->positionX + 0.44), $this->thickness - 1, BCGBarcode::COLOR_FG); + $this->positionX += 3; + } + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGs25.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGs25.php new file mode 100644 index 0000000..f08bf37 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGs25.php @@ -0,0 +1,181 @@ + 1/3 or 1/2 for the big bar + * + *-------------------------------------------------------------------- + * Copyright (C) Jean-Sebastien Goupil + * http://www.barcodebakery.com + */ +namespace BarcodeBakery\Barcode; + +use BarcodeBakery\Common\BCGBarcode1D; +use BarcodeBakery\Common\BCGParseException; + +class BCGs25 extends BCGBarcode1D +{ + private $checksum; + + /** + * Constructor. + */ + public function __construct() + { + parent::__construct(); + + $this->keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + $this->code = array( + '0000202000', /* 0 */ + '2000000020', /* 1 */ + '0020000020', /* 2 */ + '2020000000', /* 3 */ + '0000200020', /* 4 */ + '2000200000', /* 5 */ + '0020200000', /* 6 */ + '0000002020', /* 7 */ + '2000002000', /* 8 */ + '0020002000' /* 9 */ + ); + + $this->setChecksum(false); + } + + /** + * Sets if we display the checksum. + * + * @param bool $checksum + */ + public function setChecksum($checksum) + { + $this->checksum = (bool)$checksum; + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + $temp_text = $this->text; + + // Checksum + if ($this->checksum === true) { + $this->calculateChecksum(); + $temp_text .= $this->keys[$this->checksumValue]; + } + + // Starting Code + $this->drawChar($im, '101000', true); + + // Chars + $c = strlen($temp_text); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, $this->findCode($temp_text[$i]), true); + } + + // Ending Code + $this->drawChar($im, '10001', true); + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $c = strlen($this->text); + $startlength = 8; + $textlength = $c * 14; + $checksumlength = 0; + if ($c % 2 !== 0) { + $checksumlength = 14; + } + + $endlength = 7; + + $w += $startlength + $textlength + $checksumlength + $endlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('s25', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('s25', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + // Must be even + if ($c % 2 !== 0 && $this->checksum === false) { + throw new BCGParseException('s25', 's25 must contain an even amount of digits if checksum is false.'); + } elseif ($c % 2 === 0 && $this->checksum === true) { + throw new BCGParseException('s25', 's25 must contain an odd amount of digits if checksum is true.'); + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Calculating Checksum + // Consider the right-most digit of the message to be in an "even" position, + // and assign odd/even to each character moving from right to left + // Even Position = 3, Odd Position = 1 + // Multiply it by the number + // Add all of that and do 10-(?mod10) + $even = true; + $this->checksumValue = 0; + $c = strlen($this->text); + for ($i = $c; $i > 0; $i--) { + if ($even === true) { + $multiplier = 3; + $even = false; + } else { + $multiplier = 1; + $even = true; + } + + $this->checksumValue += $this->keys[$this->text[$i - 1]] * $multiplier; + } + $this->checksumValue = (10 - $this->checksumValue % 10) % 10; + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + return $this->keys[$this->checksumValue]; + } + + return false; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGupca.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGupca.php new file mode 100644 index 0000000..f8b2115 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGupca.php @@ -0,0 +1,155 @@ +text = '0' . $this->text; // We will remove it at the end... don't worry + + parent::draw($im); + + // We remove the 0 in front, as we said :) + $this->text = substr($this->text, 1); + } + + /** + * Draws the extended bars on the image. + * + * @param resource $im + * @param int $plus + */ + protected function drawExtendedBars($im, $plus) + { + $temp_text = $this->text . $this->keys[$this->checksumValue]; + $rememberX = $this->positionX; + $rememberH = $this->thickness; + + // We increase the bars + // First 2 Bars + $this->thickness = $this->thickness + intval($plus / $this->scale); + $this->positionX = 0; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + // Attemping to increase the 2 following bars + $this->positionX += 1; + $temp_value = $this->findCode($temp_text[1]); + $this->drawChar($im, $temp_value, false); + + // Center Guard Bar + $this->positionX += 36; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + // Attemping to increase the 2 last bars + $this->positionX += 37; + $temp_value = $this->findCode($temp_text[12]); + $this->drawChar($im, $temp_value, true); + + // Completly last bars + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + $this->positionX = $rememberX; + $this->thickness = $rememberH; + } + + /** + * Adds the default label. + */ + protected function addDefaultLabel() + { + if ($this->isDefaultEanLabelEnabled()) { + $this->processChecksum(); + $label = $this->getLabel(); + $font = $this->font; + + $this->labelLeft = new BCGLabel(substr($label, 0, 1), $font, BCGLabel::POSITION_LEFT, BCGLabel::ALIGN_BOTTOM); + $this->labelLeft->setSpacing(4 * $this->scale); + + $this->labelCenter1 = new BCGLabel(substr($label, 1, 5), $font, BCGLabel::POSITION_BOTTOM, BCGLabel::ALIGN_LEFT); + $labelCenter1Dimension = $this->labelCenter1->getDimension(); + $this->labelCenter1->setOffset(($this->scale * 44 - $labelCenter1Dimension[0]) / 2 + $this->scale * 6); + + $this->labelCenter2 = new BCGLabel(substr($label, 6, 5), $font, BCGLabel::POSITION_BOTTOM, BCGLabel::ALIGN_LEFT); + $this->labelCenter2->setOffset(($this->scale * 44 - $labelCenter1Dimension[0]) / 2 + $this->scale * 45); + + $this->labelRight = new BCGLabel($this->keys[$this->checksumValue], $font, BCGLabel::POSITION_RIGHT, BCGLabel::ALIGN_BOTTOM); + $this->labelRight->setSpacing(4 * $this->scale); + + if ($this->alignLabel) { + $labelDimension = $this->labelCenter1->getDimension(); + $this->labelLeft->setOffset($labelDimension[1]); + $this->labelRight->setOffset($labelDimension[1]); + } else { + $labelDimension = $this->labelLeft->getDimension(); + $this->labelLeft->setOffset($labelDimension[1] / 2); + $labelDimension = $this->labelLeft->getDimension(); + $this->labelRight->setOffset($labelDimension[1] / 2); + } + + $this->addLabel($this->labelLeft); + $this->addLabel($this->labelCenter1); + $this->addLabel($this->labelCenter2); + $this->addLabel($this->labelRight); + } + } + + /** + * Check correct length. + */ + protected function checkCorrectLength() + { + // If we have 12 chars, just flush the last one without throwing anything + $c = strlen($this->text); + if ($c === 12) { + $this->text = substr($this->text, 0, 11); + } elseif ($c !== 11) { + throw new BCGParseException('upca', 'Must contain 11 digits, the 12th digit is automatically added.'); + } + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGupce.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGupce.php new file mode 100644 index 0000000..faac3ae --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGupce.php @@ -0,0 +1,350 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + // Odd Parity starting with a space + // Even Parity is the inverse (0=0012) starting with a space + $this->code = array( + '2100', /* 0 */ + '1110', /* 1 */ + '1011', /* 2 */ + '0300', /* 3 */ + '0021', /* 4 */ + '0120', /* 5 */ + '0003', /* 6 */ + '0201', /* 7 */ + '0102', /* 8 */ + '2001' /* 9 */ + ); + + // Parity, 0=Odd, 1=Even for manufacturer code. Depending on 1st System Digit and Checksum + $this->codeParity = array( + array( + array(1, 1, 1, 0, 0, 0), /* 0,0 */ + array(1, 1, 0, 1, 0, 0), /* 0,1 */ + array(1, 1, 0, 0, 1, 0), /* 0,2 */ + array(1, 1, 0, 0, 0, 1), /* 0,3 */ + array(1, 0, 1, 1, 0, 0), /* 0,4 */ + array(1, 0, 0, 1, 1, 0), /* 0,5 */ + array(1, 0, 0, 0, 1, 1), /* 0,6 */ + array(1, 0, 1, 0, 1, 0), /* 0,7 */ + array(1, 0, 1, 0, 0, 1), /* 0,8 */ + array(1, 0, 0, 1, 0, 1) /* 0,9 */ + ), + array( + array(0, 0, 0, 1, 1, 1), /* 0,0 */ + array(0, 0, 1, 0, 1, 1), /* 0,1 */ + array(0, 0, 1, 1, 0, 1), /* 0,2 */ + array(0, 0, 1, 1, 1, 0), /* 0,3 */ + array(0, 1, 0, 0, 1, 1), /* 0,4 */ + array(0, 1, 1, 0, 0, 1), /* 0,5 */ + array(0, 1, 1, 1, 0, 0), /* 0,6 */ + array(0, 1, 0, 1, 0, 1), /* 0,7 */ + array(0, 1, 0, 1, 1, 0), /* 0,8 */ + array(0, 1, 1, 0, 1, 0) /* 0,9 */ + ) + ); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + $this->calculateChecksum(); + + // Starting Code + $this->drawChar($im, '000', true); + $c = strlen($this->upce); + for ($i = 0; $i < $c; $i++) { + $this->drawChar($im, self::inverse($this->findCode($this->upce[$i]), $this->codeParity[intval($this->text[0])][$this->checksumValue][$i]), false); + } + + // Draw Center Guard Bar + $this->drawChar($im, '00000', false); + + // Draw Right Bar + $this->drawChar($im, '0', true); + $this->text = $this->text[0] . $this->upce; + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + + if ($this->isDefaultEanLabelEnabled()) { + $dimension = $this->labelCenter->getDimension(); + $this->drawExtendedBars($im, $dimension[1] - 2); + } + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $startlength = 3; + $centerlength = 5; + $textlength = 6 * 7; + $endlength = 1; + + $w += $startlength + $centerlength + $textlength + $endlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Adds the default label. + */ + protected function addDefaultLabel() + { + if ($this->isDefaultEanLabelEnabled()) { + $this->processChecksum(); + $font = $this->font; + + $this->labelLeft = new BCGLabel(substr($this->text, 0, 1), $font, BCGLabel::POSITION_LEFT, BCGLabel::ALIGN_BOTTOM); + $labelLeftDimension = $this->labelLeft->getDimension(); + $this->labelLeft->setSpacing(8); + $this->labelLeft->setOffset($labelLeftDimension[1] / 2); + + $this->labelCenter = new BCGLabel($this->upce, $font, BCGLabel::POSITION_BOTTOM, BCGLabel::ALIGN_LEFT); + $labelCenterDimension = $this->labelCenter->getDimension(); + $this->labelCenter->setOffset(($this->scale * 46 - $labelCenterDimension[0]) / 2 + $this->scale * 2); + + $this->labelRight = new BCGLabel($this->keys[$this->checksumValue], $font, BCGLabel::POSITION_RIGHT, BCGLabel::ALIGN_BOTTOM); + $labelRightDimension = $this->labelRight->getDimension(); + $this->labelRight->setSpacing(8); + $this->labelRight->setOffset($labelRightDimension[1] / 2); + + $this->addLabel($this->labelLeft); + $this->addLabel($this->labelCenter); + $this->addLabel($this->labelRight); + } + } + + /** + * Checks if the default ean label is enabled. + * + * @return bool + */ + protected function isDefaultEanLabelEnabled() + { + $label = $this->getLabel(); + $font = $this->font; + return $label !== null && $label !== '' && $font !== null && $this->defaultLabel !== null; + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('upce', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('upce', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + // Must contain 11 chars + // Must contain 6 chars (if starting with upce directly) + // First Chars must be 0 or 1 + if ($c !== 11 && $c !== 6) { + throw new BCGParseException('upce', 'You must provide a UPC-A (11 characters) or a UPC-E (6 characters).'); + } elseif ($this->text[0] !== '0' && $this->text[0] !== '1' && $c !== 6) { + throw new BCGParseException('upce', 'UPC-A must start with 0 or 1 to be converted to UPC-E.'); + } + + // Convert part + $this->upce = ''; + if ($c !== 6) { + // Checking if UPC-A is convertible + $temp1 = substr($this->text, 3, 3); + if ($temp1 === '000' || $temp1 === '100' || $temp1 === '200') { // manufacturer code ends with 100, 200 or 300 + if (substr($this->text, 6, 2) === '00') { // Product must start with 00 + $this->upce = substr($this->text, 1, 2) . substr($this->text, 8, 3) . substr($this->text, 3, 1); + } + } elseif (substr($this->text, 4, 2) === '00') { // manufacturer code ends with 00 + if (substr($this->text, 6, 3) === '000') { // Product must start with 000 + $this->upce = substr($this->text, 1, 3) . substr($this->text, 9, 2) . '3'; + } + } elseif (substr($this->text, 5, 1) === '0') { // manufacturer code ends with 0 + if (substr($this->text, 6, 4) === '0000') { // Product must start with 0000 + $this->upce = substr($this->text, 1, 4) . substr($this->text, 10, 1) . '4'; + } + } else { // No zero leading at manufacturer code + $temp2 = intval(substr($this->text, 10, 1)); + if (substr($this->text, 6, 4) === '0000' && $temp2 >= 5 && $temp2 <= 9) { // Product must start with 0000 and must end by 5, 6, 7, 8 or 9 + $this->upce = substr($this->text, 1, 5) . substr($this->text, 10, 1); + } + } + } else { + $this->upce = $this->text; + } + + if ($this->upce === '') { + throw new BCGParseException('upce', 'Your UPC-A can\'t be converted to UPC-E.'); + } + + if ($c === 6) { + $upca = ''; + + // We convert UPC-E to UPC-A to find the checksum + if ($this->text[5] === '0' || $this->text[5] === '1' || $this->text[5] === '2') { + $upca = substr($this->text, 0, 2) . $this->text[5] . '0000' . substr($this->text, 2, 3); + } elseif ($this->text[5] === '3') { + $upca = substr($this->text, 0, 3) . '00000' . substr($this->text, 3, 2); + } elseif ($this->text[5] === '4') { + $upca = substr($this->text, 0, 4) . '00000' . $this->text[4]; + } else { + $upca = substr($this->text, 0, 5) . '0000' . $this->text[5]; + } + + $this->text = '0' . $upca; + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Calculating Checksum + // Consider the right-most digit of the message to be in an "odd" position, + // and assign odd/even to each character moving from right to left + // Odd Position = 3, Even Position = 1 + // Multiply it by the number + // Add all of that and do 10-(?mod10) + $odd = true; + $this->checksumValue = 0; + $c = strlen($this->text); + for ($i = $c; $i > 0; $i--) { + if ($odd === true) { + $multiplier = 3; + $odd = false; + } else { + $multiplier = 1; + $odd = true; + } + + if (!isset($this->keys[$this->text[$i - 1]])) { + return; + } + + $this->checksumValue += $this->keys[$this->text[$i - 1]] * $multiplier; + } + + $this->checksumValue = (10 - $this->checksumValue % 10) % 10; + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + return $this->keys[$this->checksumValue]; + } + + return false; + } + + /** + * Draws the extended bars on the image. + * + * @param resource $im + * @param int $plus + */ + protected function drawExtendedBars($im, $plus) + { + $rememberX = $this->positionX; + $rememberH = $this->thickness; + + // We increase the bars + $this->thickness = $this->thickness + intval($plus / $this->scale); + $this->positionX = 0; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + // Last Bars + $this->positionX += 46; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + $this->positionX += 2; + $this->drawSingleBar($im, BCGBarcode::COLOR_FG); + + $this->positionX = $rememberX; + $this->thickness = $rememberH; + } + + /** + * Inverses the string when the $inverse parameter is equal to 1. + * + * @param string $text + * @param int $inverse + * @return string + */ + private static function inverse($text, $inverse = 1) + { + if ($inverse === 1) { + $text = strrev($text); + } + + return $text; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGupcext2.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGupcext2.php new file mode 100644 index 0000000..a585996 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGupcext2.php @@ -0,0 +1,148 @@ +keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + $this->code = array( + '2100', /* 0 */ + '1110', /* 1 */ + '1011', /* 2 */ + '0300', /* 3 */ + '0021', /* 4 */ + '0120', /* 5 */ + '0003', /* 6 */ + '0201', /* 7 */ + '0102', /* 8 */ + '2001' /* 9 */ + ); + + // Parity, 0=Odd, 1=Even. Depending on ?%4 + $this->codeParity = array( + array(0, 0), /* 0 */ + array(0, 1), /* 1 */ + array(1, 0), /* 2 */ + array(1, 1) /* 3 */ + ); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + // Starting Code + $this->drawChar($im, '001', true); + + // Code + for ($i = 0; $i < 2; $i++) { + $this->drawChar($im, self::inverse($this->findCode($this->text[$i]), $this->codeParity[intval($this->text) % 4][$i]), false); + if ($i === 0) { + $this->drawChar($im, '00', false); // Inter-char + } + } + + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $startlength = 4; + $textlength = 2 * 7; + $intercharlength = 2; + + $w += $startlength + $textlength + $intercharlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Adds the default label. + */ + protected function addDefaultLabel() + { + parent::addDefaultLabel(); + + if ($this->defaultLabel !== null) { + $this->defaultLabel->setPosition(BCGLabel::POSITION_TOP); + } + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('upcext2', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('upcext2', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + // Must contain 2 digits + if ($c !== 2) { + throw new BCGParseException('upcext2', 'Must contain 2 digits.'); + } + + parent::validate(); + } + + /** + * Inverses the string when the $inverse parameter is equal to 1. + * + * @param string $text + * @param int $inverse + * @return string + */ + private static function inverse($text, $inverse = 1) + { + if ($inverse === 1) { + $text = strrev($text); + } + + return $text; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-1d/src/BCGupcext5.php b/serve/vendor/barcode-bakery/barcode-1d/src/BCGupcext5.php new file mode 100644 index 0000000..44783ca --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-1d/src/BCGupcext5.php @@ -0,0 +1,212 @@ + No suggested Retail Price + * If 99991 -> Book Complimentary (normally free) + * If 90001 to 98999 -> Internal Purpose of Publisher + * If 99990 -> Used by the National Association of College Stores to mark used books + * If 0xxxx -> Price Expressed in British Pounds (xx.xx) + * If 5xxxx -> Price Expressed in U.S. dollars (US$xx.xx) + * + *-------------------------------------------------------------------- + * Copyright (C) Jean-Sebastien Goupil + * http://www.barcodebakery.com + */ +namespace BarcodeBakery\Barcode; + +use BarcodeBakery\Common\BCGBarcode1D; +use BarcodeBakery\Common\BCGLabel; +use BarcodeBakery\Common\BCGParseException; + +class BCGupcext5 extends BCGBarcode1D +{ + protected $codeParity = array(); + + /** + * Constructor. + */ + public function __construct() + { + parent::__construct(); + + $this->keys = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + $this->code = array( + '2100', /* 0 */ + '1110', /* 1 */ + '1011', /* 2 */ + '0300', /* 3 */ + '0021', /* 4 */ + '0120', /* 5 */ + '0003', /* 6 */ + '0201', /* 7 */ + '0102', /* 8 */ + '2001' /* 9 */ + ); + + // Parity, 0=Odd, 1=Even. Depending Checksum + $this->codeParity = array( + array(1, 1, 0, 0, 0), /* 0 */ + array(1, 0, 1, 0, 0), /* 1 */ + array(1, 0, 0, 1, 0), /* 2 */ + array(1, 0, 0, 0, 1), /* 3 */ + array(0, 1, 1, 0, 0), /* 4 */ + array(0, 0, 1, 1, 0), /* 5 */ + array(0, 0, 0, 1, 1), /* 6 */ + array(0, 1, 0, 1, 0), /* 7 */ + array(0, 1, 0, 0, 1), /* 8 */ + array(0, 0, 1, 0, 1) /* 9 */ + ); + } + + /** + * Draws the barcode. + * + * @param resource $im + */ + public function draw($im) + { + // Checksum + $this->calculateChecksum(); + + // Starting Code + $this->drawChar($im, '001', true); + + // Code + for ($i = 0; $i < 5; $i++) { + $this->drawChar($im, self::inverse($this->findCode($this->text[$i]), $this->codeParity[$this->checksumValue][$i]), false); + if ($i < 4) { + $this->drawChar($im, '00', false); // Inter-char + } + } + + $this->drawText($im, 0, 0, $this->positionX, $this->thickness); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $startlength = 4; + $textlength = 5 * 7; + $intercharlength = 2 * 4; + + $w += $startlength + $textlength + $intercharlength; + $h += $this->thickness; + return parent::getDimension($w, $h); + } + + /** + * Adds the default label. + */ + protected function addDefaultLabel() + { + parent::addDefaultLabel(); + + if ($this->defaultLabel !== null) { + $this->defaultLabel->setPosition(BCGLabel::POSITION_TOP); + } + } + + /** + * Validates the input. + */ + protected function validate() + { + $c = strlen($this->text); + if ($c === 0) { + throw new BCGParseException('upcext5', 'No data has been entered.'); + } + + // Checking if all chars are allowed + for ($i = 0; $i < $c; $i++) { + if (array_search($this->text[$i], $this->keys) === false) { + throw new BCGParseException('upcext5', 'The character \'' . $this->text[$i] . '\' is not allowed.'); + } + } + + // Must contain 5 digits + if ($c !== 5) { + throw new BCGParseException('upcext5', 'Must contain 5 digits.'); + } + + parent::validate(); + } + + /** + * Overloaded method to calculate checksum. + */ + protected function calculateChecksum() + { + // Calculating Checksum + // Consider the right-most digit of the message to be in an "odd" position, + // and assign odd/even to each character moving from right to left + // Odd Position = 3, Even Position = 9 + // Multiply it by the number + // Add all of that and do ?mod10 + $odd = true; + $this->checksumValue = 0; + $c = strlen($this->text); + for ($i = $c; $i > 0; $i--) { + if ($odd === true) { + $multiplier = 3; + $odd = false; + } else { + $multiplier = 9; + $odd = true; + } + + if (!isset($this->keys[$this->text[$i - 1]])) { + return; + } + + $this->checksumValue += $this->keys[$this->text[$i - 1]] * $multiplier; + } + + $this->checksumValue = $this->checksumValue % 10; + } + + /** + * Overloaded method to display the checksum. + */ + protected function processChecksum() + { + if ($this->checksumValue === false) { // Calculate the checksum only once + $this->calculateChecksum(); + } + + if ($this->checksumValue !== false) { + return $this->keys[$this->checksumValue]; + } + + return false; + } + + /** + * Inverses the string when the $inverse parameter is equal to 1. + * + * @param string $text + * @param int $inverse + * @return string + */ + private static function inverse($text, $inverse = 1) + { + if ($inverse === 1) { + $text = strrev($text); + } + + return $text; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/composer.json b/serve/vendor/barcode-bakery/barcode-common/composer.json new file mode 100644 index 0000000..e72bed4 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/composer.json @@ -0,0 +1,30 @@ +{ + "name": "barcode-bakery/barcode-common", + "version": "6.0.0", + "license": [ + "Commercial", + "CC-BY-NC-ND-4.0" + ], + "support": { + "email": "contact@barcodebakery.com", + "docs": "http://www.barcodebakery.com" + }, + "type": "library", + "homepage": "http://www.barcodebakery.com", + "authors": [ + { + "name": "Jean-Sébastien Goupil", + "email": "contact@barcodebakery.com" + } + ], + "description": "Base code for generating barcode with the Barcode Bakery library. See barcode-bakery/barcode-1d.", + "autoload": { + "psr-4": { + "BarcodeBakery\\Common\\": "src" + } + }, + "require": { + "php": ">=5.6", + "ext-gd": "*" + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGArgumentException.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGArgumentException.php new file mode 100644 index 0000000..cd9213c --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGArgumentException.php @@ -0,0 +1,30 @@ +param = $param; + parent::__construct($message, 20000); + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGBarcode.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGBarcode.php new file mode 100644 index 0000000..8bfb38f --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGBarcode.php @@ -0,0 +1,481 @@ +setOffsetX(0); + $this->setOffsetY(0); + $this->setForegroundColor(0x000000); + $this->setBackgroundColor(0xffffff); + $this->setScale(1); + } + + /** + * Parses the text before displaying it. + * + * @param mixed $text + */ + public function parse($text) + { + } + + /** + * Gets the foreground color of the barcode. + * + * @return BCGColor + */ + public function getForegroundColor() + { + return $this->colorFg; + } + + /** + * Sets the foreground color of the barcode. It could be a BCGColor + * value or simply a language code (white, black, yellow...) or hex value. + * + * @param mixed $code + */ + public function setForegroundColor($code) + { + if ($code instanceof BCGColor) { + $this->colorFg = $code; + } else { + $this->colorFg = new BCGColor($code); + } + } + + /** + * Gets the background color of the barcode. + * + * @return BCGColor + */ + public function getBackgroundColor() + { + return $this->colorBg; + } + + /** + * Sets the background color of the barcode. It could be a BCGColor + * value or simply a language code (white, black, yellow...) or hex value. + * + * @param mixed $code + */ + public function setBackgroundColor($code) + { + if ($code instanceof BCGColor) { + $this->colorBg = $code; + } else { + $this->colorBg = new BCGColor($code); + } + + foreach ($this->labels as $label) { + $label->setBackgroundColor($this->colorBg); + } + } + + /** + * Sets the color. + * + * @param mixed $fg + * @param mixed $bg + */ + public function setColor($fg, $bg) + { + $this->setForegroundColor($fg); + $this->setBackgroundColor($bg); + } + + /** + * Gets the scale of the barcode. + * + * @return int + */ + public function getScale() + { + return $this->scale; + } + + /** + * Sets the scale of the barcode in pixel. + * If the scale is lower than 1, an exception is raised. + * + * @param int $scale + */ + public function setScale($scale) + { + $scale = intval($scale); + if ($scale <= 0) { + throw new BCGArgumentException('The scale must be larger than 0.', 'scale'); + } + + $this->scale = $scale; + } + + /** + * Abstract method that draws the barcode on the resource. + * + * @param resource $im + */ + abstract public function draw($im); + + /** + * Returns the maximal size of a barcode. + * [0]->width + * [1]->height + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + $labels = $this->getBiggestLabels(false); + $pixelsAround = array(0, 0, 0, 0); // TRBL + if (isset($labels[BCGLabel::POSITION_TOP])) { + $dimension = $labels[BCGLabel::POSITION_TOP]->getDimension(); + $pixelsAround[0] += $dimension[1]; + } + + if (isset($labels[BCGLabel::POSITION_RIGHT])) { + $dimension = $labels[BCGLabel::POSITION_RIGHT]->getDimension(); + $pixelsAround[1] += $dimension[0]; + } + + if (isset($labels[BCGLabel::POSITION_BOTTOM])) { + $dimension = $labels[BCGLabel::POSITION_BOTTOM]->getDimension(); + $pixelsAround[2] += $dimension[1]; + } + + if (isset($labels[BCGLabel::POSITION_LEFT])) { + $dimension = $labels[BCGLabel::POSITION_LEFT]->getDimension(); + $pixelsAround[3] += $dimension[0]; + } + + $finalW = ($w + $this->offsetX) * $this->scale; + $finalH = ($h + $this->offsetY) * $this->scale; + + // This section will check if a top/bottom label is too big for its width and left/right too big for its height + $reversedLabels = $this->getBiggestLabels(true); + foreach ($reversedLabels as $label) { + $dimension = $label->getDimension(); + $alignment = $label->getAlignment(); + if ($label->getPosition() === BCGLabel::POSITION_LEFT || $label->getPosition() === BCGLabel::POSITION_RIGHT) { + if ($alignment === BCGLabel::ALIGN_TOP) { + $pixelsAround[2] = max($pixelsAround[2], $dimension[1] - $finalH); + } elseif ($alignment === BCGLabel::ALIGN_CENTER) { + $temp = (int)ceil(($dimension[1] - $finalH) / 2); + $pixelsAround[0] = max($pixelsAround[0], $temp); + $pixelsAround[2] = max($pixelsAround[2], $temp); + } elseif ($alignment === BCGLabel::ALIGN_BOTTOM) { + $pixelsAround[0] = max($pixelsAround[0], $dimension[1] - $finalH); + } + } else { + if ($alignment === BCGLabel::ALIGN_LEFT) { + $pixelsAround[1] = max($pixelsAround[1], $dimension[0] - $finalW); + } elseif ($alignment === BCGLabel::ALIGN_CENTER) { + $temp = (int)ceil(($dimension[0] - $finalW) / 2); + $pixelsAround[1] = max($pixelsAround[1], $temp); + $pixelsAround[3] = max($pixelsAround[3], $temp); + } elseif ($alignment === BCGLabel::ALIGN_RIGHT) { + $pixelsAround[3] = max($pixelsAround[3], $dimension[0] - $finalW); + } + } + } + + $this->pushLabel[0] = $pixelsAround[3]; + $this->pushLabel[1] = $pixelsAround[0]; + + $finalW = ($w + $this->offsetX) * $this->scale + $pixelsAround[1] + $pixelsAround[3]; + $finalH = ($h + $this->offsetY) * $this->scale + $pixelsAround[0] + $pixelsAround[2]; + + return array((int)$finalW, (int)$finalH); + } + + /** + * Gets the X offset. + * + * @return int + */ + public function getOffsetX() + { + return $this->offsetX; + } + + /** + * Sets the X offset. + * + * @param int $offsetX + */ + public function setOffsetX($offsetX) + { + $offsetX = intval($offsetX); + if ($offsetX < 0) { + throw new BCGArgumentException('The offset X must be 0 or larger.', 'offsetX'); + } + + $this->offsetX = $offsetX; + } + + /** + * Gets the Y offset. + * + * @return int + */ + public function getOffsetY() + { + return $this->offsetY; + } + + /** + * Sets the Y offset. + * + * @param int $offsetY + */ + public function setOffsetY($offsetY) + { + $offsetY = intval($offsetY); + if ($offsetY < 0) { + throw new BCGArgumentException('The offset Y must be 0 or larger.', 'offsetY'); + } + + $this->offsetY = $offsetY; + } + + /** + * Adds the label to the drawing. + * + * @param BCGLabel $label + */ + public function addLabel(BCGLabel $label) + { + $label->setBackgroundColor($this->colorBg); + $this->labels[] = $label; + } + + /** + * Removes the label from the drawing. + * + * @param BCGLabel $label + */ + public function removeLabel(BCGLabel $label) + { + $remove = -1; + $c = count($this->labels); + for ($i = 0; $i < $c; $i++) { + if ($this->labels[$i] === $label) { + $remove = $i; + break; + } + } + + if ($remove > -1) { + array_splice($this->labels, $remove, 1); + } + } + + /** + * Gets the labels. + * + * @return BCGLabel[] + */ + public function getLabels() + { + return $this->labels; + } + + /** + * Clears the labels. + */ + public function clearLabels() + { + $this->labels = array(); + } + + /** + * Draws the text. + * The coordinate passed are the positions of the barcode. + * $x1 and $y1 represent the top left corner. + * $x2 and $y2 represent the bottom right corner. + * + * @param resource $im + * @param int $x1 + * @param int $y1 + * @param int $x2 + * @param int $y2 + */ + protected function drawText($im, $x1, $y1, $x2, $y2) + { + foreach ($this->labels as $label) { + $label->draw( + $im, + ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0], + ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1], + ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0], + ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + ); + } + } + + /** + * Draws 1 pixel on the resource at a specific position with a determined color. + * + * @param resource $im + * @param int $x + * @param int $y + * @param int $color + */ + protected function drawPixel($im, $x, $y, $color = self::COLOR_FG) + { + $xR = ($x + $this->offsetX) * $this->scale + $this->pushLabel[0]; + $yR = ($y + $this->offsetY) * $this->scale + $this->pushLabel[1]; + + // We always draw a rectangle + imagefilledrectangle( + $im, + $xR, + $yR, + $xR + $this->scale - 1, + $yR + $this->scale - 1, + $this->getColor($im, $color) + ); + } + + /** + * Draws an empty rectangle on the resource at a specific position with a determined color. + * + * @param resource $im + * @param int $x1 + * @param int $y1 + * @param int $x2 + * @param int $y2 + * @param int $color + */ + protected function drawRectangle($im, $x1, $y1, $x2, $y2, $color = self::COLOR_FG) + { + if ($this->scale === 1) { + imagefilledrectangle( + $im, + ($x1 + $this->offsetX) + $this->pushLabel[0], + ($y1 + $this->offsetY) + $this->pushLabel[1], + ($x2 + $this->offsetX) + $this->pushLabel[0], + ($y2 + $this->offsetY) + $this->pushLabel[1], + $this->getColor($im, $color) + ); + } else { + imagefilledrectangle($im, ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0], ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1], ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1, ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1, $this->getColor($im, $color)); + imagefilledrectangle($im, ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0], ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1], ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1, ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1, $this->getColor($im, $color)); + imagefilledrectangle($im, ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0], ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1], ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1, ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1, $this->getColor($im, $color)); + imagefilledrectangle($im, ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0], ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1], ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1, ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1, $this->getColor($im, $color)); + } + } + + /** + * Draws a filled rectangle on the resource at a specific position with a determined color. + * + * @param resource $im + * @param int $x1 + * @param int $y1 + * @param int $x2 + * @param int $y2 + * @param int $color + */ + protected function drawFilledRectangle($im, $x1, $y1, $x2, $y2, $color = self::COLOR_FG) + { + if ($x1 > $x2) { // Swap + $x1 ^= $x2 ^= $x1 ^= $x2; + } + + if ($y1 > $y2) { // Swap + $y1 ^= $y2 ^= $y1 ^= $y2; + } + + imagefilledrectangle( + $im, + ($x1 + $this->offsetX) * $this->scale + $this->pushLabel[0], + ($y1 + $this->offsetY) * $this->scale + $this->pushLabel[1], + ($x2 + $this->offsetX) * $this->scale + $this->pushLabel[0] + $this->scale - 1, + ($y2 + $this->offsetY) * $this->scale + $this->pushLabel[1] + $this->scale - 1, + $this->getColor($im, $color) + ); + } + + /** + * Allocates the color based on the integer. + * + * @param resource $im + * @param int $color + * @return resource + */ + protected function getColor($im, $color) + { + if ($color === self::COLOR_BG) { + return $this->colorBg->allocate($im); + } else { + return $this->colorFg->allocate($im); + } + } + + /** + * Returning the biggest label widths for LEFT/RIGHT and heights for TOP/BOTTOM. + * + * @param bool $reversed + * @return BCGLabel[] + */ + private function getBiggestLabels($reversed = false) + { + $searchLR = $reversed ? 1 : 0; + $searchTB = $reversed ? 0 : 1; + + $labels = array(); + foreach ($this->labels as $label) { + $position = $label->getPosition(); + if (isset($labels[$position])) { + $savedDimension = $labels[$position]->getDimension(); + $dimension = $label->getDimension(); + if ($position === BCGLabel::POSITION_LEFT || $position === BCGLabel::POSITION_RIGHT) { + if ($dimension[$searchLR] > $savedDimension[$searchLR]) { + $labels[$position] = $label; + } + } else { + if ($dimension[$searchTB] > $savedDimension[$searchTB]) { + $labels[$position] = $label; + } + } + } else { + $labels[$position] = $label; + } + } + + return $labels; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGBarcode1D.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGBarcode1D.php new file mode 100644 index 0000000..c435043 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGBarcode1D.php @@ -0,0 +1,276 @@ +setThickness(30); + + $this->defaultLabel = new BCGLabel(); + $this->defaultLabel->setPosition(BCGLabel::POSITION_BOTTOM); + $this->setLabel(self::AUTO_LABEL); + $this->setFont(new BCGFontPhp(5)); + + $this->text = ''; + $this->checksumValue = false; + $this->positionX = 0; + } + + /** + * Gets the thickness. + * + * @return int + */ + public function getThickness() + { + return $this->thickness; + } + + /** + * Sets the thickness. + * + * @param int $thickness + */ + public function setThickness($thickness) + { + $thickness = intval($thickness); + if ($thickness <= 0) { + throw new BCGArgumentException('The thickness must be larger than 0.', 'thickness'); + } + + $this->thickness = $thickness; + } + + /** + * Gets the label. + * If the label was set to BCGBarcode1D::AUTO_LABEL, the label will display the value from the text parsed. + * + * @return string + */ + public function getLabel() + { + $label = $this->label; + if ($this->label === self::AUTO_LABEL) { + $label = $this->text; + if ($this->displayChecksum === true && ($checksum = $this->processChecksum()) !== false) { + $label .= $checksum; + } + } + return $label; + } + + /** + * Sets the label. + * You can use BCGBarcode::AUTO_LABEL to have the label automatically written based on the parsed text. + * + * @param string $label + */ + public function setLabel($label) + { + $this->label = $label; + } + + /** + * Gets the font. + * + * @return BCGFont + */ + public function getFont() + { + return $this->font; + } + + /** + * Sets the font. + * + * @param mixed $font BCGFont or int + */ + public function setFont($font) + { + if (is_int($font)) { + if ($font === 0) { + $font = null; + } else { + $font = new BCGFontPhp($font); + } + } + + $this->font = $font; + } + + /** + * Parses the text before displaying it. + * + * @param mixed $text + */ + public function parse($text) + { + $this->text = $text; + $this->checksumValue = false; // Reset checksumValue + $this->validate(); + + parent::parse($text); + + $this->addDefaultLabel(); + } + + /** + * Gets the checksum of a Barcode. + * If no checksum is available, return FALSE. + * + * @return string + */ + public function getChecksum() + { + return $this->processChecksum(); + } + + /** + * Sets if the checksum is displayed with the label or not. + * The checksum must be activated in some case to make this variable effective. + * + * @param boolean $displayChecksum + */ + public function setDisplayChecksum($displayChecksum) + { + $this->displayChecksum = (bool)$displayChecksum; + } + + /** + * Adds the default label. + */ + protected function addDefaultLabel() + { + $label = $this->getLabel(); + $font = $this->font; + if ($label !== null && $label !== '' && $font !== null && $this->defaultLabel !== null) { + $this->defaultLabel->setText($label); + $this->defaultLabel->setFont($font); + $this->addLabel($this->defaultLabel); + } + } + + /** + * Validates the input + */ + protected function validate() + { + // No validation in the abstract class. + } + + /** + * Returns the index in $keys (useful for checksum). + * + * @param mixed $var + * @return mixed + */ + protected function findIndex($var) + { + return array_search($var, $this->keys); + } + + /** + * Returns the code of the char (useful for drawing bars). + * + * @param mixed $var + * @return string + */ + protected function findCode($var) + { + return $this->code[$this->findIndex($var)]; + } + + /** + * Draws all chars thanks to $code. If $startBar is true, the line begins by a space. + * If $startBar is false, the line begins by a bar. + * + * @param resource $im + * @param string $code + * @param boolean $startBar + */ + protected function drawChar($im, $code, $startBar = true) + { + $colors = array(BCGBarcode::COLOR_FG, BCGBarcode::COLOR_BG); + $currentColor = $startBar ? 0 : 1; + $c = strlen($code); + for ($i = 0; $i < $c; $i++) { + for ($j = 0; $j < intval($code[$i]) + 1; $j++) { + $this->drawSingleBar($im, $colors[$currentColor]); + $this->nextX(); + } + + $currentColor = ($currentColor + 1) % 2; + } + } + + /** + * Draws a Bar of $color depending of the resolution. + * + * @param resource $img + * @param int $color + */ + protected function drawSingleBar($im, $color) + { + $this->drawFilledRectangle($im, $this->positionX, 0, $this->positionX, $this->thickness - 1, $color); + } + + /** + * Moving the pointer right to write a bar. + */ + protected function nextX() + { + $this->positionX++; + } + + /** + * Method that saves FALSE into the checksumValue. This means no checksum + * but this method should be overriden when needed. + */ + protected function calculateChecksum() + { + $this->checksumValue = false; + } + + /** + * Returns FALSE because there is no checksum. This method should be + * overriden to return correctly the checksum in string with checksumValue. + * + * @return string + */ + protected function processChecksum() + { + return false; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGBarcode2D.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGBarcode2D.php new file mode 100644 index 0000000..16c7a5e --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGBarcode2D.php @@ -0,0 +1,191 @@ +setScaleX(1); + $this->setScaleY(1); + } + + /** + * Returns the maximal size of a barcode. + * + * @param int $w + * @param int $h + * @return int[] + */ + public function getDimension($w, $h) + { + return parent::getDimension($w * $this->scaleX, $h * $this->scaleY); + } + + /** + * Sets the scale of the barcode in pixel for X. + * If the scale is lower than 1, an exception is raised. + * + * @param int $scaleX + */ + protected function setScaleX($scaleX) + { + $scaleX = intval($scaleX); + if ($scaleX <= 0) { + throw new ArgumentException('The scale must be larger than 0.', 'scaleX'); + } + + $this->scaleX = $scaleX; + } + + /** + * Sets the scale of the barcode in pixel for Y. + * If the scale is lower than 1, an exception is raised. + * + * @param int $scaleY + */ + protected function setScaleY($scaleY) + { + $scaleY = intval($scaleY); + if ($scaleY <= 0) { + throw new ArgumentException('The scale must be larger than 0.', 'scaleY'); + } + + $this->scaleY = $scaleY; + } + + /** + * Draws the text. + * The coordinate passed are the positions of the barcode. + * $x1 and $y1 represent the top left corner. + * $x2 and $y2 represent the bottom right corner. + * + * @param resource $im + * @param int $x1 + * @param int $y1 + * @param int $x2 + * @param int $y2 + */ + protected function drawText($im, $x1, $y1, $x2, $y2) + { + foreach ($this->labels as $label) { + $label->draw( + $im, + ($x1 + $this->offsetX) * $this->scale * $this->scaleX + $this->pushLabel[0], + ($y1 + $this->offsetY) * $this->scale * $this->scaleY + $this->pushLabel[1], + ($x2 + $this->offsetX) * $this->scale * $this->scaleX + $this->pushLabel[0], + ($y2 + $this->offsetY) * $this->scale * $this->scaleY + $this->pushLabel[1] + ); + } + } + + /** + * Draws 1 pixel on the resource at a specific position with a determined color. + * + * @param resource $im + * @param int $x + * @param int $y + * @param int $color + */ + protected function drawPixel($im, $x, $y, $color = self::COLOR_FG) + { + $scaleX = $this->scale * $this->scaleX; + $scaleY = $this->scale * $this->scaleY; + + $xR = ($x + $this->offsetX) * $scaleX + $this->pushLabel[0]; + $yR = ($y + $this->offsetY) * $scaleY + $this->pushLabel[1]; + + // We always draw a rectangle + imagefilledrectangle( + $im, + $xR, + $yR, + $xR + $scaleX - 1, + $yR + $scaleY - 1, + $this->getColor($im, $color) + ); + } + + /** + * Draws an empty rectangle on the resource at a specific position with a determined color. + * + * @param resource $im + * @param int $x1 + * @param int $y1 + * @param int $x2 + * @param int $y2 + * @param int $color + */ + protected function drawRectangle($im, $x1, $y1, $x2, $y2, $color = BCGBarcode::COLOR_FG) + { + $scaleX = $this->scale * $this->scaleX; + $scaleY = $this->scale * $this->scaleY; + + if ($this->scale === 1) { + imagefilledrectangle( + $im, + ($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0], + ($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1], + ($x2 + $this->offsetX) * $scaleX + $this->pushLabel[0], + ($y2 + $this->offsetY) * $scaleY + $this->pushLabel[1], + $this->getColor($im, $color) + ); + } else { + imagefilledrectangle($im, ($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0], ($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1], ($x2 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0], ($y1 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1], $this->getColor($im, $color)); + imagefilledrectangle($im, ($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0], ($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1], ($x1 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0], ($y2 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1], $this->getColor($im, $color)); + imagefilledrectangle($im, ($x2 + $this->offsetX) * $scaleX + $this->pushLabel[0], ($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1], ($x2 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0], ($y2 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1], $this->getColor($im, $color)); + imagefilledrectangle($im, ($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0], ($y2 + $this->offsetY) * $scaleY + $this->pushLabel[1], ($x2 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0], ($y2 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1], $this->getColor($im, $color)); + } + } + + /** + * Draws a filled rectangle on the resource at a specific position with a determined color. + * + * @param resource $im + * @param int $x1 + * @param int $y1 + * @param int $x2 + * @param int $y2 + * @param int $color + */ + protected function drawFilledRectangle($im, $x1, $y1, $x2, $y2, $color = BCGBarcode::COLOR_FG) + { + if ($x1 > $x2) { // Swap + $x1 ^= $x2 ^= $x1 ^= $x2; + } + + if ($y1 > $y2) { // Swap + $y1 ^= $y2 ^= $y1 ^= $y2; + } + + $scaleX = $this->scale * $this->scaleX; + $scaleY = $this->scale * $this->scaleY; + + imagefilledrectangle( + $im, + ($x1 + $this->offsetX) * $scaleX + $this->pushLabel[0], + ($y1 + $this->offsetY) * $scaleY + $this->pushLabel[1], + ($x2 + $this->offsetX) * $scaleX + $scaleX - 1 + $this->pushLabel[0], + ($y2 + $this->offsetY) * $scaleY + $scaleY - 1 + $this->pushLabel[1], + $this->getColor($im, $color) + ); + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGColor.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGColor.php new file mode 100644 index 0000000..748da25 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGColor.php @@ -0,0 +1,168 @@ +r = intval($args[0]); + $this->g = intval($args[1]); + $this->b = intval($args[2]); + } elseif ($c === 1) { + if (is_string($args[0]) && strlen($args[0]) === 7 && $args[0][0] === '#') { // Hex Value in String + $this->r = intval(substr($args[0], 1, 2), 16); + $this->g = intval(substr($args[0], 3, 2), 16); + $this->b = intval(substr($args[0], 5, 2), 16); + } else { + if (is_string($args[0])) { + $args[0] = self::getColor($args[0]); + } + + $args[0] = intval($args[0]); + $this->r = ($args[0] & 0xff0000) >> 16; + $this->g = ($args[0] & 0x00ff00) >> 8; + $this->b = ($args[0] & 0x0000ff); + } + } else { + $this->r = $this->g = $this->b = 0; + } + } + + /** + * Sets the color transparent. + * + * @param bool $transparent + */ + public function setTransparent($transparent) + { + $this->transparent = $transparent; + } + + /** + * Returns Red Color. + * + * @return int + */ + public function r() + { + return $this->r; + } + + /** + * Returns Green Color. + * + * @return int + */ + public function g() + { + return $this->g; + } + + /** + * Returns Blue Color. + * + * @return int + */ + public function b() + { + return $this->b; + } + + /** + * Returns the int value for PHP color. + * + * @param resource $im + * @return int + */ + public function allocate(&$im) + { + $allocated = imagecolorallocate($im, $this->r, $this->g, $this->b); + if ($this->transparent) { + return imagecolortransparent($im, $allocated); + } else { + return $allocated; + } + } + + /** + * Returns class of BCGColor depending of the string color. + * + * If the color doens't exist, it takes the default one. + * + * @param string $code + * @param string $default + */ + public static function getColor($code, $default = 'white') + { + switch (strtolower($code)) { + case '': + case 'white': + return 0xffffff; + case 'black': + return 0x000000; + case 'maroon': + return 0x800000; + case 'red': + return 0xff0000; + case 'orange': + return 0xffa500; + case 'yellow': + return 0xffff00; + case 'olive': + return 0x808000; + case 'purple': + return 0x800080; + case 'fuchsia': + return 0xff00ff; + case 'lime': + return 0x00ff00; + case 'green': + return 0x008000; + case 'navy': + return 0x000080; + case 'blue': + return 0x0000ff; + case 'aqua': + return 0x00ffff; + case 'teal': + return 0x008080; + case 'silver': + return 0xc0c0c0; + case 'gray': + return 0x808080; + default: + return self::getColor($default, 'white'); + } + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGDrawException.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGDrawException.php new file mode 100644 index 0000000..327c173 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGDrawException.php @@ -0,0 +1,26 @@ +im = null; + $this->setFilename($filename); + $this->color = $color; + $this->dpi = null; + $this->rotateDegree = 0.0; + } + + /** + * Destructor. + */ + public function __destruct() + { + $this->destroy(); + } + + /** + * Gets the filename. + * + * @return string + */ + public function getFilename() + { + return $this->filename; + } + + /** + * Sets the filename. + * + * @param string $filaneme + */ + public function setFilename($filename) + { + $this->filename = $filename; + } + + /** + * @return resource. + */ + public function get_im() + { + return $this->im; + } + + /** + * Sets the image. + * + * @param resource $im + */ + public function set_im($im) + { + $this->im = $im; + } + + /** + * Gets barcode for drawing. + * + * @return BCGBarcode + */ + public function getBarcode() + { + return $this->barcode; + } + + /** + * Sets barcode for drawing. + * + * @param BCGBarcode $barcode + */ + public function setBarcode(BCGBarcode $barcode) + { + $this->barcode = $barcode; + } + + /** + * Gets the DPI for supported filetype. + * + * @return float + */ + public function getDPI() + { + return $this->dpi; + } + + /** + * Sets the DPI for supported filetype. + * + * @param float $dpi + */ + public function setDPI($dpi) + { + $this->dpi = $dpi; + } + + /** + * Gets the rotation angle in degree clockwise. + * + * @return float + */ + public function getRotationAngle() + { + return $this->rotateDegree; + } + + /** + * Sets the rotation angle in degree clockwise. + * + * @param float $degree + */ + public function setRotationAngle($degree) + { + $this->rotateDegree = (float)$degree; + } + + /** + * Draws the barcode on the image $im. + */ + public function draw() + { + $size = $this->barcode->getDimension(0, 0); + $this->w = max(1, $size[0]); + $this->h = max(1, $size[1]); + $this->init(); + $this->barcode->draw($this->im); + } + + /** + * Saves $im into the file (many format available). + * + * @param int $image_style + * @param int $quality + */ + public function finish($image_style = self::IMG_FORMAT_PNG, $quality = 100) + { + $drawer = null; + + $im = $this->im; + if ($this->rotateDegree > 0.0) { + if (function_exists('imagerotate')) { + $im = imagerotate($this->im, 360 - $this->rotateDegree, $this->color->allocate($this->im)); + } else { + throw new BCGDrawException('The method imagerotate doesn\'t exist on your server. Do not use any rotation.'); + } + } + + if ($image_style === self::IMG_FORMAT_PNG) { + $drawer = new BCGDrawPNG($im); + $drawer->setFilename($this->filename); + $drawer->setDPI($this->dpi); + } elseif ($image_style === self::IMG_FORMAT_JPEG) { + $drawer = new BCGDrawJPG($im); + $drawer->setFilename($this->filename); + $drawer->setDPI($this->dpi); + $drawer->setQuality($quality); + } elseif ($image_style === self::IMG_FORMAT_GIF) { + // Some PHP versions have a bug if passing 2nd argument as null. + if ($this->filename === null || $this->filename === '') { + imagegif($im); + } else { + imagegif($im, $this->filename); + } + } elseif ($image_style === self::IMG_FORMAT_WBMP) { + imagewbmp($im, $this->filename); + } + + if ($drawer !== null) { + $drawer->draw(); + } + } + + /** + * Writes the Error on the picture. + * + * @param Exception $exception + */ + public function drawException($exception) + { + $this->w = 1; + $this->h = 1; + $this->init(); + + // Is the image big enough? + $w = imagesx($this->im); + $h = imagesy($this->im); + + $text = 'Error: ' . $exception->getMessage(); + + $width = imagefontwidth(2) * strlen($text); + $height = imagefontheight(2); + if ($width > $w || $height > $h) { + $width = max($w, $width); + $height = max($h, $height); + + // We change the size of the image + $newimg = imagecreatetruecolor($width, $height); + imagefill($newimg, 0, 0, imagecolorat($this->im, 0, 0)); + imagecopy($newimg, $this->im, 0, 0, 0, 0, $w, $h); + $this->im = $newimg; + } + + $black = new BCGColor('black'); + imagestring($this->im, 2, 0, 0, $text, $black->allocate($this->im)); + } + + /** + * Free the memory of PHP (called also by destructor). + */ + public function destroy() + { + @imagedestroy($this->im); + } + + /** + * Init Image and color background. + */ + private function init() + { + if ($this->im === null) { + $this->im = imagecreatetruecolor($this->w, $this->h) + or die('Can\'t Initialize the GD Libraty'); + imagefilledrectangle($this->im, 0, 0, $this->w - 1, $this->h - 1, $this->color->allocate($this->im)); + } + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGFont.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGFont.php new file mode 100644 index 0000000..58cfe06 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGFont.php @@ -0,0 +1,27 @@ +box = $box; + } + + public function getBox() + { + return $this->box; + } + + public function getAscender() + { + return abs($this->box[7]); + } + + public function getDescender() + { + return abs($this->box[1] > 0 ? $this->box[1] : 0); + } + + public function getWidth() + { + // We drew at 0, so even if the box starts at 1, we need more space + // So we don't do -box[0]. + return max($this->box[2], $this->box[4]); + } + + public function getHeight() + { + $minY = min(array($this->box[1], $this->box[3], $this->box[5], $this->box[7])); + $maxY = max(array($this->box[1], $this->box[3], $this->box[5], $this->box[7])); + return $maxY - $minY; + } +} + +class BCGFontFile implements BCGFont +{ + private $path; + private $size; + private $text = ''; + private $foregroundColor; + private $rotationAngle; + private $fontInfo; // BCGFontInfo + private $descenderSize; + + /** + * Constructor. + * + * @param string $fontPath path to the file + * @param int $size size in point + */ + public function __construct($fontPath, $size) + { + if (!file_exists($fontPath)) { + throw new BCGArgumentException('The font path is incorrect.', 'fontPath'); + } + + $this->path = $fontPath; + $this->size = $size; + $this->foregroundColor = new BCGColor('black'); + $this->setRotationAngle(0); + } + + /** + * Gets the text associated to the font. + * + * @return string + */ + public function getText() + { + return $this->text; + } + + /** + * Sets the text associated to the font. + * + * @param string text + */ + public function setText($text) + { + $this->text = $text; + $this->fontInfo = null; + } + + /** + * Gets the rotation in degree. + * + * @return int + */ + public function getRotationAngle() + { + return (360 - $this->rotationAngle) % 360; + } + + /** + * Sets the rotation in degree. + * + * @param int + */ + public function setRotationAngle($rotationAngle) + { + $this->rotationAngle = (int)$rotationAngle; + if ($this->rotationAngle !== 90 && $this->rotationAngle !== 180 && $this->rotationAngle !== 270) { + $this->rotationAngle = 0; + } + + $this->rotationAngle = (360 - $this->rotationAngle) % 360; + + $this->fontInfo = null; + } + + /** + * Gets the background color. + * + * @return BCGColor + */ + public function getBackgroundColor() + { + } + + /** + * Sets the background color. + * + * @param BCGColor $backgroundColor + */ + public function setBackgroundColor($backgroundColor) + { + } + + /** + * Gets the foreground color. + * + * @return BCGColor + */ + public function getForegroundColor() + { + return $this->foregroundColor; + } + + /** + * Sets the foreground color. + * + * @param BCGColor $foregroundColor + */ + public function setForegroundColor($foregroundColor) + { + $this->foregroundColor = $foregroundColor; + } + + /** + * Returns the width and height that the text takes to be written. + * + * @return int[] + */ + public function getDimension() + { + $fontInfo = $this->getFontInfo(); + $rotationAngle = $this->getRotationAngle(); + $w = $fontInfo->getWidth(); + $h = $fontInfo->getHeight(); + if ($rotationAngle === 90 || $rotationAngle === 270) { + return array($h, $w); + } else { + return array($w, $h); + } + } + + /** + * Draws the text on the image at a specific position. + * $x and $y represent the left bottom corner. + * + * @param resource $im + * @param int $x + * @param int $y + */ + public function draw($im, $x, $y) + { + $drawingPosition = $this->getDrawingPosition($x, $y); + imagettftext($im, $this->size, $this->rotationAngle, $drawingPosition[0], $drawingPosition[1], $this->foregroundColor->allocate($im), $this->path, $this->text); + } + + private function getDrawingPosition($x, $y) + { + $fontInfo = $this->getFontInfo(); + $dimension = $this->getDimension(); + $rotationAngle = $this->getRotationAngle(); + + if ($rotationAngle === 0) { + $y += $fontInfo->getAscender(); + } elseif ($rotationAngle === 90) { + $x += $fontInfo->getDescender(); + } elseif ($rotationAngle === 180) { + $x += $dimension[0]; + $y += $fontInfo->getDescender(); + } elseif ($rotationAngle === 270) { + $x += $fontInfo->getAscender(); + $y += $dimension[1]; + } + + return array($x, $y); + } + + private function getFontInfo() + { + if ($this->fontInfo === null) { + $box = imagettfbbox($this->size, 0, $this->path, $this->text); + $this->fontInfo = new BCGFontInfo($box); + } + + return $this->fontInfo; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGFontPhp.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGFontPhp.php new file mode 100644 index 0000000..4e2ae7a --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGFontPhp.php @@ -0,0 +1,165 @@ +font = max(0, intval($font)); + $this->backgroundColor = new BCGColor('white'); + $this->foregroundColor = new BCGColor('black'); + $this->setRotationAngle(0); + } + + /** + * Gets the text associated to the font. + * + * @return string + */ + public function getText() + { + return $this->text; + } + + /** + * Sets the text associated to the font. + * + * @param string text + */ + public function setText($text) + { + $this->text = $text; + } + + /** + * Gets the rotation in degree. + * + * @return int + */ + public function getRotationAngle() + { + return (360 - $this->rotationAngle) % 360; + } + + /** + * Sets the rotation in degree. + * + * @param int + */ + public function setRotationAngle($rotationAngle) + { + $this->rotationAngle = (int)$rotationAngle; + if ($this->rotationAngle !== 90 && $this->rotationAngle !== 180 && $this->rotationAngle !== 270) { + $this->rotationAngle = 0; + } + + $this->rotationAngle = (360 - $this->rotationAngle) % 360; + } + + /** + * Gets the background color. + * + * @return BCGColor + */ + public function getBackgroundColor() + { + return $this->backgroundColor; + } + + /** + * Sets the background color. + * + * @param BCGColor $backgroundColor + */ + public function setBackgroundColor($backgroundColor) + { + $this->backgroundColor = $backgroundColor; + } + + /** + * Gets the foreground color. + * + * @return BCGColor + */ + public function getForegroundColor() + { + return $this->foregroundColor; + } + + /** + * Sets the foreground color. + * + * @param BCGColor $foregroundColor + */ + public function setForegroundColor($foregroundColor) + { + $this->foregroundColor = $foregroundColor; + } + + /** + * Returns the width and height that the text takes to be written. + * + * @return int[] + */ + public function getDimension() + { + $w = imagefontwidth($this->font) * strlen($this->text); + $h = imagefontheight($this->font); + + $rotationAngle = $this->getRotationAngle(); + if ($rotationAngle === 90 || $rotationAngle === 270) { + return array($h, $w); + } else { + return array($w, $h); + } + } + + /** + * Draws the text on the image at a specific position. + * $x and $y represent the left bottom corner. + * + * @param resource $im + * @param int $x + * @param int $y + */ + public function draw($im, $x, $y) + { + if ($this->getRotationAngle() !== 0) { + if (!function_exists('imagerotate')) { + throw new BCGDrawException('The method imagerotate doesn\'t exist on your server. Do not use any rotation.'); + } + + $w = imagefontwidth($this->font) * strlen($this->text); + $h = imagefontheight($this->font); + $gd = imagecreatetruecolor($w, $h); + imagefilledrectangle($gd, 0, 0, $w - 1, $h - 1, $this->backgroundColor->allocate($gd)); + imagestring($gd, $this->font, 0, 0, $this->text, $this->foregroundColor->allocate($gd)); + $gd = imagerotate($gd, $this->rotationAngle, 0); + imagecopy($im, $gd, $x, $y, 0, 0, imagesx($gd), imagesy($gd)); + } else { + imagestring($im, $this->font, $x, $y, $this->text, $this->foregroundColor->allocate($im)); + } + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGLabel.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGLabel.php new file mode 100644 index 0000000..e1219fb --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGLabel.php @@ -0,0 +1,341 @@ +setFont($font); + $this->setText($text); + $this->setPosition($position); + $this->setAlignment($alignment); + $this->setSpacing(4); + $this->setOffset(0); + $this->setRotationAngle(0); + $this->setBackgroundColor(new BCGColor('white')); + $this->setForegroundColor(new BCGColor('black')); + } + + /** + * Gets the text. + * + * @return string + */ + public function getText() + { + return $this->font->getText(); + } + + /** + * Sets the text. + * + * @param string $text + */ + public function setText($text) + { + $this->text = $text; + $this->font->setText($this->text); + } + + /** + * Gets the font. + * + * @return BCGFont + */ + public function getFont() + { + return $this->font; + } + + /** + * Sets the font. + * + * @param BCGFont $font + */ + public function setFont($font) + { + if ($font === null) { + throw new BCGArgumentException('Font cannot be null.', 'font'); + } + + $this->font = clone $font; + $this->font->setText($this->text); + $this->font->setRotationAngle($this->rotationAngle); + $this->font->setBackgroundColor($this->backgroundColor); + $this->font->setForegroundColor($this->foregroundColor); + } + + /** + * Gets the text position for drawing. + * + * @return int + */ + public function getPosition() + { + return $this->position; + } + + /** + * Sets the text position for drawing. + * + * @param int $position + */ + public function setPosition($position) + { + $position = intval($position); + if ($position !== self::POSITION_TOP && $position !== self::POSITION_RIGHT && $position !== self::POSITION_BOTTOM && $position !== self::POSITION_LEFT) { + throw new BCGArgumentException('The text position must be one of a valid constant.', 'position'); + } + + $this->position = $position; + } + + /** + * Gets the text alignment for drawing. + * + * @return int + */ + public function getAlignment() + { + return $this->alignment; + } + + /** + * Sets the text alignment for drawing. + * + * @param int $alignment + */ + public function setAlignment($alignment) + { + $alignment = intval($alignment); + if ($alignment !== self::ALIGN_LEFT && $alignment !== self::ALIGN_TOP && $alignment !== self::ALIGN_CENTER && $alignment !== self::ALIGN_RIGHT && $alignment !== self::ALIGN_BOTTOM) { + throw new BCGArgumentException('The text alignment must be one of a valid constant.', 'alignment'); + } + + $this->alignment = $alignment; + } + + /** + * Gets the offset. + * + * @return int + */ + public function getOffset() + { + return $this->offset; + } + + /** + * Sets the offset. + * + * @param int $offset + */ + public function setOffset($offset) + { + $this->offset = intval($offset); + } + + /** + * Gets the spacing. + * + * @return int + */ + public function getSpacing() + { + return $this->spacing; + } + + /** + * Sets the spacing. + * + * @param int $spacing + */ + public function setSpacing($spacing) + { + $this->spacing = max(0, intval($spacing)); + } + + /** + * Gets the rotation angle in degree. + * + * @return int + */ + public function getRotationAngle() + { + return $this->font->getRotationAngle(); + } + + /** + * Sets the rotation angle in degree. + * + * @param int $rotationAngle + */ + public function setRotationAngle($rotationAngle) + { + $this->rotationAngle = intval($rotationAngle); + $this->font->setRotationAngle($this->rotationAngle); + } + + /** + * Gets the background color in case of rotation. + * + * @return BCGColor + */ + public function getBackgroundColor() + { + return $this->backgroundColor; + } + + /** + * Sets the background color in case of rotation. + * + * @param BCGColor $backgroundColor + */ + public function setBackgroundColor($backgroundColor) + { + $this->backgroundColor = $backgroundColor; + $this->font->setBackgroundColor($this->backgroundColor); + } + + /** + * Gets the foreground color. + * + * @return BCGColor + */ + public function getForegroundColor() + { + return $this->font->getForegroundColor(); + } + + /** + * Sets the foreground color. + * + * @param BCGColor $foregroundColor + */ + public function setForegroundColor($foregroundColor) + { + $this->foregroundColor = $foregroundColor; + $this->font->setForegroundColor($this->foregroundColor); + } + + /** + * Gets the dimension taken by the label, including the spacing and offset. + * [0]: width + * [1]: height + * + * @return int[] + */ + public function getDimension() + { + $w = 0; + $h = 0; + + $dimension = $this->font->getDimension(); + $w = $dimension[0]; + $h = $dimension[1]; + + if ($this->position === self::POSITION_TOP || $this->position === self::POSITION_BOTTOM) { + $h += $this->spacing; + $w += max(0, $this->offset); + } else { + $w += $this->spacing; + $h += max(0, $this->offset); + } + + return array($w, $h); + } + + /** + * Draws the text. + * The coordinate passed are the positions of the barcode. + * $x1 and $y1 represent the top left corner. + * $x2 and $y2 represent the bottom right corner. + * + * @param resource $im + * @param int $x1 + * @param int $y1 + * @param int $x2 + * @param int $y2 + */ + public function draw($im, $x1, $y1, $x2, $y2) + { + $x = 0; + $y = 0; + + $fontDimension = $this->font->getDimension(); + + if ($this->position === self::POSITION_TOP || $this->position === self::POSITION_BOTTOM) { + if ($this->position === self::POSITION_TOP) { + $y = $y1 - $this->spacing - $fontDimension[1]; + } elseif ($this->position === self::POSITION_BOTTOM) { + $y = $y2 + $this->spacing; + } + + if ($this->alignment === self::ALIGN_CENTER) { + $x = (int)(($x2 - $x1) / 2 + $x1 - $fontDimension[0] / 2 + $this->offset); + } elseif ($this->alignment === self::ALIGN_LEFT) { + $x = $x1 + $this->offset; + } else { + $x = $x2 + $this->offset - $fontDimension[0]; + } + } else { + if ($this->position === self::POSITION_LEFT) { + $x = $x1 - $this->spacing - $fontDimension[0]; + } elseif ($this->position === self::POSITION_RIGHT) { + $x = $x2 + $this->spacing; + } + + if ($this->alignment === self::ALIGN_CENTER) { + $y = (int)(($y2 - $y1) / 2 + $y1 - $fontDimension[1] / 2 + $this->offset); + } elseif ($this->alignment === self::ALIGN_TOP) { + $y = $y1 + $this->offset; + } else { + $y = $y2 + $this->offset - $fontDimension[1]; + } + } + + $this->font->setText($this->text); + $this->font->draw($im, $x, $y); + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/BCGParseException.php b/serve/vendor/barcode-bakery/barcode-common/src/BCGParseException.php new file mode 100644 index 0000000..41587e1 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/BCGParseException.php @@ -0,0 +1,30 @@ +barcode = $barcode; + parent::__construct($message, 10000); + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/Drawer/BCGDraw.php b/serve/vendor/barcode-bakery/barcode-common/src/Drawer/BCGDraw.php new file mode 100644 index 0000000..c8be54e --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/Drawer/BCGDraw.php @@ -0,0 +1,44 @@ +im = $im; + } + + /** + * Sets the filename. + * + * @param string $filename + */ + public function setFilename($filename) + { + $this->filename = $filename; + } + + /** + * Method needed to draw the image based on its specification (JPG, GIF, etc.). + */ + abstract public function draw(); +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/Drawer/BCGDrawJPG.php b/serve/vendor/barcode-bakery/barcode-common/src/Drawer/BCGDrawJPG.php new file mode 100644 index 0000000..74aed75 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/Drawer/BCGDrawJPG.php @@ -0,0 +1,112 @@ +dpi = max(1, $dpi); + } else { + $this->dpi = null; + } + } + + /** + * Sets the quality of the JPG. + * + * @param int $quality + */ + public function setQuality($quality) + { + $this->quality = $quality; + } + + /** + * Draws the JPG on the screen or in a file. + */ + public function draw() + { + ob_start(); + imagejpeg($this->im, null, $this->quality); + $bin = ob_get_contents(); + ob_end_clean(); + + $this->setInternalProperties($bin); + + if (empty($this->filename)) { + echo $bin; + } else { + file_put_contents($this->filename, $bin); + } + } + + private function setInternalProperties(&$bin) + { + $this->internalSetDPI($bin); + $this->internalSetC($bin); + } + + private function internalSetDPI(&$bin) + { + if ($this->dpi !== null) { + $bin = substr_replace($bin, pack("Cnn", 0x01, $this->dpi, $this->dpi), 13, 5); + } + } + + private function internalSetC(&$bin) + { + if (strcmp(substr($bin, 0, 4), pack('H*', 'FFD8FFE0')) === 0) { + $offset = 4 + (ord($bin[4]) << 8 | ord($bin[5])); + $firstPart = substr($bin, 0, $offset); + $secondPart = substr($bin, $offset); + $cr = pack('H*', 'FFFE004447656E657261746564207769746820426172636F64652042616B65727920666F722050485020687474703A2F2F7777772E626172636F646562616B6572792E636F6D'); + $bin = $firstPart; + $bin .= $cr; + $bin .= $secondPart; + } + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/Drawer/BCGDrawPNG.php b/serve/vendor/barcode-bakery/barcode-common/src/Drawer/BCGDrawPNG.php new file mode 100644 index 0000000..4de44af --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/Drawer/BCGDrawPNG.php @@ -0,0 +1,216 @@ +dpi = max(1, $dpi); + } else { + $this->dpi = null; + } + } + + /** + * Draws the PNG on the screen or in a file. + */ + public function draw() + { + ob_start(); + imagepng($this->im); + $bin = ob_get_contents(); + ob_end_clean(); + + $this->setInternalProperties($bin); + + if (empty($this->filename)) { + echo $bin; + } else { + file_put_contents($this->filename, $bin); + } + } + + private function setInternalProperties(&$bin) + { + // Scan all the ChunkType + if (strcmp(substr($bin, 0, 8), pack('H*', '89504E470D0A1A0A')) === 0) { + $chunks = $this->detectChunks($bin); + + $this->internalSetDPI($bin, $chunks); + $this->internalSetC($bin, $chunks); + } + } + + private function detectChunks($bin) + { + $data = substr($bin, 8); + $chunks = array(); + $c = strlen($data); + + $offset = 0; + while ($offset < $c) { + $packed = unpack('Nsize/a4chunk', $data); + $size = $packed['size']; + $chunk = $packed['chunk']; + + $chunks[] = array('offset' => $offset + 8, 'size' => $size, 'chunk' => $chunk); + $jump = $size + 12; + $offset += $jump; + $data = substr($data, $jump); + } + + return $chunks; + } + + private function internalSetDPI(&$bin, &$chunks) + { + if ($this->dpi !== null) { + $meters = (int)($this->dpi * 39.37007874); + + $found = -1; + $c = count($chunks); + for ($i = 0; $i < $c; $i++) { + // We already have a pHYs + if ($chunks[$i]['chunk'] === 'pHYs') { + $found = $i; + break; + } + } + + $data = 'pHYs' . pack('NNC', $meters, $meters, 0x01); + $crc = self::crc($data, 13); + $cr = pack('Na13N', 9, $data, $crc); + + // We didn't have a pHYs + if ($found == -1) { + // Don't do anything if we have a bad PNG + if ($c >= 2 && $chunks[0]['chunk'] === 'IHDR') { + array_splice($chunks, 1, 0, array(array('offset' => 33, 'size' => 9, 'chunk' => 'pHYs'))); + + // Push the data + for ($i = 2; $i < $c; $i++) { + $chunks[$i]['offset'] += 21; + } + + $firstPart = substr($bin, 0, 33); + $secondPart = substr($bin, 33); + $bin = $firstPart; + $bin .= $cr; + $bin .= $secondPart; + } + } else { + $bin = substr_replace($bin, $cr, $chunks[$i]['offset'], 21); + } + } + } + + private function internalSetC(&$bin, &$chunks) + { + if (count($chunks) >= 2 && $chunks[0]['chunk'] === 'IHDR') { + $firstPart = substr($bin, 0, 33); + $secondPart = substr($bin, 33); + $cr = pack('H*', '0000004C74455874436F707972696768740047656E657261746564207769746820426172636F64652042616B65727920666F722050485020687474703A2F2F7777772E626172636F646562616B6572792E636F6DC57F50A1'); + $bin = $firstPart; + $bin .= $cr; + $bin .= $secondPart; + } + + // Chunks is dirty!! But we are done. + } + + private static $crc_table = array(); + private static $crc_table_computed = false; + + private static function make_crc_table() + { + for ($n = 0; $n < 256; $n++) { + $c = $n; + for ($k = 0; $k < 8; $k++) { + if (($c & 1) == 1) { + $c = 0xedb88320 ^ (self::SHR($c, 1)); + } else { + $c = self::SHR($c, 1); + } + } + self::$crc_table[$n] = $c; + } + + self::$crc_table_computed = true; + } + + private static function SHR($x, $n) + { + $mask = 0x40000000; + + if ($x < 0) { + $x &= 0x7FFFFFFF; + $mask = $mask >> ($n - 1); + return ($x >> $n) | $mask; + } + + return (int)$x >> (int)$n; + } + + private static function update_crc($crc, $buf, $len) + { + $c = $crc; + + if (!self::$crc_table_computed) { + self::make_crc_table(); + } + + for ($n = 0; $n < $len; $n++) { + $c = self::$crc_table[($c ^ ord($buf[$n])) & 0xff] ^ (self::SHR($c, 8)); + } + + return $c; + } + + private static function crc($data, $len) + { + return self::update_crc(-1, $data, $len) ^ -1; + } +} diff --git a/serve/vendor/barcode-bakery/barcode-common/src/Drawer/_generate.txt b/serve/vendor/barcode-bakery/barcode-common/src/Drawer/_generate.txt new file mode 100644 index 0000000..8ec98fe --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/Drawer/_generate.txt @@ -0,0 +1,114 @@ +> ($n - 1); + return ($x >> $n) | $mask; + } + + return (int)$x >> (int)$n; +} + +function update_crc($crc, $buf, $len) { + global $crc_table_computed, $crc_table; + + $c = $crc; + + if (!$crc_table_computed) { + make_crc_table(); + } + + for ($n = 0; $n < $len; $n++) { + $c = $crc_table[($c ^ ord($buf[$n])) & 0xff] ^ (SHR($c, 8)); + } + + return $c; +} + +function crc($data, $len) { + return update_crc(-1, $data, $len) ^ -1; +} + +/** + * Debug method only to display on the screen the hexadecimal of a file. + */ +function hex($bin) { + echo ''; + $c = strlen($bin); + $remember = ''; + for($i = 0; $i < $c;) { + for($j = 0; $j < 16; $j++, $i++) { + if($i < $c) { + $o = ord($bin[$i]); + $remember .= ($o >= 32 && $o <= 126) ? $bin[$i] : '.'; + printf('%02X ', ord($bin[$i])); + } else { + break 2; + } + } + echo '    '; + echo htmlentities($remember); + $remember = ''; + echo '
'; + } + + echo str_repeat('   ', 16 - ($i % 16)); + echo '    '; + echo htmlentities($remember); + echo '
'; +} + + +function createCode($code, $content) { + $contentLength = strlen($content); + return "\0\0\0" . chr($contentLength) . $code . $content . pack('N', crc($code . $content, $contentLength + 4)); +} + +// PNG: +$text = "Copyright\0Generated with Barcode Bakery for PHP http://www.barcodebakery.com"; +$encoded = createCode('tEXt', $text); +$unpacked = unpack('H*', $encoded); +$unpacked = $unpacked[1]; +echo '
'; +hex($encoded); +echo '
'; +echo strtoupper($unpacked); +echo '
'; +echo pack('H*', $unpacked); + +echo '


'; +// JPG: +$text = "Generated with Barcode Bakery for PHP http://www.barcodebakery.com"; +$length = strlen($text) + 2; +$encoded = chr(0xff) . chr(0xfe) . chr($length & 0xff00) . chr($length & 0x00ff) . $text; +$unpacked = unpack('H*', $encoded); +$unpacked = $unpacked[1]; +echo '
'; +hex($encoded); +echo '
'; +echo strtoupper($unpacked); +echo '
'; +echo pack('H*', $unpacked); diff --git a/serve/vendor/barcode-bakery/barcode-common/src/JoinDraw.php b/serve/vendor/barcode-bakery/barcode-common/src/JoinDraw.php new file mode 100644 index 0000000..a85b5c9 --- /dev/null +++ b/serve/vendor/barcode-bakery/barcode-common/src/JoinDraw.php @@ -0,0 +1,204 @@ +image1 = $image1->get_im(); + } else { + $this->image1 = $image1; + } + if ($image2 instanceof BCGDrawing) { + $this->image2 = $image2->get_im(); + } else { + $this->image2 = $image2; + } + + $this->background = $background; + $this->space = (int)$space; + $this->position = (int)$position; + $this->alignment = (int)$alignment; + + $this->createIm(); + } + + /** + * Destroys the image. + */ + public function __destruct() + { + imagedestroy($this->im); + } + + /** + * Finds the position where the barcode should be aligned. + * + * @param int $size1 + * @param int $size2 + * @param int $ailgnment + * @return int + */ + private function findPosition($size1, $size2, $alignment) + { + $rsize1 = max($size1, $size2); + $rsize2 = min($size1, $size2); + + if ($alignment === self::ALIGN_LEFT) { // Or TOP + return 0; + } elseif ($alignment === self::ALIGN_CENTER) { + return $rsize1 / 2 - $rsize2 / 2; + } else { // RIGHT or TOP + return $rsize1 - $rsize2; + } + } + + /** + * Change the alignments. + * + * @param int $alignment + * @return int + */ + private function changeAlignment($alignment) + { + if ($alignment === 0) { + return 1; + } elseif ($alignment === 1) { + return 0; + } else { + return 2; + } + } + + /** + * Creates the image. + */ + private function createIm() + { + $w1 = imagesx($this->image1); + $w2 = imagesx($this->image2); + $h1 = imagesy($this->image1); + $h2 = imagesy($this->image2); + + if ($this->position === self::POSITION_LEFT || $this->position === self::POSITION_RIGHT) { + $w = $w1 + $w2 + $this->space; + $h = max($h1, $h2); + } else { + $w = max($w1, $w2); + $h = $h1 + $h2 + $this->space; + } + + $this->im = imagecreatetruecolor($w, $h); + imagefill($this->im, 0, 0, $this->background->allocate($this->im)); + + // We start defining position of images + if ($this->position === self::POSITION_TOP) { + if ($w1 > $w2) { + $posX1 = 0; + $posX2 = $this->findPosition($w1, $w2, $this->alignment); + } else { + $a = $this->changeAlignment($this->alignment); + $posX1 = $this->findPosition($w1, $w2, $a); + $posX2 = 0; + } + + $posY2 = 0; + $posY1 = $h2 + $this->space; + } elseif ($this->position === self::POSITION_LEFT) { + if ($w1 > $w2) { + $posY1 = 0; + $posY2 = $this->findPosition($h1, $h2, $this->alignment); + } else { + $a = $this->changeAlignment($this->alignment); + $posY2 = 0; + $posY1 = $this->findPosition($h1, $h2, $a); + } + + $posX2 = 0; + $posX1 = $w2 + $this->space; + } elseif ($this->position === self::POSITION_BOTTOM) { + if ($w1 > $w2) { + $posX2 = $this->findPosition($w1, $w2, $this->alignment); + $posX1 = 0; + } else { + $a = $this->changeAlignment($this->alignment); + $posX2 = 0; + $posX1 = $this->findPosition($w1, $w2, $a); + } + + $posY1 = 0; + $posY2 = $h1 + $this->space; + } else { // defaults to RIGHT + if ($w1 > $w2) { + $posY2 = $this->findPosition($h1, $h2, $this->alignment); + $posY1 = 0; + } else { + $a = $this->changeAlignment($this->alignment); + $posY2 = 0; + $posY1 = $this->findPosition($h1, $h2, $a); + } + + $posX1 = 0; + $posX2 = $w1 + $this->space; + } + + imagecopy($this->im, $this->image1, $posX1, $posY1, 0, 0, $w1, $h1); + imagecopy($this->im, $this->image2, $posX2, $posY2, 0, 0, $w2, $h2); + } + + /** + * Returns the new $im created. + * + * @return resource + */ + public function get_im() + { + return $this->im; + } +} diff --git a/serve/vendor/composer/ClassLoader.php b/serve/vendor/composer/ClassLoader.php new file mode 100644 index 0000000..1a58957 --- /dev/null +++ b/serve/vendor/composer/ClassLoader.php @@ -0,0 +1,445 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/serve/vendor/composer/InstalledVersions.php b/serve/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..650726a --- /dev/null +++ b/serve/vendor/composer/InstalledVersions.php @@ -0,0 +1,718 @@ + + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => 'efa014cb2ddcd746897e68f1ddef6caf94c484f9', + 'name' => 'topthink/think', + ), + 'versions' => + array ( + 'adbario/php-dot-notation' => + array ( + 'pretty_version' => '2.2.0', + 'version' => '2.2.0.0', + 'aliases' => + array ( + ), + 'reference' => 'eee4fc81296531e6aafba4c2bbccfc5adab1676e', + ), + 'alibabacloud/tea' => + array ( + 'pretty_version' => '3.1.21', + 'version' => '3.1.21.0', + 'aliases' => + array ( + ), + 'reference' => '379faffe240ee97134cf3f796cb28059f9fb7fa9', + ), + 'alibabacloud/tea-fileform' => + array ( + 'pretty_version' => '0.3.4', + 'version' => '0.3.4.0', + 'aliases' => + array ( + ), + 'reference' => '4bf0c75a045c8115aa8cb1a394bd08d8bb833181', + ), + 'alipaysdk/easysdk' => + array ( + 'pretty_version' => '2.2.0', + 'version' => '2.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '7a1cfa83c7e140bded957498ea072c77611e6480', + ), + 'bacon/bacon-qr-code' => + array ( + 'pretty_version' => '2.0.3', + 'version' => '2.0.3.0', + 'aliases' => + array ( + ), + 'reference' => '3e9d791b67d0a2912922b7b7c7312f4b37af41e4', + ), + 'barcode-bakery/barcode-1d' => + array ( + 'pretty_version' => '6.0.0', + 'version' => '6.0.0.0', + 'aliases' => + array ( + ), + 'reference' => 'cd8c30d754d6595bfda13a0fa88e5033179d71f2', + ), + 'barcode-bakery/barcode-common' => + array ( + 'pretty_version' => '6.0.0', + 'version' => '6.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '289043a2fd5fc8e18c28f1565b50bfd21a712fbd', + ), + 'danielstjules/stringy' => + array ( + 'pretty_version' => '3.1.0', + 'version' => '3.1.0.0', + 'aliases' => + array ( + ), + 'reference' => 'df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e', + ), + 'dasprid/enum' => + array ( + 'pretty_version' => '1.0.3', + 'version' => '1.0.3.0', + 'aliases' => + array ( + ), + 'reference' => '5abf82f213618696dda8e3bf6f64dd042d8542b2', + ), + 'endroid/qr-code' => + array ( + 'pretty_version' => '3.9.7', + 'version' => '3.9.7.0', + 'aliases' => + array ( + ), + 'reference' => '94563d7b3105288e6ac53a67ae720e3669fac1f6', + ), + 'ezyang/htmlpurifier' => + array ( + 'pretty_version' => 'v4.13.0', + 'version' => '4.13.0.0', + 'aliases' => + array ( + ), + 'reference' => '08e27c97e4c6ed02f37c5b2b20488046c8d90d75', + ), + 'guzzlehttp/guzzle' => + array ( + 'pretty_version' => '7.3.0', + 'version' => '7.3.0.0', + 'aliases' => + array ( + ), + 'reference' => '7008573787b430c1c1f650e3722d9bba59967628', + ), + 'guzzlehttp/promises' => + array ( + 'pretty_version' => '1.4.1', + 'version' => '1.4.1.0', + 'aliases' => + array ( + ), + 'reference' => '8e7d04f1f6450fef59366c399cfad4b9383aa30d', + ), + 'guzzlehttp/psr7' => + array ( + 'pretty_version' => '1.8.2', + 'version' => '1.8.2.0', + 'aliases' => + array ( + ), + 'reference' => 'dc960a912984efb74d0a90222870c72c87f10c91', + ), + 'khanamiryan/qrcode-detector-decoder' => + array ( + 'pretty_version' => '1.0.5', + 'version' => '1.0.5.0', + 'aliases' => + array ( + ), + 'reference' => '6c8c23003a87ecd7458807cd49372b1fb590d1f5', + ), + 'league/flysystem' => + array ( + 'pretty_version' => '1.1.3', + 'version' => '1.1.3.0', + 'aliases' => + array ( + ), + 'reference' => '9be3b16c877d477357c015cec057548cf9b2a14a', + ), + 'league/flysystem-cached-adapter' => + array ( + 'pretty_version' => '1.1.0', + 'version' => '1.1.0.0', + 'aliases' => + array ( + ), + 'reference' => 'd1925efb2207ac4be3ad0c40b8277175f99ffaff', + ), + 'league/mime-type-detection' => + array ( + 'pretty_version' => '1.7.0', + 'version' => '1.7.0.0', + 'aliases' => + array ( + ), + 'reference' => '3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3', + ), + 'maennchen/zipstream-php' => + array ( + 'pretty_version' => '2.1.0', + 'version' => '2.1.0.0', + 'aliases' => + array ( + ), + 'reference' => 'c4c5803cc1f93df3d2448478ef79394a5981cc58', + ), + 'markbaker/complex' => + array ( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '9999f1432fae467bc93c53f357105b4c31bb994c', + ), + 'markbaker/matrix' => + array ( + 'pretty_version' => '2.1.2', + 'version' => '2.1.2.0', + 'aliases' => + array ( + ), + 'reference' => '361c0f545c3172ee26c3d596a0aa03f0cef65e6a', + ), + 'mtdowling/jmespath.php' => + array ( + 'pretty_version' => '2.6.0', + 'version' => '2.6.0.0', + 'aliases' => + array ( + ), + 'reference' => '42dae2cbd13154083ca6d70099692fef8ca84bfb', + ), + 'myclabs/php-enum' => + array ( + 'pretty_version' => '1.8.0', + 'version' => '1.8.0.0', + 'aliases' => + array ( + ), + 'reference' => '46cf3d8498b095bd33727b13fd5707263af99421', + ), + 'phpoffice/phpspreadsheet' => + array ( + 'pretty_version' => '1.17.1', + 'version' => '1.17.1.0', + 'aliases' => + array ( + ), + 'reference' => 'c55269cb06911575a126dc225a05c0e4626e5fb4', + ), + 'pimple/pimple' => + array ( + 'pretty_version' => 'v3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '86406047271859ffc13424a048541f4531f53601', + ), + 'psr/cache' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8', + ), + 'psr/container' => + array ( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'aliases' => + array ( + ), + 'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf', + ), + 'psr/http-client' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621', + ), + 'psr/http-client-implementation' => + array ( + 'provided' => + array ( + 0 => '1.0', + ), + ), + 'psr/http-factory' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be', + ), + 'psr/http-message' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', + ), + 'psr/http-message-implementation' => + array ( + 'provided' => + array ( + 0 => '1.0', + ), + ), + 'psr/log' => + array ( + 'pretty_version' => '1.1.3', + 'version' => '1.1.3.0', + 'aliases' => + array ( + ), + 'reference' => '0f73288fd15629204f9d42b7055f72dacbe811fc', + ), + 'psr/simple-cache' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', + ), + 'ralouphie/getallheaders' => + array ( + 'pretty_version' => '3.0.3', + 'version' => '3.0.3.0', + 'aliases' => + array ( + ), + 'reference' => '120b605dfeb996808c31b6477290a714d356e822', + ), + 'songshenzong/support' => + array ( + 'pretty_version' => '2.0.5', + 'version' => '2.0.5.0', + 'aliases' => + array ( + ), + 'reference' => '34973c04ffcf226e503f1c3a69d30ac49f7621f6', + ), + 'symfony/deprecation-contracts' => + array ( + 'pretty_version' => 'v2.4.0', + 'version' => '2.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '5f38c8804a9e97d23e0c8d63341088cd8a22d627', + ), + 'symfony/options-resolver' => + array ( + 'pretty_version' => 'v5.2.4', + 'version' => '5.2.4.0', + 'aliases' => + array ( + ), + 'reference' => '5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce', + ), + 'symfony/polyfill-ctype' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => 'c6c942b1ac76c82448322025e084cadc56048b4e', + ), + 'symfony/polyfill-intl-grapheme' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => '5601e09b69f26c1828b13b6bb87cb07cddba3170', + ), + 'symfony/polyfill-intl-normalizer' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => '43a0283138253ed1d48d352ab6d0bdb3f809f248', + ), + 'symfony/polyfill-mbstring' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => '5232de97ee3b75b0360528dae24e73db49566ab1', + ), + 'symfony/polyfill-php72' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => 'cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9', + ), + 'symfony/polyfill-php73' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => 'a678b42e92f86eca04b7fa4c0f6f19d097fb69e2', + ), + 'symfony/polyfill-php80' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => 'dc3063ba22c2a1fd2f45ed856374d79114998f91', + ), + 'symfony/property-access' => + array ( + 'pretty_version' => 'v5.2.4', + 'version' => '5.2.4.0', + 'aliases' => + array ( + ), + 'reference' => '3af8ed262bd3217512a13b023981fe68f36ad5f3', + ), + 'symfony/property-info' => + array ( + 'pretty_version' => 'v5.2.4', + 'version' => '5.2.4.0', + 'aliases' => + array ( + ), + 'reference' => '7185bbc74e6f49c3f1b5936b4d9e4ca133921189', + ), + 'symfony/string' => + array ( + 'pretty_version' => 'v5.2.6', + 'version' => '5.2.6.0', + 'aliases' => + array ( + ), + 'reference' => 'ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572', + ), + 'symfony/var-dumper' => + array ( + 'pretty_version' => 'v4.4.21', + 'version' => '4.4.21.0', + 'aliases' => + array ( + ), + 'reference' => '0da0e174f728996f5d5072d6a9f0a42259dbc806', + ), + 'topthink/framework' => + array ( + 'pretty_version' => 'v6.0.8', + 'version' => '6.0.8.0', + 'aliases' => + array ( + ), + 'reference' => '4789343672aef06d571d556da369c0e156609bce', + ), + 'topthink/think' => + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => 'efa014cb2ddcd746897e68f1ddef6caf94c484f9', + ), + 'topthink/think-helper' => + array ( + 'pretty_version' => 'v3.1.4', + 'version' => '3.1.4.0', + 'aliases' => + array ( + ), + 'reference' => 'c28d37743bda4a0455286ca85b17b5791d626e10', + ), + 'topthink/think-orm' => + array ( + 'pretty_version' => 'v2.0.40', + 'version' => '2.0.40.0', + 'aliases' => + array ( + ), + 'reference' => '1119d979b850849f3725856460cf108eec1c3eb8', + ), + 'topthink/think-template' => + array ( + 'pretty_version' => 'v2.0.8', + 'version' => '2.0.8.0', + 'aliases' => + array ( + ), + 'reference' => 'abfc293f74f9ef5127b5c416310a01fe42e59368', + ), + 'topthink/think-trace' => + array ( + 'pretty_version' => 'v1.4', + 'version' => '1.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '9a9fa8f767b6c66c5a133ad21ca1bc96ad329444', + ), + 'topthink/think-view' => + array ( + 'pretty_version' => 'v1.0.14', + 'version' => '1.0.14.0', + 'aliases' => + array ( + ), + 'reference' => 'edce0ae2c9551ab65f9e94a222604b0dead3576d', + ), + 'xin/container' => + array ( + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '97bb67f87dd851545938a1f2fe0ffbd379e3ff81', + ), + 'xin/helper' => + array ( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '02a58132dae2aea2d1c0b8e66f55125969224747', + ), + ), +); + + + + + + + +public static function getInstalledPackages() +{ +return array_keys(self::$installed['versions']); +} + + + + + + + + + +public static function isInstalled($packageName) +{ +return isset(self::$installed['versions'][$packageName]); +} + + + + + + + + + + + + + + +public static function satisfies(VersionParser $parser, $packageName, $constraint) +{ +$constraint = $parser->parseConstraints($constraint); +$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + +return $provided->matches($constraint); +} + + + + + + + + + + +public static function getVersionRanges($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +$ranges = array(); +if (isset(self::$installed['versions'][$packageName]['pretty_version'])) { +$ranges[] = self::$installed['versions'][$packageName]['pretty_version']; +} +if (array_key_exists('aliases', self::$installed['versions'][$packageName])) { +$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']); +} +if (array_key_exists('replaced', self::$installed['versions'][$packageName])) { +$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']); +} +if (array_key_exists('provided', self::$installed['versions'][$packageName])) { +$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']); +} + +return implode(' || ', $ranges); +} + + + + + +public static function getVersion($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +if (!isset(self::$installed['versions'][$packageName]['version'])) { +return null; +} + +return self::$installed['versions'][$packageName]['version']; +} + + + + + +public static function getPrettyVersion($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) { +return null; +} + +return self::$installed['versions'][$packageName]['pretty_version']; +} + + + + + +public static function getReference($packageName) +{ +if (!isset(self::$installed['versions'][$packageName])) { +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + +if (!isset(self::$installed['versions'][$packageName]['reference'])) { +return null; +} + +return self::$installed['versions'][$packageName]['reference']; +} + + + + + +public static function getRootPackage() +{ +return self::$installed['root']; +} + + + + + + + +public static function getRawData() +{ +return self::$installed; +} + + + + + + + + + + + + + + + + + + + +public static function reload($data) +{ +self::$installed = $data; +} +} diff --git a/serve/vendor/composer/LICENSE b/serve/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/serve/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/serve/vendor/composer/autoload_classmap.php b/serve/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..83006fa --- /dev/null +++ b/serve/vendor/composer/autoload_classmap.php @@ -0,0 +1,16 @@ + $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', + 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', +); diff --git a/serve/vendor/composer/autoload_files.php b/serve/vendor/composer/autoload_files.php new file mode 100644 index 0000000..4f61bf8 --- /dev/null +++ b/serve/vendor/composer/autoload_files.php @@ -0,0 +1,90 @@ + $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', + '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', + 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', + 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', + 'd767e4fc2dc52fe66584ab8c6684783e' => $vendorDir . '/adbario/php-dot-notation/src/helpers.php', + '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', + '9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', + '65fec9ebcfbb3cbb4fd0d519687aea01' => $vendorDir . '/danielstjules/stringy/src/Create.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', + '35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php', + '2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', + 'abede361264e2ae69ec1eee813a101af' => $vendorDir . '/markbaker/complex/classes/src/functions/abs.php', + '21a5860fbef5be28db5ddfbc3cca67c4' => $vendorDir . '/markbaker/complex/classes/src/functions/acos.php', + '1546e3f9d127f2a9bb2d1b6c31c26ef1' => $vendorDir . '/markbaker/complex/classes/src/functions/acosh.php', + 'd2516f7f4fba5ea5905f494b4a8262e0' => $vendorDir . '/markbaker/complex/classes/src/functions/acot.php', + '4511163d560956219b96882c0980b65e' => $vendorDir . '/markbaker/complex/classes/src/functions/acoth.php', + 'c361f5616dc2a8da4fa3e137077cd4ea' => $vendorDir . '/markbaker/complex/classes/src/functions/acsc.php', + '02d68920fc98da71991ce569c91df0f6' => $vendorDir . '/markbaker/complex/classes/src/functions/acsch.php', + '88e19525eae308b4a6aa3419364875d3' => $vendorDir . '/markbaker/complex/classes/src/functions/argument.php', + '60e8e2d0827b58bfc904f13957e51849' => $vendorDir . '/markbaker/complex/classes/src/functions/asec.php', + '13d2f040713999eab66c359b4d79871d' => $vendorDir . '/markbaker/complex/classes/src/functions/asech.php', + '838ab38beb32c68a79d3cd2c007d5a04' => $vendorDir . '/markbaker/complex/classes/src/functions/asin.php', + 'bb28eccd0f8f008333a1b3c163d604ac' => $vendorDir . '/markbaker/complex/classes/src/functions/asinh.php', + '9e483de83558c98f7d3feaa402c78cb3' => $vendorDir . '/markbaker/complex/classes/src/functions/atan.php', + '36b74b5b765ded91ee58c8ee3c0e85e3' => $vendorDir . '/markbaker/complex/classes/src/functions/atanh.php', + '05c15ee9510da7fd6bf6136f436500c0' => $vendorDir . '/markbaker/complex/classes/src/functions/conjugate.php', + 'd3208dfbce2505e370788f9f22f6785f' => $vendorDir . '/markbaker/complex/classes/src/functions/cos.php', + '141cf1fb3a3046f8b64534b0ebab33ca' => $vendorDir . '/markbaker/complex/classes/src/functions/cosh.php', + 'be660df75fd0dbe7fa7c03b7434b3294' => $vendorDir . '/markbaker/complex/classes/src/functions/cot.php', + '01e31ea298a51bc9e91517e3ce6b9e76' => $vendorDir . '/markbaker/complex/classes/src/functions/coth.php', + '803ddd97f7b1da68982a7b087c3476f6' => $vendorDir . '/markbaker/complex/classes/src/functions/csc.php', + '3001cdfd101ec3c32da34ee43c2e149b' => $vendorDir . '/markbaker/complex/classes/src/functions/csch.php', + '77b2d7629ef2a93fabb8c56754a91051' => $vendorDir . '/markbaker/complex/classes/src/functions/exp.php', + '4a4471296dec796c21d4f4b6552396a9' => $vendorDir . '/markbaker/complex/classes/src/functions/inverse.php', + 'c3e9897e1744b88deb56fcdc39d34d85' => $vendorDir . '/markbaker/complex/classes/src/functions/ln.php', + 'a83cacf2de942cff288de15a83afd26d' => $vendorDir . '/markbaker/complex/classes/src/functions/log2.php', + '6a861dacc9ee2f3061241d4c7772fa21' => $vendorDir . '/markbaker/complex/classes/src/functions/log10.php', + '4d2522d968c8ba78d6c13548a1b4200e' => $vendorDir . '/markbaker/complex/classes/src/functions/negative.php', + 'fd587ca933fc0447fa5ab4843bdd97f7' => $vendorDir . '/markbaker/complex/classes/src/functions/pow.php', + '383ef01c62028fc78cd4388082fce3c2' => $vendorDir . '/markbaker/complex/classes/src/functions/rho.php', + '150fbd1b95029dc47292da97ecab9375' => $vendorDir . '/markbaker/complex/classes/src/functions/sec.php', + '549abd9bae174286d660bdaa07407c68' => $vendorDir . '/markbaker/complex/classes/src/functions/sech.php', + '6bfbf5eaea6b17a0ed85cb21ba80370c' => $vendorDir . '/markbaker/complex/classes/src/functions/sin.php', + '22efe13f1a497b8e199540ae2d9dc59c' => $vendorDir . '/markbaker/complex/classes/src/functions/sinh.php', + 'e90135ab8e787795a509ed7147de207d' => $vendorDir . '/markbaker/complex/classes/src/functions/sqrt.php', + 'bb0a7923ffc6a90919cd64ec54ff06bc' => $vendorDir . '/markbaker/complex/classes/src/functions/tan.php', + '2d302f32ce0fd4e433dd91c5bb404a28' => $vendorDir . '/markbaker/complex/classes/src/functions/tanh.php', + '24dd4658a952171a4ee79218c4f9fd06' => $vendorDir . '/markbaker/complex/classes/src/functions/theta.php', + 'e49b7876281d6f5bc39536dde96d1f4a' => $vendorDir . '/markbaker/complex/classes/src/operations/add.php', + '47596e02b43cd6da7700134fd08f88cf' => $vendorDir . '/markbaker/complex/classes/src/operations/subtract.php', + '883af48563631547925fa4c3b48ead07' => $vendorDir . '/markbaker/complex/classes/src/operations/multiply.php', + 'f190e3308e6ca23234a2875edc985c03' => $vendorDir . '/markbaker/complex/classes/src/operations/divideby.php', + 'ac9e33ce6841aa5bf5d16d465a2f03a7' => $vendorDir . '/markbaker/complex/classes/src/operations/divideinto.php', + '3af723442581d6c310bf44543f9f5c60' => $vendorDir . '/markbaker/matrix/classes/src/Functions/adjoint.php', + 'd803221834c8b57fec95debb5406a797' => $vendorDir . '/markbaker/matrix/classes/src/Functions/antidiagonal.php', + '4714cafbd3be4c72c274a25eae9396bb' => $vendorDir . '/markbaker/matrix/classes/src/Functions/cofactors.php', + '89719dc7c77436609d1c1c31f0797b8f' => $vendorDir . '/markbaker/matrix/classes/src/Functions/determinant.php', + 'c28af79ec7730859d83f2d4310b8dd0b' => $vendorDir . '/markbaker/matrix/classes/src/Functions/diagonal.php', + 'c5d82bf1ac485e445f911e55789ab4e6' => $vendorDir . '/markbaker/matrix/classes/src/Functions/identity.php', + '0d2d594de24a247f7a33499e933aa21e' => $vendorDir . '/markbaker/matrix/classes/src/Functions/inverse.php', + 'f37c25880804a014ef40c8bffbab1b10' => $vendorDir . '/markbaker/matrix/classes/src/Functions/minors.php', + 'd6e4e42171df0dbea253b3067fefda38' => $vendorDir . '/markbaker/matrix/classes/src/Functions/trace.php', + '2c9b19fa954fd3e6fcc7e7a1383caddd' => $vendorDir . '/markbaker/matrix/classes/src/Functions/transpose.php', + '0a538fc9b897450ec362480ebbebe94f' => $vendorDir . '/markbaker/matrix/classes/src/Operations/add.php', + 'f0843f7f4089ec2343c7445544356385' => $vendorDir . '/markbaker/matrix/classes/src/Operations/directsum.php', + 'ad3e8c29aa16d134661a414265677b61' => $vendorDir . '/markbaker/matrix/classes/src/Operations/subtract.php', + '8d37dad4703fab45bfec9dd0bbf3278e' => $vendorDir . '/markbaker/matrix/classes/src/Operations/multiply.php', + '4888a6f58c08148ebe17682f9ce9b2a8' => $vendorDir . '/markbaker/matrix/classes/src/Operations/divideby.php', + 'eef6fa3879d3efa347cd24d5eb348f85' => $vendorDir . '/markbaker/matrix/classes/src/Operations/divideinto.php', + 'b067bc7112e384b61c701452d53a14a8' => $vendorDir . '/mtdowling/jmespath.php/src/JmesPath.php', + '0d0b82117c23db94c492fee02b2ed01f' => $vendorDir . '/songshenzong/support/src/StringsHelpers.php', + 'd96a90b43bcdea846705672ffd4e9294' => $vendorDir . '/songshenzong/support/src/BashEchoHelpers.php', + 'a9ed0d27b5a698798a89181429f162c5' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Common/customFunctions.php', +); diff --git a/serve/vendor/composer/autoload_namespaces.php b/serve/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..1f254da --- /dev/null +++ b/serve/vendor/composer/autoload_namespaces.php @@ -0,0 +1,12 @@ + array($vendorDir . '/pimple/pimple/src'), + 'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'), + '' => array($baseDir . '/extend'), +); diff --git a/serve/vendor/composer/autoload_psr4.php b/serve/vendor/composer/autoload_psr4.php new file mode 100644 index 0000000..b3e3d39 --- /dev/null +++ b/serve/vendor/composer/autoload_psr4.php @@ -0,0 +1,57 @@ + array($vendorDir . '/xin/helper/src'), + 'xin\\container\\' => array($vendorDir . '/xin/container/src'), + 'think\\view\\driver\\' => array($vendorDir . '/topthink/think-view/src'), + 'think\\trace\\' => array($vendorDir . '/topthink/think-trace/src'), + 'think\\' => array($vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-template/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/framework/src/think'), + 'app\\' => array($baseDir . '/app'), + 'Zxing\\' => array($vendorDir . '/khanamiryan/qrcode-detector-decoder/lib'), + 'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'), + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), + 'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'), + 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), + 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'), + 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), + 'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'), + 'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'), + 'Symfony\\Component\\PropertyInfo\\' => array($vendorDir . '/symfony/property-info'), + 'Symfony\\Component\\PropertyAccess\\' => array($vendorDir . '/symfony/property-access'), + 'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'), + 'Stringy\\' => array($vendorDir . '/danielstjules/stringy/src'), + 'Songshenzong\\Support\\' => array($vendorDir . '/songshenzong/support/src'), + 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), + 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), + 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), + 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), + 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'), + 'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'), + 'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'), + 'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'), + 'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'), + 'League\\Flysystem\\Cached\\' => array($vendorDir . '/league/flysystem-cached-adapter/src'), + 'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), + 'JmesPath\\' => array($vendorDir . '/mtdowling/jmespath.php/src'), + 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), + 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), + 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), + 'Endroid\\QrCode\\' => array($vendorDir . '/endroid/qr-code/src'), + 'DASPRiD\\Enum\\' => array($vendorDir . '/dasprid/enum/src'), + 'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'), + 'BarcodeBakery\\Common\\' => array($vendorDir . '/barcode-bakery/barcode-common/src'), + 'BarcodeBakery\\Barcode\\' => array($vendorDir . '/barcode-bakery/barcode-1d/src'), + 'BaconQrCode\\' => array($vendorDir . '/bacon/bacon-qr-code/src'), + 'Alipay\\EasySDK\\' => array($vendorDir . '/alipaysdk/easysdk/php/src'), + 'AlibabaCloud\\Tea\\FileForm\\' => array($vendorDir . '/alibabacloud/tea-fileform/src'), + 'AlibabaCloud\\Tea\\' => array($vendorDir . '/alibabacloud/tea/src'), + 'Adbar\\' => array($vendorDir . '/adbario/php-dot-notation/src'), +); diff --git a/serve/vendor/composer/autoload_real.php b/serve/vendor/composer/autoload_real.php new file mode 100644 index 0000000..77a19ca --- /dev/null +++ b/serve/vendor/composer/autoload_real.php @@ -0,0 +1,75 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit90b856d7abf7e0eea063f6ff76390209::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInit90b856d7abf7e0eea063f6ff76390209::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequire90b856d7abf7e0eea063f6ff76390209($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequire90b856d7abf7e0eea063f6ff76390209($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/serve/vendor/composer/autoload_static.php b/serve/vendor/composer/autoload_static.php new file mode 100644 index 0000000..027341d --- /dev/null +++ b/serve/vendor/composer/autoload_static.php @@ -0,0 +1,430 @@ + __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', + 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', + 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', + 'd767e4fc2dc52fe66584ab8c6684783e' => __DIR__ . '/..' . '/adbario/php-dot-notation/src/helpers.php', + '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', + '9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', + 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', + '65fec9ebcfbb3cbb4fd0d519687aea01' => __DIR__ . '/..' . '/danielstjules/stringy/src/Create.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', + '35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php', + '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', + 'abede361264e2ae69ec1eee813a101af' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/abs.php', + '21a5860fbef5be28db5ddfbc3cca67c4' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acos.php', + '1546e3f9d127f2a9bb2d1b6c31c26ef1' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acosh.php', + 'd2516f7f4fba5ea5905f494b4a8262e0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acot.php', + '4511163d560956219b96882c0980b65e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acoth.php', + 'c361f5616dc2a8da4fa3e137077cd4ea' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsc.php', + '02d68920fc98da71991ce569c91df0f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsch.php', + '88e19525eae308b4a6aa3419364875d3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/argument.php', + '60e8e2d0827b58bfc904f13957e51849' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asec.php', + '13d2f040713999eab66c359b4d79871d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asech.php', + '838ab38beb32c68a79d3cd2c007d5a04' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asin.php', + 'bb28eccd0f8f008333a1b3c163d604ac' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asinh.php', + '9e483de83558c98f7d3feaa402c78cb3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atan.php', + '36b74b5b765ded91ee58c8ee3c0e85e3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atanh.php', + '05c15ee9510da7fd6bf6136f436500c0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/conjugate.php', + 'd3208dfbce2505e370788f9f22f6785f' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cos.php', + '141cf1fb3a3046f8b64534b0ebab33ca' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cosh.php', + 'be660df75fd0dbe7fa7c03b7434b3294' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cot.php', + '01e31ea298a51bc9e91517e3ce6b9e76' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/coth.php', + '803ddd97f7b1da68982a7b087c3476f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csc.php', + '3001cdfd101ec3c32da34ee43c2e149b' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csch.php', + '77b2d7629ef2a93fabb8c56754a91051' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/exp.php', + '4a4471296dec796c21d4f4b6552396a9' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/inverse.php', + 'c3e9897e1744b88deb56fcdc39d34d85' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/ln.php', + 'a83cacf2de942cff288de15a83afd26d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log2.php', + '6a861dacc9ee2f3061241d4c7772fa21' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log10.php', + '4d2522d968c8ba78d6c13548a1b4200e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/negative.php', + 'fd587ca933fc0447fa5ab4843bdd97f7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/pow.php', + '383ef01c62028fc78cd4388082fce3c2' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/rho.php', + '150fbd1b95029dc47292da97ecab9375' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sec.php', + '549abd9bae174286d660bdaa07407c68' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sech.php', + '6bfbf5eaea6b17a0ed85cb21ba80370c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sin.php', + '22efe13f1a497b8e199540ae2d9dc59c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sinh.php', + 'e90135ab8e787795a509ed7147de207d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sqrt.php', + 'bb0a7923ffc6a90919cd64ec54ff06bc' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tan.php', + '2d302f32ce0fd4e433dd91c5bb404a28' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tanh.php', + '24dd4658a952171a4ee79218c4f9fd06' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/theta.php', + 'e49b7876281d6f5bc39536dde96d1f4a' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/add.php', + '47596e02b43cd6da7700134fd08f88cf' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/subtract.php', + '883af48563631547925fa4c3b48ead07' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/multiply.php', + 'f190e3308e6ca23234a2875edc985c03' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideby.php', + 'ac9e33ce6841aa5bf5d16d465a2f03a7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideinto.php', + '3af723442581d6c310bf44543f9f5c60' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/adjoint.php', + 'd803221834c8b57fec95debb5406a797' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/antidiagonal.php', + '4714cafbd3be4c72c274a25eae9396bb' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/cofactors.php', + '89719dc7c77436609d1c1c31f0797b8f' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/determinant.php', + 'c28af79ec7730859d83f2d4310b8dd0b' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/diagonal.php', + 'c5d82bf1ac485e445f911e55789ab4e6' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/identity.php', + '0d2d594de24a247f7a33499e933aa21e' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/inverse.php', + 'f37c25880804a014ef40c8bffbab1b10' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/minors.php', + 'd6e4e42171df0dbea253b3067fefda38' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/trace.php', + '2c9b19fa954fd3e6fcc7e7a1383caddd' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Functions/transpose.php', + '0a538fc9b897450ec362480ebbebe94f' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/add.php', + 'f0843f7f4089ec2343c7445544356385' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/directsum.php', + 'ad3e8c29aa16d134661a414265677b61' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/subtract.php', + '8d37dad4703fab45bfec9dd0bbf3278e' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/multiply.php', + '4888a6f58c08148ebe17682f9ce9b2a8' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/divideby.php', + 'eef6fa3879d3efa347cd24d5eb348f85' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/Operations/divideinto.php', + 'b067bc7112e384b61c701452d53a14a8' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/JmesPath.php', + '0d0b82117c23db94c492fee02b2ed01f' => __DIR__ . '/..' . '/songshenzong/support/src/StringsHelpers.php', + 'd96a90b43bcdea846705672ffd4e9294' => __DIR__ . '/..' . '/songshenzong/support/src/BashEchoHelpers.php', + 'a9ed0d27b5a698798a89181429f162c5' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Common/customFunctions.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'x' => + array ( + 'xin\\helper\\' => 11, + 'xin\\container\\' => 14, + ), + 't' => + array ( + 'think\\view\\driver\\' => 18, + 'think\\trace\\' => 12, + 'think\\' => 6, + ), + 'a' => + array ( + 'app\\' => 4, + ), + 'Z' => + array ( + 'Zxing\\' => 6, + 'ZipStream\\' => 10, + ), + 'S' => + array ( + 'Symfony\\Polyfill\\Php80\\' => 23, + 'Symfony\\Polyfill\\Php73\\' => 23, + 'Symfony\\Polyfill\\Php72\\' => 23, + 'Symfony\\Polyfill\\Mbstring\\' => 26, + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => 31, + 'Symfony\\Polyfill\\Ctype\\' => 23, + 'Symfony\\Component\\VarDumper\\' => 28, + 'Symfony\\Component\\String\\' => 25, + 'Symfony\\Component\\PropertyInfo\\' => 31, + 'Symfony\\Component\\PropertyAccess\\' => 33, + 'Symfony\\Component\\OptionsResolver\\' => 34, + 'Stringy\\' => 8, + 'Songshenzong\\Support\\' => 21, + ), + 'P' => + array ( + 'Psr\\SimpleCache\\' => 16, + 'Psr\\Log\\' => 8, + 'Psr\\Http\\Message\\' => 17, + 'Psr\\Http\\Client\\' => 16, + 'Psr\\Container\\' => 14, + 'Psr\\Cache\\' => 10, + 'PhpOffice\\PhpSpreadsheet\\' => 25, + ), + 'M' => + array ( + 'MyCLabs\\Enum\\' => 13, + 'Matrix\\' => 7, + ), + 'L' => + array ( + 'League\\MimeTypeDetection\\' => 25, + 'League\\Flysystem\\Cached\\' => 24, + 'League\\Flysystem\\' => 17, + ), + 'J' => + array ( + 'JmesPath\\' => 9, + ), + 'G' => + array ( + 'GuzzleHttp\\Psr7\\' => 16, + 'GuzzleHttp\\Promise\\' => 19, + 'GuzzleHttp\\' => 11, + ), + 'E' => + array ( + 'Endroid\\QrCode\\' => 15, + ), + 'D' => + array ( + 'DASPRiD\\Enum\\' => 13, + ), + 'C' => + array ( + 'Complex\\' => 8, + ), + 'B' => + array ( + 'BarcodeBakery\\Common\\' => 21, + 'BarcodeBakery\\Barcode\\' => 22, + 'BaconQrCode\\' => 12, + ), + 'A' => + array ( + 'Alipay\\EasySDK\\' => 15, + 'AlibabaCloud\\Tea\\FileForm\\' => 26, + 'AlibabaCloud\\Tea\\' => 17, + 'Adbar\\' => 6, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'xin\\helper\\' => + array ( + 0 => __DIR__ . '/..' . '/xin/helper/src', + ), + 'xin\\container\\' => + array ( + 0 => __DIR__ . '/..' . '/xin/container/src', + ), + 'think\\view\\driver\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/think-view/src', + ), + 'think\\trace\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/think-trace/src', + ), + 'think\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/think-helper/src', + 1 => __DIR__ . '/..' . '/topthink/think-template/src', + 2 => __DIR__ . '/..' . '/topthink/think-orm/src', + 3 => __DIR__ . '/..' . '/topthink/framework/src/think', + ), + 'app\\' => + array ( + 0 => __DIR__ . '/../..' . '/app', + ), + 'Zxing\\' => + array ( + 0 => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib', + ), + 'ZipStream\\' => + array ( + 0 => __DIR__ . '/..' . '/maennchen/zipstream-php/src', + ), + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), + 'Symfony\\Polyfill\\Php73\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php73', + ), + 'Symfony\\Polyfill\\Php72\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', + ), + 'Symfony\\Polyfill\\Mbstring\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', + ), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer', + ), + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme', + ), + 'Symfony\\Polyfill\\Ctype\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', + ), + 'Symfony\\Component\\VarDumper\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/var-dumper', + ), + 'Symfony\\Component\\String\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/string', + ), + 'Symfony\\Component\\PropertyInfo\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/property-info', + ), + 'Symfony\\Component\\PropertyAccess\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/property-access', + ), + 'Symfony\\Component\\OptionsResolver\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/options-resolver', + ), + 'Stringy\\' => + array ( + 0 => __DIR__ . '/..' . '/danielstjules/stringy/src', + ), + 'Songshenzong\\Support\\' => + array ( + 0 => __DIR__ . '/..' . '/songshenzong/support/src', + ), + 'Psr\\SimpleCache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/simple-cache/src', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', + ), + 'Psr\\Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-factory/src', + 1 => __DIR__ . '/..' . '/psr/http-message/src', + ), + 'Psr\\Http\\Client\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-client/src', + ), + 'Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), + 'Psr\\Cache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/cache/src', + ), + 'PhpOffice\\PhpSpreadsheet\\' => + array ( + 0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet', + ), + 'MyCLabs\\Enum\\' => + array ( + 0 => __DIR__ . '/..' . '/myclabs/php-enum/src', + ), + 'Matrix\\' => + array ( + 0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src', + ), + 'League\\MimeTypeDetection\\' => + array ( + 0 => __DIR__ . '/..' . '/league/mime-type-detection/src', + ), + 'League\\Flysystem\\Cached\\' => + array ( + 0 => __DIR__ . '/..' . '/league/flysystem-cached-adapter/src', + ), + 'League\\Flysystem\\' => + array ( + 0 => __DIR__ . '/..' . '/league/flysystem/src', + ), + 'JmesPath\\' => + array ( + 0 => __DIR__ . '/..' . '/mtdowling/jmespath.php/src', + ), + 'GuzzleHttp\\Psr7\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', + ), + 'GuzzleHttp\\Promise\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/promises/src', + ), + 'GuzzleHttp\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src', + ), + 'Endroid\\QrCode\\' => + array ( + 0 => __DIR__ . '/..' . '/endroid/qr-code/src', + ), + 'DASPRiD\\Enum\\' => + array ( + 0 => __DIR__ . '/..' . '/dasprid/enum/src', + ), + 'Complex\\' => + array ( + 0 => __DIR__ . '/..' . '/markbaker/complex/classes/src', + ), + 'BarcodeBakery\\Common\\' => + array ( + 0 => __DIR__ . '/..' . '/barcode-bakery/barcode-common/src', + ), + 'BarcodeBakery\\Barcode\\' => + array ( + 0 => __DIR__ . '/..' . '/barcode-bakery/barcode-1d/src', + ), + 'BaconQrCode\\' => + array ( + 0 => __DIR__ . '/..' . '/bacon/bacon-qr-code/src', + ), + 'Alipay\\EasySDK\\' => + array ( + 0 => __DIR__ . '/..' . '/alipaysdk/easysdk/php/src', + ), + 'AlibabaCloud\\Tea\\FileForm\\' => + array ( + 0 => __DIR__ . '/..' . '/alibabacloud/tea-fileform/src', + ), + 'AlibabaCloud\\Tea\\' => + array ( + 0 => __DIR__ . '/..' . '/alibabacloud/tea/src', + ), + 'Adbar\\' => + array ( + 0 => __DIR__ . '/..' . '/adbario/php-dot-notation/src', + ), + ); + + public static $prefixesPsr0 = array ( + 'P' => + array ( + 'Pimple' => + array ( + 0 => __DIR__ . '/..' . '/pimple/pimple/src', + ), + ), + 'H' => + array ( + 'HTMLPurifier' => + array ( + 0 => __DIR__ . '/..' . '/ezyang/htmlpurifier/library', + ), + ), + ); + + public static $fallbackDirsPsr0 = array ( + 0 => __DIR__ . '/../..' . '/extend', + ); + + public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', + 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit90b856d7abf7e0eea063f6ff76390209::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit90b856d7abf7e0eea063f6ff76390209::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInit90b856d7abf7e0eea063f6ff76390209::$prefixesPsr0; + $loader->fallbackDirsPsr0 = ComposerStaticInit90b856d7abf7e0eea063f6ff76390209::$fallbackDirsPsr0; + $loader->classMap = ComposerStaticInit90b856d7abf7e0eea063f6ff76390209::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/serve/vendor/composer/installed.json b/serve/vendor/composer/installed.json new file mode 100644 index 0000000..a4c2726 --- /dev/null +++ b/serve/vendor/composer/installed.json @@ -0,0 +1,3678 @@ +{ + "packages": [ + { + "name": "adbario/php-dot-notation", + "version": "2.2.0", + "version_normalized": "2.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/adbario/php-dot-notation.git", + "reference": "eee4fc81296531e6aafba4c2bbccfc5adab1676e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/eee4fc81296531e6aafba4c2bbccfc5adab1676e", + "reference": "eee4fc81296531e6aafba4c2bbccfc5adab1676e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0|^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "time": "2019-01-01T23:59:15+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Adbar\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Riku Särkinen", + "email": "riku@adbar.io" + } + ], + "description": "PHP dot notation access to arrays", + "homepage": "https://github.com/adbario/php-dot-notation", + "keywords": [ + "ArrayAccess", + "dotnotation" + ], + "support": { + "issues": "https://github.com/adbario/php-dot-notation/issues", + "source": "https://github.com/adbario/php-dot-notation/tree/2.x" + }, + "install-path": "../adbario/php-dot-notation" + }, + { + "name": "alibabacloud/tea", + "version": "3.1.21", + "version_normalized": "3.1.21.0", + "source": { + "type": "git", + "url": "https://github.com/aliyun/tea-php.git", + "reference": "379faffe240ee97134cf3f796cb28059f9fb7fa9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/tea-php/zipball/379faffe240ee97134cf3f796cb28059f9fb7fa9", + "reference": "379faffe240ee97134cf3f796cb28059f9fb7fa9", + "shasum": "" + }, + "require": { + "adbario/php-dot-notation": "^2.2", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "*", + "symfony/dotenv": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "time": "2021-03-15T03:31:41+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com", + "homepage": "http://www.alibabacloud.com" + } + ], + "description": "Client of Tea for PHP", + "homepage": "https://www.alibabacloud.com/", + "keywords": [ + "alibabacloud", + "client", + "cloud", + "tea" + ], + "support": { + "issues": "https://github.com/aliyun/tea-php/issues", + "source": "https://github.com/aliyun/tea-php" + }, + "install-path": "../alibabacloud/tea" + }, + { + "name": "alibabacloud/tea-fileform", + "version": "0.3.4", + "version_normalized": "0.3.4.0", + "source": { + "type": "git", + "url": "https://github.com/alibabacloud-sdk-php/tea-fileform.git", + "reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alibabacloud-sdk-php/tea-fileform/zipball/4bf0c75a045c8115aa8cb1a394bd08d8bb833181", + "reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181", + "shasum": "" + }, + "require": { + "alibabacloud/tea": "^3.0", + "php": ">5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "time": "2020-12-01T07:24:35+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\FileForm\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "description": "Alibaba Cloud Tea File Library for PHP", + "support": { + "issues": "https://github.com/alibabacloud-sdk-php/tea-fileform/issues", + "source": "https://github.com/alibabacloud-sdk-php/tea-fileform/tree/0.3.4" + }, + "install-path": "../alibabacloud/tea-fileform" + }, + { + "name": "alipaysdk/easysdk", + "version": "2.2.0", + "version_normalized": "2.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/alipay/alipay-easysdk.git", + "reference": "7a1cfa83c7e140bded957498ea072c77611e6480" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alipay/alipay-easysdk/zipball/7a1cfa83c7e140bded957498ea072c77611e6480", + "reference": "7a1cfa83c7e140bded957498ea072c77611e6480", + "shasum": "" + }, + "require": { + "adbario/php-dot-notation": "^2.2", + "alibabacloud/tea": "^3.1", + "alibabacloud/tea-fileform": "^0.3.2", + "danielstjules/stringy": "^3.1", + "ext-ctype": "*", + "ext-curl": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": ">=6.3", + "mtdowling/jmespath.php": "^2.4", + "php": ">=7.0", + "pimple/pimple": "^3.0", + "psr/log": "^1.1", + "songshenzong/support": "^2.0", + "xin/container": "^2.0.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "time": "2021-01-19T07:30:32+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Alipay\\EasySDK\\": "php/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "junying.wjy", + "email": "junying.wjy@antfin.com" + } + ], + "description": "支付宝官方 Alipay Easy SDK", + "support": { + "issues": "https://github.com/alipay/alipay-easysdk/issues", + "source": "https://github.com/alipay/alipay-easysdk/tree/v2.2.0" + }, + "install-path": "../alipaysdk/easysdk" + }, + { + "name": "bacon/bacon-qr-code", + "version": "2.0.3", + "version_normalized": "2.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "3e9d791b67d0a2912922b7b7c7312f4b37af41e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/3e9d791b67d0a2912922b7b7c7312f4b37af41e4", + "reference": "3e9d791b67d0a2912922b7b7c7312f4b37af41e4", + "shasum": "" + }, + "require": { + "dasprid/enum": "^1.0.3", + "ext-iconv": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phly/keep-a-changelog": "^1.4", + "phpunit/phpunit": "^7 | ^8 | ^9", + "squizlabs/php_codesniffer": "^3.4" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "time": "2020-10-30T02:02:47+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "support": { + "issues": "https://github.com/Bacon/BaconQrCode/issues", + "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.3" + }, + "install-path": "../bacon/bacon-qr-code" + }, + { + "name": "barcode-bakery/barcode-1d", + "version": "6.0.0", + "version_normalized": "6.0.0.0", + "dist": { + "type": "path", + "url": "vendor/packages/barcode-1d", + "reference": "cd8c30d754d6595bfda13a0fa88e5033179d71f2" + }, + "require": { + "ext-gd": "*", + "php": ">=5.6" + }, + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "BarcodeBakery\\Barcode\\": "src" + } + }, + "license": [ + "Commercial", + "CC-BY-NC-ND-4.0" + ], + "authors": [ + { + "name": "Jean-Sébastien Goupil", + "email": "contact@barcodebakery.com" + } + ], + "description": "Generates 1D barcodes from a PHP server to a file or HTML document.", + "homepage": "http://www.barcodebakery.com", + "keywords": [ + "bakery", + "barcode", + "codabar", + "code11", + "code128", + "code39", + "code39extended", + "code93", + "ean-13", + "ean-8", + "ean13", + "ean8", + "generator", + "i25", + "isbn", + "msi", + "s25", + "upc-a", + "upc-e", + "upcext2", + "upcext5" + ], + "support": { + "email": "contact@barcodebakery.com", + "docs": "http://www.barcodebakery.com" + }, + "transport-options": { + "relative": true + }, + "install-path": "../barcode-bakery/barcode-1d" + }, + { + "name": "barcode-bakery/barcode-common", + "version": "6.0.0", + "version_normalized": "6.0.0.0", + "dist": { + "type": "path", + "url": "vendor/packages/barcode-common", + "reference": "289043a2fd5fc8e18c28f1565b50bfd21a712fbd" + }, + "require": { + "ext-gd": "*", + "php": ">=5.6" + }, + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "BarcodeBakery\\Common\\": "src" + } + }, + "license": [ + "Commercial", + "CC-BY-NC-ND-4.0" + ], + "authors": [ + { + "name": "Jean-Sébastien Goupil", + "email": "contact@barcodebakery.com" + } + ], + "description": "Base code for generating barcode with the Barcode Bakery library. See barcode-bakery/barcode-1d.", + "homepage": "http://www.barcodebakery.com", + "support": { + "email": "contact@barcodebakery.com", + "docs": "http://www.barcodebakery.com" + }, + "transport-options": { + "relative": true + }, + "install-path": "../barcode-bakery/barcode-common" + }, + { + "name": "danielstjules/stringy", + "version": "3.1.0", + "version_normalized": "3.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/danielstjules/Stringy.git", + "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", + "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "time": "2017-06-12T01:10:27+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Stringy\\": "src/" + }, + "files": [ + "src/Create.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel St. Jules", + "email": "danielst.jules@gmail.com", + "homepage": "http://www.danielstjules.com" + } + ], + "description": "A string manipulation library with multibyte support", + "homepage": "https://github.com/danielstjules/Stringy", + "keywords": [ + "UTF", + "helpers", + "manipulation", + "methods", + "multibyte", + "string", + "utf-8", + "utility", + "utils" + ], + "support": { + "issues": "https://github.com/danielstjules/Stringy/issues", + "source": "https://github.com/danielstjules/Stringy" + }, + "install-path": "../danielstjules/stringy" + }, + { + "name": "dasprid/enum", + "version": "1.0.3", + "version_normalized": "1.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "5abf82f213618696dda8e3bf6f64dd042d8542b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/5abf82f213618696dda8e3bf6f64dd042d8542b2", + "reference": "5abf82f213618696dda8e3bf6f64dd042d8542b2", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "^7 | ^8 | ^9", + "squizlabs/php_codesniffer": "^3.4" + }, + "time": "2020-10-02T16:03:48+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "support": { + "issues": "https://github.com/DASPRiD/Enum/issues", + "source": "https://github.com/DASPRiD/Enum/tree/1.0.3" + }, + "install-path": "../dasprid/enum" + }, + { + "name": "endroid/qr-code", + "version": "3.9.7", + "version_normalized": "3.9.7.0", + "source": { + "type": "git", + "url": "https://github.com/endroid/qr-code.git", + "reference": "94563d7b3105288e6ac53a67ae720e3669fac1f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/endroid/qr-code/zipball/94563d7b3105288e6ac53a67ae720e3669fac1f6", + "reference": "94563d7b3105288e6ac53a67ae720e3669fac1f6", + "shasum": "" + }, + "require": { + "bacon/bacon-qr-code": "^2.0", + "khanamiryan/qrcode-detector-decoder": "^1.0.5", + "myclabs/php-enum": "^1.5", + "php": "^7.3||^8.0", + "symfony/options-resolver": "^3.4||^4.4||^5.0", + "symfony/property-access": "^3.4||^4.4||^5.0" + }, + "require-dev": { + "endroid/quality": "^1.5.2", + "setasign/fpdf": "^1.8" + }, + "suggest": { + "ext-gd": "Required for generating PNG images", + "roave/security-advisories": "Avoids installation of package versions with vulnerabilities", + "setasign/fpdf": "Required to use the FPDF writer.", + "symfony/security-checker": "Checks your composer.lock for vulnerabilities" + }, + "time": "2021-04-20T19:10:54+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Endroid\\QrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeroen van den Enden", + "email": "info@endroid.nl" + } + ], + "description": "Endroid QR Code", + "homepage": "https://github.com/endroid/qr-code", + "keywords": [ + "bundle", + "code", + "endroid", + "php", + "qr", + "qrcode" + ], + "support": { + "issues": "https://github.com/endroid/qr-code/issues", + "source": "https://github.com/endroid/qr-code/tree/3.9.7" + }, + "funding": [ + { + "url": "https://github.com/endroid", + "type": "github" + } + ], + "install-path": "../endroid/qr-code" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.13.0", + "version_normalized": "4.13.0.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "require-dev": { + "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" + }, + "time": "2020-06-29T00:56:53+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "HTMLPurifier": "library/" + }, + "files": [ + "library/HTMLPurifier.composer.php" + ], + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/master" + }, + "install-path": "../ezyang/htmlpurifier" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.3.0", + "version_normalized": "7.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "7008573787b430c1c1f650e3722d9bba59967628" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7008573787b430c1c1f650e3722d9bba59967628", + "reference": "7008573787b430c1c1f650e3722d9bba59967628", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.4", + "guzzlehttp/psr7": "^1.7 || ^2.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", + "psr/log": "^1.1" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "time": "2021-03-23T11:33:13+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.3-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://github.com/alexeyshockov", + "type": "github" + }, + { + "url": "https://github.com/gmponos", + "type": "github" + } + ], + "install-path": "../guzzlehttp/guzzle" + }, + { + "name": "guzzlehttp/promises", + "version": "1.4.1", + "version_normalized": "1.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "time": "2021-03-07T09:25:29+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.4.1" + }, + "install-path": "../guzzlehttp/promises" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.8.2", + "version_normalized": "1.8.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "time": "2021-04-26T09:17:50+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.8.2" + }, + "install-path": "../guzzlehttp/psr7" + }, + { + "name": "khanamiryan/qrcode-detector-decoder", + "version": "1.0.5", + "version_normalized": "1.0.5.0", + "source": { + "type": "git", + "url": "https://github.com/khanamiryan/php-qrcode-detector-decoder.git", + "reference": "6c8c23003a87ecd7458807cd49372b1fb590d1f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/khanamiryan/php-qrcode-detector-decoder/zipball/6c8c23003a87ecd7458807cd49372b1fb590d1f5", + "reference": "6c8c23003a87ecd7458807cd49372b1fb590d1f5", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 | ^7.5 | ^8.0 | ^9.0" + }, + "time": "2021-04-20T18:34:35+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Zxing\\": "lib/" + }, + "files": [ + "lib/Common/customFunctions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ashot Khanamiryan", + "email": "a.khanamiryan@gmail.com", + "homepage": "https://github.com/khanamiryan", + "role": "Developer" + } + ], + "description": "QR code decoder / reader", + "homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder/", + "keywords": [ + "barcode", + "qr", + "zxing" + ], + "support": { + "issues": "https://github.com/khanamiryan/php-qrcode-detector-decoder/issues", + "source": "https://github.com/khanamiryan/php-qrcode-detector-decoder/tree/1.0.5" + }, + "install-path": "../khanamiryan/qrcode-detector-decoder" + }, + { + "name": "league/flysystem", + "version": "1.1.3", + "version_normalized": "1.1.3.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "9be3b16c877d477357c015cec057548cf9b2a14a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/9be3b16c877d477357c015cec057548cf9b2a14a", + "reference": "9be3b16c877d477357c015cec057548cf9b2a14a", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "time": "2020-08-23T07:39:11+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.x" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "install-path": "../league/flysystem" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "time": "2020-07-25T15:56:04+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "support": { + "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues", + "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master" + }, + "install-path": "../league/flysystem-cached-adapter" + }, + { + "name": "league/mime-type-detection", + "version": "1.7.0", + "version_normalized": "1.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.18", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3" + }, + "time": "2021-01-18T20:58:21+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.7.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "install-path": "../league/mime-type-detection" + }, + { + "name": "maennchen/zipstream-php", + "version": "2.1.0", + "version_normalized": "2.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/c4c5803cc1f93df3d2448478ef79394a5981cc58", + "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58", + "shasum": "" + }, + "require": { + "myclabs/php-enum": "^1.5", + "php": ">= 7.1", + "psr/http-message": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "ext-zip": "*", + "guzzlehttp/guzzle": ">= 6.3", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": ">= 7.5" + }, + "time": "2020-05-30T13:11:16+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/master" + }, + "funding": [ + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], + "install-path": "../maennchen/zipstream-php" + }, + { + "name": "markbaker/complex", + "version": "2.0.0", + "version_normalized": "2.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "9999f1432fae467bc93c53f357105b4c31bb994c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/9999f1432fae467bc93c53f357105b4c31bb994c", + "reference": "9999f1432fae467bc93c53f357105b4c31bb994c", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "phpcompatibility/php-compatibility": "^9.0", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.4" + }, + "time": "2020-08-26T10:42:07+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + }, + "files": [ + "classes/src/functions/abs.php", + "classes/src/functions/acos.php", + "classes/src/functions/acosh.php", + "classes/src/functions/acot.php", + "classes/src/functions/acoth.php", + "classes/src/functions/acsc.php", + "classes/src/functions/acsch.php", + "classes/src/functions/argument.php", + "classes/src/functions/asec.php", + "classes/src/functions/asech.php", + "classes/src/functions/asin.php", + "classes/src/functions/asinh.php", + "classes/src/functions/atan.php", + "classes/src/functions/atanh.php", + "classes/src/functions/conjugate.php", + "classes/src/functions/cos.php", + "classes/src/functions/cosh.php", + "classes/src/functions/cot.php", + "classes/src/functions/coth.php", + "classes/src/functions/csc.php", + "classes/src/functions/csch.php", + "classes/src/functions/exp.php", + "classes/src/functions/inverse.php", + "classes/src/functions/ln.php", + "classes/src/functions/log2.php", + "classes/src/functions/log10.php", + "classes/src/functions/negative.php", + "classes/src/functions/pow.php", + "classes/src/functions/rho.php", + "classes/src/functions/sec.php", + "classes/src/functions/sech.php", + "classes/src/functions/sin.php", + "classes/src/functions/sinh.php", + "classes/src/functions/sqrt.php", + "classes/src/functions/tan.php", + "classes/src/functions/tanh.php", + "classes/src/functions/theta.php", + "classes/src/operations/add.php", + "classes/src/operations/subtract.php", + "classes/src/operations/multiply.php", + "classes/src/operations/divideby.php", + "classes/src/operations/divideinto.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/PHP8" + }, + "install-path": "../markbaker/complex" + }, + { + "name": "markbaker/matrix", + "version": "2.1.2", + "version_normalized": "2.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/361c0f545c3172ee26c3d596a0aa03f0cef65e6a", + "reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "phpcompatibility/php-compatibility": "^9.0", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.4" + }, + "time": "2021-01-23T16:37:31+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + }, + "files": [ + "classes/src/Functions/adjoint.php", + "classes/src/Functions/antidiagonal.php", + "classes/src/Functions/cofactors.php", + "classes/src/Functions/determinant.php", + "classes/src/Functions/diagonal.php", + "classes/src/Functions/identity.php", + "classes/src/Functions/inverse.php", + "classes/src/Functions/minors.php", + "classes/src/Functions/trace.php", + "classes/src/Functions/transpose.php", + "classes/src/Operations/add.php", + "classes/src/Operations/directsum.php", + "classes/src/Operations/subtract.php", + "classes/src/Operations/multiply.php", + "classes/src/Operations/divideby.php", + "classes/src/Operations/divideinto.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/2.1.2" + }, + "install-path": "../markbaker/matrix" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.6.0", + "version_normalized": "2.6.0.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/42dae2cbd13154083ca6d70099692fef8ca84bfb", + "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^1.4", + "phpunit/phpunit": "^4.8.36 || ^7.5.15" + }, + "time": "2020-07-31T21:01:56+00:00", + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "JmesPath\\": "src/" + }, + "files": [ + "src/JmesPath.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.6.0" + }, + "install-path": "../mtdowling/jmespath.php" + }, + { + "name": "myclabs/php-enum", + "version": "1.8.0", + "version_normalized": "1.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "46cf3d8498b095bd33727b13fd5707263af99421" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/46cf3d8498b095bd33727b13fd5707263af99421", + "reference": "46cf3d8498b095bd33727b13fd5707263af99421", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^4.5.1" + }, + "time": "2021-02-15T16:11:48+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "http://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "support": { + "issues": "https://github.com/myclabs/php-enum/issues", + "source": "https://github.com/myclabs/php-enum/tree/1.8.0" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "install-path": "../myclabs/php-enum" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.17.1", + "version_normalized": "1.17.1.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "c55269cb06911575a126dc225a05c0e4626e5fb4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/c55269cb06911575a126dc225a05c0e4626e5fb4", + "reference": "c55269cb06911575a126dc225a05c0e4626e5fb4", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.13", + "maennchen/zipstream-php": "^2.1", + "markbaker/complex": "^1.5||^2.0", + "markbaker/matrix": "^1.2||^2.0", + "php": "^7.2||^8.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0" + }, + "require-dev": { + "dompdf/dompdf": "^0.8.5", + "friendsofphp/php-cs-fixer": "^2.18", + "jpgraph/jpgraph": "^4.0", + "mpdf/mpdf": "^8.0", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^8.5||^9.3", + "squizlabs/php_codesniffer": "^3.5", + "tecnickcom/tcpdf": "^6.3" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)", + "jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)" + }, + "time": "2021-03-02T17:54:11+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.17.1" + }, + "install-path": "../phpoffice/phpspreadsheet" + }, + { + "name": "pimple/pimple", + "version": "v3.4.0", + "version_normalized": "3.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "86406047271859ffc13424a048541f4531f53601" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/86406047271859ffc13424a048541f4531f53601", + "reference": "86406047271859ffc13424a048541f4531f53601", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.0" + }, + "time": "2021-03-06T08:28:00+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "https://pimple.symfony.com", + "keywords": [ + "container", + "dependency injection" + ], + "support": { + "source": "https://github.com/silexphp/Pimple/tree/v3.4.0" + }, + "install-path": "../pimple/pimple" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-08-06T20:24:11+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "install-path": "../psr/cache" + }, + { + "name": "psr/container", + "version": "1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "time": "2021-03-05T17:36:06+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, + "install-path": "../psr/container" + }, + { + "name": "psr/http-client", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "time": "2020-06-29T06:28:15+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "install-path": "../psr/http-client" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "time": "2019-04-30T12:38:16+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "install-path": "../psr/http-factory" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-08-06T14:39:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "install-path": "../psr/http-message" + }, + { + "name": "psr/log", + "version": "1.1.3", + "version_normalized": "1.1.3.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2020-03-23T09:12:05+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.3" + }, + "install-path": "../psr/log" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2017-10-23T01:57:42+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "install-path": "../psr/simple-cache" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "version_normalized": "3.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "time": "2019-03-08T08:55:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "install-path": "../ralouphie/getallheaders" + }, + { + "name": "songshenzong/support", + "version": "2.0.5", + "version_normalized": "2.0.5.0", + "source": { + "type": "git", + "url": "https://github.com/songshenzong/support.git", + "reference": "34973c04ffcf226e503f1c3a69d30ac49f7621f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/songshenzong/support/zipball/34973c04ffcf226e503f1c3a69d30ac49f7621f6", + "reference": "34973c04ffcf226e503f1c3a69d30ac49f7621f6", + "shasum": "" + }, + "require": { + "danielstjules/stringy": "^3.1", + "ext-json": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "php": ">=5.5" + }, + "require-dev": { + "laravel/framework": "^5.8", + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "time": "2019-08-29T01:59:12+00:00", + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Songshenzong\\Support\\StringsServiceProvider" + ], + "aliases": { + "Strings": "Songshenzong\\Support\\StringsFacade" + } + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Songshenzong\\Support\\": "src/" + }, + "files": [ + "src/StringsHelpers.php", + "src/BashEchoHelpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Songshenzong", + "email": "i@songshenzong.com" + } + ], + "description": "The Songshenzong Support package.", + "homepage": "http://songshenzong.com", + "keywords": [ + "laravel", + "support", + "tools", + "web" + ], + "support": { + "issues": "https://github.com/songshenzong/support/issues", + "source": "https://github.com/songshenzong/support" + }, + "install-path": "../songshenzong/support" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.4.0", + "version_normalized": "2.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-03-23T23:28:01+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/deprecation-contracts" + }, + { + "name": "symfony/options-resolver", + "version": "v5.2.4", + "version_normalized": "5.2.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.15" + }, + "time": "2021-01-27T12:56:27+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/options-resolver" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.22.1", + "version_normalized": "1.22.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "time": "2021-01-07T16:49:33+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-ctype" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.22.1", + "version_normalized": "1.22.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5601e09b69f26c1828b13b6bb87cb07cddba3170", + "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2021-01-22T09:19:47+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-grapheme" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.22.1", + "version_normalized": "1.22.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2021-01-22T09:19:47+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-normalizer" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.22.1", + "version_normalized": "1.22.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "time": "2021-01-22T09:19:47+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-mbstring" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.22.1", + "version_normalized": "1.22.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-01-07T16:49:33+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php72" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.22.1", + "version_normalized": "1.22.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-01-07T16:49:33+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php73" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.22.1", + "version_normalized": "1.22.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-01-07T16:49:33+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php80" + }, + { + "name": "symfony/property-access", + "version": "v5.2.4", + "version_normalized": "5.2.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "3af8ed262bd3217512a13b023981fe68f36ad5f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/3af8ed262bd3217512a13b023981fe68f36ad5f3", + "reference": "3af8ed262bd3217512a13b023981fe68f36ad5f3", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15", + "symfony/property-info": "^5.2" + }, + "require-dev": { + "symfony/cache": "^4.4|^5.0" + }, + "suggest": { + "psr/cache-implementation": "To cache access methods." + }, + "time": "2021-01-27T10:15:41+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v5.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/property-access" + }, + { + "name": "symfony/property-info", + "version": "v5.2.4", + "version_normalized": "5.2.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "7185bbc74e6f49c3f1b5936b4d9e4ca133921189" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/7185bbc74e6f49c3f1b5936b4d9e4ca133921189", + "reference": "7185bbc74e6f49c3f1b5936b4d9e4ca133921189", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15", + "symfony/string": "^5.1" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/cache": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "suggest": { + "phpdocumentor/reflection-docblock": "To use the PHPDoc", + "psr/cache-implementation": "To cache results", + "symfony/doctrine-bridge": "To use Doctrine metadata", + "symfony/serializer": "To use Serializer metadata" + }, + "time": "2021-02-17T15:24:54+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v5.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/property-info" + }, + { + "name": "symfony/string", + "version": "v5.2.6", + "version_normalized": "5.2.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", + "reference": "ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "time": "2021-03-17T17:12:15+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/string" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.21", + "version_normalized": "4.4.21.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0da0e174f728996f5d5072d6a9f0a42259dbc806", + "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "time": "2021-03-27T19:49:03+00:00", + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/var-dumper" + }, + { + "name": "topthink/framework", + "version": "v6.0.8", + "version_normalized": "6.0.8.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "4789343672aef06d571d556da369c0e156609bce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/4789343672aef06d571d556da369c0e156609bce", + "reference": "4789343672aef06d571d556da369c0e156609bce", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "league/flysystem": "^1.0", + "league/flysystem-cached-adapter": "^1.0", + "php": ">=7.1.0", + "psr/container": "~1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1.1", + "topthink/think-orm": "^2.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "time": "2021-04-27T00:41:08+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP Framework.", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "support": { + "issues": "https://github.com/top-think/framework/issues", + "source": "https://github.com/top-think/framework/tree/v6.0.8" + }, + "install-path": "../topthink/framework" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.4", + "version_normalized": "3.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "c28d37743bda4a0455286ca85b17b5791d626e10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/c28d37743bda4a0455286ca85b17b5791d626e10", + "reference": "c28d37743bda4a0455286ca85b17b5791d626e10", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "time": "2019-11-08T08:01:10+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "src/helper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/3.0" + }, + "install-path": "../topthink/think-helper" + }, + { + "name": "topthink/think-orm", + "version": "v2.0.40", + "version_normalized": "2.0.40.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "1119d979b850849f3725856460cf108eec1c3eb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/1119d979b850849f3725856460cf108eec1c3eb8", + "reference": "1119d979b850849f3725856460cf108eec1c3eb8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pdo": "*", + "php": ">=7.1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9.5" + }, + "time": "2021-04-19T13:29:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "stubs/load_stubs.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "think orm", + "keywords": [ + "database", + "orm" + ], + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v2.0.40" + }, + "install-path": "../topthink/think-orm" + }, + { + "name": "topthink/think-template", + "version": "v2.0.8", + "version_normalized": "2.0.8.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-template.git", + "reference": "abfc293f74f9ef5127b5c416310a01fe42e59368" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-template/zipball/abfc293f74f9ef5127b5c416310a01fe42e59368", + "reference": "abfc293f74f9ef5127b5c416310a01fe42e59368", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "psr/simple-cache": "^1.0" + }, + "time": "2020-12-10T07:52:03+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "the php template engine", + "support": { + "issues": "https://github.com/top-think/think-template/issues", + "source": "https://github.com/top-think/think-template/tree/v2.0.8" + }, + "install-path": "../topthink/think-template" + }, + { + "name": "topthink/think-trace", + "version": "v1.4", + "version_normalized": "1.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-trace.git", + "reference": "9a9fa8f767b6c66c5a133ad21ca1bc96ad329444" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-trace/zipball/9a9fa8f767b6c66c5a133ad21ca1bc96ad329444", + "reference": "9a9fa8f767b6c66c5a133ad21ca1bc96ad329444", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "time": "2020-06-29T05:27:28+00:00", + "type": "library", + "extra": { + "think": { + "services": [ + "think\\trace\\Service" + ], + "config": { + "trace": "src/config.php" + } + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\trace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp debug trace", + "support": { + "issues": "https://github.com/top-think/think-trace/issues", + "source": "https://github.com/top-think/think-trace/tree/v1.4" + }, + "install-path": "../topthink/think-trace" + }, + { + "name": "topthink/think-view", + "version": "v1.0.14", + "version_normalized": "1.0.14.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-view.git", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-view/zipball/edce0ae2c9551ab65f9e94a222604b0dead3576d", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/think-template": "^2.0" + }, + "time": "2019-11-06T11:40:13+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\view\\driver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp template driver", + "support": { + "issues": "https://github.com/top-think/think-view/issues", + "source": "https://github.com/top-think/think-view/tree/v1.0.14" + }, + "install-path": "../topthink/think-view" + }, + { + "name": "xin/container", + "version": "2.0.1", + "version_normalized": "2.0.1.0", + "source": { + "type": "git", + "url": "https://gitee.com/liuxiaojinla/php-container", + "reference": "97bb67f87dd851545938a1f2fe0ffbd379e3ff81" + }, + "require": { + "ext-ctype": "*", + "ext-iconv": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "psr/container": "^1.0", + "xin/helper": "^1.0" + }, + "time": "2019-10-21T03:51:25+00:00", + "type": "library", + "installation-source": "source", + "autoload": { + "psr-4": { + "xin\\container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "晋", + "email": "657306123@qq.com" + } + ], + "description": "严格基于PSR11规范实现基础的容器和依赖注入", + "install-path": "../xin/container" + }, + { + "name": "xin/helper", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://gitee.com/liuxiaojinla/php-helper", + "reference": "02a58132dae2aea2d1c0b8e66f55125969224747" + }, + "require": { + "ext-ctype": "*", + "ext-iconv": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*" + }, + "time": "2019-06-22T08:28:23+00:00", + "type": "library", + "installation-source": "source", + "autoload": { + "psr-4": { + "xin\\helper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "晋", + "email": "1540175452@qq.com" + } + ], + "description": "PHP项目日常开发必备基础库,数组工具类、字符串工具类、数字工具类、函数工具类、服务器工具类、加密工具类", + "install-path": "../xin/helper" + } + ], + "dev": true, + "dev-package-names": [ + "symfony/polyfill-php72", + "symfony/var-dumper", + "topthink/think-trace" + ] +} diff --git a/serve/vendor/composer/installed.php b/serve/vendor/composer/installed.php new file mode 100644 index 0000000..a027ea8 --- /dev/null +++ b/serve/vendor/composer/installed.php @@ -0,0 +1,533 @@ + + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => 'efa014cb2ddcd746897e68f1ddef6caf94c484f9', + 'name' => 'topthink/think', + ), + 'versions' => + array ( + 'adbario/php-dot-notation' => + array ( + 'pretty_version' => '2.2.0', + 'version' => '2.2.0.0', + 'aliases' => + array ( + ), + 'reference' => 'eee4fc81296531e6aafba4c2bbccfc5adab1676e', + ), + 'alibabacloud/tea' => + array ( + 'pretty_version' => '3.1.21', + 'version' => '3.1.21.0', + 'aliases' => + array ( + ), + 'reference' => '379faffe240ee97134cf3f796cb28059f9fb7fa9', + ), + 'alibabacloud/tea-fileform' => + array ( + 'pretty_version' => '0.3.4', + 'version' => '0.3.4.0', + 'aliases' => + array ( + ), + 'reference' => '4bf0c75a045c8115aa8cb1a394bd08d8bb833181', + ), + 'alipaysdk/easysdk' => + array ( + 'pretty_version' => '2.2.0', + 'version' => '2.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '7a1cfa83c7e140bded957498ea072c77611e6480', + ), + 'bacon/bacon-qr-code' => + array ( + 'pretty_version' => '2.0.3', + 'version' => '2.0.3.0', + 'aliases' => + array ( + ), + 'reference' => '3e9d791b67d0a2912922b7b7c7312f4b37af41e4', + ), + 'barcode-bakery/barcode-1d' => + array ( + 'pretty_version' => '6.0.0', + 'version' => '6.0.0.0', + 'aliases' => + array ( + ), + 'reference' => 'cd8c30d754d6595bfda13a0fa88e5033179d71f2', + ), + 'barcode-bakery/barcode-common' => + array ( + 'pretty_version' => '6.0.0', + 'version' => '6.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '289043a2fd5fc8e18c28f1565b50bfd21a712fbd', + ), + 'danielstjules/stringy' => + array ( + 'pretty_version' => '3.1.0', + 'version' => '3.1.0.0', + 'aliases' => + array ( + ), + 'reference' => 'df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e', + ), + 'dasprid/enum' => + array ( + 'pretty_version' => '1.0.3', + 'version' => '1.0.3.0', + 'aliases' => + array ( + ), + 'reference' => '5abf82f213618696dda8e3bf6f64dd042d8542b2', + ), + 'endroid/qr-code' => + array ( + 'pretty_version' => '3.9.7', + 'version' => '3.9.7.0', + 'aliases' => + array ( + ), + 'reference' => '94563d7b3105288e6ac53a67ae720e3669fac1f6', + ), + 'ezyang/htmlpurifier' => + array ( + 'pretty_version' => 'v4.13.0', + 'version' => '4.13.0.0', + 'aliases' => + array ( + ), + 'reference' => '08e27c97e4c6ed02f37c5b2b20488046c8d90d75', + ), + 'guzzlehttp/guzzle' => + array ( + 'pretty_version' => '7.3.0', + 'version' => '7.3.0.0', + 'aliases' => + array ( + ), + 'reference' => '7008573787b430c1c1f650e3722d9bba59967628', + ), + 'guzzlehttp/promises' => + array ( + 'pretty_version' => '1.4.1', + 'version' => '1.4.1.0', + 'aliases' => + array ( + ), + 'reference' => '8e7d04f1f6450fef59366c399cfad4b9383aa30d', + ), + 'guzzlehttp/psr7' => + array ( + 'pretty_version' => '1.8.2', + 'version' => '1.8.2.0', + 'aliases' => + array ( + ), + 'reference' => 'dc960a912984efb74d0a90222870c72c87f10c91', + ), + 'khanamiryan/qrcode-detector-decoder' => + array ( + 'pretty_version' => '1.0.5', + 'version' => '1.0.5.0', + 'aliases' => + array ( + ), + 'reference' => '6c8c23003a87ecd7458807cd49372b1fb590d1f5', + ), + 'league/flysystem' => + array ( + 'pretty_version' => '1.1.3', + 'version' => '1.1.3.0', + 'aliases' => + array ( + ), + 'reference' => '9be3b16c877d477357c015cec057548cf9b2a14a', + ), + 'league/flysystem-cached-adapter' => + array ( + 'pretty_version' => '1.1.0', + 'version' => '1.1.0.0', + 'aliases' => + array ( + ), + 'reference' => 'd1925efb2207ac4be3ad0c40b8277175f99ffaff', + ), + 'league/mime-type-detection' => + array ( + 'pretty_version' => '1.7.0', + 'version' => '1.7.0.0', + 'aliases' => + array ( + ), + 'reference' => '3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3', + ), + 'maennchen/zipstream-php' => + array ( + 'pretty_version' => '2.1.0', + 'version' => '2.1.0.0', + 'aliases' => + array ( + ), + 'reference' => 'c4c5803cc1f93df3d2448478ef79394a5981cc58', + ), + 'markbaker/complex' => + array ( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '9999f1432fae467bc93c53f357105b4c31bb994c', + ), + 'markbaker/matrix' => + array ( + 'pretty_version' => '2.1.2', + 'version' => '2.1.2.0', + 'aliases' => + array ( + ), + 'reference' => '361c0f545c3172ee26c3d596a0aa03f0cef65e6a', + ), + 'mtdowling/jmespath.php' => + array ( + 'pretty_version' => '2.6.0', + 'version' => '2.6.0.0', + 'aliases' => + array ( + ), + 'reference' => '42dae2cbd13154083ca6d70099692fef8ca84bfb', + ), + 'myclabs/php-enum' => + array ( + 'pretty_version' => '1.8.0', + 'version' => '1.8.0.0', + 'aliases' => + array ( + ), + 'reference' => '46cf3d8498b095bd33727b13fd5707263af99421', + ), + 'phpoffice/phpspreadsheet' => + array ( + 'pretty_version' => '1.17.1', + 'version' => '1.17.1.0', + 'aliases' => + array ( + ), + 'reference' => 'c55269cb06911575a126dc225a05c0e4626e5fb4', + ), + 'pimple/pimple' => + array ( + 'pretty_version' => 'v3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '86406047271859ffc13424a048541f4531f53601', + ), + 'psr/cache' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8', + ), + 'psr/container' => + array ( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'aliases' => + array ( + ), + 'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf', + ), + 'psr/http-client' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621', + ), + 'psr/http-client-implementation' => + array ( + 'provided' => + array ( + 0 => '1.0', + ), + ), + 'psr/http-factory' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be', + ), + 'psr/http-message' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', + ), + 'psr/http-message-implementation' => + array ( + 'provided' => + array ( + 0 => '1.0', + ), + ), + 'psr/log' => + array ( + 'pretty_version' => '1.1.3', + 'version' => '1.1.3.0', + 'aliases' => + array ( + ), + 'reference' => '0f73288fd15629204f9d42b7055f72dacbe811fc', + ), + 'psr/simple-cache' => + array ( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', + ), + 'ralouphie/getallheaders' => + array ( + 'pretty_version' => '3.0.3', + 'version' => '3.0.3.0', + 'aliases' => + array ( + ), + 'reference' => '120b605dfeb996808c31b6477290a714d356e822', + ), + 'songshenzong/support' => + array ( + 'pretty_version' => '2.0.5', + 'version' => '2.0.5.0', + 'aliases' => + array ( + ), + 'reference' => '34973c04ffcf226e503f1c3a69d30ac49f7621f6', + ), + 'symfony/deprecation-contracts' => + array ( + 'pretty_version' => 'v2.4.0', + 'version' => '2.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '5f38c8804a9e97d23e0c8d63341088cd8a22d627', + ), + 'symfony/options-resolver' => + array ( + 'pretty_version' => 'v5.2.4', + 'version' => '5.2.4.0', + 'aliases' => + array ( + ), + 'reference' => '5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce', + ), + 'symfony/polyfill-ctype' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => 'c6c942b1ac76c82448322025e084cadc56048b4e', + ), + 'symfony/polyfill-intl-grapheme' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => '5601e09b69f26c1828b13b6bb87cb07cddba3170', + ), + 'symfony/polyfill-intl-normalizer' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => '43a0283138253ed1d48d352ab6d0bdb3f809f248', + ), + 'symfony/polyfill-mbstring' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => '5232de97ee3b75b0360528dae24e73db49566ab1', + ), + 'symfony/polyfill-php72' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => 'cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9', + ), + 'symfony/polyfill-php73' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => 'a678b42e92f86eca04b7fa4c0f6f19d097fb69e2', + ), + 'symfony/polyfill-php80' => + array ( + 'pretty_version' => 'v1.22.1', + 'version' => '1.22.1.0', + 'aliases' => + array ( + ), + 'reference' => 'dc3063ba22c2a1fd2f45ed856374d79114998f91', + ), + 'symfony/property-access' => + array ( + 'pretty_version' => 'v5.2.4', + 'version' => '5.2.4.0', + 'aliases' => + array ( + ), + 'reference' => '3af8ed262bd3217512a13b023981fe68f36ad5f3', + ), + 'symfony/property-info' => + array ( + 'pretty_version' => 'v5.2.4', + 'version' => '5.2.4.0', + 'aliases' => + array ( + ), + 'reference' => '7185bbc74e6f49c3f1b5936b4d9e4ca133921189', + ), + 'symfony/string' => + array ( + 'pretty_version' => 'v5.2.6', + 'version' => '5.2.6.0', + 'aliases' => + array ( + ), + 'reference' => 'ad0bd91bce2054103f5eaa18ebeba8d3bc2a0572', + ), + 'symfony/var-dumper' => + array ( + 'pretty_version' => 'v4.4.21', + 'version' => '4.4.21.0', + 'aliases' => + array ( + ), + 'reference' => '0da0e174f728996f5d5072d6a9f0a42259dbc806', + ), + 'topthink/framework' => + array ( + 'pretty_version' => 'v6.0.8', + 'version' => '6.0.8.0', + 'aliases' => + array ( + ), + 'reference' => '4789343672aef06d571d556da369c0e156609bce', + ), + 'topthink/think' => + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => 'efa014cb2ddcd746897e68f1ddef6caf94c484f9', + ), + 'topthink/think-helper' => + array ( + 'pretty_version' => 'v3.1.4', + 'version' => '3.1.4.0', + 'aliases' => + array ( + ), + 'reference' => 'c28d37743bda4a0455286ca85b17b5791d626e10', + ), + 'topthink/think-orm' => + array ( + 'pretty_version' => 'v2.0.40', + 'version' => '2.0.40.0', + 'aliases' => + array ( + ), + 'reference' => '1119d979b850849f3725856460cf108eec1c3eb8', + ), + 'topthink/think-template' => + array ( + 'pretty_version' => 'v2.0.8', + 'version' => '2.0.8.0', + 'aliases' => + array ( + ), + 'reference' => 'abfc293f74f9ef5127b5c416310a01fe42e59368', + ), + 'topthink/think-trace' => + array ( + 'pretty_version' => 'v1.4', + 'version' => '1.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '9a9fa8f767b6c66c5a133ad21ca1bc96ad329444', + ), + 'topthink/think-view' => + array ( + 'pretty_version' => 'v1.0.14', + 'version' => '1.0.14.0', + 'aliases' => + array ( + ), + 'reference' => 'edce0ae2c9551ab65f9e94a222604b0dead3576d', + ), + 'xin/container' => + array ( + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '97bb67f87dd851545938a1f2fe0ffbd379e3ff81', + ), + 'xin/helper' => + array ( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '02a58132dae2aea2d1c0b8e66f55125969224747', + ), + ), +); diff --git a/serve/vendor/composer/platform_check.php b/serve/vendor/composer/platform_check.php new file mode 100644 index 0000000..92370c5 --- /dev/null +++ b/serve/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70300)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.3.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/serve/vendor/danielstjules/stringy/CHANGELOG.md b/serve/vendor/danielstjules/stringy/CHANGELOG.md new file mode 100644 index 0000000..3f13575 --- /dev/null +++ b/serve/vendor/danielstjules/stringy/CHANGELOG.md @@ -0,0 +1,180 @@ +### 3.1.0 (2017-06-11) +* Add $language support to slugify +* Add bg specific transliteration +* ЬЪ/ьъ handling is now language-specific + +### 3.0.1 (2017-04-12) +* Don't replace @ in toAscii +* Use normal replacement for @ in slugify, e.g. user@home => user-home + +### 3.0.0 (2017-03-08) + +* Breaking change: added $language parameter to toAscii, before + $removeUnsupported +* Breaking change: dropped PHP 5.3 support +* Breaking change: any StaticStringy methods that previously returned instances + of Stringy now return strings + +### 2.4.0 (2017-03-02) + +* Add startsWithAny +* Add endsWithAny +* Add stripWhitespace +* Fix error handling for unsupported encodings +* Change private methods to protected for extending class +* Fix safeTruncate for strings without spaces +* Additional char support in toAscii, e.g. full width chars and wide + non-breaking space + +### 2.3.2 (2016-05-02) + +* Improve support without mbstring + +### 2.3.1 (2016-03-21) + +* Always use root namespace for mbstring functions + +### 2.3.0 (2016-03-19) + +* Add Persian characters in Stringy::charsArray() +* Use symfony/polyfill-mbstring to avoid dependency on ext-mbstring + +### 2.2.0 (2015-12-20) + +* isJSON now returns false for empty strings +* Update for German umlaut transformation +* Use reflection to generate method list for StaticStringy +* Added isBase64 method +* Improved toAscii char coverage + +### 2.1.0 (2015-09-02) + +* Added simplified StaticStringy class +* str in Stringy::create and constructor is now optional + +### 2.0.0 (2015-07-29) + + * Removed StaticStringy class + * Added append, prepend, toBoolean, repeat, between, slice, split, and lines + * camelize/upperCamelize now strip leading dashes and underscores + * titleize converts to lowercase, thus no longer preserving acronyms + +### 1.10.0 (2015-07-22) + + * Added trimLeft, trimRight + * Added support for unicode whitespace to trim + * Added delimit + * Added indexOf and indexOfLast + * Added htmlEncode and htmlDecode + * Added "Ç" in toAscii() + +### 1.9.0 (2015-02-09) + + * Added hasUpperCase and hasLowerCase + * Added $removeUnsupported parameter to toAscii() + * Improved toAscii support with additional Unicode spaces, Vietnamese chars, + and numerous other characters + * Separated the charsArray from toAscii as a protected method that may be + extended by inheriting classes + * Chars array is cached for better performance + +### 1.8.1 (2015-01-08) + + * Optimized chars() + * Added "ä Ä Ö Ü"" in toAscii() + * Added support for Unicode spaces in toAscii() + * Replaced instances of self::create() with static::create() + * Added missing test cases for safeTruncate() and longestCommonSuffix() + * Updated Stringy\create() to avoid collision when it already exists + +### 1.8.0 (2015-01-03) + + * Listed ext-mbstring in composer.json + * Added Stringy\create function for PHP 5.6 + +### 1.7.0 (2014-10-14) + + * Added containsAll and containsAny + * Light cleanup + +### 1.6.0 (2014-09-14) + + * Added toTitleCase + +### 1.5.2 (2014-07-09) + + * Announced support for HHVM + +### 1.5.1 (2014-04-19) + + * Fixed toAscii() failing to remove remaining non-ascii characters + * Updated slugify() to treat dash and underscore as delimiters by default + * Updated slugify() to remove leading and trailing delimiter, if present + +### 1.5.0 (2014-03-19) + + * Made both str and encoding protected, giving property access to subclasses + * Added getEncoding() + * Fixed isJSON() giving false negatives + * Cleaned up and simplified: replace(), collapseWhitespace(), underscored(), + dasherize(), pad(), padLeft(), padRight() and padBoth() + * Fixed handling consecutive invalid chars in slugify() + * Removed conflicting hard sign transliteration in toAscii() + +### 1.4.0 (2014-02-12) + + * Implemented the IteratorAggregate interface, added chars() + * Renamed count() to countSubstr() + * Updated count() to implement Countable interface + * Implemented the ArrayAccess interface with positive and negative indices + * Switched from PSR-0 to PSR-4 autoloading + +### 1.3.0 (2013-12-16) + + * Additional Bulgarian support for toAscii + * str property made private + * Constructor casts first argument to string + * Constructor throws an InvalidArgumentException when given an array + * Constructor throws an InvalidArgumentException when given an object without + a __toString method + +### 1.2.2 (2013-12-04) + + * Updated create function to use late static binding + * Added optional $replacement param to slugify + +### 1.2.1 (2013-10-11) + + * Cleaned up tests + * Added homepage to composer.json + +### 1.2.0 (2013-09-15) + + * Fixed pad's use of InvalidArgumentException + * Fixed replace(). It now correctly treats regex special chars as normal chars + * Added additional Cyrillic letters to toAscii + * Added $caseSensitive to contains() and count() + * Added toLowerCase() + * Added toUpperCase() + * Added regexReplace() + +### 1.1.0 (2013-08-31) + + * Fix for collapseWhitespace() + * Added isHexadecimal() + * Added constructor to Stringy\Stringy + * Added isSerialized() + * Added isJson() + +### 1.0.0 (2013-08-1) + + * 1.0.0 release + * Added test coverage for Stringy::create and method chaining + * Added tests for returned type + * Fixed StaticStringy::replace(). It was returning a Stringy object instead of string + * Renamed standardize() to the more appropriate toAscii() + * Cleaned up comments and README + +### 1.0.0-rc.1 (2013-07-28) + + * Release candidate diff --git a/serve/vendor/danielstjules/stringy/LICENSE.txt b/serve/vendor/danielstjules/stringy/LICENSE.txt new file mode 100644 index 0000000..0b70302 --- /dev/null +++ b/serve/vendor/danielstjules/stringy/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (C) 2013 Daniel St. Jules + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/serve/vendor/danielstjules/stringy/README.md b/serve/vendor/danielstjules/stringy/README.md new file mode 100644 index 0000000..df48e39 --- /dev/null +++ b/serve/vendor/danielstjules/stringy/README.md @@ -0,0 +1,1082 @@ +![Stringy](http://danielstjules.com/github/stringy-logo.png) + +A PHP string manipulation library with multibyte support. Compatible with PHP +5.4+, PHP 7+, and HHVM. + +``` php +s('string')->toTitleCase()->ensureRight('y') == 'Stringy' +``` + +Refer to the [1.x branch](https://github.com/danielstjules/Stringy/tree/1.x) or +[2.x branch](https://github.com/danielstjules/Stringy/tree/2.x) for older +documentation. + +[![Build Status](https://api.travis-ci.org/danielstjules/Stringy.svg?branch=master)](https://travis-ci.org/danielstjules/Stringy) +[![Total Downloads](https://poser.pugx.org/danielstjules/stringy/downloads)](https://packagist.org/packages/danielstjules/stringy) +[![License](https://poser.pugx.org/danielstjules/stringy/license)](https://packagist.org/packages/danielstjules/stringy) + +* [Why?](#why) +* [Installation](#installation) +* [OO and Chaining](#oo-and-chaining) +* [Implemented Interfaces](#implemented-interfaces) +* [PHP 5.6 Creation](#php-56-creation) +* [StaticStringy](#staticstringy) +* [Class methods](#class-methods) + * [create](#createmixed-str--encoding-) +* [Instance methods](#instance-methods) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
appendatbetweencamelize
charscollapseWhitespacecontainscontainsAll
containsAnycountSubstrdasherizedelimit
endsWithendsWithAnyensureLeftensureRight
firstgetEncodinghasLowerCasehasUpperCase
htmlDecodehtmlEncodehumanizeindexOf
indexOfLastinsertisAlphaisAlphanumeric
isBase64isBlankisHexadecimalisJson
isLowerCaseisSerializedisUpperCaselast
lengthlineslongestCommonPrefixlongestCommonSuffix
longestCommonSubstringlowerCaseFirstpadpadBoth
padLeftpadRightprependregexReplace
removeLeftremoveRightrepeatreplace
reversesafeTruncateshuffleslugify
slicesplitstartsWithstartsWithAny
stripWhitespacesubstrsurroundswapCase
tidytitleizetoAsciitoBoolean
toLowerCasetoSpacestoTabstoTitleCase
toUpperCasetrimtrimLefttrimRight
truncateunderscoredupperCamelizeupperCaseFirst
+ +* [Extensions](#extensions) +* [Tests](#tests) +* [License](#license) + +## Why? + +In part due to a lack of multibyte support (including UTF-8) across many of +PHP's standard string functions. But also to offer an OO wrapper around the +`mbstring` module's multibyte-compatible functions. Stringy handles some quirks, +provides additional functionality, and hopefully makes strings a little easier +to work with! + +```php +// Standard library +strtoupper('fòôbàř'); // 'FòôBàř' +strlen('fòôbàř'); // 10 + +// mbstring +mb_strtoupper('fòôbàř'); // 'FÒÔBÀŘ' +mb_strlen('fòôbàř'); // '6' + +// Stringy +s('fòôbàř')->toUpperCase(); // 'FÒÔBÀŘ' +s('fòôbàř')->length(); // '6' +``` + +## Installation + +If you're using Composer to manage dependencies, you can include the following +in your composer.json file: + +```json +"require": { + "danielstjules/stringy": "~3.1.0" +} +``` + +Then, after running `composer update` or `php composer.phar update`, you can +load the class using Composer's autoloading: + +```php +require 'vendor/autoload.php'; +``` + +Otherwise, you can simply require the file directly: + +```php +require_once 'path/to/Stringy/src/Stringy.php'; +``` + +And in either case, I'd suggest using an alias. + +```php +use Stringy\Stringy as S; +``` + +Please note that Stringy relies on the `mbstring` module for its underlying +multibyte support. If the module is not found, Stringy will use +[symfony/polyfill-mbstring](https://github.com/symfony/polyfill-mbstring). +ex-mbstring is a non-default, but very common module. For example, with debian +and ubuntu, it's included in libapache2-mod-php5, php5-cli, and php5-fpm. For +OSX users, it's a default for any version of PHP installed with homebrew. +If compiling PHP from scratch, it can be included with the +`--enable-mbstring` flag. + +## OO and Chaining + +The library offers OO method chaining, as seen below: + +```php +use Stringy\Stringy as S; +echo S::create('fòô bàř')->collapseWhitespace()->swapCase(); // 'FÒÔ BÀŘ' +``` + +`Stringy\Stringy` has a __toString() method, which returns the current string +when the object is used in a string context, ie: +`(string) S::create('foo') // 'foo'` + +## Implemented Interfaces + +`Stringy\Stringy` implements the `IteratorAggregate` interface, meaning that +`foreach` can be used with an instance of the class: + +``` php +$stringy = S::create('fòôbàř'); +foreach ($stringy as $char) { + echo $char; +} +// 'fòôbàř' +``` + +It implements the `Countable` interface, enabling the use of `count()` to +retrieve the number of characters in the string: + +``` php +$stringy = S::create('fòô'); +count($stringy); // 3 +``` + +Furthermore, the `ArrayAccess` interface has been implemented. As a result, +`isset()` can be used to check if a character at a specific index exists. And +since `Stringy\Stringy` is immutable, any call to `offsetSet` or `offsetUnset` +will throw an exception. `offsetGet` has been implemented, however, and accepts +both positive and negative indexes. Invalid indexes result in an +`OutOfBoundsException`. + +``` php +$stringy = S::create('bàř'); +echo $stringy[2]; // 'ř' +echo $stringy[-2]; // 'à' +isset($stringy[-4]); // false + +$stringy[3]; // OutOfBoundsException +$stringy[2] = 'a'; // Exception +``` + +## PHP 5.6 Creation + +As of PHP 5.6, [`use function`](https://wiki.php.net/rfc/use_function) is +available for importing functions. Stringy exposes a namespaced function, +`Stringy\create`, which emits the same behaviour as `Stringy\Stringy::create()`. +If running PHP 5.6, or another runtime that supports the `use function` syntax, +you can take advantage of an even simpler API as seen below: + +``` php +use function Stringy\create as s; + +// Instead of: S::create('fòô bàř') +s('fòô bàř')->collapseWhitespace()->swapCase(); +``` + +## StaticStringy + +All methods listed under "Instance methods" are available as part of a static +wrapper. For StaticStringy methods, the optional encoding is expected to be the +last argument. The return value is not cast, and may thus be of type Stringy, +integer, boolean, etc. + +```php +use Stringy\StaticStringy as S; + +// Translates to Stringy::create('fòôbàř')->slice(0, 3); +// Returns a Stringy object with the string "fòô" +S::slice('fòôbàř', 0, 3); +``` + +## Class methods + +##### create(mixed $str [, $encoding ]) + +Creates a Stringy object and assigns both str and encoding properties +the supplied values. $str is cast to a string prior to assignment, and if +$encoding is not specified, it defaults to mb_internal_encoding(). It +then returns the initialized object. Throws an InvalidArgumentException +if the first argument is an array or object without a __toString method. + +```php +$stringy = S::create('fòôbàř'); // 'fòôbàř' +``` + +## Instance Methods + +Stringy objects are immutable. All examples below make use of PHP 5.6 +function importing, and PHP 5.4 short array syntax. They also assume the +encoding returned by mb_internal_encoding() is UTF-8. For further details, +see the documentation for the create method above, as well as the notes +on PHP 5.6 creation. + +##### append(string $string) + +Returns a new string with $string appended. + +```php +s('fòô')->append('bàř'); // 'fòôbàř' +``` + +##### at(int $index) + +Returns the character at $index, with indexes starting at 0. + +```php +s('fòôbàř')->at(3); // 'b' +``` + +##### between(string $start, string $end [, int $offset]) + +Returns the substring between $start and $end, if found, or an empty +string. An optional offset may be supplied from which to begin the +search for the start string. + +```php +s('{foo} and {bar}')->between('{', '}'); // 'foo' +``` + +##### camelize() + +Returns a camelCase version of the string. Trims surrounding spaces, +capitalizes letters following digits, spaces, dashes and underscores, +and removes spaces, dashes, as well as underscores. + +```php +s('Camel-Case')->camelize(); // 'camelCase' +``` + +##### chars() + +Returns an array consisting of the characters in the string. + +```php +s('fòôbàř')->chars(); // ['f', 'ò', 'ô', 'b', 'à', 'ř'] +``` + +##### collapseWhitespace() + +Trims the string and replaces consecutive whitespace characters with a +single space. This includes tabs and newline characters, as well as +multibyte whitespace such as the thin space and ideographic space. + +```php +s(' Ο συγγραφέας ')->collapseWhitespace(); // 'Ο συγγραφέας' +``` + +##### contains(string $needle [, boolean $caseSensitive = true ]) + +Returns true if the string contains $needle, false otherwise. By default, +the comparison is case-sensitive, but can be made insensitive +by setting $caseSensitive to false. + +```php +s('Ο συγγραφέας είπε')->contains('συγγραφέας'); // true +``` + +##### containsAll(array $needles [, boolean $caseSensitive = true ]) + +Returns true if the string contains all $needles, false otherwise. By +default the comparison is case-sensitive, but can be made insensitive by +setting $caseSensitive to false. + +```php +s('foo & bar')->containsAll(['foo', 'bar']); // true +``` + +##### containsAny(array $needles [, boolean $caseSensitive = true ]) + +Returns true if the string contains any $needles, false otherwise. By +default the comparison is case-sensitive, but can be made insensitive by +setting $caseSensitive to false. + +```php +s('str contains foo')->containsAny(['foo', 'bar']); // true +``` + +##### countSubstr(string $substring [, boolean $caseSensitive = true ]) + +Returns the number of occurrences of $substring in the given string. +By default, the comparison is case-sensitive, but can be made insensitive +by setting $caseSensitive to false. + +```php +s('Ο συγγραφέας είπε')->countSubstr('α'); // 2 +``` + +##### dasherize() + +Returns a lowercase and trimmed string separated by dashes. Dashes are +inserted before uppercase characters (with the exception of the first +character of the string), and in place of spaces as well as underscores. + +```php +s('fooBar')->dasherize(); // 'foo-bar' +``` + +##### delimit(int $delimiter) + +Returns a lowercase and trimmed string separated by the given delimiter. +Delimiters are inserted before uppercase characters (with the exception +of the first character of the string), and in place of spaces, dashes, +and underscores. Alpha delimiters are not converted to lowercase. + +```php +s('fooBar')->delimit('::'); // 'foo::bar' +``` + +##### endsWith(string $substring [, boolean $caseSensitive = true ]) + +Returns true if the string ends with $substring, false otherwise. By +default, the comparison is case-sensitive, but can be made insensitive by +setting $caseSensitive to false. + +```php +s('fòôbàř')->endsWith('bàř'); // true +``` + +##### endsWithAny(string[] $substrings [, boolean $caseSensitive = true ]) + +Returns true if the string ends with any of $substrings, false otherwise. +By default, the comparison is case-sensitive, but can be made insensitive +by setting $caseSensitive to false. + +```php +s('fòôbàř')->endsWithAny(['bàř', 'baz']); // true +``` + +##### ensureLeft(string $substring) + +Ensures that the string begins with $substring. If it doesn't, it's prepended. + +```php +s('foobar')->ensureLeft('http://'); // 'http://foobar' +``` + +##### ensureRight(string $substring) + +Ensures that the string ends with $substring. If it doesn't, it's appended. + +```php +s('foobar')->ensureRight('.com'); // 'foobar.com' +``` + +##### first(int $n) + +Returns the first $n characters of the string. + +```php +s('fòôbàř')->first(3); // 'fòô' +``` + +##### getEncoding() + +Returns the encoding used by the Stringy object. + +```php +s('fòôbàř')->getEncoding(); // 'UTF-8' +``` + +##### hasLowerCase() + +Returns true if the string contains a lower case char, false otherwise. + +```php +s('fòôbàř')->hasLowerCase(); // true +``` + +##### hasUpperCase() + +Returns true if the string contains an upper case char, false otherwise. + +```php +s('fòôbàř')->hasUpperCase(); // false +``` + +##### htmlDecode() + +Convert all HTML entities to their applicable characters. An alias of +html_entity_decode. For a list of flags, refer to +http://php.net/manual/en/function.html-entity-decode.php + +```php +s('&')->htmlDecode(); // '&' +``` + +##### htmlEncode() + +Convert all applicable characters to HTML entities. An alias of +htmlentities. Refer to http://php.net/manual/en/function.htmlentities.php +for a list of flags. + +```php +s('&')->htmlEncode(); // '&' +``` + +##### humanize() + +Capitalizes the first word of the string, replaces underscores with +spaces, and strips '_id'. + +```php +s('author_id')->humanize(); // 'Author' +``` + +##### indexOf(string $needle [, $offset = 0 ]); + +Returns the index of the first occurrence of $needle in the string, +and false if not found. Accepts an optional offset from which to begin +the search. A negative index searches from the end + +```php +s('string')->indexOf('ing'); // 3 +``` + +##### indexOfLast(string $needle [, $offset = 0 ]); + +Returns the index of the last occurrence of $needle in the string, +and false if not found. Accepts an optional offset from which to begin +the search. Offsets may be negative to count from the last character +in the string. + +```php +s('foobarfoo')->indexOfLast('foo'); // 10 +``` + +##### insert(int $index, string $substring) + +Inserts $substring into the string at the $index provided. + +```php +s('fòôbř')->insert('à', 4); // 'fòôbàř' +``` + +##### isAlpha() + +Returns true if the string contains only alphabetic chars, false otherwise. + +```php +s('丹尼爾')->isAlpha(); // true +``` + +##### isAlphanumeric() + +Returns true if the string contains only alphabetic and numeric chars, false +otherwise. + +```php +s('دانيال1')->isAlphanumeric(); // true +``` + +##### isBase64() + +Returns true if the string is base64 encoded, false otherwise. + +```php +s('Zm9vYmFy')->isBase64(); // true +``` + +##### isBlank() + +Returns true if the string contains only whitespace chars, false otherwise. + +```php +s("\n\t \v\f")->isBlank(); // true +``` + +##### isHexadecimal() + +Returns true if the string contains only hexadecimal chars, false otherwise. + +```php +s('A102F')->isHexadecimal(); // true +``` + +##### isJson() + +Returns true if the string is JSON, false otherwise. Unlike json_decode +in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers, +in that an empty string is not considered valid JSON. + +```php +s('{"foo":"bar"}')->isJson(); // true +``` + +##### isLowerCase() + +Returns true if the string contains only lower case chars, false otherwise. + +```php +s('fòôbàř')->isLowerCase(); // true +``` + +##### isSerialized() + +Returns true if the string is serialized, false otherwise. + +```php +s('a:1:{s:3:"foo";s:3:"bar";}')->isSerialized(); // true +``` + +##### isUpperCase() + +Returns true if the string contains only upper case chars, false otherwise. + +```php +s('FÒÔBÀŘ')->isUpperCase(); // true +``` + +##### last(int $n) + +Returns the last $n characters of the string. + +```php +s('fòôbàř')->last(3); // 'bàř' +``` + +##### length() + +Returns the length of the string. An alias for PHP's mb_strlen() function. + +```php +s('fòôbàř')->length(); // 6 +``` + +##### lines() + +Splits on newlines and carriage returns, returning an array of Stringy +objects corresponding to the lines in the string. + +```php +s("fòô\r\nbàř\n")->lines(); // ['fòô', 'bàř', ''] +``` + +##### longestCommonPrefix(string $otherStr) + +Returns the longest common prefix between the string and $otherStr. + +```php +s('foobar')->longestCommonPrefix('foobaz'); // 'fooba' +``` + +##### longestCommonSuffix(string $otherStr) + +Returns the longest common suffix between the string and $otherStr. + +```php +s('fòôbàř')->longestCommonSuffix('fòrbàř'); // 'bàř' +``` + +##### longestCommonSubstring(string $otherStr) + +Returns the longest common substring between the string and $otherStr. In the +case of ties, it returns that which occurs first. + +```php +s('foobar')->longestCommonSubstring('boofar'); // 'oo' +``` + +##### lowerCaseFirst() + +Converts the first character of the supplied string to lower case. + +```php +s('Σ foo')->lowerCaseFirst(); // 'σ foo' +``` + +##### pad(int $length [, string $padStr = ' ' [, string $padType = 'right' ]]) + +Pads the string to a given length with $padStr. If length is less than +or equal to the length of the string, no padding takes places. The default +string used for padding is a space, and the default type (one of 'left', +'right', 'both') is 'right'. Throws an InvalidArgumentException if +$padType isn't one of those 3 values. + +```php +s('fòôbàř')->pad(9, '-/', 'left'); // '-/-fòôbàř' +``` + +##### padBoth(int $length [, string $padStr = ' ' ]) + +Returns a new string of a given length such that both sides of the string +string are padded. Alias for pad() with a $padType of 'both'. + +```php +s('foo bar')->padBoth(9, ' '); // ' foo bar ' +``` + +##### padLeft(int $length [, string $padStr = ' ' ]) + +Returns a new string of a given length such that the beginning of the +string is padded. Alias for pad() with a $padType of 'left'. + +```php +s('foo bar')->padLeft(9, ' '); // ' foo bar' +``` + +##### padRight(int $length [, string $padStr = ' ' ]) + +Returns a new string of a given length such that the end of the string is +padded. Alias for pad() with a $padType of 'right'. + +```php +s('foo bar')->padRight(10, '_*'); // 'foo bar_*_' +``` + +##### prepend(string $string) + +Returns a new string starting with $string. + +```php +s('bàř')->prepend('fòô'); // 'fòôbàř' +``` + +##### regexReplace(string $pattern, string $replacement [, string $options = 'msr']) + +Replaces all occurrences of $pattern in $str by $replacement. An alias +for mb_ereg_replace(). Note that the 'i' option with multibyte patterns +in mb_ereg_replace() requires PHP 5.6+ for correct results. This is due +to a lack of support in the bundled version of Oniguruma in PHP < 5.6, +and current versions of HHVM (3.8 and below). + +```php +s('fòô ')->regexReplace('f[òô]+\s', 'bàř'); // 'bàř' +s('fò')->regexReplace('(ò)', '\\1ô'); // 'fòô' +``` + +##### removeLeft(string $substring) + +Returns a new string with the prefix $substring removed, if present. + +```php +s('fòôbàř')->removeLeft('fòô'); // 'bàř' +``` + +##### removeRight(string $substring) + +Returns a new string with the suffix $substring removed, if present. + +```php +s('fòôbàř')->removeRight('bàř'); // 'fòô' +``` + +##### repeat(int $multiplier) + +Returns a repeated string given a multiplier. An alias for str_repeat. + +```php +s('α')->repeat(3); // 'ααα' +``` + +##### replace(string $search, string $replacement) + +Replaces all occurrences of $search in $str by $replacement. + +```php +s('fòô bàř fòô bàř')->replace('fòô ', ''); // 'bàř bàř' +``` + +##### reverse() + +Returns a reversed string. A multibyte version of strrev(). + +```php +s('fòôbàř')->reverse(); // 'řàbôòf' +``` + +##### safeTruncate(int $length [, string $substring = '' ]) + +Truncates the string to a given length, while ensuring that it does not +split words. If $substring is provided, and truncating occurs, the +string is further truncated so that the substring may be appended without +exceeding the desired length. + +```php +s('What are your plans today?')->safeTruncate(22, '...'); +// 'What are your plans...' +``` + +##### shuffle() + +A multibyte str_shuffle() function. It returns a string with its characters in +random order. + +```php +s('fòôbàř')->shuffle(); // 'àôřbòf' +``` + +##### slugify([, string $replacement = '-' [, string $language = 'en']]) + +Converts the string into an URL slug. This includes replacing non-ASCII +characters with their closest ASCII equivalents, removing remaining +non-ASCII and non-alphanumeric characters, and replacing whitespace with +$replacement. The replacement defaults to a single dash, and the string +is also converted to lowercase. The language of the source string can +also be supplied for language-specific transliteration. + +```php +s('Using strings like fòô bàř')->slugify(); // 'using-strings-like-foo-bar' +``` + +##### slice(int $start [, int $end ]) + +Returns the substring beginning at $start, and up to, but not including +the index specified by $end. If $end is omitted, the function extracts +the remaining string. If $end is negative, it is computed from the end +of the string. + +```php +s('fòôbàř')->slice(3, -1); // 'bà' +``` + +##### split(string $pattern [, int $limit ]) + +Splits the string with the provided regular expression, returning an +array of Stringy objects. An optional integer $limit will truncate the +results. + +```php +s('foo,bar,baz')->split(',', 2); // ['foo', 'bar'] +``` + +##### startsWith(string $substring [, boolean $caseSensitive = true ]) + +Returns true if the string begins with $substring, false otherwise. +By default, the comparison is case-sensitive, but can be made insensitive +by setting $caseSensitive to false. + +```php +s('FÒÔbàřbaz')->startsWith('fòôbàř', false); // true +``` + +##### startsWithAny(string[] $substrings [, boolean $caseSensitive = true ]) + +Returns true if the string begins with any of $substrings, false +otherwise. By default the comparison is case-sensitive, but can be made +insensitive by setting $caseSensitive to false. + +```php +s('FÒÔbàřbaz')->startsWithAny(['fòô', 'bàř'], false); // true +``` + +##### stripWhitespace() + +Strip all whitespace characters. This includes tabs and newline +characters, as well as multibyte whitespace such as the thin space +and ideographic space. + +```php +s(' Ο συγγραφέας ')->stripWhitespace(); // 'Οσυγγραφέας' +``` + +##### substr(int $start [, int $length ]) + +Returns the substring beginning at $start with the specified $length. +It differs from the mb_substr() function in that providing a $length of +null will return the rest of the string, rather than an empty string. + +```php +s('fòôbàř')->substr(2, 3); // 'ôbà' +``` + +##### surround(string $substring) + +Surrounds a string with the given substring. + +```php +s(' ͜ ')->surround('ʘ'); // 'ʘ ͜ ʘ' +``` + +##### swapCase() + +Returns a case swapped version of the string. + +```php +s('Ντανιλ')->swapCase(); // 'νΤΑΝΙΛ' +``` + +##### tidy() + +Returns a string with smart quotes, ellipsis characters, and dashes from +Windows-1252 (commonly used in Word documents) replaced by their ASCII equivalents. + +```php +s('“I see…”')->tidy(); // '"I see..."' +``` + +##### titleize([, array $ignore]) + +Returns a trimmed string with the first letter of each word capitalized. +Also accepts an array, $ignore, allowing you to list words not to be +capitalized. + +```php +$ignore = ['at', 'by', 'for', 'in', 'of', 'on', 'out', 'to', 'the']; +s('i like to watch television')->titleize($ignore); +// 'I Like to Watch Television' +``` + +##### toAscii([, string $language = 'en' [, bool $removeUnsupported = true ]]) + +Returns an ASCII version of the string. A set of non-ASCII characters are +replaced with their closest ASCII counterparts, and the rest are removed +by default. The language or locale of the source string can be supplied +for language-specific transliteration in any of the following formats: +en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping +to "aeoeue" rather than "aou" as in other languages. + +```php +s('fòôbàř')->toAscii(); // 'foobar' +s('äöü')->toAscii(); // 'aou' +s('äöü')->toAscii('de'); // 'aeoeue' +``` + +##### toBoolean() + +Returns a boolean representation of the given logical string value. +For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0', +'off', and 'no' will return false. In all instances, case is ignored. +For other numeric strings, their sign will determine the return value. +In addition, blank strings consisting of only whitespace will return +false. For all other strings, the return value is a result of a +boolean cast. + +```php +s('OFF')->toBoolean(); // false +``` + +##### toLowerCase() + +Converts all characters in the string to lowercase. An alias for PHP's +mb_strtolower(). + +```php +s('FÒÔBÀŘ')->toLowerCase(); // 'fòôbàř' +``` + +##### toSpaces([, tabLength = 4 ]) + +Converts each tab in the string to some number of spaces, as defined by +$tabLength. By default, each tab is converted to 4 consecutive spaces. + +```php +s(' String speech = "Hi"')->toSpaces(); // ' String speech = "Hi"' +``` + +##### toTabs([, tabLength = 4 ]) + +Converts each occurrence of some consecutive number of spaces, as defined +by $tabLength, to a tab. By default, each 4 consecutive spaces are +converted to a tab. + +```php +s(' fòô bàř')->toTabs(); +// ' fòô bàř' +``` + +##### toTitleCase() + +Converts the first character of each word in the string to uppercase. + +```php +s('fòô bàř')->toTitleCase(); // 'Fòô Bàř' +``` + +##### toUpperCase() + +Converts all characters in the string to uppercase. An alias for PHP's +mb_strtoupper(). + +```php +s('fòôbàř')->toUpperCase(); // 'FÒÔBÀŘ' +``` + +##### trim([, string $chars]) + +Returns a string with whitespace removed from the start and end of the +string. Supports the removal of unicode whitespace. Accepts an optional +string of characters to strip instead of the defaults. + +```php +s(' fòôbàř ')->trim(); // 'fòôbàř' +``` + +##### trimLeft([, string $chars]) + +Returns a string with whitespace removed from the start of the string. +Supports the removal of unicode whitespace. Accepts an optional +string of characters to strip instead of the defaults. + +```php +s(' fòôbàř ')->trimLeft(); // 'fòôbàř ' +``` + +##### trimRight([, string $chars]) + +Returns a string with whitespace removed from the end of the string. +Supports the removal of unicode whitespace. Accepts an optional +string of characters to strip instead of the defaults. + +```php +s(' fòôbàř ')->trimRight(); // ' fòôbàř' +``` + +##### truncate(int $length [, string $substring = '' ]) + +Truncates the string to a given length. If $substring is provided, and +truncating occurs, the string is further truncated so that the substring +may be appended without exceeding the desired length. + +```php +s('What are your plans today?')->truncate(19, '...'); // 'What are your pl...' +``` + +##### underscored() + +Returns a lowercase and trimmed string separated by underscores. +Underscores are inserted before uppercase characters (with the exception +of the first character of the string), and in place of spaces as well as dashes. + +```php +s('TestUCase')->underscored(); // 'test_u_case' +``` + +##### upperCamelize() + +Returns an UpperCamelCase version of the supplied string. It trims +surrounding spaces, capitalizes letters following digits, spaces, dashes +and underscores, and removes spaces, dashes, underscores. + +```php +s('Upper Camel-Case')->upperCamelize(); // 'UpperCamelCase' +``` + +##### upperCaseFirst() + +Converts the first character of the supplied string to upper case. + +```php +s('σ foo')->upperCaseFirst(); // 'Σ foo' +``` + +## Extensions + +The following is a list of libraries that extend Stringy: + + * [SliceableStringy](https://github.com/danielstjules/SliceableStringy): +Python-like string slices in PHP + * [SubStringy](https://github.com/TCB13/SubStringy): +Advanced substring methods + +## Tests + +From the project directory, tests can be ran using `phpunit` + +## License + +Released under the MIT License - see `LICENSE.txt` for details. diff --git a/serve/vendor/danielstjules/stringy/composer.json b/serve/vendor/danielstjules/stringy/composer.json new file mode 100644 index 0000000..092989f --- /dev/null +++ b/serve/vendor/danielstjules/stringy/composer.json @@ -0,0 +1,35 @@ +{ + "name": "danielstjules/stringy", + "description": "A string manipulation library with multibyte support", + "keywords": [ + "multibyte", "string", "manipulation", "utility", "methods", "utf-8", + "helpers", "utils", "utf" + ], + "homepage": "https://github.com/danielstjules/Stringy", + "license": "MIT", + "authors": [ + { + "name": "Daniel St. Jules", + "email": "danielst.jules@gmail.com", + "homepage": "http://www.danielstjules.com" + } + ], + "require": { + "php": ">=5.4.0", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "support": { + "issues": "https://github.com/danielstjules/Stringy/issues", + "source": "https://github.com/danielstjules/Stringy" + }, + "autoload": { + "psr-4": { "Stringy\\": "src/" }, + "files": ["src/Create.php"] + }, + "autoload-dev": { + "classmap": [ "tests" ] + } +} diff --git a/serve/vendor/danielstjules/stringy/src/Create.php b/serve/vendor/danielstjules/stringy/src/Create.php new file mode 100644 index 0000000..c6a2f44 --- /dev/null +++ b/serve/vendor/danielstjules/stringy/src/Create.php @@ -0,0 +1,19 @@ +slice(0, 3); + * The result is not cast, so the return value may be of type Stringy, + * integer, boolean, etc. + * + * @param string $name + * @param mixed[] $arguments + * + * @return Stringy + * + * @throws \BadMethodCallException + */ + public static function __callStatic($name, $arguments) + { + if (!static::$methodArgs) { + $stringyClass = new ReflectionClass('Stringy\Stringy'); + $methods = $stringyClass->getMethods(ReflectionMethod::IS_PUBLIC); + + foreach ($methods as $method) { + $params = $method->getNumberOfParameters() + 2; + static::$methodArgs[$method->name] = $params; + } + } + + if (!isset(static::$methodArgs[$name])) { + throw new BadMethodCallException($name . ' is not a valid method'); + } + + $numArgs = count($arguments); + $str = ($numArgs) ? $arguments[0] : ''; + + if ($numArgs === static::$methodArgs[$name]) { + $args = array_slice($arguments, 1, -1); + $encoding = $arguments[$numArgs - 1]; + } else { + $args = array_slice($arguments, 1); + $encoding = null; + } + + $stringy = Stringy::create($str, $encoding); + + $result = call_user_func_array([$stringy, $name], $args); + + $cast = function($val) { + if (is_object($val) && $val instanceof Stringy) { + return (string) $val; + } else { + return $val; + } + }; + + return is_array($result) ? array_map($cast, $result) : $cast($result); + } +} diff --git a/serve/vendor/danielstjules/stringy/src/Stringy.php b/serve/vendor/danielstjules/stringy/src/Stringy.php new file mode 100644 index 0000000..ccb6f5a --- /dev/null +++ b/serve/vendor/danielstjules/stringy/src/Stringy.php @@ -0,0 +1,1986 @@ +str = (string) $str; + $this->encoding = $encoding ?: \mb_internal_encoding(); + } + + /** + * Creates a Stringy object and assigns both str and encoding properties + * the supplied values. $str is cast to a string prior to assignment, and if + * $encoding is not specified, it defaults to mb_internal_encoding(). It + * then returns the initialized object. Throws an InvalidArgumentException + * if the first argument is an array or object without a __toString method. + * + * @param mixed $str Value to modify, after being cast to string + * @param string $encoding The character encoding + * @return static A Stringy object + * @throws \InvalidArgumentException if an array or object without a + * __toString method is passed as the first argument + */ + public static function create($str = '', $encoding = null) + { + return new static($str, $encoding); + } + + /** + * Returns the value in $str. + * + * @return string The current value of the $str property + */ + public function __toString() + { + return $this->str; + } + + /** + * Returns a new string with $string appended. + * + * @param string $string The string to append + * @return static Object with appended $string + */ + public function append($string) + { + return static::create($this->str . $string, $this->encoding); + } + + /** + * Returns the character at $index, with indexes starting at 0. + * + * @param int $index Position of the character + * @return static The character at $index + */ + public function at($index) + { + return $this->substr($index, 1); + } + + /** + * Returns the substring between $start and $end, if found, or an empty + * string. An optional offset may be supplied from which to begin the + * search for the start string. + * + * @param string $start Delimiter marking the start of the substring + * @param string $end Delimiter marking the end of the substring + * @param int $offset Index from which to begin the search + * @return static Object whose $str is a substring between $start and $end + */ + public function between($start, $end, $offset = 0) + { + $startIndex = $this->indexOf($start, $offset); + if ($startIndex === false) { + return static::create('', $this->encoding); + } + + $substrIndex = $startIndex + \mb_strlen($start, $this->encoding); + $endIndex = $this->indexOf($end, $substrIndex); + if ($endIndex === false) { + return static::create('', $this->encoding); + } + + return $this->substr($substrIndex, $endIndex - $substrIndex); + } + + /** + * Returns a camelCase version of the string. Trims surrounding spaces, + * capitalizes letters following digits, spaces, dashes and underscores, + * and removes spaces, dashes, as well as underscores. + * + * @return static Object with $str in camelCase + */ + public function camelize() + { + $encoding = $this->encoding; + $stringy = $this->trim()->lowerCaseFirst(); + $stringy->str = preg_replace('/^[-_]+/', '', $stringy->str); + + $stringy->str = preg_replace_callback( + '/[-_\s]+(.)?/u', + function ($match) use ($encoding) { + if (isset($match[1])) { + return \mb_strtoupper($match[1], $encoding); + } + + return ''; + }, + $stringy->str + ); + + $stringy->str = preg_replace_callback( + '/[\d]+(.)?/u', + function ($match) use ($encoding) { + return \mb_strtoupper($match[0], $encoding); + }, + $stringy->str + ); + + return $stringy; + } + + /** + * Returns an array consisting of the characters in the string. + * + * @return array An array of string chars + */ + public function chars() + { + $chars = []; + for ($i = 0, $l = $this->length(); $i < $l; $i++) { + $chars[] = $this->at($i)->str; + } + + return $chars; + } + + /** + * Trims the string and replaces consecutive whitespace characters with a + * single space. This includes tabs and newline characters, as well as + * multibyte whitespace such as the thin space and ideographic space. + * + * @return static Object with a trimmed $str and condensed whitespace + */ + public function collapseWhitespace() + { + return $this->regexReplace('[[:space:]]+', ' ')->trim(); + } + + /** + * Returns true if the string contains $needle, false otherwise. By default + * the comparison is case-sensitive, but can be made insensitive by setting + * $caseSensitive to false. + * + * @param string $needle Substring to look for + * @param bool $caseSensitive Whether or not to enforce case-sensitivity + * @return bool Whether or not $str contains $needle + */ + public function contains($needle, $caseSensitive = true) + { + $encoding = $this->encoding; + + if ($caseSensitive) { + return (\mb_strpos($this->str, $needle, 0, $encoding) !== false); + } + + return (\mb_stripos($this->str, $needle, 0, $encoding) !== false); + } + + /** + * Returns true if the string contains all $needles, false otherwise. By + * default the comparison is case-sensitive, but can be made insensitive by + * setting $caseSensitive to false. + * + * @param string[] $needles Substrings to look for + * @param bool $caseSensitive Whether or not to enforce case-sensitivity + * @return bool Whether or not $str contains $needle + */ + public function containsAll($needles, $caseSensitive = true) + { + if (empty($needles)) { + return false; + } + + foreach ($needles as $needle) { + if (!$this->contains($needle, $caseSensitive)) { + return false; + } + } + + return true; + } + + /** + * Returns true if the string contains any $needles, false otherwise. By + * default the comparison is case-sensitive, but can be made insensitive by + * setting $caseSensitive to false. + * + * @param string[] $needles Substrings to look for + * @param bool $caseSensitive Whether or not to enforce case-sensitivity + * @return bool Whether or not $str contains $needle + */ + public function containsAny($needles, $caseSensitive = true) + { + if (empty($needles)) { + return false; + } + + foreach ($needles as $needle) { + if ($this->contains($needle, $caseSensitive)) { + return true; + } + } + + return false; + } + + /** + * Returns the length of the string, implementing the countable interface. + * + * @return int The number of characters in the string, given the encoding + */ + public function count() + { + return $this->length(); + } + + /** + * Returns the number of occurrences of $substring in the given string. + * By default, the comparison is case-sensitive, but can be made insensitive + * by setting $caseSensitive to false. + * + * @param string $substring The substring to search for + * @param bool $caseSensitive Whether or not to enforce case-sensitivity + * @return int The number of $substring occurrences + */ + public function countSubstr($substring, $caseSensitive = true) + { + if ($caseSensitive) { + return \mb_substr_count($this->str, $substring, $this->encoding); + } + + $str = \mb_strtoupper($this->str, $this->encoding); + $substring = \mb_strtoupper($substring, $this->encoding); + + return \mb_substr_count($str, $substring, $this->encoding); + } + + /** + * Returns a lowercase and trimmed string separated by dashes. Dashes are + * inserted before uppercase characters (with the exception of the first + * character of the string), and in place of spaces as well as underscores. + * + * @return static Object with a dasherized $str + */ + public function dasherize() + { + return $this->delimit('-'); + } + + /** + * Returns a lowercase and trimmed string separated by the given delimiter. + * Delimiters are inserted before uppercase characters (with the exception + * of the first character of the string), and in place of spaces, dashes, + * and underscores. Alpha delimiters are not converted to lowercase. + * + * @param string $delimiter Sequence used to separate parts of the string + * @return static Object with a delimited $str + */ + public function delimit($delimiter) + { + $regexEncoding = $this->regexEncoding(); + $this->regexEncoding($this->encoding); + + $str = $this->eregReplace('\B([A-Z])', '-\1', $this->trim()); + $str = \mb_strtolower($str, $this->encoding); + $str = $this->eregReplace('[-_\s]+', $delimiter, $str); + + $this->regexEncoding($regexEncoding); + + return static::create($str, $this->encoding); + } + + /** + * Returns true if the string ends with $substring, false otherwise. By + * default, the comparison is case-sensitive, but can be made insensitive + * by setting $caseSensitive to false. + * + * @param string $substring The substring to look for + * @param bool $caseSensitive Whether or not to enforce case-sensitivity + * @return bool Whether or not $str ends with $substring + */ + public function endsWith($substring, $caseSensitive = true) + { + $substringLength = \mb_strlen($substring, $this->encoding); + $strLength = $this->length(); + + $endOfStr = \mb_substr($this->str, $strLength - $substringLength, + $substringLength, $this->encoding); + + if (!$caseSensitive) { + $substring = \mb_strtolower($substring, $this->encoding); + $endOfStr = \mb_strtolower($endOfStr, $this->encoding); + } + + return (string) $substring === $endOfStr; + } + + /** + * Returns true if the string ends with any of $substrings, false otherwise. + * By default, the comparison is case-sensitive, but can be made insensitive + * by setting $caseSensitive to false. + * + * @param string[] $substrings Substrings to look for + * @param bool $caseSensitive Whether or not to enforce + * case-sensitivity + * @return bool Whether or not $str ends with $substring + */ + public function endsWithAny($substrings, $caseSensitive = true) + { + if (empty($substrings)) { + return false; + } + + foreach ($substrings as $substring) { + if ($this->endsWith($substring, $caseSensitive)) { + return true; + } + } + + return false; + } + + /** + * Ensures that the string begins with $substring. If it doesn't, it's + * prepended. + * + * @param string $substring The substring to add if not present + * @return static Object with its $str prefixed by the $substring + */ + public function ensureLeft($substring) + { + $stringy = static::create($this->str, $this->encoding); + + if (!$stringy->startsWith($substring)) { + $stringy->str = $substring . $stringy->str; + } + + return $stringy; + } + + /** + * Ensures that the string ends with $substring. If it doesn't, it's + * appended. + * + * @param string $substring The substring to add if not present + * @return static Object with its $str suffixed by the $substring + */ + public function ensureRight($substring) + { + $stringy = static::create($this->str, $this->encoding); + + if (!$stringy->endsWith($substring)) { + $stringy->str .= $substring; + } + + return $stringy; + } + + /** + * Returns the first $n characters of the string. + * + * @param int $n Number of characters to retrieve from the start + * @return static Object with its $str being the first $n chars + */ + public function first($n) + { + $stringy = static::create($this->str, $this->encoding); + + if ($n < 0) { + $stringy->str = ''; + return $stringy; + } + + return $stringy->substr(0, $n); + } + + /** + * Returns the encoding used by the Stringy object. + * + * @return string The current value of the $encoding property + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Returns a new ArrayIterator, thus implementing the IteratorAggregate + * interface. The ArrayIterator's constructor is passed an array of chars + * in the multibyte string. This enables the use of foreach with instances + * of Stringy\Stringy. + * + * @return \ArrayIterator An iterator for the characters in the string + */ + public function getIterator() + { + return new ArrayIterator($this->chars()); + } + + /** + * Returns true if the string contains a lower case char, false + * otherwise. + * + * @return bool Whether or not the string contains a lower case character. + */ + public function hasLowerCase() + { + return $this->matchesPattern('.*[[:lower:]]'); + } + + /** + * Returns true if the string contains an upper case char, false + * otherwise. + * + * @return bool Whether or not the string contains an upper case character. + */ + public function hasUpperCase() + { + return $this->matchesPattern('.*[[:upper:]]'); + } + + + /** + * Convert all HTML entities to their applicable characters. An alias of + * html_entity_decode. For a list of flags, refer to + * http://php.net/manual/en/function.html-entity-decode.php + * + * @param int|null $flags Optional flags + * @return static Object with the resulting $str after being html decoded. + */ + public function htmlDecode($flags = ENT_COMPAT) + { + $str = html_entity_decode($this->str, $flags, $this->encoding); + + return static::create($str, $this->encoding); + } + + /** + * Convert all applicable characters to HTML entities. An alias of + * htmlentities. Refer to http://php.net/manual/en/function.htmlentities.php + * for a list of flags. + * + * @param int|null $flags Optional flags + * @return static Object with the resulting $str after being html encoded. + */ + public function htmlEncode($flags = ENT_COMPAT) + { + $str = htmlentities($this->str, $flags, $this->encoding); + + return static::create($str, $this->encoding); + } + + /** + * Capitalizes the first word of the string, replaces underscores with + * spaces, and strips '_id'. + * + * @return static Object with a humanized $str + */ + public function humanize() + { + $str = str_replace(['_id', '_'], ['', ' '], $this->str); + + return static::create($str, $this->encoding)->trim()->upperCaseFirst(); + } + + /** + * Returns the index of the first occurrence of $needle in the string, + * and false if not found. Accepts an optional offset from which to begin + * the search. + * + * @param string $needle Substring to look for + * @param int $offset Offset from which to search + * @return int|bool The occurrence's index if found, otherwise false + */ + public function indexOf($needle, $offset = 0) + { + return \mb_strpos($this->str, (string) $needle, + (int) $offset, $this->encoding); + } + + /** + * Returns the index of the last occurrence of $needle in the string, + * and false if not found. Accepts an optional offset from which to begin + * the search. Offsets may be negative to count from the last character + * in the string. + * + * @param string $needle Substring to look for + * @param int $offset Offset from which to search + * @return int|bool The last occurrence's index if found, otherwise false + */ + public function indexOfLast($needle, $offset = 0) + { + return \mb_strrpos($this->str, (string) $needle, + (int) $offset, $this->encoding); + } + + /** + * Inserts $substring into the string at the $index provided. + * + * @param string $substring String to be inserted + * @param int $index The index at which to insert the substring + * @return static Object with the resulting $str after the insertion + */ + public function insert($substring, $index) + { + $stringy = static::create($this->str, $this->encoding); + if ($index > $stringy->length()) { + return $stringy; + } + + $start = \mb_substr($stringy->str, 0, $index, $stringy->encoding); + $end = \mb_substr($stringy->str, $index, $stringy->length(), + $stringy->encoding); + + $stringy->str = $start . $substring . $end; + + return $stringy; + } + + /** + * Returns true if the string contains only alphabetic chars, false + * otherwise. + * + * @return bool Whether or not $str contains only alphabetic chars + */ + public function isAlpha() + { + return $this->matchesPattern('^[[:alpha:]]*$'); + } + + /** + * Returns true if the string contains only alphabetic and numeric chars, + * false otherwise. + * + * @return bool Whether or not $str contains only alphanumeric chars + */ + public function isAlphanumeric() + { + return $this->matchesPattern('^[[:alnum:]]*$'); + } + + /** + * Returns true if the string contains only whitespace chars, false + * otherwise. + * + * @return bool Whether or not $str contains only whitespace characters + */ + public function isBlank() + { + return $this->matchesPattern('^[[:space:]]*$'); + } + + /** + * Returns true if the string contains only hexadecimal chars, false + * otherwise. + * + * @return bool Whether or not $str contains only hexadecimal chars + */ + public function isHexadecimal() + { + return $this->matchesPattern('^[[:xdigit:]]*$'); + } + + /** + * Returns true if the string is JSON, false otherwise. Unlike json_decode + * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers, + * in that an empty string is not considered valid JSON. + * + * @return bool Whether or not $str is JSON + */ + public function isJson() + { + if (!$this->length()) { + return false; + } + + json_decode($this->str); + + return (json_last_error() === JSON_ERROR_NONE); + } + + /** + * Returns true if the string contains only lower case chars, false + * otherwise. + * + * @return bool Whether or not $str contains only lower case characters + */ + public function isLowerCase() + { + return $this->matchesPattern('^[[:lower:]]*$'); + } + + /** + * Returns true if the string is serialized, false otherwise. + * + * @return bool Whether or not $str is serialized + */ + public function isSerialized() + { + return $this->str === 'b:0;' || @unserialize($this->str) !== false; + } + + + /** + * Returns true if the string is base64 encoded, false otherwise. + * + * @return bool Whether or not $str is base64 encoded + */ + public function isBase64() + { + return (base64_encode(base64_decode($this->str, true)) === $this->str); + } + + /** + * Returns true if the string contains only lower case chars, false + * otherwise. + * + * @return bool Whether or not $str contains only lower case characters + */ + public function isUpperCase() + { + return $this->matchesPattern('^[[:upper:]]*$'); + } + + /** + * Returns the last $n characters of the string. + * + * @param int $n Number of characters to retrieve from the end + * @return static Object with its $str being the last $n chars + */ + public function last($n) + { + $stringy = static::create($this->str, $this->encoding); + + if ($n <= 0) { + $stringy->str = ''; + return $stringy; + } + + return $stringy->substr(-$n); + } + + /** + * Returns the length of the string. An alias for PHP's mb_strlen() function. + * + * @return int The number of characters in $str given the encoding + */ + public function length() + { + return \mb_strlen($this->str, $this->encoding); + } + + /** + * Splits on newlines and carriage returns, returning an array of Stringy + * objects corresponding to the lines in the string. + * + * @return static[] An array of Stringy objects + */ + public function lines() + { + $array = $this->split('[\r\n]{1,2}', $this->str); + for ($i = 0; $i < count($array); $i++) { + $array[$i] = static::create($array[$i], $this->encoding); + } + + return $array; + } + + /** + * Returns the longest common prefix between the string and $otherStr. + * + * @param string $otherStr Second string for comparison + * @return static Object with its $str being the longest common prefix + */ + public function longestCommonPrefix($otherStr) + { + $encoding = $this->encoding; + $maxLength = min($this->length(), \mb_strlen($otherStr, $encoding)); + + $longestCommonPrefix = ''; + for ($i = 0; $i < $maxLength; $i++) { + $char = \mb_substr($this->str, $i, 1, $encoding); + + if ($char == \mb_substr($otherStr, $i, 1, $encoding)) { + $longestCommonPrefix .= $char; + } else { + break; + } + } + + return static::create($longestCommonPrefix, $encoding); + } + + /** + * Returns the longest common suffix between the string and $otherStr. + * + * @param string $otherStr Second string for comparison + * @return static Object with its $str being the longest common suffix + */ + public function longestCommonSuffix($otherStr) + { + $encoding = $this->encoding; + $maxLength = min($this->length(), \mb_strlen($otherStr, $encoding)); + + $longestCommonSuffix = ''; + for ($i = 1; $i <= $maxLength; $i++) { + $char = \mb_substr($this->str, -$i, 1, $encoding); + + if ($char == \mb_substr($otherStr, -$i, 1, $encoding)) { + $longestCommonSuffix = $char . $longestCommonSuffix; + } else { + break; + } + } + + return static::create($longestCommonSuffix, $encoding); + } + + /** + * Returns the longest common substring between the string and $otherStr. + * In the case of ties, it returns that which occurs first. + * + * @param string $otherStr Second string for comparison + * @return static Object with its $str being the longest common substring + */ + public function longestCommonSubstring($otherStr) + { + // Uses dynamic programming to solve + // http://en.wikipedia.org/wiki/Longest_common_substring_problem + $encoding = $this->encoding; + $stringy = static::create($this->str, $encoding); + $strLength = $stringy->length(); + $otherLength = \mb_strlen($otherStr, $encoding); + + // Return if either string is empty + if ($strLength == 0 || $otherLength == 0) { + $stringy->str = ''; + return $stringy; + } + + $len = 0; + $end = 0; + $table = array_fill(0, $strLength + 1, + array_fill(0, $otherLength + 1, 0)); + + for ($i = 1; $i <= $strLength; $i++) { + for ($j = 1; $j <= $otherLength; $j++) { + $strChar = \mb_substr($stringy->str, $i - 1, 1, $encoding); + $otherChar = \mb_substr($otherStr, $j - 1, 1, $encoding); + + if ($strChar == $otherChar) { + $table[$i][$j] = $table[$i - 1][$j - 1] + 1; + if ($table[$i][$j] > $len) { + $len = $table[$i][$j]; + $end = $i; + } + } else { + $table[$i][$j] = 0; + } + } + } + + $stringy->str = \mb_substr($stringy->str, $end - $len, $len, $encoding); + + return $stringy; + } + + /** + * Converts the first character of the string to lower case. + * + * @return static Object with the first character of $str being lower case + */ + public function lowerCaseFirst() + { + $first = \mb_substr($this->str, 0, 1, $this->encoding); + $rest = \mb_substr($this->str, 1, $this->length() - 1, + $this->encoding); + + $str = \mb_strtolower($first, $this->encoding) . $rest; + + return static::create($str, $this->encoding); + } + + /** + * Returns whether or not a character exists at an index. Offsets may be + * negative to count from the last character in the string. Implements + * part of the ArrayAccess interface. + * + * @param mixed $offset The index to check + * @return boolean Whether or not the index exists + */ + public function offsetExists($offset) + { + $length = $this->length(); + $offset = (int) $offset; + + if ($offset >= 0) { + return ($length > $offset); + } + + return ($length >= abs($offset)); + } + + /** + * Returns the character at the given index. Offsets may be negative to + * count from the last character in the string. Implements part of the + * ArrayAccess interface, and throws an OutOfBoundsException if the index + * does not exist. + * + * @param mixed $offset The index from which to retrieve the char + * @return mixed The character at the specified index + * @throws \OutOfBoundsException If the positive or negative offset does + * not exist + */ + public function offsetGet($offset) + { + $offset = (int) $offset; + $length = $this->length(); + + if (($offset >= 0 && $length <= $offset) || $length < abs($offset)) { + throw new OutOfBoundsException('No character exists at the index'); + } + + return \mb_substr($this->str, $offset, 1, $this->encoding); + } + + /** + * Implements part of the ArrayAccess interface, but throws an exception + * when called. This maintains the immutability of Stringy objects. + * + * @param mixed $offset The index of the character + * @param mixed $value Value to set + * @throws \Exception When called + */ + public function offsetSet($offset, $value) + { + // Stringy is immutable, cannot directly set char + throw new Exception('Stringy object is immutable, cannot modify char'); + } + + /** + * Implements part of the ArrayAccess interface, but throws an exception + * when called. This maintains the immutability of Stringy objects. + * + * @param mixed $offset The index of the character + * @throws \Exception When called + */ + public function offsetUnset($offset) + { + // Don't allow directly modifying the string + throw new Exception('Stringy object is immutable, cannot unset char'); + } + + /** + * Pads the string to a given length with $padStr. If length is less than + * or equal to the length of the string, no padding takes places. The + * default string used for padding is a space, and the default type (one of + * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException + * if $padType isn't one of those 3 values. + * + * @param int $length Desired string length after padding + * @param string $padStr String used to pad, defaults to space + * @param string $padType One of 'left', 'right', 'both' + * @return static Object with a padded $str + * @throws /InvalidArgumentException If $padType isn't one of 'right', + * 'left' or 'both' + */ + public function pad($length, $padStr = ' ', $padType = 'right') + { + if (!in_array($padType, ['left', 'right', 'both'])) { + throw new InvalidArgumentException('Pad expects $padType ' . + "to be one of 'left', 'right' or 'both'"); + } + + switch ($padType) { + case 'left': + return $this->padLeft($length, $padStr); + case 'right': + return $this->padRight($length, $padStr); + default: + return $this->padBoth($length, $padStr); + } + } + + /** + * Returns a new string of a given length such that both sides of the + * string are padded. Alias for pad() with a $padType of 'both'. + * + * @param int $length Desired string length after padding + * @param string $padStr String used to pad, defaults to space + * @return static String with padding applied + */ + public function padBoth($length, $padStr = ' ') + { + $padding = $length - $this->length(); + + return $this->applyPadding(floor($padding / 2), ceil($padding / 2), + $padStr); + } + + /** + * Returns a new string of a given length such that the beginning of the + * string is padded. Alias for pad() with a $padType of 'left'. + * + * @param int $length Desired string length after padding + * @param string $padStr String used to pad, defaults to space + * @return static String with left padding + */ + public function padLeft($length, $padStr = ' ') + { + return $this->applyPadding($length - $this->length(), 0, $padStr); + } + + /** + * Returns a new string of a given length such that the end of the string + * is padded. Alias for pad() with a $padType of 'right'. + * + * @param int $length Desired string length after padding + * @param string $padStr String used to pad, defaults to space + * @return static String with right padding + */ + public function padRight($length, $padStr = ' ') + { + return $this->applyPadding(0, $length - $this->length(), $padStr); + } + + /** + * Returns a new string starting with $string. + * + * @param string $string The string to append + * @return static Object with appended $string + */ + public function prepend($string) + { + return static::create($string . $this->str, $this->encoding); + } + + /** + * Replaces all occurrences of $pattern in $str by $replacement. An alias + * for mb_ereg_replace(). Note that the 'i' option with multibyte patterns + * in mb_ereg_replace() requires PHP 5.6+ for correct results. This is due + * to a lack of support in the bundled version of Oniguruma in PHP < 5.6, + * and current versions of HHVM (3.8 and below). + * + * @param string $pattern The regular expression pattern + * @param string $replacement The string to replace with + * @param string $options Matching conditions to be used + * @return static Object with the resulting $str after the replacements + */ + public function regexReplace($pattern, $replacement, $options = 'msr') + { + $regexEncoding = $this->regexEncoding(); + $this->regexEncoding($this->encoding); + + $str = $this->eregReplace($pattern, $replacement, $this->str, $options); + $this->regexEncoding($regexEncoding); + + return static::create($str, $this->encoding); + } + + /** + * Returns a new string with the prefix $substring removed, if present. + * + * @param string $substring The prefix to remove + * @return static Object having a $str without the prefix $substring + */ + public function removeLeft($substring) + { + $stringy = static::create($this->str, $this->encoding); + + if ($stringy->startsWith($substring)) { + $substringLength = \mb_strlen($substring, $stringy->encoding); + return $stringy->substr($substringLength); + } + + return $stringy; + } + + /** + * Returns a new string with the suffix $substring removed, if present. + * + * @param string $substring The suffix to remove + * @return static Object having a $str without the suffix $substring + */ + public function removeRight($substring) + { + $stringy = static::create($this->str, $this->encoding); + + if ($stringy->endsWith($substring)) { + $substringLength = \mb_strlen($substring, $stringy->encoding); + return $stringy->substr(0, $stringy->length() - $substringLength); + } + + return $stringy; + } + + /** + * Returns a repeated string given a multiplier. An alias for str_repeat. + * + * @param int $multiplier The number of times to repeat the string + * @return static Object with a repeated str + */ + public function repeat($multiplier) + { + $repeated = str_repeat($this->str, $multiplier); + + return static::create($repeated, $this->encoding); + } + + /** + * Replaces all occurrences of $search in $str by $replacement. + * + * @param string $search The needle to search for + * @param string $replacement The string to replace with + * @return static Object with the resulting $str after the replacements + */ + public function replace($search, $replacement) + { + return $this->regexReplace(preg_quote($search), $replacement); + } + + /** + * Returns a reversed string. A multibyte version of strrev(). + * + * @return static Object with a reversed $str + */ + public function reverse() + { + $strLength = $this->length(); + $reversed = ''; + + // Loop from last index of string to first + for ($i = $strLength - 1; $i >= 0; $i--) { + $reversed .= \mb_substr($this->str, $i, 1, $this->encoding); + } + + return static::create($reversed, $this->encoding); + } + + /** + * Truncates the string to a given length, while ensuring that it does not + * split words. If $substring is provided, and truncating occurs, the + * string is further truncated so that the substring may be appended without + * exceeding the desired length. + * + * @param int $length Desired length of the truncated string + * @param string $substring The substring to append if it can fit + * @return static Object with the resulting $str after truncating + */ + public function safeTruncate($length, $substring = '') + { + $stringy = static::create($this->str, $this->encoding); + if ($length >= $stringy->length()) { + return $stringy; + } + + // Need to further trim the string so we can append the substring + $encoding = $stringy->encoding; + $substringLength = \mb_strlen($substring, $encoding); + $length = $length - $substringLength; + + $truncated = \mb_substr($stringy->str, 0, $length, $encoding); + + // If the last word was truncated + if (mb_strpos($stringy->str, ' ', $length - 1, $encoding) != $length) { + // Find pos of the last occurrence of a space, get up to that + $lastPos = \mb_strrpos($truncated, ' ', 0, $encoding); + if ($lastPos !== false) { + $truncated = \mb_substr($truncated, 0, $lastPos, $encoding); + } + } + + $stringy->str = $truncated . $substring; + + return $stringy; + } + + /* + * A multibyte str_shuffle() function. It returns a string with its + * characters in random order. + * + * @return static Object with a shuffled $str + */ + public function shuffle() + { + $indexes = range(0, $this->length() - 1); + shuffle($indexes); + + $shuffledStr = ''; + foreach ($indexes as $i) { + $shuffledStr .= \mb_substr($this->str, $i, 1, $this->encoding); + } + + return static::create($shuffledStr, $this->encoding); + } + + /** + * Converts the string into an URL slug. This includes replacing non-ASCII + * characters with their closest ASCII equivalents, removing remaining + * non-ASCII and non-alphanumeric characters, and replacing whitespace with + * $replacement. The replacement defaults to a single dash, and the string + * is also converted to lowercase. The language of the source string can + * also be supplied for language-specific transliteration. + * + * @param string $replacement The string used to replace whitespace + * @param string $language Language of the source string + * @return static Object whose $str has been converted to an URL slug + */ + public function slugify($replacement = '-', $language = 'en') + { + $stringy = $this->toAscii($language); + + $stringy->str = str_replace('@', $replacement, $stringy); + $quotedReplacement = preg_quote($replacement); + $pattern = "/[^a-zA-Z\d\s-_$quotedReplacement]/u"; + $stringy->str = preg_replace($pattern, '', $stringy); + + return $stringy->toLowerCase()->delimit($replacement) + ->removeLeft($replacement)->removeRight($replacement); + } + + /** + * Returns true if the string begins with $substring, false otherwise. By + * default, the comparison is case-sensitive, but can be made insensitive + * by setting $caseSensitive to false. + * + * @param string $substring The substring to look for + * @param bool $caseSensitive Whether or not to enforce + * case-sensitivity + * @return bool Whether or not $str starts with $substring + */ + public function startsWith($substring, $caseSensitive = true) + { + $substringLength = \mb_strlen($substring, $this->encoding); + $startOfStr = \mb_substr($this->str, 0, $substringLength, + $this->encoding); + + if (!$caseSensitive) { + $substring = \mb_strtolower($substring, $this->encoding); + $startOfStr = \mb_strtolower($startOfStr, $this->encoding); + } + + return (string) $substring === $startOfStr; + } + + /** + * Returns true if the string begins with any of $substrings, false + * otherwise. By default the comparison is case-sensitive, but can be made + * insensitive by setting $caseSensitive to false. + * + * @param string[] $substrings Substrings to look for + * @param bool $caseSensitive Whether or not to enforce + * case-sensitivity + * @return bool Whether or not $str starts with $substring + */ + public function startsWithAny($substrings, $caseSensitive = true) + { + if (empty($substrings)) { + return false; + } + + foreach ($substrings as $substring) { + if ($this->startsWith($substring, $caseSensitive)) { + return true; + } + } + + return false; + } + + /** + * Returns the substring beginning at $start, and up to, but not including + * the index specified by $end. If $end is omitted, the function extracts + * the remaining string. If $end is negative, it is computed from the end + * of the string. + * + * @param int $start Initial index from which to begin extraction + * @param int $end Optional index at which to end extraction + * @return static Object with its $str being the extracted substring + */ + public function slice($start, $end = null) + { + if ($end === null) { + $length = $this->length(); + } elseif ($end >= 0 && $end <= $start) { + return static::create('', $this->encoding); + } elseif ($end < 0) { + $length = $this->length() + $end - $start; + } else { + $length = $end - $start; + } + + return $this->substr($start, $length); + } + + /** + * Splits the string with the provided regular expression, returning an + * array of Stringy objects. An optional integer $limit will truncate the + * results. + * + * @param string $pattern The regex with which to split the string + * @param int $limit Optional maximum number of results to return + * @return static[] An array of Stringy objects + */ + public function split($pattern, $limit = null) + { + if ($limit === 0) { + return []; + } + + // mb_split errors when supplied an empty pattern in < PHP 5.4.13 + // and HHVM < 3.8 + if ($pattern === '') { + return [static::create($this->str, $this->encoding)]; + } + + $regexEncoding = $this->regexEncoding(); + $this->regexEncoding($this->encoding); + + // mb_split returns the remaining unsplit string in the last index when + // supplying a limit + $limit = ($limit > 0) ? $limit += 1 : -1; + + static $functionExists; + if ($functionExists === null) { + $functionExists = function_exists('\mb_split'); + } + + if ($functionExists) { + $array = \mb_split($pattern, $this->str, $limit); + } else if ($this->supportsEncoding()) { + $array = \preg_split("/$pattern/", $this->str, $limit); + } + + $this->regexEncoding($regexEncoding); + + if ($limit > 0 && count($array) === $limit) { + array_pop($array); + } + + for ($i = 0; $i < count($array); $i++) { + $array[$i] = static::create($array[$i], $this->encoding); + } + + return $array; + } + + /** + * Strip all whitespace characters. This includes tabs and newline + * characters, as well as multibyte whitespace such as the thin space + * and ideographic space. + * + * @return static Object with whitespace stripped + */ + public function stripWhitespace() + { + return $this->regexReplace('[[:space:]]+', ''); + } + + /** + * Returns the substring beginning at $start with the specified $length. + * It differs from the mb_substr() function in that providing a $length of + * null will return the rest of the string, rather than an empty string. + * + * @param int $start Position of the first character to use + * @param int $length Maximum number of characters used + * @return static Object with its $str being the substring + */ + public function substr($start, $length = null) + { + $length = $length === null ? $this->length() : $length; + $str = \mb_substr($this->str, $start, $length, $this->encoding); + + return static::create($str, $this->encoding); + } + + /** + * Surrounds $str with the given substring. + * + * @param string $substring The substring to add to both sides + * @return static Object whose $str had the substring both prepended and + * appended + */ + public function surround($substring) + { + $str = implode('', [$substring, $this->str, $substring]); + + return static::create($str, $this->encoding); + } + + /** + * Returns a case swapped version of the string. + * + * @return static Object whose $str has each character's case swapped + */ + public function swapCase() + { + $stringy = static::create($this->str, $this->encoding); + $encoding = $stringy->encoding; + + $stringy->str = preg_replace_callback( + '/[\S]/u', + function ($match) use ($encoding) { + if ($match[0] == \mb_strtoupper($match[0], $encoding)) { + return \mb_strtolower($match[0], $encoding); + } + + return \mb_strtoupper($match[0], $encoding); + }, + $stringy->str + ); + + return $stringy; + } + + /** + * Returns a string with smart quotes, ellipsis characters, and dashes from + * Windows-1252 (commonly used in Word documents) replaced by their ASCII + * equivalents. + * + * @return static Object whose $str has those characters removed + */ + public function tidy() + { + $str = preg_replace([ + '/\x{2026}/u', + '/[\x{201C}\x{201D}]/u', + '/[\x{2018}\x{2019}]/u', + '/[\x{2013}\x{2014}]/u', + ], [ + '...', + '"', + "'", + '-', + ], $this->str); + + return static::create($str, $this->encoding); + } + + /** + * Returns a trimmed string with the first letter of each word capitalized. + * Also accepts an array, $ignore, allowing you to list words not to be + * capitalized. + * + * @param array $ignore An array of words not to capitalize + * @return static Object with a titleized $str + */ + public function titleize($ignore = null) + { + $stringy = static::create($this->trim(), $this->encoding); + $encoding = $this->encoding; + + $stringy->str = preg_replace_callback( + '/([\S]+)/u', + function ($match) use ($encoding, $ignore) { + if ($ignore && in_array($match[0], $ignore)) { + return $match[0]; + } + + $stringy = new Stringy($match[0], $encoding); + + return (string) $stringy->toLowerCase()->upperCaseFirst(); + }, + $stringy->str + ); + + return $stringy; + } + + /** + * Returns an ASCII version of the string. A set of non-ASCII characters are + * replaced with their closest ASCII counterparts, and the rest are removed + * by default. The language or locale of the source string can be supplied + * for language-specific transliteration in any of the following formats: + * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping + * to "aeoeue" rather than "aou" as in other languages. + * + * @param string $language Language of the source string + * @param bool $removeUnsupported Whether or not to remove the + * unsupported characters + * @return static Object whose $str contains only ASCII characters + */ + public function toAscii($language = 'en', $removeUnsupported = true) + { + $str = $this->str; + + $langSpecific = $this->langSpecificCharsArray($language); + if (!empty($langSpecific)) { + $str = str_replace($langSpecific[0], $langSpecific[1], $str); + } + + foreach ($this->charsArray() as $key => $value) { + $str = str_replace($value, $key, $str); + } + + if ($removeUnsupported) { + $str = preg_replace('/[^\x20-\x7E]/u', '', $str); + } + + return static::create($str, $this->encoding); + } + + /** + * Returns a boolean representation of the given logical string value. + * For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0', + * 'off', and 'no' will return false. In all instances, case is ignored. + * For other numeric strings, their sign will determine the return value. + * In addition, blank strings consisting of only whitespace will return + * false. For all other strings, the return value is a result of a + * boolean cast. + * + * @return bool A boolean value for the string + */ + public function toBoolean() + { + $key = $this->toLowerCase()->str; + $map = [ + 'true' => true, + '1' => true, + 'on' => true, + 'yes' => true, + 'false' => false, + '0' => false, + 'off' => false, + 'no' => false + ]; + + if (array_key_exists($key, $map)) { + return $map[$key]; + } elseif (is_numeric($this->str)) { + return (intval($this->str) > 0); + } + + return (bool) $this->regexReplace('[[:space:]]', '')->str; + } + + /** + * Converts all characters in the string to lowercase. An alias for PHP's + * mb_strtolower(). + * + * @return static Object with all characters of $str being lowercase + */ + public function toLowerCase() + { + $str = \mb_strtolower($this->str, $this->encoding); + + return static::create($str, $this->encoding); + } + + /** + * Converts each tab in the string to some number of spaces, as defined by + * $tabLength. By default, each tab is converted to 4 consecutive spaces. + * + * @param int $tabLength Number of spaces to replace each tab with + * @return static Object whose $str has had tabs switched to spaces + */ + public function toSpaces($tabLength = 4) + { + $spaces = str_repeat(' ', $tabLength); + $str = str_replace("\t", $spaces, $this->str); + + return static::create($str, $this->encoding); + } + + /** + * Converts each occurrence of some consecutive number of spaces, as + * defined by $tabLength, to a tab. By default, each 4 consecutive spaces + * are converted to a tab. + * + * @param int $tabLength Number of spaces to replace with a tab + * @return static Object whose $str has had spaces switched to tabs + */ + public function toTabs($tabLength = 4) + { + $spaces = str_repeat(' ', $tabLength); + $str = str_replace($spaces, "\t", $this->str); + + return static::create($str, $this->encoding); + } + + /** + * Converts the first character of each word in the string to uppercase. + * + * @return static Object with all characters of $str being title-cased + */ + public function toTitleCase() + { + $str = \mb_convert_case($this->str, \MB_CASE_TITLE, $this->encoding); + + return static::create($str, $this->encoding); + } + + /** + * Converts all characters in the string to uppercase. An alias for PHP's + * mb_strtoupper(). + * + * @return static Object with all characters of $str being uppercase + */ + public function toUpperCase() + { + $str = \mb_strtoupper($this->str, $this->encoding); + + return static::create($str, $this->encoding); + } + + /** + * Returns a string with whitespace removed from the start and end of the + * string. Supports the removal of unicode whitespace. Accepts an optional + * string of characters to strip instead of the defaults. + * + * @param string $chars Optional string of characters to strip + * @return static Object with a trimmed $str + */ + public function trim($chars = null) + { + $chars = ($chars) ? preg_quote($chars) : '[:space:]'; + + return $this->regexReplace("^[$chars]+|[$chars]+\$", ''); + } + + /** + * Returns a string with whitespace removed from the start of the string. + * Supports the removal of unicode whitespace. Accepts an optional + * string of characters to strip instead of the defaults. + * + * @param string $chars Optional string of characters to strip + * @return static Object with a trimmed $str + */ + public function trimLeft($chars = null) + { + $chars = ($chars) ? preg_quote($chars) : '[:space:]'; + + return $this->regexReplace("^[$chars]+", ''); + } + + /** + * Returns a string with whitespace removed from the end of the string. + * Supports the removal of unicode whitespace. Accepts an optional + * string of characters to strip instead of the defaults. + * + * @param string $chars Optional string of characters to strip + * @return static Object with a trimmed $str + */ + public function trimRight($chars = null) + { + $chars = ($chars) ? preg_quote($chars) : '[:space:]'; + + return $this->regexReplace("[$chars]+\$", ''); + } + + /** + * Truncates the string to a given length. If $substring is provided, and + * truncating occurs, the string is further truncated so that the substring + * may be appended without exceeding the desired length. + * + * @param int $length Desired length of the truncated string + * @param string $substring The substring to append if it can fit + * @return static Object with the resulting $str after truncating + */ + public function truncate($length, $substring = '') + { + $stringy = static::create($this->str, $this->encoding); + if ($length >= $stringy->length()) { + return $stringy; + } + + // Need to further trim the string so we can append the substring + $substringLength = \mb_strlen($substring, $stringy->encoding); + $length = $length - $substringLength; + + $truncated = \mb_substr($stringy->str, 0, $length, $stringy->encoding); + $stringy->str = $truncated . $substring; + + return $stringy; + } + + /** + * Returns a lowercase and trimmed string separated by underscores. + * Underscores are inserted before uppercase characters (with the exception + * of the first character of the string), and in place of spaces as well as + * dashes. + * + * @return static Object with an underscored $str + */ + public function underscored() + { + return $this->delimit('_'); + } + + /** + * Returns an UpperCamelCase version of the supplied string. It trims + * surrounding spaces, capitalizes letters following digits, spaces, dashes + * and underscores, and removes spaces, dashes, underscores. + * + * @return static Object with $str in UpperCamelCase + */ + public function upperCamelize() + { + return $this->camelize()->upperCaseFirst(); + } + + /** + * Converts the first character of the supplied string to upper case. + * + * @return static Object with the first character of $str being upper case + */ + public function upperCaseFirst() + { + $first = \mb_substr($this->str, 0, 1, $this->encoding); + $rest = \mb_substr($this->str, 1, $this->length() - 1, + $this->encoding); + + $str = \mb_strtoupper($first, $this->encoding) . $rest; + + return static::create($str, $this->encoding); + } + + /** + * Returns the replacements for the toAscii() method. + * + * @return array An array of replacements. + */ + protected function charsArray() + { + static $charsArray; + if (isset($charsArray)) return $charsArray; + + return $charsArray = [ + '0' => ['°', '₀', '۰', '0'], + '1' => ['¹', '₁', '۱', '1'], + '2' => ['²', '₂', '۲', '2'], + '3' => ['³', '₃', '۳', '3'], + '4' => ['⁴', '₄', '۴', '٤', '4'], + '5' => ['⁵', '₅', '۵', '٥', '5'], + '6' => ['⁶', '₆', '۶', '٦', '6'], + '7' => ['⁷', '₇', '۷', '7'], + '8' => ['⁸', '₈', '۸', '8'], + '9' => ['⁹', '₉', '۹', '9'], + 'a' => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ', + 'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å', + 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ', 'ἇ', + 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', 'ά', + 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ', 'အ', + 'ာ', 'ါ', 'ǻ', 'ǎ', 'ª', 'ა', 'अ', 'ا', 'a', 'ä'], + 'b' => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b'], + 'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'], + 'd' => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', + 'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ', 'd'], + 'e' => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ', + 'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ', + 'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э', + 'є', 'ə', 'ဧ', 'ေ', 'ဲ', 'ე', 'ए', 'إ', 'ئ', 'e'], + 'f' => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f'], + 'g' => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ဂ', 'გ', 'گ', + 'g'], + 'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h'], + 'i' => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į', + 'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ', + 'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ', + 'ῗ', 'і', 'ї', 'и', 'ဣ', 'ိ', 'ီ', 'ည်', 'ǐ', 'ი', + 'इ', 'ی', 'i'], + 'j' => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'], + 'k' => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ', + 'ک', 'k'], + 'l' => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ', + 'l'], + 'm' => ['м', 'μ', 'م', 'မ', 'მ', 'm'], + 'n' => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န', + 'ნ', 'n'], + 'o' => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ', + 'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő', + 'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό', + 'о', 'و', 'θ', 'ို', 'ǒ', 'ǿ', 'º', 'ო', 'ओ', 'o', + 'ö'], + 'p' => ['п', 'π', 'ပ', 'პ', 'پ', 'p'], + 'q' => ['ყ', 'q'], + 'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r'], + 's' => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ', + 'ſ', 'ს', 's'], + 't' => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ', + 'თ', 'ტ', 't'], + 'u' => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ', + 'ự', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у', 'ဉ', + 'ု', 'ူ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'უ', 'उ', 'u', + 'ў', 'ü'], + 'v' => ['в', 'ვ', 'ϐ', 'v'], + 'w' => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'], + 'x' => ['χ', 'ξ', 'x'], + 'y' => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', + 'ϋ', 'ύ', 'ΰ', 'ي', 'ယ', 'y'], + 'z' => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z'], + 'aa' => ['ع', 'आ', 'آ'], + 'ae' => ['æ', 'ǽ'], + 'ai' => ['ऐ'], + 'ch' => ['ч', 'ჩ', 'ჭ', 'چ'], + 'dj' => ['ђ', 'đ'], + 'dz' => ['џ', 'ძ'], + 'ei' => ['ऍ'], + 'gh' => ['غ', 'ღ'], + 'ii' => ['ई'], + 'ij' => ['ij'], + 'kh' => ['х', 'خ', 'ხ'], + 'lj' => ['љ'], + 'nj' => ['њ'], + 'oe' => ['œ', 'ؤ'], + 'oi' => ['ऑ'], + 'oii' => ['ऒ'], + 'ps' => ['ψ'], + 'sh' => ['ш', 'შ', 'ش'], + 'shch' => ['щ'], + 'ss' => ['ß'], + 'sx' => ['ŝ'], + 'th' => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'], + 'ts' => ['ц', 'ც', 'წ'], + 'uu' => ['ऊ'], + 'ya' => ['я'], + 'yu' => ['ю'], + 'zh' => ['ж', 'ჟ', 'ژ'], + '(c)' => ['©'], + 'A' => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', + 'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą', + 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ', + 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', 'Ᾱ', + 'Ὰ', 'Ά', 'ᾼ', 'А', 'Ǻ', 'Ǎ', 'A', 'Ä'], + 'B' => ['Б', 'Β', 'ब', 'B'], + 'C' => ['Ç','Ć', 'Č', 'Ĉ', 'Ċ', 'C'], + 'D' => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ', + 'D'], + 'E' => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ', + 'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ', + 'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э', + 'Є', 'Ə', 'E'], + 'F' => ['Ф', 'Φ', 'F'], + 'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'], + 'H' => ['Η', 'Ή', 'Ħ', 'H'], + 'I' => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į', + 'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ', + 'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї', 'Ǐ', 'ϒ', + 'I'], + 'J' => ['J'], + 'K' => ['К', 'Κ', 'K'], + 'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'], + 'M' => ['М', 'Μ', 'M'], + 'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'], + 'O' => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ', + 'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő', + 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ', + 'Ό', 'О', 'Θ', 'Ө', 'Ǒ', 'Ǿ', 'O', 'Ö'], + 'P' => ['П', 'Π', 'P'], + 'Q' => ['Q'], + 'R' => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'], + 'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'], + 'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'], + 'U' => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ', + 'Ự', 'Û', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У', 'Ǔ', 'Ǖ', + 'Ǘ', 'Ǚ', 'Ǜ', 'U', 'Ў', 'Ü'], + 'V' => ['В', 'V'], + 'W' => ['Ω', 'Ώ', 'Ŵ', 'W'], + 'X' => ['Χ', 'Ξ', 'X'], + 'Y' => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', + 'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ', 'Y'], + 'Z' => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'], + 'AE' => ['Æ', 'Ǽ'], + 'Ch' => ['Ч'], + 'Dj' => ['Ђ'], + 'Dz' => ['Џ'], + 'Gx' => ['Ĝ'], + 'Hx' => ['Ĥ'], + 'Ij' => ['IJ'], + 'Jx' => ['Ĵ'], + 'Kh' => ['Х'], + 'Lj' => ['Љ'], + 'Nj' => ['Њ'], + 'Oe' => ['Œ'], + 'Ps' => ['Ψ'], + 'Sh' => ['Ш'], + 'Shch' => ['Щ'], + 'Ss' => ['ẞ'], + 'Th' => ['Þ'], + 'Ts' => ['Ц'], + 'Ya' => ['Я'], + 'Yu' => ['Ю'], + 'Zh' => ['Ж'], + ' ' => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", + "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", + "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", + "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", + "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80", + "\xEF\xBE\xA0"], + ]; + } + + /** + * Returns language-specific replacements for the toAscii() method. + * For example, German will map 'ä' to 'ae', while other languages + * will simply return 'a'. + * + * @param string $language Language of the source string + * @return array An array of replacements. + */ + protected static function langSpecificCharsArray($language = 'en') + { + $split = preg_split('/[-_]/', $language); + $language = strtolower($split[0]); + + static $charsArray = []; + if (isset($charsArray[$language])) { + return $charsArray[$language]; + } + + $languageSpecific = [ + 'de' => [ + ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü' ], + ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], + ], + 'bg' => [ + ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'], + ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'] + ] + ]; + + if (isset($languageSpecific[$language])) { + $charsArray[$language] = $languageSpecific[$language]; + } else { + $charsArray[$language] = []; + } + + return $charsArray[$language]; + } + + /** + * Adds the specified amount of left and right padding to the given string. + * The default character used is a space. + * + * @param int $left Length of left padding + * @param int $right Length of right padding + * @param string $padStr String used to pad + * @return static String with padding applied + */ + protected function applyPadding($left = 0, $right = 0, $padStr = ' ') + { + $stringy = static::create($this->str, $this->encoding); + $length = \mb_strlen($padStr, $stringy->encoding); + + $strLength = $stringy->length(); + $paddedLength = $strLength + $left + $right; + + if (!$length || $paddedLength <= $strLength) { + return $stringy; + } + + $leftPadding = \mb_substr(str_repeat($padStr, ceil($left / $length)), 0, + $left, $stringy->encoding); + $rightPadding = \mb_substr(str_repeat($padStr, ceil($right / $length)), + 0, $right, $stringy->encoding); + + $stringy->str = $leftPadding . $stringy->str . $rightPadding; + + return $stringy; + } + + /** + * Returns true if $str matches the supplied pattern, false otherwise. + * + * @param string $pattern Regex pattern to match against + * @return bool Whether or not $str matches the pattern + */ + protected function matchesPattern($pattern) + { + $regexEncoding = $this->regexEncoding(); + $this->regexEncoding($this->encoding); + + $match = \mb_ereg_match($pattern, $this->str); + $this->regexEncoding($regexEncoding); + + return $match; + } + + /** + * Alias for mb_ereg_replace with a fallback to preg_replace if the + * mbstring module is not installed. + */ + protected function eregReplace($pattern, $replacement, $string, $option = 'msr') + { + static $functionExists; + if ($functionExists === null) { + $functionExists = function_exists('\mb_split'); + } + + if ($functionExists) { + return \mb_ereg_replace($pattern, $replacement, $string, $option); + } else if ($this->supportsEncoding()) { + $option = str_replace('r', '', $option); + return \preg_replace("/$pattern/u$option", $replacement, $string); + } + } + + /** + * Alias for mb_regex_encoding which default to a noop if the mbstring + * module is not installed. + */ + protected function regexEncoding() + { + static $functionExists; + + if ($functionExists === null) { + $functionExists = function_exists('\mb_regex_encoding'); + } + + if ($functionExists) { + $args = func_get_args(); + return call_user_func_array('\mb_regex_encoding', $args); + } + } + + protected function supportsEncoding() + { + $supported = ['UTF-8' => true, 'ASCII' => true]; + + if (isset($supported[$this->encoding])) { + return true; + } else { + throw new \RuntimeException('Stringy method requires the ' . + 'mbstring module for encodings other than ASCII and UTF-8. ' . + 'Encoding used: ' . $this->encoding); + } + } +} diff --git a/serve/vendor/dasprid/enum/LICENSE b/serve/vendor/dasprid/enum/LICENSE new file mode 100644 index 0000000..d45a356 --- /dev/null +++ b/serve/vendor/dasprid/enum/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2017, Ben Scholzen 'DASPRiD' +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/serve/vendor/dasprid/enum/README.md b/serve/vendor/dasprid/enum/README.md new file mode 100644 index 0000000..9e9ca12 --- /dev/null +++ b/serve/vendor/dasprid/enum/README.md @@ -0,0 +1,164 @@ +# PHP 7.1 enums + +[![Build Status](https://travis-ci.org/DASPRiD/Enum.svg?branch=master)](https://travis-ci.org/DASPRiD/Enum) +[![Coverage Status](https://coveralls.io/repos/github/DASPRiD/Enum/badge.svg?branch=master)](https://coveralls.io/github/DASPRiD/Enum?branch=master) +[![Latest Stable Version](https://poser.pugx.org/dasprid/enum/v/stable)](https://packagist.org/packages/dasprid/enum) +[![Total Downloads](https://poser.pugx.org/dasprid/enum/downloads)](https://packagist.org/packages/dasprid/enum) +[![License](https://poser.pugx.org/dasprid/enum/license)](https://packagist.org/packages/dasprid/enum) + +It is a well known fact that PHP is missing a basic enum type, ignoring the rather incomplete `SplEnum` implementation +which is only available as a PECL extension. There are also quite a few other userland enum implementations around, +but all of them have one or another compromise. This library tries to close that gap as far as PHP allows it to. + +## Usage + +### Basics + +At its core, there is the `DASPRiD\Enum\AbstractEnum` class, which by default will work with constants like any other +enum implementation you might know. The first clear difference is that you should define all the constants as protected +(so nobody outside your class can read them but the `AbstractEnum` can still do so). The other even mightier difference +is that, for simple enums, the value of the constant doesn't matter at all. Let's have a look at a simple example: + +```php +use DASPRiD\Enum\AbstractEnum; + +/** + * @method static self MONDAY() + * @method static self TUESDAY() + * @method static self WEDNESDAY() + * @method static self THURSDAY() + * @method static self FRIDAY() + * @method static self SATURDAY() + * @method static self SUNDAY() + */ +final class WeekDay extends AbstractEnum +{ + protected const MONDAY = null; + protected const TUESDAY = null; + protected const WEDNESDAY = null; + protected const THURSDAY = null; + protected const FRIDAY = null; + protected const SATURDAY = null; + protected const SUNDAY = null; +} +``` + +If you need to provide constants for either internal use or public use, you can mark them as either private or public, +in which case they will be ignored by the enum, which only considers protected constants as valid values. As you can +see, we specifically defined the generated magic methods in a class level doc block, so anyone using this class will +automatically have proper auto-completion in their IDE. Now since you have defined the enum, you can simply use it like +that: + +```php +function tellItLikeItIs(WeekDay $weekDay) +{ + switch ($weekDay) { + case WeekDay::MONDAY(): + echo 'Mondays are bad.'; + break; + + case WeekDay::FRIDAY(): + echo 'Fridays are better.'; + break; + + case WeekDay::SATURDAY(): + case WeekDay::SUNDAY(): + echo 'Weekends are best.'; + break; + + default: + echo 'Midweek days are so-so.'; + } +} + +tellItLikeItIs(WeekDay::MONDAY()); +tellItLikeItIs(WeekDay::WEDNESDAY()); +tellItLikeItIs(WeekDay::FRIDAY()); +tellItLikeItIs(WeekDay::SATURDAY()); +tellItLikeItIs(WeekDay::SUNDAY()); +``` + +### More complex example + +Of course, all enums are singletons, which are not cloneable or serializable. Thus you can be sure that there is always +just one instance of the same type. Of course, the values of constants are not completely useless, let's have a look at +a more complex example: + +```php +use DASPRiD\Enum\AbstractEnum; + +/** + * @method static self MERCURY() + * @method static self VENUS() + * @method static self EARTH() + * @method static self MARS() + * @method static self JUPITER() + * @method static self SATURN() + * @method static self URANUS() + * @method static self NEPTUNE() + */ +final class Planet extends AbstractEnum +{ + protected const MERCURY = [3.303e+23, 2.4397e6]; + protected const VENUS = [4.869e+24, 6.0518e6]; + protected const EARTH = [5.976e+24, 6.37814e6]; + protected const MARS = [6.421e+23, 3.3972e6]; + protected const JUPITER = [1.9e+27, 7.1492e7]; + protected const SATURN = [5.688e+26, 6.0268e7]; + protected const URANUS = [8.686e+25, 2.5559e7]; + protected const NEPTUNE = [1.024e+26, 2.4746e7]; + + /** + * Universal gravitational constant. + * + * @var float + */ + private const G = 6.67300E-11; + + /** + * Mass in kilograms. + * + * @var float + */ + private $mass; + + /** + * Radius in meters. + * + * @var float + */ + private $radius; + + protected function __construct(float $mass, float $radius) + { + $this->mass = $mass; + $this->radius = $radius; + } + + public function mass() : float + { + return $this->mass; + } + + public function radius() : float + { + return $this->radius; + } + + public function surfaceGravity() : float + { + return self::G * $this->mass / ($this->radius * $this->radius); + } + + public function surfaceWeight(float $otherMass) : float + { + return $otherMass * $this->surfaceGravity(); + } +} + +$myMass = 80; + +foreach (Planet::values() as $planet) { + printf("Your weight on %s is %f\n", $planet, $planet->surfaceWeight($myMass)); +} +``` diff --git a/serve/vendor/dasprid/enum/composer.json b/serve/vendor/dasprid/enum/composer.json new file mode 100644 index 0000000..b3d745a --- /dev/null +++ b/serve/vendor/dasprid/enum/composer.json @@ -0,0 +1,31 @@ +{ + "name": "dasprid/enum", + "description": "PHP 7.1 enum implementation", + "license": "BSD-2-Clause", + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "keywords": [ + "enum", + "map" + ], + "require-dev": { + "phpunit/phpunit": "^7 | ^8 | ^9", + "squizlabs/php_codesniffer": "^3.4" + }, + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "DASPRiD\\EnumTest\\": "test/" + } + } +} diff --git a/serve/vendor/dasprid/enum/phpunit.xml.dist b/serve/vendor/dasprid/enum/phpunit.xml.dist new file mode 100644 index 0000000..307a430 --- /dev/null +++ b/serve/vendor/dasprid/enum/phpunit.xml.dist @@ -0,0 +1,17 @@ + + + + + ./test + + + + + + src + + + diff --git a/serve/vendor/dasprid/enum/src/AbstractEnum.php b/serve/vendor/dasprid/enum/src/AbstractEnum.php new file mode 100644 index 0000000..79fe81c --- /dev/null +++ b/serve/vendor/dasprid/enum/src/AbstractEnum.php @@ -0,0 +1,241 @@ +> + */ + private static $values = []; + + /** + * @var array + */ + private static $allValuesLoaded = []; + + /** + * @var array + */ + private static $constants = []; + + /** + * The constructor is private by default to avoid arbitrary enum creation. + * + * When creating your own constructor for a parameterized enum, make sure to declare it as protected, so that + * the static methods are able to construct it. Avoid making it public, as that would allow creation of + * non-singleton enum instances. + */ + private function __construct() + { + } + + /** + * Magic getter which forwards all calls to {@see self::valueOf()}. + * + * @return static + */ + final public static function __callStatic(string $name, array $arguments) : self + { + return static::valueOf($name); + } + + /** + * Returns an enum with the specified name. + * + * The name must match exactly an identifier used to declare an enum in this type (extraneous whitespace characters + * are not permitted). + * + * @return static + * @throws IllegalArgumentException if the enum has no constant with the specified name + */ + final public static function valueOf(string $name) : self + { + if (isset(self::$values[static::class][$name])) { + return self::$values[static::class][$name]; + } + + $constants = self::constants(); + + if (array_key_exists($name, $constants)) { + return self::createValue($name, $constants[$name][0], $constants[$name][1]); + } + + throw new IllegalArgumentException(sprintf('No enum constant %s::%s', static::class, $name)); + } + + /** + * @return static + */ + private static function createValue(string $name, int $ordinal, array $arguments) : self + { + $instance = new static(...$arguments); + $instance->name = $name; + $instance->ordinal = $ordinal; + self::$values[static::class][$name] = $instance; + return $instance; + } + + /** + * Obtains all possible types defined by this enum. + * + * @return static[] + */ + final public static function values() : array + { + if (isset(self::$allValuesLoaded[static::class])) { + return self::$values[static::class]; + } + + if (! isset(self::$values[static::class])) { + self::$values[static::class] = []; + } + + foreach (self::constants() as $name => $constant) { + if (array_key_exists($name, self::$values[static::class])) { + continue; + } + + static::createValue($name, $constant[0], $constant[1]); + } + + uasort(self::$values[static::class], function (self $a, self $b) { + return $a->ordinal() <=> $b->ordinal(); + }); + + self::$allValuesLoaded[static::class] = true; + return self::$values[static::class]; + } + + private static function constants() : array + { + if (isset(self::$constants[static::class])) { + return self::$constants[static::class]; + } + + self::$constants[static::class] = []; + $reflectionClass = new ReflectionClass(static::class); + $ordinal = -1; + + foreach ($reflectionClass->getReflectionConstants() as $reflectionConstant) { + if (! $reflectionConstant->isProtected()) { + continue; + } + + $value = $reflectionConstant->getValue(); + + self::$constants[static::class][$reflectionConstant->name] = [ + ++$ordinal, + is_array($value) ? $value : [] + ]; + } + + return self::$constants[static::class]; + } + + /** + * Returns the name of this enum constant, exactly as declared in its enum declaration. + * + * Most programmers should use the {@see self::__toString()} method in preference to this one, as the toString + * method may return a more user-friendly name. This method is designed primarily for use in specialized situations + * where correctness depends on getting the exact name, which will not vary from release to release. + */ + final public function name() : string + { + return $this->name; + } + + /** + * Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial + * constant is assigned an ordinal of zero). + * + * Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data + * structures. + */ + final public function ordinal() : int + { + return $this->ordinal; + } + + /** + * Compares this enum with the specified object for order. + * + * Returns negative integer, zero or positive integer as this object is less than, equal to or greater than the + * specified object. + * + * Enums are only comparable to other enums of the same type. The natural order implemented by this method is the + * order in which the constants are declared. + * + * @throws MismatchException if the passed enum is not of the same type + */ + final public function compareTo(self $other) : int + { + if (! $other instanceof static) { + throw new MismatchException(sprintf( + 'The passed enum %s is not of the same type as %s', + get_class($other), + static::class + )); + } + + return $this->ordinal - $other->ordinal; + } + + /** + * Forbid cloning enums. + * + * @throws CloneNotSupportedException + */ + final public function __clone() + { + throw new CloneNotSupportedException(); + } + + /** + * Forbid serializing enums. + * + * @throws SerializeNotSupportedException + */ + final public function __sleep() : array + { + throw new SerializeNotSupportedException(); + } + + /** + * Forbid unserializing enums. + * + * @throws UnserializeNotSupportedException + */ + final public function __wakeup() : void + { + throw new UnserializeNotSupportedException(); + } + + /** + * Turns the enum into a string representation. + * + * You may override this method to give a more user-friendly version. + */ + public function __toString() : string + { + return $this->name; + } +} diff --git a/serve/vendor/dasprid/enum/src/EnumMap.php b/serve/vendor/dasprid/enum/src/EnumMap.php new file mode 100644 index 0000000..77c5f35 --- /dev/null +++ b/serve/vendor/dasprid/enum/src/EnumMap.php @@ -0,0 +1,375 @@ + + */ + private $keyUniverse; + + /** + * Array representation of this map. The ith element is the value to which universe[i] is currently mapped, or null + * if it isn't mapped to anything, or NullValue if it's mapped to null. + * + * @var array + */ + private $values; + + /** + * @var int + */ + private $size = 0; + + /** + * Creates a new enum map. + * + * @param string $keyType the type of the keys, must extend AbstractEnum + * @param string $valueType the type of the values + * @param bool $allowNullValues whether to allow null values + * @throws IllegalArgumentException when key type does not extend AbstractEnum + */ + public function __construct(string $keyType, string $valueType, bool $allowNullValues) + { + if (! is_subclass_of($keyType, AbstractEnum::class)) { + throw new IllegalArgumentException(sprintf( + 'Class %s does not extend %s', + $keyType, + AbstractEnum::class + )); + } + + $this->keyType = $keyType; + $this->valueType = $valueType; + $this->allowNullValues = $allowNullValues; + $this->keyUniverse = $keyType::values(); + $this->values = array_fill(0, count($this->keyUniverse), null); + } + + /** + * Checks whether the map types match the supplied ones. + * + * You should call this method when an EnumMap is passed to you and you want to ensure that it's made up of the + * correct types. + * + * @throws ExpectationException when supplied key type mismatches local key type + * @throws ExpectationException when supplied value type mismatches local value type + * @throws ExpectationException when the supplied map allows null values, abut should not + */ + public function expect(string $keyType, string $valueType, bool $allowNullValues) : void + { + if ($keyType !== $this->keyType) { + throw new ExpectationException(sprintf( + 'Callee expected an EnumMap with key type %s, but got %s', + $keyType, + $this->keyType + )); + } + + if ($valueType !== $this->valueType) { + throw new ExpectationException(sprintf( + 'Callee expected an EnumMap with value type %s, but got %s', + $keyType, + $this->keyType + )); + } + + if ($allowNullValues !== $this->allowNullValues) { + throw new ExpectationException(sprintf( + 'Callee expected an EnumMap with nullable flag %s, but got %s', + ($allowNullValues ? 'true' : 'false'), + ($this->allowNullValues ? 'true' : 'false') + )); + } + } + + /** + * Returns the number of key-value mappings in this map. + */ + public function size() : int + { + return $this->size; + } + + /** + * Returns true if this map maps one or more keys to the specified value. + */ + public function containsValue($value) : bool + { + return in_array($this->maskNull($value), $this->values, true); + } + + /** + * Returns true if this map contains a mapping for the specified key. + */ + public function containsKey(AbstractEnum $key) : bool + { + $this->checkKeyType($key); + return null !== $this->values[$key->ordinal()]; + } + + /** + * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. + * + * More formally, if this map contains a mapping from a key to a value, then this method returns the value; + * otherwise it returns null (there can be at most one such mapping). + * + * A return value of null does not necessarily indicate that the map contains no mapping for the key; it's also + * possible that hte map explicitly maps the key to null. The {@see self::containsKey()} operation may be used to + * distinguish these two cases. + * + * @return mixed + */ + public function get(AbstractEnum $key) + { + $this->checkKeyType($key); + return $this->unmaskNull($this->values[$key->ordinal()]); + } + + /** + * Associates the specified value with the specified key in this map. + * + * If the map previously contained a mapping for this key, the old value is replaced. + * + * @return mixed the previous value associated with the specified key, or null if there was no mapping for the key. + * (a null return can also indicate that the map previously associated null with the specified key.) + * @throws IllegalArgumentException when the passed values does not match the internal value type + */ + public function put(AbstractEnum $key, $value) + { + $this->checkKeyType($key); + + if (! $this->isValidValue($value)) { + throw new IllegalArgumentException(sprintf('Value is not of type %s', $this->valueType)); + } + + $index = $key->ordinal(); + $oldValue = $this->values[$index]; + $this->values[$index] = $this->maskNull($value); + + if (null === $oldValue) { + ++$this->size; + } + + return $this->unmaskNull($oldValue); + } + + /** + * Removes the mapping for this key frm this map if present. + * + * @return mixed the previous value associated with the specified key, or null if there was no mapping for the key. + * (a null return can also indicate that the map previously associated null with the specified key.) + */ + public function remove(AbstractEnum $key) + { + $this->checkKeyType($key); + + $index = $key->ordinal(); + $oldValue = $this->values[$index]; + $this->values[$index] = null; + + if (null !== $oldValue) { + --$this->size; + } + + return $this->unmaskNull($oldValue); + } + + /** + * Removes all mappings from this map. + */ + public function clear() : void + { + $this->values = array_fill(0, count($this->keyUniverse), null); + $this->size = 0; + } + + /** + * Compares the specified map with this map for quality. + * + * Returns true if the two maps represent the same mappings. + */ + public function equals(self $other) : bool + { + if ($this === $other) { + return true; + } + + if ($this->size !== $other->size) { + return false; + } + + return $this->values === $other->values; + } + + /** + * Returns the values contained in this map. + * + * The array will contain the values in the order their corresponding keys appear in the map, which is their natural + * order (the order in which the num constants are declared). + */ + public function values() : array + { + return array_values(array_map(function ($value) { + return $this->unmaskNull($value); + }, array_filter($this->values, function ($value) : bool { + return null !== $value; + }))); + } + + public function serialize() : string + { + $values = []; + + foreach ($this->values as $ordinal => $value) { + if (null === $value) { + continue; + } + + $values[$ordinal] = $this->unmaskNull($value); + } + + return serialize([ + 'keyType' => $this->keyType, + 'valueType' => $this->valueType, + 'allowNullValues' => $this->allowNullValues, + 'values' => $values, + ]); + } + + public function unserialize($serialized) : void + { + $data = unserialize($serialized); + $this->__construct($data['keyType'], $data['valueType'], $data['allowNullValues']); + + foreach ($this->keyUniverse as $key) { + if (array_key_exists($key->ordinal(), $data['values'])) { + $this->put($key, $data['values'][$key->ordinal()]); + } + } + } + + public function getIterator() : Traversable + { + foreach ($this->keyUniverse as $key) { + if (null === $this->values[$key->ordinal()]) { + continue; + } + + yield $key => $this->unmaskNull($this->values[$key->ordinal()]); + } + } + + private function maskNull($value) + { + if (null === $value) { + return NullValue::instance(); + } + + return $value; + } + + private function unmaskNull($value) + { + if ($value instanceof NullValue) { + return null; + } + + return $value; + } + + /** + * @throws IllegalArgumentException when the passed key does not match the internal key type + */ + private function checkKeyType(AbstractEnum $key) : void + { + if (get_class($key) !== $this->keyType) { + throw new IllegalArgumentException(sprintf( + 'Object of type %s is not the same type as %s', + get_class($key), + $this->keyType + )); + } + } + + private function isValidValue($value) : bool + { + if (null === $value) { + if ($this->allowNullValues) { + return true; + } + + return false; + } + + switch ($this->valueType) { + case 'mixed': + return true; + + case 'bool': + case 'boolean': + return is_bool($value); + + case 'int': + case 'integer': + return is_int($value); + + case 'float': + case 'double': + return is_float($value); + + case 'string': + return is_string($value); + + case 'object': + return is_object($value); + + case 'array': + return is_array($value); + } + + return $value instanceof $this->valueType; + } +} diff --git a/serve/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php b/serve/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php new file mode 100644 index 0000000..4b37dbe --- /dev/null +++ b/serve/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php @@ -0,0 +1,10 @@ +getProperty('constants'); + $constantsProperty->setAccessible(true); + $constantsProperty->setValue([]); + + $valuesProperty = $reflectionClass->getProperty('values'); + $valuesProperty->setAccessible(true); + $valuesProperty->setValue([]); + + $allValuesLoadedProperty = $reflectionClass->getProperty('allValuesLoaded'); + $allValuesLoadedProperty->setAccessible(true); + $allValuesLoadedProperty->setValue([]); + } + + public function testToString() : void + { + $weekday = WeekDay::FRIDAY(); + self::assertSame('FRIDAY', (string) $weekday); + } + + public function testName() : void + { + $this->assertSame('WEDNESDAY', WeekDay::WEDNESDAY()->name()); + } + + public function testOrdinal() : void + { + $this->assertSame(2, WeekDay::WEDNESDAY()->ordinal()); + } + + public function testSameInstanceIsReturned() : void + { + self::assertSame(WeekDay::FRIDAY(), WeekDay::FRIDAY()); + } + + public static function testValueOf() : void + { + self::assertSame(WeekDay::FRIDAY(), WeekDay::valueOf('FRIDAY')); + } + + public function testValueOfInvalidConstant() : void + { + $this->expectException(IllegalArgumentException::class); + WeekDay::valueOf('CATURDAY'); + } + + public function testExceptionOnCloneAttempt() : void + { + $this->expectException(CloneNotSupportedException::class); + clone WeekDay::FRIDAY(); + } + + public function testExceptionOnSerializeAttempt() : void + { + $this->expectException(SerializeNotSupportedException::class); + serialize(WeekDay::FRIDAY()); + } + + public function testExceptionOnUnserializeAttempt() : void + { + $this->expectException(UnserializeNotSupportedException::class); + unserialize('O:24:"DASPRiD\\EnumTest\\WeekDay":0:{}'); + } + + public function testReturnValueOfValuesIsSortedByOrdinal() : void + { + // Initialize some week days out of order + WeekDay::SATURDAY(); + WeekDay::TUESDAY(); + + $ordinals = array_values(array_map(function (WeekDay $weekDay) : int { + return $weekDay->ordinal(); + }, WeekDay::values())); + + self::assertSame([0, 1, 2, 3, 4, 5, 6], $ordinals); + + $cachedOrdinals = array_values(array_map(function (WeekDay $weekDay) : int { + return $weekDay->ordinal(); + }, WeekDay::values())); + $this->assertSame($ordinals, $cachedOrdinals); + } + + public function testCompareTo() : void + { + $this->assertSame(-4, WeekDay::WEDNESDAY()->compareTo(WeekDay::SUNDAY())); + $this->assertSame(4, WeekDay::SUNDAY()->compareTo(WeekDay::WEDNESDAY())); + $this->assertSame(0, WeekDay::WEDNESDAY()->compareTo(WeekDay::WEDNESDAY())); + } + + public function testCompareToWrongEnum() : void + { + $this->expectException(MismatchException::class); + WeekDay::MONDAY()->compareTo(Planet::EARTH()); + } + + public function testParameterizedEnum() : void + { + $planet = Planet::EARTH(); + $this->assertSame(5.976e+24, $planet->mass()); + $this->assertSame(6.37814e6, $planet->radius()); + } +} diff --git a/serve/vendor/dasprid/enum/test/EnumMapTest.php b/serve/vendor/dasprid/enum/test/EnumMapTest.php new file mode 100644 index 0000000..d51a86c --- /dev/null +++ b/serve/vendor/dasprid/enum/test/EnumMapTest.php @@ -0,0 +1,243 @@ +expectException(IllegalArgumentException::class); + new EnumMap(stdClass::class, 'string', false); + } + + public function testUnexpectedKeyType() : void + { + $this->expectException(ExpectationException::class); + $map = new EnumMap(WeekDay::class, 'string', false); + $map->expect(Planet::class, 'string', false); + } + + public function testUnexpectedValueType() : void + { + $this->expectException(ExpectationException::class); + $map = new EnumMap(WeekDay::class, 'string', false); + $map->expect(WeekDay::class, 'int', false); + } + + public function testUnexpectedNullableValueType() : void + { + $this->expectException(ExpectationException::class); + $map = new EnumMap(WeekDay::class, 'string', true); + $map->expect(WeekDay::class, 'string', false); + } + + public function testExpectedTypes() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->expect(WeekDay::class, 'string', true); + $this->addToAssertionCount(1); + } + + public function testSize() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertSame(0, $map->size()); + $map->put(WeekDay::MONDAY(), 'foo'); + $this->assertSame(1, $map->size()); + } + + public function testContainsValue() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertFalse($map->containsValue('foo')); + $map->put(WeekDay::TUESDAY(), 'foo'); + $this->assertTrue($map->containsValue('foo')); + $this->assertFalse($map->containsValue(null)); + $map->put(WeekDay::WEDNESDAY(), null); + $this->assertTrue($map->containsValue(null)); + } + + public function testContainsKey() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertFalse($map->containsKey(WeekDay::TUESDAY())); + $map->put(WeekDay::TUESDAY(), 'foo'); + $this->assertTrue($map->containsKey(WeekDay::TUESDAY())); + $map->put(WeekDay::WEDNESDAY(), null); + $this->assertTrue($map->containsKey(WeekDay::WEDNESDAY())); + } + + public function testPutAndGet() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(WeekDay::TUESDAY(), 'foo'); + $map->put(WeekDay::FRIDAY(), null); + $this->assertSame('foo', $map->get(WeekDay::TUESDAY())); + $this->assertSame(null, $map->get(WeekDay::WEDNESDAY())); + $this->assertSame(null, $map->get(WeekDay::FRIDAY())); + } + + public function testPutInvalidKey() : void + { + $this->expectException(IllegalArgumentException::class); + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(Planet::MARS(), 'foo'); + } + + public function invalidValues() : array + { + return [ + ['bool', null, false], + ['bool', 0], + ['boolean', 0], + ['int', 2.4], + ['integer', 5.3], + ['float', 3], + ['double', 7], + ['string', 1], + ['object', 1], + ['array', 1], + [stdClass::class, 1], + ]; + } + + /** + * @dataProvider invalidValues + * @param mixed $value + */ + public function testPutInvalidValue(string $valueType, $value, bool $allowNull = true) : void + { + $this->expectException(IllegalArgumentException::class); + $map = new EnumMap(WeekDay::class, $valueType, $allowNull); + $map->put(WeekDay::TUESDAY(), $value); + } + + public function validValues() : array + { + return [ + ['bool', null], + ['mixed', 'foo'], + ['mixed', 1], + ['mixed', new stdClass()], + ['bool', true], + ['boolean', false], + ['int', 1], + ['integer', 4], + ['float', 2.5], + ['double', 6.4], + ['string', 'foo'], + ['object', new stdClass()], + ['array', ['foo']], + [stdClass::class, new stdClass()], + ]; + } + + /** + * @dataProvider validValues + * @param mixed $value + */ + public function testPutValidValue(string $valueType, $value, bool $allowNull = true) : void + { + $map = new EnumMap(WeekDay::class, $valueType, $allowNull); + $map->put(WeekDay::TUESDAY(), $value); + $this->addToAssertionCount(1); + } + + public function testRemove() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(WeekDay::TUESDAY(), 'foo'); + $map->remove(WeekDay::TUESDAY()); + $map->remove(WeekDay::WEDNESDAY()); + $this->assertSame(null, $map->get(WeekDay::TUESDAY())); + $this->assertSame(0, $map->size()); + } + + public function testClear() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(WeekDay::TUESDAY(), 'foo'); + $map->clear(); + $this->assertSame(null, $map->get(WeekDay::TUESDAY())); + $this->assertSame(0, $map->size()); + } + + public function testEqualsWithSameInstance() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertTrue($map->equals($map)); + } + + public function testEqualsWithDifferentSize() : void + { + $mapA = new EnumMap(WeekDay::class, 'string', true); + $mapB = new EnumMap(WeekDay::class, 'string', true); + $mapB->put(WeekDay::MONDAY(), 'foo'); + + $this->assertFalse($mapA->equals($mapB)); + } + + public function testEqualsWithDifferentValues() : void + { + $mapA = new EnumMap(WeekDay::class, 'string', true); + $mapA->put(WeekDay::MONDAY(), 'foo'); + $mapB = new EnumMap(WeekDay::class, 'string', true); + $mapB->put(WeekDay::MONDAY(), 'bar'); + + $this->assertFalse($mapA->equals($mapB)); + } + + public function testEqualsWithDifferentConstants() : void + { + $mapA = new EnumMap(WeekDay::class, 'string', true); + $mapA->put(WeekDay::MONDAY(), 'foo'); + $mapB = new EnumMap(WeekDay::class, 'string', true); + $mapB->put(WeekDay::TUESDAY(), 'foo'); + + $this->assertFalse($mapA->equals($mapB)); + } + + public function testValues() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $this->assertSame([], $map->values()); + + $map->put(WeekDay::FRIDAY(), 'foo'); + $map->put(WeekDay::TUESDAY(), 'bar'); + $map->put(WeekDay::SUNDAY(), null); + + $this->assertSame(['bar', 'foo', null], $map->values()); + } + + public function testSerializeAndUnserialize() : void + { + $mapA = new EnumMap(WeekDay::class, 'string', true); + $mapA->put(WeekDay::MONDAY(), 'foo'); + $mapB = unserialize(serialize($mapA)); + + $this->assertTrue($mapA->equals($mapB)); + } + + public function testIterator() : void + { + $map = new EnumMap(WeekDay::class, 'string', true); + $map->put(WeekDay::FRIDAY(), 'foo'); + $map->put(WeekDay::TUESDAY(), 'bar'); + $map->put(WeekDay::SUNDAY(), null); + + $result = []; + + foreach ($map as $key => $value) { + $result[$key->ordinal()] = $value; + } + + $this->assertSame([1 => 'bar', 4 => 'foo', 6 => null], $result); + } +} diff --git a/serve/vendor/dasprid/enum/test/NullValueTest.php b/serve/vendor/dasprid/enum/test/NullValueTest.php new file mode 100644 index 0000000..9f70640 --- /dev/null +++ b/serve/vendor/dasprid/enum/test/NullValueTest.php @@ -0,0 +1,31 @@ +expectException(CloneNotSupportedException::class); + clone NullValue::instance(); + } + + public function testExceptionOnSerializeAttempt() : void + { + $this->expectException(SerializeNotSupportedException::class); + serialize(NullValue::instance()); + } + + public function testExceptionOnUnserializeAttempt() : void + { + $this->expectException(UnserializeNotSupportedException::class); + unserialize('O:22:"DASPRiD\\Enum\\NullValue":0:{}'); + } +} diff --git a/serve/vendor/dasprid/enum/test/Planet.php b/serve/vendor/dasprid/enum/test/Planet.php new file mode 100644 index 0000000..3c44c1d --- /dev/null +++ b/serve/vendor/dasprid/enum/test/Planet.php @@ -0,0 +1,73 @@ +mass = $mass; + $this->radius = $radius; + } + + public function mass() : float + { + return $this->mass; + } + + public function radius() : float + { + return $this->radius; + } + + public function surfaceGravity() : float + { + return self::G * $this->mass / ($this->radius * $this->radius); + } + + public function surfaceWeight(float $otherMass) : float + { + return $otherMass * $this->surfaceGravity(); + } +} diff --git a/serve/vendor/dasprid/enum/test/WeekDay.php b/serve/vendor/dasprid/enum/test/WeekDay.php new file mode 100644 index 0000000..70b8db5 --- /dev/null +++ b/serve/vendor/dasprid/enum/test/WeekDay.php @@ -0,0 +1,26 @@ +getContentType()); +echo $qrCode->writeString(); +``` + +## Advanced usage + +```php +use Endroid\QrCode\ErrorCorrectionLevel; +use Endroid\QrCode\LabelAlignment; +use Endroid\QrCode\QrCode; +use Endroid\QrCode\Response\QrCodeResponse; + +// Create a basic QR code +$qrCode = new QrCode('Life is too short to be generating QR codes'); +$qrCode->setSize(300); +$qrCode->setMargin(10); + +// Set advanced options +$qrCode->setWriterByName('png'); +$qrCode->setEncoding('UTF-8'); +$qrCode->setErrorCorrectionLevel(ErrorCorrectionLevel::HIGH()); +$qrCode->setForegroundColor(['r' => 0, 'g' => 0, 'b' => 0, 'a' => 0]); +$qrCode->setBackgroundColor(['r' => 255, 'g' => 255, 'b' => 255, 'a' => 0]); +$qrCode->setLabel('Scan the code', 16, __DIR__.'/../assets/fonts/noto_sans.otf', LabelAlignment::CENTER()); +$qrCode->setLogoPath(__DIR__.'/../assets/images/symfony.png'); +$qrCode->setLogoSize(150, 200); +$qrCode->setValidateResult(false); + +// Round block sizes to improve readability and make the blocks sharper in pixel based outputs (like png). +// There are three approaches: +$qrCode->setRoundBlockSize(true, QrCode::ROUND_BLOCK_SIZE_MODE_MARGIN); // The size of the qr code is shrinked, if necessary, but the size of the final image remains unchanged due to additional margin being added (default) +$qrCode->setRoundBlockSize(true, QrCode::ROUND_BLOCK_SIZE_MODE_ENLARGE); // The size of the qr code and the final image is enlarged, if necessary +$qrCode->setRoundBlockSize(true, QrCode::ROUND_BLOCK_SIZE_MODE_SHRINK); // The size of the qr code and the final image is shrinked, if necessary + +// Set additional writer options (SvgWriter example) +$qrCode->setWriterOptions(['exclude_xml_declaration' => true]); + +// Directly output the QR code +header('Content-Type: '.$qrCode->getContentType()); +echo $qrCode->writeString(); + +// Save it to a file +$qrCode->writeFile(__DIR__.'/qrcode.png'); + +// Generate a data URI to include image data inline (i.e. inside an tag) +$dataUri = $qrCode->writeDataUri(); +``` + +![QR Code](https://endroid.nl/qr-code/Life%20is%20too%20short%20to%20be%20generating%20QR%20codes.png) + +### Encoding +You can pick one of these values for encoding: + +`ISO-8859-1`, `ISO-8859-2`, `ISO-8859-3`, `ISO-8859-4`, `ISO-8859-5`, `ISO-8859-6`, `ISO-8859-7`, `ISO-8859-8`, `ISO-8859-9`, `ISO-8859-10`, `ISO-8859-11`, `ISO-8859-12`, `ISO-8859-13`, `ISO-8859-14`, `ISO-8859-15`, `ISO-8859-16`, `Shift_JIS`, `windows-1250`, `windows-1251`, `windows-1252`, `windows-1256`, `UTF-16BE`, `UTF-8`, `US-ASCII`, `GBK` `EUC-KR` + +If you use a barcode scanner you can have some troubles while reading the generated QR codes. Depending on the encoding you chose you will have an extra amount of data corresponding to the ECI block. Some barcode scanner are not programmed to interpret this block of information. For exemple the ECI block for `UTF-8` is `000026` so the above exemple will produce : `\000026Life is too short to be generating QR codes`. To ensure a maximum compatibility you can use the `ISO-8859-1` encoding that is the default encoding used by barcode scanners. + +## Readability + +The readability of a QR code is primarily determined by the size, the input +length, the error correction level and any possible logo over the image so you +can tweak these parameters if you are looking for optimal results. You can also +check $qrCode->getRoundBlockSize() value to see if block dimensions are rounded +so that the image is more sharp and readable. Please note that rounding block +size can result in additional padding to compensate for the rounding difference. + +## Built-in validation reader + +You can enable the built-in validation reader (disabled by default) by calling +setValidateResult(true). This validation reader does not guarantee that the QR +code will be readable by all readers but it helps you provide a minimum level +of quality. + +Take note that the validator can consume quite amount of additional resources. + +## Symfony integration + +The [endroid/qr-code-bundle](https://github.com/endroid/qr-code-bundle) +integrates the QR code library in Symfony for an even better experience. + +* Configure your defaults (like image size, default writer etc.) +* Generate QR codes quickly from anywhere via the factory service +* Generate QR codes directly by typing an URL like /qr-code/\.png?size=300 +* Generate QR codes or URLs directly from Twig using dedicated functions + +Read the [bundle documentation](https://github.com/endroid/qr-code-bundle) +for more information. + +## Versioning + +Version numbers follow the MAJOR.MINOR.PATCH scheme. Backwards compatibility +breaking changes will be kept to a minimum but be aware that these can occur. +Lock your dependencies for production and test your code when upgrading. + +## License + +This bundle is under the MIT license. For the full copyright and license +information please view the LICENSE file that was distributed with this source code. diff --git a/serve/vendor/endroid/qr-code/assets/fonts/noto_sans.otf b/serve/vendor/endroid/qr-code/assets/fonts/noto_sans.otf new file mode 100644 index 0000000..296fbeb Binary files /dev/null and b/serve/vendor/endroid/qr-code/assets/fonts/noto_sans.otf differ diff --git a/serve/vendor/endroid/qr-code/assets/fonts/open_sans.ttf b/serve/vendor/endroid/qr-code/assets/fonts/open_sans.ttf new file mode 100644 index 0000000..db43334 Binary files /dev/null and b/serve/vendor/endroid/qr-code/assets/fonts/open_sans.ttf differ diff --git a/serve/vendor/endroid/qr-code/assets/images/symfony.png b/serve/vendor/endroid/qr-code/assets/images/symfony.png new file mode 100644 index 0000000..55fe198 Binary files /dev/null and b/serve/vendor/endroid/qr-code/assets/images/symfony.png differ diff --git a/serve/vendor/endroid/qr-code/composer.json b/serve/vendor/endroid/qr-code/composer.json new file mode 100644 index 0000000..dff0500 --- /dev/null +++ b/serve/vendor/endroid/qr-code/composer.json @@ -0,0 +1,50 @@ +{ + "name": "endroid/qr-code", + "description": "Endroid QR Code", + "keywords": ["endroid", "qrcode", "qr", "code", "bundle", "php"], + "homepage": "https://github.com/endroid/qr-code", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Jeroen van den Enden", + "email": "info@endroid.nl" + } + ], + "require": { + "php": "^7.3||^8.0", + "bacon/bacon-qr-code": "^2.0", + "khanamiryan/qrcode-detector-decoder": "^1.0.5", + "myclabs/php-enum": "^1.5", + "symfony/options-resolver": "^3.4||^4.4||^5.0", + "symfony/property-access": "^3.4||^4.4||^5.0" + }, + "require-dev": { + "endroid/quality": "^1.5.2", + "setasign/fpdf": "^1.8" + }, + "suggest": { + "ext-gd": "Required for generating PNG images", + "roave/security-advisories": "Avoids installation of package versions with vulnerabilities", + "setasign/fpdf": "Required to use the FPDF writer.", + "symfony/security-checker": "Checks your composer.lock for vulnerabilities" + }, + "autoload": { + "psr-4": { + "Endroid\\QrCode\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Endroid\\QrCode\\Tests\\": "tests/" + } + }, + "config": { + "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + } +} diff --git a/serve/vendor/endroid/qr-code/src/ErrorCorrectionLevel.php b/serve/vendor/endroid/qr-code/src/ErrorCorrectionLevel.php new file mode 100644 index 0000000..02d4dac --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/ErrorCorrectionLevel.php @@ -0,0 +1,42 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +use BaconQrCode\Common\ErrorCorrectionLevel as BaconErrorCorrectionLevel; +use MyCLabs\Enum\Enum; + +/** + * @method static ErrorCorrectionLevel LOW() + * @method static ErrorCorrectionLevel MEDIUM() + * @method static ErrorCorrectionLevel QUARTILE() + * @method static ErrorCorrectionLevel HIGH() + * + * @extends Enum + * @psalm-immutable + */ +class ErrorCorrectionLevel extends Enum +{ + const LOW = 'low'; + const MEDIUM = 'medium'; + const QUARTILE = 'quartile'; + const HIGH = 'high'; + + /** + * @psalm-suppress ImpureMethodCall + */ + public function toBaconErrorCorrectionLevel(): BaconErrorCorrectionLevel + { + $name = strtoupper(substr($this->getValue(), 0, 1)); + + return BaconErrorCorrectionLevel::valueOf($name); + } +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/GenerateImageException.php b/serve/vendor/endroid/qr-code/src/Exception/GenerateImageException.php new file mode 100644 index 0000000..02a3906 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/GenerateImageException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +class GenerateImageException extends QrCodeException +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/InvalidFontException.php b/serve/vendor/endroid/qr-code/src/Exception/InvalidFontException.php new file mode 100644 index 0000000..bd39abd --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/InvalidFontException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +class InvalidFontException extends QrCodeException +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/InvalidLogoException.php b/serve/vendor/endroid/qr-code/src/Exception/InvalidLogoException.php new file mode 100644 index 0000000..6137e56 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/InvalidLogoException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +class InvalidLogoException extends QrCodeException +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/InvalidWriterException.php b/serve/vendor/endroid/qr-code/src/Exception/InvalidWriterException.php new file mode 100644 index 0000000..62a609f --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/InvalidWriterException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +class InvalidWriterException extends QrCodeException +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/MissingExtensionException.php b/serve/vendor/endroid/qr-code/src/Exception/MissingExtensionException.php new file mode 100644 index 0000000..d9ea2c7 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/MissingExtensionException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +class MissingExtensionException extends QrCodeException +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/MissingFunctionException.php b/serve/vendor/endroid/qr-code/src/Exception/MissingFunctionException.php new file mode 100644 index 0000000..667dbbd --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/MissingFunctionException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +class MissingFunctionException extends QrCodeException +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/MissingLogoHeightException.php b/serve/vendor/endroid/qr-code/src/Exception/MissingLogoHeightException.php new file mode 100644 index 0000000..fcd66bc --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/MissingLogoHeightException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +class MissingLogoHeightException extends QrCodeException +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/QrCodeException.php b/serve/vendor/endroid/qr-code/src/Exception/QrCodeException.php new file mode 100644 index 0000000..74e6139 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/QrCodeException.php @@ -0,0 +1,18 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +use Exception; + +abstract class QrCodeException extends Exception +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/UnsupportedExtensionException.php b/serve/vendor/endroid/qr-code/src/Exception/UnsupportedExtensionException.php new file mode 100644 index 0000000..520e491 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/UnsupportedExtensionException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +class UnsupportedExtensionException extends QrCodeException +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Exception/ValidationException.php b/serve/vendor/endroid/qr-code/src/Exception/ValidationException.php new file mode 100644 index 0000000..4f6a227 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Exception/ValidationException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Exception; + +class ValidationException extends QrCodeException +{ +} diff --git a/serve/vendor/endroid/qr-code/src/Factory/QrCodeFactory.php b/serve/vendor/endroid/qr-code/src/Factory/QrCodeFactory.php new file mode 100644 index 0000000..d9655a1 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Factory/QrCodeFactory.php @@ -0,0 +1,112 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Factory; + +use Endroid\QrCode\ErrorCorrectionLevel; +use Endroid\QrCode\Exception\ValidationException; +use Endroid\QrCode\QrCode; +use Endroid\QrCode\QrCodeInterface; +use Endroid\QrCode\WriterRegistryInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\PropertyAccess\PropertyAccess; + +class QrCodeFactory implements QrCodeFactoryInterface +{ + private $writerRegistry; + + /** @var OptionsResolver */ + private $optionsResolver; + + /** @var array */ + private $defaultOptions; + + /** @var array */ + private $definedOptions = [ + 'writer', + 'writer_options', + 'size', + 'margin', + 'foreground_color', + 'background_color', + 'encoding', + 'round_block_size', + 'round_block_size_mode', + 'error_correction_level', + 'logo_path', + 'logo_width', + 'logo_height', + 'label', + 'label_font_size', + 'label_font_path', + 'label_alignment', + 'label_margin', + 'validate_result', + ]; + + /** @param array $defaultOptions */ + public function __construct(array $defaultOptions = [], WriterRegistryInterface $writerRegistry = null) + { + $this->defaultOptions = $defaultOptions; + $this->writerRegistry = $writerRegistry; + } + + public function create(string $text = '', array $options = []): QrCodeInterface + { + $options = $this->getOptionsResolver()->resolve($options); + $accessor = PropertyAccess::createPropertyAccessor(); + + $qrCode = new QrCode($text); + + if ($this->writerRegistry instanceof WriterRegistryInterface) { + $qrCode->setWriterRegistry($this->writerRegistry); + } + + foreach ($this->definedOptions as $option) { + if (isset($options[$option])) { + if ('writer' === $option) { + $options['writer_by_name'] = $options[$option]; + $option = 'writer_by_name'; + } + if ('error_correction_level' === $option) { + $options[$option] = new ErrorCorrectionLevel($options[$option]); + } + $accessor->setValue($qrCode, $option, $options[$option]); + } + } + + if (!$qrCode instanceof QrCodeInterface) { + throw new ValidationException('QR Code was messed up by property accessor'); + } + + return $qrCode; + } + + private function getOptionsResolver(): OptionsResolver + { + if (!$this->optionsResolver instanceof OptionsResolver) { + $this->optionsResolver = $this->createOptionsResolver(); + } + + return $this->optionsResolver; + } + + private function createOptionsResolver(): OptionsResolver + { + $optionsResolver = new OptionsResolver(); + $optionsResolver + ->setDefaults($this->defaultOptions) + ->setDefined($this->definedOptions) + ; + + return $optionsResolver; + } +} diff --git a/serve/vendor/endroid/qr-code/src/Factory/QrCodeFactoryInterface.php b/serve/vendor/endroid/qr-code/src/Factory/QrCodeFactoryInterface.php new file mode 100644 index 0000000..3ddce5c --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Factory/QrCodeFactoryInterface.php @@ -0,0 +1,20 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Factory; + +use Endroid\QrCode\QrCodeInterface; + +interface QrCodeFactoryInterface +{ + /** @param array $options */ + public function create(string $text = '', array $options = []): QrCodeInterface; +} diff --git a/serve/vendor/endroid/qr-code/src/LabelAlignment.php b/serve/vendor/endroid/qr-code/src/LabelAlignment.php new file mode 100644 index 0000000..f4a792e --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/LabelAlignment.php @@ -0,0 +1,29 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +use MyCLabs\Enum\Enum; + +/** + * @method static LabelAlignment LEFT() + * @method static LabelAlignment CENTER() + * @method static LabelAlignment RIGHT() + * + * @extends Enum + * @psalm-immutable + */ +class LabelAlignment extends Enum +{ + const LEFT = 'left'; + const CENTER = 'center'; + const RIGHT = 'right'; +} diff --git a/serve/vendor/endroid/qr-code/src/QrCode.php b/serve/vendor/endroid/qr-code/src/QrCode.php new file mode 100644 index 0000000..814237c --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/QrCode.php @@ -0,0 +1,478 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +use BaconQrCode\Encoder\Encoder; +use Endroid\QrCode\Exception\InvalidFontException; +use Endroid\QrCode\Exception\UnsupportedExtensionException; +use Endroid\QrCode\Exception\ValidationException; +use Endroid\QrCode\Writer\WriterInterface; + +class QrCode implements QrCodeInterface +{ + const LABEL_FONT_PATH_DEFAULT = __DIR__.'/../assets/fonts/noto_sans.otf'; + + const ROUND_BLOCK_SIZE_MODE_MARGIN = 'margin'; + const ROUND_BLOCK_SIZE_MODE_SHRINK = 'shrink'; + const ROUND_BLOCK_SIZE_MODE_ENLARGE = 'enlarge'; + + private $text; + + /** @var int */ + private $size = 300; + + /** @var int */ + private $margin = 10; + + /** @var array */ + private $foregroundColor = [ + 'r' => 0, + 'g' => 0, + 'b' => 0, + 'a' => 0, + ]; + + /** @var array */ + private $backgroundColor = [ + 'r' => 255, + 'g' => 255, + 'b' => 255, + 'a' => 0, + ]; + + /** @var string */ + private $encoding = 'UTF-8'; + + /** @var bool */ + private $roundBlockSize = true; + + /** @var string */ + private $roundBlockSizeMode = self::ROUND_BLOCK_SIZE_MODE_MARGIN; + + private $errorCorrectionLevel; + + /** @var string */ + private $logoPath; + + /** @var int|null */ + private $logoWidth; + + /** @var int|null */ + private $logoHeight; + + /** @var string */ + private $label; + + /** @var int */ + private $labelFontSize = 16; + + /** @var string */ + private $labelFontPath = self::LABEL_FONT_PATH_DEFAULT; + + private $labelAlignment; + + /** @var array */ + private $labelMargin = [ + 't' => 0, + 'r' => 10, + 'b' => 10, + 'l' => 10, + ]; + + /** @var WriterRegistryInterface */ + private $writerRegistry; + + /** @var WriterInterface|null */ + private $writer; + + /** @var array */ + private $writerOptions = []; + + /** @var bool */ + private $validateResult = false; + + public function __construct(string $text = '') + { + $this->text = $text; + + $this->errorCorrectionLevel = ErrorCorrectionLevel::LOW(); + $this->labelAlignment = LabelAlignment::CENTER(); + + $this->createWriterRegistry(); + } + + public function setText(string $text): void + { + $this->text = $text; + } + + public function getText(): string + { + return $this->text; + } + + public function setSize(int $size): void + { + $this->size = $size; + } + + public function getSize(): int + { + return $this->size; + } + + public function setMargin(int $margin): void + { + $this->margin = $margin; + } + + public function getMargin(): int + { + return $this->margin; + } + + /** @param array $foregroundColor */ + public function setForegroundColor(array $foregroundColor): void + { + if (!isset($foregroundColor['a'])) { + $foregroundColor['a'] = 0; + } + + foreach ($foregroundColor as &$color) { + $color = intval($color); + } + + $this->foregroundColor = $foregroundColor; + } + + public function getForegroundColor(): array + { + return $this->foregroundColor; + } + + /** @param array $backgroundColor */ + public function setBackgroundColor(array $backgroundColor): void + { + if (!isset($backgroundColor['a'])) { + $backgroundColor['a'] = 0; + } + + foreach ($backgroundColor as &$color) { + $color = intval($color); + } + + $this->backgroundColor = $backgroundColor; + } + + public function getBackgroundColor(): array + { + return $this->backgroundColor; + } + + public function setEncoding(string $encoding): void + { + $this->encoding = $encoding; + } + + public function getEncoding(): string + { + return $this->encoding; + } + + public function setRoundBlockSize(bool $roundBlockSize, string $roundBlockSizeMode = self::ROUND_BLOCK_SIZE_MODE_MARGIN): void + { + $this->roundBlockSize = $roundBlockSize; + $this->setRoundBlockSizeMode($roundBlockSizeMode); + } + + public function getRoundBlockSize(): bool + { + return $this->roundBlockSize; + } + + public function setRoundBlockSizeMode(string $roundBlockSizeMode): void + { + if (!in_array($roundBlockSizeMode, [ + self::ROUND_BLOCK_SIZE_MODE_ENLARGE, + self::ROUND_BLOCK_SIZE_MODE_MARGIN, + self::ROUND_BLOCK_SIZE_MODE_SHRINK, + ])) { + throw new ValidationException('Invalid round block size mode: '.$roundBlockSizeMode); + } + + $this->roundBlockSizeMode = $roundBlockSizeMode; + } + + public function setErrorCorrectionLevel(ErrorCorrectionLevel $errorCorrectionLevel): void + { + $this->errorCorrectionLevel = $errorCorrectionLevel; + } + + public function getErrorCorrectionLevel(): ErrorCorrectionLevel + { + return $this->errorCorrectionLevel; + } + + public function setLogoPath(string $logoPath): void + { + $this->logoPath = $logoPath; + } + + public function getLogoPath(): ?string + { + return $this->logoPath; + } + + public function setLogoSize(int $logoWidth, int $logoHeight = null): void + { + $this->logoWidth = $logoWidth; + $this->logoHeight = $logoHeight; + } + + public function setLogoWidth(int $logoWidth): void + { + $this->logoWidth = $logoWidth; + } + + public function getLogoWidth(): ?int + { + return $this->logoWidth; + } + + public function setLogoHeight(int $logoHeight): void + { + $this->logoHeight = $logoHeight; + } + + public function getLogoHeight(): ?int + { + return $this->logoHeight; + } + + /** @param array $labelMargin */ + public function setLabel(string $label, int $labelFontSize = null, string $labelFontPath = null, string $labelAlignment = null, array $labelMargin = null): void + { + $this->label = $label; + + if (null !== $labelFontSize) { + $this->setLabelFontSize($labelFontSize); + } + + if (null !== $labelFontPath) { + $this->setLabelFontPath($labelFontPath); + } + + if (null !== $labelAlignment) { + $this->setLabelAlignment($labelAlignment); + } + + if (null !== $labelMargin) { + $this->setLabelMargin($labelMargin); + } + } + + public function getLabel(): ?string + { + return $this->label; + } + + public function setLabelFontSize(int $labelFontSize): void + { + $this->labelFontSize = $labelFontSize; + } + + public function getLabelFontSize(): int + { + return $this->labelFontSize; + } + + public function setLabelFontPath(string $labelFontPath): void + { + $resolvedLabelFontPath = (string) realpath($labelFontPath); + + if (!is_file($resolvedLabelFontPath)) { + throw new InvalidFontException('Invalid label font path: '.$labelFontPath); + } + + $this->labelFontPath = $resolvedLabelFontPath; + } + + public function getLabelFontPath(): string + { + return $this->labelFontPath; + } + + public function setLabelAlignment(string $labelAlignment): void + { + $this->labelAlignment = new LabelAlignment($labelAlignment); + } + + public function getLabelAlignment(): string + { + return $this->labelAlignment->getValue(); + } + + /** @param array $labelMargin */ + public function setLabelMargin(array $labelMargin): void + { + $this->labelMargin = array_merge($this->labelMargin, $labelMargin); + } + + public function getLabelMargin(): array + { + return $this->labelMargin; + } + + public function setWriterRegistry(WriterRegistryInterface $writerRegistry): void + { + $this->writerRegistry = $writerRegistry; + } + + public function setWriter(WriterInterface $writer): void + { + $this->writer = $writer; + } + + public function getWriter(string $name = null): WriterInterface + { + if (!is_null($name)) { + return $this->writerRegistry->getWriter($name); + } + + if ($this->writer instanceof WriterInterface) { + return $this->writer; + } + + return $this->writerRegistry->getDefaultWriter(); + } + + /** @param array $writerOptions */ + public function setWriterOptions(array $writerOptions): void + { + $this->writerOptions = $writerOptions; + } + + public function getWriterOptions(): array + { + return $this->writerOptions; + } + + private function createWriterRegistry(): void + { + $this->writerRegistry = new WriterRegistry(); + $this->writerRegistry->loadDefaultWriters(); + } + + public function setWriterByName(string $name): void + { + $this->writer = $this->getWriter($name); + } + + public function setWriterByPath(string $path): void + { + $extension = pathinfo($path, PATHINFO_EXTENSION); + + $this->setWriterByExtension($extension); + } + + public function setWriterByExtension(string $extension): void + { + foreach ($this->writerRegistry->getWriters() as $writer) { + if ($writer->supportsExtension($extension)) { + $this->writer = $writer; + + return; + } + } + + throw new UnsupportedExtensionException('Missing writer for extension "'.$extension.'"'); + } + + public function writeString(): string + { + return $this->getWriter()->writeString($this); + } + + public function writeDataUri(): string + { + return $this->getWriter()->writeDataUri($this); + } + + public function writeFile(string $path): void + { + $this->getWriter()->writeFile($this, $path); + } + + public function getContentType(): string + { + return $this->getWriter()->getContentType(); + } + + public function setValidateResult(bool $validateResult): void + { + $this->validateResult = $validateResult; + } + + public function getValidateResult(): bool + { + return $this->validateResult; + } + + public function getData(): array + { + $baconErrorCorrectionLevel = $this->errorCorrectionLevel->toBaconErrorCorrectionLevel(); + + $baconQrCode = Encoder::encode($this->text, $baconErrorCorrectionLevel, $this->encoding); + + $baconMatrix = $baconQrCode->getMatrix(); + + $matrix = []; + $columnCount = $baconMatrix->getWidth(); + $rowCount = $baconMatrix->getHeight(); + for ($rowIndex = 0; $rowIndex < $rowCount; ++$rowIndex) { + $matrix[$rowIndex] = []; + for ($columnIndex = 0; $columnIndex < $columnCount; ++$columnIndex) { + $matrix[$rowIndex][$columnIndex] = $baconMatrix->get($columnIndex, $rowIndex); + } + } + + $data = ['matrix' => $matrix]; + $data['block_count'] = count($matrix[0]); + $data['block_size'] = $this->size / $data['block_count']; + if ($this->roundBlockSize) { + switch ($this->roundBlockSizeMode) { + case self::ROUND_BLOCK_SIZE_MODE_ENLARGE: + $data['block_size'] = intval(ceil($data['block_size'])); + $this->size = $data['block_size'] * $data['block_count']; + break; + case self::ROUND_BLOCK_SIZE_MODE_SHRINK: + $data['block_size'] = intval(floor($data['block_size'])); + $this->size = $data['block_size'] * $data['block_count']; + break; + case self::ROUND_BLOCK_SIZE_MODE_MARGIN: + default: + $data['block_size'] = intval(floor($data['block_size'])); + } + } + $data['inner_width'] = $data['block_size'] * $data['block_count']; + $data['inner_height'] = $data['block_size'] * $data['block_count']; + $data['outer_width'] = $this->size + 2 * $this->margin; + $data['outer_height'] = $this->size + 2 * $this->margin; + $data['margin_left'] = ($data['outer_width'] - $data['inner_width']) / 2; + if ($this->roundBlockSize) { + $data['margin_left'] = intval(floor($data['margin_left'])); + } + $data['margin_right'] = $data['outer_width'] - $data['inner_width'] - $data['margin_left']; + + return $data; + } +} diff --git a/serve/vendor/endroid/qr-code/src/QrCodeInterface.php b/serve/vendor/endroid/qr-code/src/QrCodeInterface.php new file mode 100644 index 0000000..5068ecd --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/QrCodeInterface.php @@ -0,0 +1,68 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +interface QrCodeInterface +{ + public function getText(): string; + + public function getSize(): int; + + public function getMargin(): int; + + /** @return array */ + public function getForegroundColor(): array; + + /** @return array */ + public function getBackgroundColor(): array; + + public function getEncoding(): string; + + public function getRoundBlockSize(): bool; + + public function getErrorCorrectionLevel(): ErrorCorrectionLevel; + + public function getLogoPath(): ?string; + + public function getLogoWidth(): ?int; + + public function getLogoHeight(): ?int; + + public function getLabel(): ?string; + + public function getLabelFontPath(): string; + + public function getLabelFontSize(): int; + + public function getLabelAlignment(): string; + + /** @return array */ + public function getLabelMargin(): array; + + public function getValidateResult(): bool; + + /** @return array */ + public function getWriterOptions(): array; + + public function getContentType(): string; + + public function setWriterRegistry(WriterRegistryInterface $writerRegistry): void; + + public function writeString(): string; + + public function writeDataUri(): string; + + public function writeFile(string $path): void; + + /** @return array */ + public function getData(): array; +} diff --git a/serve/vendor/endroid/qr-code/src/Writer/AbstractWriter.php b/serve/vendor/endroid/qr-code/src/Writer/AbstractWriter.php new file mode 100644 index 0000000..60231c1 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Writer/AbstractWriter.php @@ -0,0 +1,92 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Writer; + +use Endroid\QrCode\Exception\GenerateImageException; +use Endroid\QrCode\Exception\InvalidLogoException; +use Endroid\QrCode\Exception\MissingExtensionException; +use Endroid\QrCode\QrCodeInterface; + +abstract class AbstractWriter implements WriterInterface +{ + protected function getMimeType(string $path): string + { + if (false !== filter_var($path, FILTER_VALIDATE_URL)) { + return $this->getMimeTypeFromUrl($path); + } + + return $this->getMimeTypeFromPath($path); + } + + private function getMimeTypeFromUrl(string $url): string + { + /** @var mixed $format */ + $format = PHP_VERSION > 80000 ? true : 1; + + $headers = get_headers($url, $format); + + if (!is_array($headers) || !isset($headers['Content-Type'])) { + throw new InvalidLogoException(sprintf('Content type could not be determined for logo URL "%s"', $url)); + } + + return $headers['Content-Type']; + } + + private function getMimeTypeFromPath(string $path): string + { + if (!function_exists('mime_content_type')) { + throw new MissingExtensionException('You need the ext-fileinfo extension to determine logo mime type'); + } + + $mimeType = mime_content_type($path); + + if (!is_string($mimeType)) { + throw new InvalidLogoException('Could not determine mime type'); + } + + if (!preg_match('#^image/#', $mimeType)) { + throw new GenerateImageException('Logo path is not an image'); + } + + // Passing mime type image/svg results in invisible images + if ('image/svg' === $mimeType) { + return 'image/svg+xml'; + } + + return $mimeType; + } + + public function writeDataUri(QrCodeInterface $qrCode): string + { + $dataUri = 'data:'.$this->getContentType().';base64,'.base64_encode($this->writeString($qrCode)); + + return $dataUri; + } + + public function writeFile(QrCodeInterface $qrCode, string $path): void + { + $string = $this->writeString($qrCode); + file_put_contents($path, $string); + } + + public static function supportsExtension(string $extension): bool + { + return in_array($extension, static::getSupportedExtensions()); + } + + public static function getSupportedExtensions(): array + { + return []; + } + + abstract public function getName(): string; +} diff --git a/serve/vendor/endroid/qr-code/src/Writer/BinaryWriter.php b/serve/vendor/endroid/qr-code/src/Writer/BinaryWriter.php new file mode 100644 index 0000000..aed418f --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Writer/BinaryWriter.php @@ -0,0 +1,47 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Writer; + +use Endroid\QrCode\QrCodeInterface; + +class BinaryWriter extends AbstractWriter +{ + public function writeString(QrCodeInterface $qrCode): string + { + $rows = []; + $data = $qrCode->getData(); + foreach ($data['matrix'] as $row) { + $values = ''; + foreach ($row as $value) { + $values .= $value; + } + $rows[] = $values; + } + + return implode("\n", $rows); + } + + public static function getContentType(): string + { + return 'text/plain'; + } + + public static function getSupportedExtensions(): array + { + return ['bin', 'txt']; + } + + public function getName(): string + { + return 'binary'; + } +} diff --git a/serve/vendor/endroid/qr-code/src/Writer/DebugWriter.php b/serve/vendor/endroid/qr-code/src/Writer/DebugWriter.php new file mode 100644 index 0000000..81be0ea --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Writer/DebugWriter.php @@ -0,0 +1,60 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Writer; + +use Endroid\QrCode\QrCodeInterface; +use Exception; +use ReflectionClass; + +class DebugWriter extends AbstractWriter +{ + public function writeString(QrCodeInterface $qrCode): string + { + $data = []; + $skip = ['getData']; + + $reflectionClass = new ReflectionClass($qrCode); + foreach ($reflectionClass->getMethods() as $method) { + $methodName = $method->getShortName(); + if (0 === strpos($methodName, 'get') && 0 == $method->getNumberOfParameters() && !in_array($methodName, $skip)) { + $value = $qrCode->{$methodName}(); + if (is_array($value) && !is_object(current($value))) { + $value = '['.implode(', ', $value).']'; + } elseif (is_bool($value)) { + $value = $value ? 'true' : 'false'; + } elseif (is_string($value)) { + $value = '"'.$value.'"'; + } elseif (is_null($value)) { + $value = 'null'; + } + try { + $data[] = $methodName.': '.$value; + } catch (Exception $exception) { + } + } + } + + $string = implode(" \n", $data); + + return $string; + } + + public static function getContentType(): string + { + return 'text/plain'; + } + + public function getName(): string + { + return 'debug'; + } +} diff --git a/serve/vendor/endroid/qr-code/src/Writer/EpsWriter.php b/serve/vendor/endroid/qr-code/src/Writer/EpsWriter.php new file mode 100644 index 0000000..9979680 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Writer/EpsWriter.php @@ -0,0 +1,59 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Writer; + +use Endroid\QrCode\QrCodeInterface; + +class EpsWriter extends AbstractWriter +{ + public function writeString(QrCodeInterface $qrCode): string + { + $data = $qrCode->getData(); + + $epsData = []; + $epsData[] = '%!PS-Adobe-3.0 EPSF-3.0'; + $epsData[] = '%%BoundingBox: 0 0 '.$data['outer_width'].' '.$data['outer_height']; + $epsData[] = '/F { rectfill } def'; + $epsData[] = number_format($qrCode->getBackgroundColor()['r'] / 100, 2, '.', ',').' '.number_format($qrCode->getBackgroundColor()['g'] / 100, 2, '.', ',').' '.number_format($qrCode->getBackgroundColor()['b'] / 100, 2, '.', ',').' setrgbcolor'; + $epsData[] = '0 0 '.$data['outer_width'].' '.$data['outer_height'].' F'; + $epsData[] = number_format($qrCode->getForegroundColor()['r'] / 100, 2, '.', ',').' '.number_format($qrCode->getForegroundColor()['g'] / 100, 2, '.', ',').' '.number_format($qrCode->getForegroundColor()['b'] / 100, 2, '.', ',').' setrgbcolor'; + + // Please note an EPS has a reversed Y axis compared to PNG and SVG + $data['matrix'] = array_reverse($data['matrix']); + foreach ($data['matrix'] as $row => $values) { + foreach ($values as $column => $value) { + if (1 === $value) { + $x = $data['margin_left'] + $data['block_size'] * $column; + $y = $data['margin_left'] + $data['block_size'] * $row; + $epsData[] = $x.' '.$y.' '.$data['block_size'].' '.$data['block_size'].' F'; + } + } + } + + return implode("\n", $epsData); + } + + public static function getContentType(): string + { + return 'image/eps'; + } + + public static function getSupportedExtensions(): array + { + return ['eps']; + } + + public function getName(): string + { + return 'eps'; + } +} diff --git a/serve/vendor/endroid/qr-code/src/Writer/FpdfWriter.php b/serve/vendor/endroid/qr-code/src/Writer/FpdfWriter.php new file mode 100644 index 0000000..6c58f01 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Writer/FpdfWriter.php @@ -0,0 +1,131 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Writer; + +use Endroid\QrCode\Exception\ValidationException; +use Endroid\QrCode\QrCodeInterface; + +class FpdfWriter extends AbstractWriter +{ + /** + * Defines as which unit the size is handled. Default is: "mm". + * + * Allowed values: 'mm', 'pt', 'cm', 'in' + */ + public const WRITER_OPTION_MEASURE_UNIT = 'fpdf_measure_unit'; + + public function writeString(QrCodeInterface $qrCode): string + { + if (!\class_exists(\FPDF::class)) { + throw new \BadMethodCallException('The Fpdf writer requires FPDF as dependency but the class "\\FPDF" couldn\'t be found.'); + } + + if ($qrCode->getValidateResult()) { + throw new ValidationException('Built-in validation reader can not check fpdf qr codes: please disable via setValidateResult(false)'); + } + $foregroundColor = $qrCode->getForegroundColor(); + if (0 !== $foregroundColor['a']) { + throw new \InvalidArgumentException('The foreground color has an alpha channel, but the fpdf qr writer doesn\'t support alpha channels.'); + } + $backgroundColor = $qrCode->getBackgroundColor(); + if (0 !== $backgroundColor['a']) { + throw new \InvalidArgumentException('The foreground color has an alpha channel, but the fpdf qr writer doesn\'t support alpha channels.'); + } + + $label = $qrCode->getLabel(); + $labelHeight = null !== $label ? 30 : 0; + + $data = $qrCode->getData(); + $options = $qrCode->getWriterOptions(); + + $fpdf = new \FPDF( + 'P', + $options[self::WRITER_OPTION_MEASURE_UNIT] ?? 'mm', + [$data['outer_width'], $data['outer_height'] + $labelHeight] + ); + $fpdf->AddPage(); + + $fpdf->SetFillColor($backgroundColor['r'], $backgroundColor['g'], $backgroundColor['b']); + $fpdf->Rect(0, 0, $data['outer_width'], $data['outer_height'], 'F'); + + $fpdf->SetFillColor($foregroundColor['r'], $foregroundColor['g'], $foregroundColor['b']); + foreach ($data['matrix'] as $row => $values) { + foreach ($values as $column => $value) { + if (1 === $value) { + $fpdf->Rect( + $data['margin_left'] + ($column * $data['block_size']), + $data['margin_left'] + ($row * $data['block_size']), + $data['block_size'], + $data['block_size'], + 'F' + ); + } + } + } + + $logoPath = $qrCode->getLogoPath(); + if (null !== $logoPath) { + $this->addLogo( + $fpdf, + $logoPath, + $qrCode->getLogoWidth(), + $qrCode->getLogoHeight(), + $data['outer_width'], + $data['outer_height'] + ); + } + + if (null !== $label) { + $fpdf->setY($data['outer_height'] + 5); + $fpdf->SetFont('Helvetica', null, $qrCode->getLabelFontSize()); + $fpdf->Cell(0, 0, $label, 0, 0, strtoupper($qrCode->getLabelAlignment()[0])); + } + + return $fpdf->Output('S'); + } + + protected function addLogo(\FPDF $fpdf, string $logoPath, ?int $logoWidth, ?int $logoHeight, int $imageWidth, int $imageHeight): void + { + if (null === $logoHeight || null === $logoWidth) { + [$logoSourceWidth, $logoSourceHeight] = \getimagesize($logoPath); + + if (null === $logoWidth) { + $logoWidth = (int) $logoSourceWidth; + } + + if (null === $logoHeight) { + $aspectRatio = $logoWidth / $logoSourceWidth; + $logoHeight = (int) ($logoSourceHeight * $aspectRatio); + } + } + + $logoX = $imageWidth / 2 - (int) $logoWidth / 2; + $logoY = $imageHeight / 2 - (int) $logoHeight / 2; + + $fpdf->Image($logoPath, $logoX, $logoY, $logoWidth, $logoHeight); + } + + public static function getContentType(): string + { + return 'application/pdf'; + } + + public static function getSupportedExtensions(): array + { + return ['pdf']; + } + + public function getName(): string + { + return 'fpdf'; + } +} diff --git a/serve/vendor/endroid/qr-code/src/Writer/PngWriter.php b/serve/vendor/endroid/qr-code/src/Writer/PngWriter.php new file mode 100644 index 0000000..001e175 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Writer/PngWriter.php @@ -0,0 +1,281 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Writer; + +use Endroid\QrCode\Exception\GenerateImageException; +use Endroid\QrCode\Exception\MissingFunctionException; +use Endroid\QrCode\Exception\MissingLogoHeightException; +use Endroid\QrCode\Exception\ValidationException; +use Endroid\QrCode\LabelAlignment; +use Endroid\QrCode\QrCodeInterface; +use Zxing\QrReader; + +class PngWriter extends AbstractWriter +{ + public function writeString(QrCodeInterface $qrCode): string + { + if (!extension_loaded('gd')) { + throw new GenerateImageException('Unable to generate image: check your GD installation'); + } + + $image = $this->createImage($qrCode->getData(), $qrCode); + + $logoPath = $qrCode->getLogoPath(); + if (null !== $logoPath) { + $image = $this->addLogo($image, $logoPath, $qrCode->getLogoWidth(), $qrCode->getLogoHeight()); + } + + $label = $qrCode->getLabel(); + if (null !== $label) { + $image = $this->addLabel($image, $label, $qrCode->getLabelFontPath(), $qrCode->getLabelFontSize(), $qrCode->getLabelAlignment(), $qrCode->getLabelMargin(), $qrCode->getForegroundColor(), $qrCode->getBackgroundColor()); + } + + $string = $this->imageToString($image); + + if (PHP_VERSION_ID < 80000) { + imagedestroy($image); + } + + if ($qrCode->getValidateResult()) { + $reader = new QrReader($string, QrReader::SOURCE_TYPE_BLOB); + if ($reader->text() !== $qrCode->getText()) { + throw new ValidationException('Built-in validation reader read "'.$reader->text().'" instead of "'.$qrCode->getText().'". + Adjust your parameters to increase readability or disable built-in validation.'); + } + } + + return $string; + } + + /** + * @param array $data + * + * @return mixed + */ + private function createImage(array $data, QrCodeInterface $qrCode) + { + $baseSize = $qrCode->getRoundBlockSize() ? $data['block_size'] : 25; + + $baseImage = $this->createBaseImage($baseSize, $data, $qrCode); + $interpolatedImage = $this->createInterpolatedImage($baseImage, $data, $qrCode); + + if (PHP_VERSION_ID < 80000) { + imagedestroy($baseImage); + } + + return $interpolatedImage; + } + + /** + * @param array $data + * + * @return mixed + */ + private function createBaseImage(int $baseSize, array $data, QrCodeInterface $qrCode) + { + $image = imagecreatetruecolor($data['block_count'] * $baseSize, $data['block_count'] * $baseSize); + + if (!$image) { + throw new GenerateImageException('Unable to generate image: check your GD installation'); + } + + $foregroundColor = imagecolorallocatealpha($image, $qrCode->getForegroundColor()['r'], $qrCode->getForegroundColor()['g'], $qrCode->getForegroundColor()['b'], $qrCode->getForegroundColor()['a']); + if (!is_int($foregroundColor)) { + throw new GenerateImageException('Foreground color could not be allocated'); + } + + $backgroundColor = imagecolorallocatealpha($image, $qrCode->getBackgroundColor()['r'], $qrCode->getBackgroundColor()['g'], $qrCode->getBackgroundColor()['b'], $qrCode->getBackgroundColor()['a']); + if (!is_int($backgroundColor)) { + throw new GenerateImageException('Background color could not be allocated'); + } + + imagefill($image, 0, 0, $backgroundColor); + + foreach ($data['matrix'] as $row => $values) { + foreach ($values as $column => $value) { + if (1 === $value) { + imagefilledrectangle($image, $column * $baseSize, $row * $baseSize, intval(($column + 1) * $baseSize), intval(($row + 1) * $baseSize), $foregroundColor); + } + } + } + + return $image; + } + + /** + * @param mixed $baseImage + * @param array $data + * + * @return mixed + */ + private function createInterpolatedImage($baseImage, array $data, QrCodeInterface $qrCode) + { + $image = imagecreatetruecolor($data['outer_width'], $data['outer_height']); + + if (!$image) { + throw new GenerateImageException('Unable to generate image: check your GD installation'); + } + + $backgroundColor = imagecolorallocatealpha($image, $qrCode->getBackgroundColor()['r'], $qrCode->getBackgroundColor()['g'], $qrCode->getBackgroundColor()['b'], $qrCode->getBackgroundColor()['a']); + if (!is_int($backgroundColor)) { + throw new GenerateImageException('Background color could not be allocated'); + } + + imagefill($image, 0, 0, $backgroundColor); + imagecopyresampled($image, $baseImage, (int) $data['margin_left'], (int) $data['margin_left'], 0, 0, (int) $data['inner_width'], (int) $data['inner_height'], imagesx($baseImage), imagesy($baseImage)); + + if ($qrCode->getBackgroundColor()['a'] > 0) { + imagesavealpha($image, true); + } + + return $image; + } + + /** + * @param mixed $sourceImage + * + * @return mixed + */ + private function addLogo($sourceImage, string $logoPath, int $logoWidth = null, int $logoHeight = null) + { + $mimeType = $this->getMimeType($logoPath); + $logoImage = imagecreatefromstring(strval(file_get_contents($logoPath))); + + if ('image/svg+xml' === $mimeType && (null === $logoHeight || null === $logoWidth)) { + throw new MissingLogoHeightException('SVG Logos require an explicit height set via setLogoSize($width, $height)'); + } + + if (!$logoImage) { + throw new GenerateImageException('Unable to generate image: check your GD installation or logo path'); + } + + $logoSourceWidth = imagesx($logoImage); + $logoSourceHeight = imagesy($logoImage); + + if (null === $logoWidth) { + $logoWidth = $logoSourceWidth; + } + + if (null === $logoHeight) { + $aspectRatio = $logoWidth / $logoSourceWidth; + $logoHeight = intval($logoSourceHeight * $aspectRatio); + } + + $logoX = imagesx($sourceImage) / 2 - $logoWidth / 2; + $logoY = imagesy($sourceImage) / 2 - $logoHeight / 2; + + imagecopyresampled($sourceImage, $logoImage, intval($logoX), intval($logoY), 0, 0, $logoWidth, $logoHeight, $logoSourceWidth, $logoSourceHeight); + + if (PHP_VERSION_ID < 80000) { + imagedestroy($logoImage); + } + + return $sourceImage; + } + + /** + * @param mixed $sourceImage + * @param array $labelMargin + * @param array $foregroundColor + * @param array $backgroundColor + * + * @return mixed + */ + private function addLabel($sourceImage, string $label, string $labelFontPath, int $labelFontSize, string $labelAlignment, array $labelMargin, array $foregroundColor, array $backgroundColor) + { + if (!function_exists('imagettfbbox')) { + throw new MissingFunctionException('Missing function "imagettfbbox", please make sure you installed the FreeType library'); + } + + $labelBox = imagettfbbox($labelFontSize, 0, $labelFontPath, $label); + if (!$labelBox) { + throw new GenerateImageException('Unable to add label: check your GD installation'); + } + + $labelBoxWidth = intval($labelBox[2] - $labelBox[0]); + $labelBoxHeight = intval($labelBox[0] - $labelBox[7]); + + $sourceWidth = imagesx($sourceImage); + $sourceHeight = imagesy($sourceImage); + $targetWidth = $sourceWidth; + $targetHeight = $sourceHeight + $labelBoxHeight + $labelMargin['t'] + $labelMargin['b']; + + // Create empty target image + $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); + + if (!$targetImage) { + throw new GenerateImageException('Unable to generate image: check your GD installation'); + } + + $foregroundColor = imagecolorallocate($targetImage, $foregroundColor['r'], $foregroundColor['g'], $foregroundColor['b']); + if (!is_int($foregroundColor)) { + throw new GenerateImageException('Foreground color could not be allocated'); + } + + $backgroundColor = imagecolorallocate($targetImage, $backgroundColor['r'], $backgroundColor['g'], $backgroundColor['b']); + if (!is_int($backgroundColor)) { + throw new GenerateImageException('Background color could not be allocated'); + } + + imagefill($targetImage, 0, 0, $backgroundColor); + + // Copy source image to target image + imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $sourceWidth, $sourceHeight, $sourceWidth, $sourceHeight); + + if (PHP_VERSION_ID < 80000) { + imagedestroy($sourceImage); + } + + switch ($labelAlignment) { + case LabelAlignment::LEFT: + $labelX = $labelMargin['l']; + break; + case LabelAlignment::RIGHT: + $labelX = $targetWidth - $labelBoxWidth - $labelMargin['r']; + break; + default: + $labelX = intval($targetWidth / 2 - $labelBoxWidth / 2); + break; + } + + $labelY = $targetHeight - $labelMargin['b']; + imagettftext($targetImage, $labelFontSize, 0, $labelX, $labelY, $foregroundColor, $labelFontPath, $label); + + return $targetImage; + } + + /** + * @param mixed $image + */ + private function imageToString($image): string + { + ob_start(); + imagepng($image); + + return (string) ob_get_clean(); + } + + public static function getContentType(): string + { + return 'image/png'; + } + + public static function getSupportedExtensions(): array + { + return ['png']; + } + + public function getName(): string + { + return 'png'; + } +} diff --git a/serve/vendor/endroid/qr-code/src/Writer/SvgWriter.php b/serve/vendor/endroid/qr-code/src/Writer/SvgWriter.php new file mode 100644 index 0000000..1d34fa2 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Writer/SvgWriter.php @@ -0,0 +1,169 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Writer; + +use Endroid\QrCode\Exception\GenerateImageException; +use Endroid\QrCode\Exception\MissingLogoHeightException; +use Endroid\QrCode\Exception\ValidationException; +use Endroid\QrCode\QrCodeInterface; +use SimpleXMLElement; + +class SvgWriter extends AbstractWriter +{ + public function writeString(QrCodeInterface $qrCode): string + { + $options = $qrCode->getWriterOptions(); + + if ($qrCode->getValidateResult()) { + throw new ValidationException('Built-in validation reader can not check SVG images: please disable via setValidateResult(false)'); + } + + $data = $qrCode->getData(); + + $svg = new SimpleXMLElement(''); + $svg->addAttribute('version', '1.1'); + $svg->addAttribute('width', $data['outer_width'].'px'); + $svg->addAttribute('height', $data['outer_height'].'px'); + $svg->addAttribute('viewBox', '0 0 '.$data['outer_width'].' '.$data['outer_height']); + $svg->addChild('defs'); + + // Block definition + $block_id = isset($options['rect_id']) && $options['rect_id'] ? $options['rect_id'] : 'block'; + $blockDefinition = $svg->defs->addChild('rect'); + $blockDefinition->addAttribute('id', $block_id); + $blockDefinition->addAttribute('width', strval($data['block_size'])); + $blockDefinition->addAttribute('height', strval($data['block_size'])); + $blockDefinition->addAttribute('fill', '#'.sprintf('%02x%02x%02x', $qrCode->getForegroundColor()['r'], $qrCode->getForegroundColor()['g'], $qrCode->getForegroundColor()['b'])); + $blockDefinition->addAttribute('fill-opacity', strval($this->getOpacity($qrCode->getForegroundColor()['a']))); + + // Background + $background = $svg->addChild('rect'); + $background->addAttribute('x', '0'); + $background->addAttribute('y', '0'); + $background->addAttribute('width', strval($data['outer_width'])); + $background->addAttribute('height', strval($data['outer_height'])); + $background->addAttribute('fill', '#'.sprintf('%02x%02x%02x', $qrCode->getBackgroundColor()['r'], $qrCode->getBackgroundColor()['g'], $qrCode->getBackgroundColor()['b'])); + $background->addAttribute('fill-opacity', strval($this->getOpacity($qrCode->getBackgroundColor()['a']))); + + foreach ($data['matrix'] as $row => $values) { + foreach ($values as $column => $value) { + if (1 === $value) { + $block = $svg->addChild('use'); + $block->addAttribute('x', strval($data['margin_left'] + $data['block_size'] * $column)); + $block->addAttribute('y', strval($data['margin_left'] + $data['block_size'] * $row)); + $block->addAttribute('xlink:href', '#'.$block_id, 'http://www.w3.org/1999/xlink'); + } + } + } + + $logoPath = $qrCode->getLogoPath(); + if (is_string($logoPath)) { + $forceXlinkHref = false; + if (isset($options['force_xlink_href']) && $options['force_xlink_href']) { + $forceXlinkHref = true; + } + + $this->addLogo($svg, $data['outer_width'], $data['outer_height'], $logoPath, $qrCode->getLogoWidth(), $qrCode->getLogoHeight(), $forceXlinkHref); + } + + $xml = $svg->asXML(); + + if (!is_string($xml)) { + throw new GenerateImageException('Unable to save SVG XML'); + } + + if (isset($options['exclude_xml_declaration']) && $options['exclude_xml_declaration']) { + $xml = str_replace("\n", '', $xml); + } + + return $xml; + } + + private function addLogo(SimpleXMLElement $svg, int $imageWidth, int $imageHeight, string $logoPath, int $logoWidth = null, int $logoHeight = null, bool $forceXlinkHref = false): void + { + $mimeType = $this->getMimeType($logoPath); + $imageData = file_get_contents($logoPath); + + if (!is_string($imageData)) { + throw new GenerateImageException('Unable to read image data: check your logo path'); + } + + if ('image/svg+xml' === $mimeType && (null === $logoHeight || null === $logoWidth)) { + throw new MissingLogoHeightException('SVG Logos require an explicit height set via setLogoSize($width, $height)'); + } + + if (null === $logoHeight || null === $logoWidth) { + $logoImage = imagecreatefromstring(strval($imageData)); + + if (!$logoImage) { + throw new GenerateImageException('Unable to generate image: check your GD installation or logo path'); + } + + /** @var mixed $logoImage */ + $logoSourceWidth = imagesx($logoImage); + $logoSourceHeight = imagesy($logoImage); + + if (PHP_VERSION_ID < 80000) { + imagedestroy($logoImage); + } + + if (null === $logoWidth) { + $logoWidth = $logoSourceWidth; + } + + if (null === $logoHeight) { + $aspectRatio = $logoWidth / $logoSourceWidth; + $logoHeight = intval($logoSourceHeight * $aspectRatio); + } + } + + $logoX = $imageWidth / 2 - $logoWidth / 2; + $logoY = $imageHeight / 2 - $logoHeight / 2; + + $imageDefinition = $svg->addChild('image'); + $imageDefinition->addAttribute('x', strval($logoX)); + $imageDefinition->addAttribute('y', strval($logoY)); + $imageDefinition->addAttribute('width', strval($logoWidth)); + $imageDefinition->addAttribute('height', strval($logoHeight)); + $imageDefinition->addAttribute('preserveAspectRatio', 'none'); + + // xlink:href is actually deprecated, but still required when placing the qr code in a pdf. + // SimpleXML strips out the xlink part by using addAttribute(), so it must be set directly. + if ($forceXlinkHref) { + $imageDefinition['xlink:href'] = 'data:'.$mimeType.';base64,'.base64_encode($imageData); + } else { + $imageDefinition->addAttribute('href', 'data:'.$mimeType.';base64,'.base64_encode($imageData)); + } + } + + private function getOpacity(int $alpha): float + { + $opacity = 1 - $alpha / 127; + + return $opacity; + } + + public static function getContentType(): string + { + return 'image/svg+xml'; + } + + public static function getSupportedExtensions(): array + { + return ['svg']; + } + + public function getName(): string + { + return 'svg'; + } +} diff --git a/serve/vendor/endroid/qr-code/src/Writer/WriterInterface.php b/serve/vendor/endroid/qr-code/src/Writer/WriterInterface.php new file mode 100644 index 0000000..f64a36c --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/Writer/WriterInterface.php @@ -0,0 +1,32 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Writer; + +use Endroid\QrCode\QrCodeInterface; + +interface WriterInterface +{ + public function writeString(QrCodeInterface $qrCode): string; + + public function writeDataUri(QrCodeInterface $qrCode): string; + + public function writeFile(QrCodeInterface $qrCode, string $path): void; + + public static function getContentType(): string; + + public static function supportsExtension(string $extension): bool; + + /** @return array */ + public static function getSupportedExtensions(): array; + + public function getName(): string; +} diff --git a/serve/vendor/endroid/qr-code/src/WriterRegistry.php b/serve/vendor/endroid/qr-code/src/WriterRegistry.php new file mode 100644 index 0000000..9f00437 --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/WriterRegistry.php @@ -0,0 +1,93 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +use Endroid\QrCode\Exception\InvalidWriterException; +use Endroid\QrCode\Writer\BinaryWriter; +use Endroid\QrCode\Writer\DebugWriter; +use Endroid\QrCode\Writer\EpsWriter; +use Endroid\QrCode\Writer\FpdfWriter; +use Endroid\QrCode\Writer\PngWriter; +use Endroid\QrCode\Writer\SvgWriter; +use Endroid\QrCode\Writer\WriterInterface; + +class WriterRegistry implements WriterRegistryInterface +{ + /** @var WriterInterface[] */ + private $writers = []; + + /** @var WriterInterface|null */ + private $defaultWriter; + + public function loadDefaultWriters(): void + { + if (count($this->writers) > 0) { + return; + } + + $this->addWriters([ + new BinaryWriter(), + new DebugWriter(), + new EpsWriter(), + new PngWriter(), + new SvgWriter(), + new FpdfWriter(), + ]); + + $this->setDefaultWriter('png'); + } + + public function addWriters(iterable $writers): void + { + foreach ($writers as $writer) { + $this->addWriter($writer); + } + } + + public function addWriter(WriterInterface $writer): void + { + $this->writers[$writer->getName()] = $writer; + } + + public function getWriter(string $name): WriterInterface + { + $this->assertValidWriter($name); + + return $this->writers[$name]; + } + + public function getDefaultWriter(): WriterInterface + { + if ($this->defaultWriter instanceof WriterInterface) { + return $this->defaultWriter; + } + + throw new InvalidWriterException('Please set the default writer via the second argument of addWriter'); + } + + public function setDefaultWriter(string $name): void + { + $this->defaultWriter = $this->writers[$name]; + } + + public function getWriters(): array + { + return $this->writers; + } + + private function assertValidWriter(string $name): void + { + if (!isset($this->writers[$name])) { + throw new InvalidWriterException('Invalid writer "'.$name.'"'); + } + } +} diff --git a/serve/vendor/endroid/qr-code/src/WriterRegistryInterface.php b/serve/vendor/endroid/qr-code/src/WriterRegistryInterface.php new file mode 100644 index 0000000..4fb245e --- /dev/null +++ b/serve/vendor/endroid/qr-code/src/WriterRegistryInterface.php @@ -0,0 +1,29 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +use Endroid\QrCode\Writer\WriterInterface; + +interface WriterRegistryInterface +{ + /** @param WriterInterface[] $writers */ + public function addWriters(iterable $writers): void; + + public function addWriter(WriterInterface $writer): void; + + public function getWriter(string $name): WriterInterface; + + public function getDefaultWriter(): WriterInterface; + + /** @return WriterInterface[] */ + public function getWriters(): array; +} diff --git a/serve/vendor/endroid/qr-code/tests/QrCodeTest.php b/serve/vendor/endroid/qr-code/tests/QrCodeTest.php new file mode 100644 index 0000000..75f1929 --- /dev/null +++ b/serve/vendor/endroid/qr-code/tests/QrCodeTest.php @@ -0,0 +1,296 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Tests; + +use Endroid\QrCode\Exception\GenerateImageException; +use Endroid\QrCode\Factory\QrCodeFactory; +use Endroid\QrCode\QrCode; +use PHPUnit\Framework\TestCase; +use Zxing\QrReader; + +class QrCodeTest extends TestCase +{ + /** + * @dataProvider stringProvider + * @testdox QR code created with text $text is readable + */ + public function testReadable(string $text): void + { + $qrCode = new QrCode(); + $qrCode->setSize(300); + $qrCode->setText($text); + $pngData = $qrCode->writeString(); + $this->assertTrue(is_string($pngData)); + $reader = new QrReader($pngData, QrReader::SOURCE_TYPE_BLOB); + $this->assertEquals($text, $reader->text()); + } + + public function stringProvider(): array + { + return [ + ['Tiny'], + ['This one has spaces'], + ['d2llMS9uU01BVmlvalM2YU9BUFBPTTdQMmJabHpqdndt'], + ['http://this.is.an/url?with=query&string=attached'], + ['11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], + ['{"i":"serialized.data","v":1,"t":1,"d":"4AEPc9XuIQ0OjsZoSRWp9DRWlN6UyDvuMlyOYy8XjOw="}'], + ['Spëci&al ch@ract3rs'], + ['有限公司'], + ]; + } + + /** + * @dataProvider writerNameProvider + * @testdox Writer set by name $writerName results in the correct data type + */ + public function testWriteQrCodeByWriterName(string $writerName, ?string $fileContent): void + { + $qrCode = new QrCode('QR Code'); + $qrCode->setLogoPath(__DIR__.'/../assets/images/symfony.png'); + $qrCode->setLogoWidth(100); + + $qrCode->setWriterByName($writerName); + $data = $qrCode->writeString(); + $this->assertTrue(is_string($data)); + + if (null !== $fileContent) { + $uriData = $qrCode->writeDataUri(); + $this->assertTrue(0 === strpos($uriData, $fileContent)); + } + } + + public function writerNameProvider(): array + { + return [ + ['binary', null], + ['debug', null], + ['eps', null], + ['png', 'data:image/png;base64'], + ['svg', 'data:image/svg+xml;base64'], + ]; + } + + /** + * @dataProvider extensionsProvider + * @testdox Writer set by extension $extension results in the correct data type + */ + public function testWriteQrCodeByWriterExtension(string $extension, ?string $fileContent): void + { + $qrCode = new QrCode('QR Code'); + $qrCode->setLogoPath(__DIR__.'/../assets/images/symfony.png'); + $qrCode->setLogoWidth(100); + + $qrCode->setWriterByExtension($extension); + $data = $qrCode->writeString(); + $this->assertTrue(is_string($data)); + + if (null !== $fileContent) { + $uriData = $qrCode->writeDataUri(); + $this->assertTrue(0 === strpos($uriData, $fileContent)); + } + } + + public function extensionsProvider(): array + { + return [ + ['bin', null], + ['txt', null], + ['eps', null], + ['png', 'data:image/png;base64'], + ['svg', 'data:image/svg+xml;base64'], + ]; + } + + /** + * @testdox Factory creates a valid QR code + */ + public function testFactory(): void + { + $qrCodeFactory = new QrCodeFactory(); + $qrCode = $qrCodeFactory->create('QR Code', [ + 'writer' => 'png', + 'size' => 300, + 'margin' => 10, + 'round_block_size_mode' => 'shrink', + ]); + + $pngData = $qrCode->writeString(); + $this->assertTrue(is_string($pngData)); + $reader = new QrReader($pngData, QrReader::SOURCE_TYPE_BLOB); + $this->assertEquals('QR Code', $reader->text()); + } + + /** + * @testdox Size and margin are handled correctly + */ + public function testSetSize(): void + { + $size = 400; + $margin = 10; + + $qrCode = new QrCode('QR Code'); + $qrCode->setSize($size); + $qrCode->setMargin($margin); + + $pngData = $qrCode->writeString(); + $image = imagecreatefromstring($pngData); + + $this->assertTrue(imagesx($image) === $size + 2 * $margin); + $this->assertTrue(imagesy($image) === $size + 2 * $margin); + } + + /** + * @testdox Size and margin are handled correctly with rounded blocks + * @dataProvider roundedSizeProvider + */ + public function testSetSizeRounded($size, $margin, $round, $mode, $expectedSize): void + { + $qrCode = new QrCode('QR Code contents with some length to have some data'); + $qrCode->setRoundBlockSize($round, $mode); + $qrCode->setSize($size); + $qrCode->setMargin($margin); + + $pngData = $qrCode->writeString(); + $image = imagecreatefromstring($pngData); + + $this->assertTrue(imagesx($image) === $expectedSize); + $this->assertTrue(imagesy($image) === $expectedSize); + } + + public function roundedSizeProvider() + { + return [ + [ + 'size' => 400, + 'margin' => 0, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_ENLARGE, + 'expectedSize' => 406, + ], + [ + 'size' => 400, + 'margin' => 5, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_ENLARGE, + 'expectedSize' => 416, + ], + [ + 'size' => 400, + 'margin' => 0, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_MARGIN, + 'expectedSize' => 400, + ], + [ + 'size' => 400, + 'margin' => 5, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_MARGIN, + 'expectedSize' => 410, + ], + [ + 'size' => 400, + 'margin' => 0, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_SHRINK, + 'expectedSize' => 377, + ], + [ + 'size' => 400, + 'margin' => 5, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_SHRINK, + 'expectedSize' => 387, + ], + ]; + } + + /** + * @testdox Label can be added and QR code is still readable + */ + public function testSetLabel(): void + { + $qrCode = new QrCode('QR Code'); + $qrCode->setSize(300); + $qrCode->setLabel('Scan the code', 15); + + $pngData = $qrCode->writeString(); + $this->assertTrue(is_string($pngData)); + $reader = new QrReader($pngData, QrReader::SOURCE_TYPE_BLOB); + $this->assertEquals('QR Code', $reader->text()); + } + + /** + * @testdox Logo can be added and QR code is still readable + */ + public function testSetLogo(): void + { + $qrCode = new QrCode('QR Code'); + $qrCode->setSize(500); + $qrCode->setLogoPath(__DIR__.'/../assets/images/symfony.png'); + $qrCode->setLogoWidth(100); + $qrCode->setValidateResult(true); + + $pngData = $qrCode->writeString(); + $this->assertTrue(is_string($pngData)); + } + + /** + * @testdox Resulting QR code can be written to file + */ + public function testWriteFile(): void + { + $filename = __DIR__.'/output/qr-code.png'; + + $qrCode = new QrCode('QR Code'); + $qrCode->writeFile($filename); + + $image = imagecreatefromstring(file_get_contents($filename)); + + $this->assertTrue(false !== $image); + + imagedestroy($image); + } + + /** + * @testdox QR code data can be retrieved + */ + public function testData(): void + { + $qrCode = new QrCode('QR Code'); + + $data = $qrCode->getData(); + + $this->assertArrayHasKey('block_count', $data); + $this->assertArrayHasKey('block_size', $data); + $this->assertArrayHasKey('inner_width', $data); + $this->assertArrayHasKey('inner_height', $data); + $this->assertArrayHasKey('outer_width', $data); + $this->assertArrayHasKey('outer_height', $data); + $this->assertArrayHasKey('margin_left', $data); + $this->assertArrayHasKey('margin_right', $data); + } + + /** + * @testdox Invalid image data results in appropriate exception + */ + public function testNonImageData(): void + { + $qrCode = new QrCode('QR Code'); + $qrCode->setLogoPath(__DIR__.'/QrCodeTest.php'); + $qrCode->setLogoSize(200, 200); + $qrCode->setWriterByExtension('svg'); + + $this->expectException(GenerateImageException::class); + $qrCode->writeString(); + } +} diff --git a/serve/vendor/endroid/qr-code/tests/output/.gitignore b/serve/vendor/endroid/qr-code/tests/output/.gitignore new file mode 100644 index 0000000..a68d087 --- /dev/null +++ b/serve/vendor/endroid/qr-code/tests/output/.gitignore @@ -0,0 +1,2 @@ +/* +!/.gitignore diff --git a/serve/vendor/ezyang/htmlpurifier/CREDITS b/serve/vendor/ezyang/htmlpurifier/CREDITS new file mode 100644 index 0000000..7921b45 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/CREDITS @@ -0,0 +1,9 @@ + +CREDITS + +Almost everything written by Edward Z. Yang (Ambush Commander). Lots of thanks +to the DevNetwork Community for their help (see docs/ref-devnetwork.html for +more details), Feyd especially (namely IPv6 and optimization). Thanks to RSnake +for letting me package his fantastic XSS cheatsheet for a smoketest. + + vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/LICENSE b/serve/vendor/ezyang/htmlpurifier/LICENSE new file mode 100644 index 0000000..8c88a20 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/README.md b/serve/vendor/ezyang/htmlpurifier/README.md new file mode 100644 index 0000000..9e0becc --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/README.md @@ -0,0 +1,29 @@ +HTML Purifier [![Build Status](https://secure.travis-ci.org/ezyang/htmlpurifier.svg?branch=master)](http://travis-ci.org/ezyang/htmlpurifier) +============= + +HTML Purifier is an HTML filtering solution that uses a unique combination +of robust whitelists and aggressive parsing to ensure that not only are +XSS attacks thwarted, but the resulting HTML is standards compliant. + +HTML Purifier is oriented towards richly formatted documents from +untrusted sources that require CSS and a full tag-set. This library can +be configured to accept a more restrictive set of tags, but it won't be +as efficient as more bare-bones parsers. It will, however, do the job +right, which may be more important. + +Places to go: + +* See INSTALL for a quick installation guide +* See docs/ for developer-oriented documentation, code examples and + an in-depth installation guide. +* See WYSIWYG for information on editors like TinyMCE and FCKeditor + +HTML Purifier can be found on the web at: [http://htmlpurifier.org/](http://htmlpurifier.org/) + +## Installation + +Package available on [Composer](https://packagist.org/packages/ezyang/htmlpurifier). + +If you're using Composer to manage dependencies, you can use + + $ composer require ezyang/htmlpurifier diff --git a/serve/vendor/ezyang/htmlpurifier/VERSION b/serve/vendor/ezyang/htmlpurifier/VERSION new file mode 100644 index 0000000..01b73ab --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/VERSION @@ -0,0 +1 @@ +4.13.0 \ No newline at end of file diff --git a/serve/vendor/ezyang/htmlpurifier/composer.json b/serve/vendor/ezyang/htmlpurifier/composer.json new file mode 100644 index 0000000..0ff86b5 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/composer.json @@ -0,0 +1,28 @@ +{ + "name": "ezyang/htmlpurifier", + "description": "Standards compliant HTML filter written in PHP", + "type": "library", + "keywords": ["html"], + "homepage": "http://htmlpurifier.org/", + "license": "LGPL-2.1-or-later", + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "require": { + "php": ">=5.2" + }, + "require-dev": { + "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" + }, + "autoload": { + "psr-0": { "HTMLPurifier": "library/" }, + "files": ["library/HTMLPurifier.composer.php"], + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + } +} diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php new file mode 100644 index 0000000..1960c39 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php @@ -0,0 +1,11 @@ +purify($html, $config); +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php new file mode 100644 index 0000000..151e675 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php @@ -0,0 +1,234 @@ + $attributes) { + $allowed_elements[$element] = true; + foreach ($attributes as $attribute => $x) { + $allowed_attributes["$element.$attribute"] = true; + } + } + $config->set('HTML.AllowedElements', $allowed_elements); + $config->set('HTML.AllowedAttributes', $allowed_attributes); + if ($allowed_protocols !== null) { + $config->set('URI.AllowedSchemes', $allowed_protocols); + } + $purifier = new HTMLPurifier($config); + return $purifier->purify($string); +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php new file mode 100644 index 0000000..39b1b65 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php @@ -0,0 +1,11 @@ +config = HTMLPurifier_Config::create($config); + $this->strategy = new HTMLPurifier_Strategy_Core(); + } + + /** + * Adds a filter to process the output. First come first serve + * + * @param HTMLPurifier_Filter $filter HTMLPurifier_Filter object + */ + public function addFilter($filter) + { + trigger_error( + 'HTMLPurifier->addFilter() is deprecated, use configuration directives' . + ' in the Filter namespace or Filter.Custom', + E_USER_WARNING + ); + $this->filters[] = $filter; + } + + /** + * Filters an HTML snippet/document to be XSS-free and standards-compliant. + * + * @param string $html String of HTML to purify + * @param HTMLPurifier_Config $config Config object for this operation, + * if omitted, defaults to the config object specified during this + * object's construction. The parameter can also be any type + * that HTMLPurifier_Config::create() supports. + * + * @return string Purified HTML + */ + public function purify($html, $config = null) + { + // :TODO: make the config merge in, instead of replace + $config = $config ? HTMLPurifier_Config::create($config) : $this->config; + + // implementation is partially environment dependant, partially + // configuration dependant + $lexer = HTMLPurifier_Lexer::create($config); + + $context = new HTMLPurifier_Context(); + + // setup HTML generator + $this->generator = new HTMLPurifier_Generator($config, $context); + $context->register('Generator', $this->generator); + + // set up global context variables + if ($config->get('Core.CollectErrors')) { + // may get moved out if other facilities use it + $language_factory = HTMLPurifier_LanguageFactory::instance(); + $language = $language_factory->create($config, $context); + $context->register('Locale', $language); + + $error_collector = new HTMLPurifier_ErrorCollector($context); + $context->register('ErrorCollector', $error_collector); + } + + // setup id_accumulator context, necessary due to the fact that + // AttrValidator can be called from many places + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + + $html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context); + + // setup filters + $filter_flags = $config->getBatch('Filter'); + $custom_filters = $filter_flags['Custom']; + unset($filter_flags['Custom']); + $filters = array(); + foreach ($filter_flags as $filter => $flag) { + if (!$flag) { + continue; + } + if (strpos($filter, '.') !== false) { + continue; + } + $class = "HTMLPurifier_Filter_$filter"; + $filters[] = new $class; + } + foreach ($custom_filters as $filter) { + // maybe "HTMLPurifier_Filter_$filter", but be consistent with AutoFormat + $filters[] = $filter; + } + $filters = array_merge($filters, $this->filters); + // maybe prepare(), but later + + for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) { + $html = $filters[$i]->preFilter($html, $config, $context); + } + + // purified HTML + $html = + $this->generator->generateFromTokens( + // list of tokens + $this->strategy->execute( + // list of un-purified tokens + $lexer->tokenizeHTML( + // un-purified HTML + $html, + $config, + $context + ), + $config, + $context + ) + ); + + for ($i = $filter_size - 1; $i >= 0; $i--) { + $html = $filters[$i]->postFilter($html, $config, $context); + } + + $html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context); + $this->context =& $context; + return $html; + } + + /** + * Filters an array of HTML snippets + * + * @param string[] $array_of_html Array of html snippets + * @param HTMLPurifier_Config $config Optional config object for this operation. + * See HTMLPurifier::purify() for more details. + * + * @return string[] Array of purified HTML + */ + public function purifyArray($array_of_html, $config = null) + { + $context_array = array(); + $array = array(); + foreach($array_of_html as $key=>$value){ + if (is_array($value)) { + $array[$key] = $this->purifyArray($value, $config); + } else { + $array[$key] = $this->purify($value, $config); + } + $context_array[$key] = $this->context; + } + $this->context = $context_array; + return $array; + } + + /** + * Singleton for enforcing just one HTML Purifier in your system + * + * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype + * HTMLPurifier instance to overload singleton with, + * or HTMLPurifier_Config instance to configure the + * generated version with. + * + * @return HTMLPurifier + */ + public static function instance($prototype = null) + { + if (!self::$instance || $prototype) { + if ($prototype instanceof HTMLPurifier) { + self::$instance = $prototype; + } elseif ($prototype) { + self::$instance = new HTMLPurifier($prototype); + } else { + self::$instance = new HTMLPurifier(); + } + } + return self::$instance; + } + + /** + * Singleton for enforcing just one HTML Purifier in your system + * + * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype + * HTMLPurifier instance to overload singleton with, + * or HTMLPurifier_Config instance to configure the + * generated version with. + * + * @return HTMLPurifier + * @note Backwards compatibility, see instance() + */ + public static function getInstance($prototype = null) + { + return HTMLPurifier::instance($prototype); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php new file mode 100644 index 0000000..a3261f8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php @@ -0,0 +1,228 @@ +getHTMLDefinition(); + $parent = new HTMLPurifier_Token_Start($definition->info_parent); + $stack = array($parent->toNode()); + foreach ($tokens as $token) { + $token->skip = null; // [MUT] + $token->carryover = null; // [MUT] + if ($token instanceof HTMLPurifier_Token_End) { + $token->start = null; // [MUT] + $r = array_pop($stack); + //assert($r->name === $token->name); + //assert(empty($token->attr)); + $r->endCol = $token->col; + $r->endLine = $token->line; + $r->endArmor = $token->armor; + continue; + } + $node = $token->toNode(); + $stack[count($stack)-1]->children[] = $node; + if ($token instanceof HTMLPurifier_Token_Start) { + $stack[] = $node; + } + } + //assert(count($stack) == 1); + return $stack[0]; + } + + public static function flatten($node, $config, $context) { + $level = 0; + $nodes = array($level => new HTMLPurifier_Queue(array($node))); + $closingTokens = array(); + $tokens = array(); + do { + while (!$nodes[$level]->isEmpty()) { + $node = $nodes[$level]->shift(); // FIFO + list($start, $end) = $node->toTokenPair(); + if ($level > 0) { + $tokens[] = $start; + } + if ($end !== NULL) { + $closingTokens[$level][] = $end; + } + if ($node instanceof HTMLPurifier_Node_Element) { + $level++; + $nodes[$level] = new HTMLPurifier_Queue(); + foreach ($node->children as $childNode) { + $nodes[$level]->push($childNode); + } + } + } + $level--; + if ($level && isset($closingTokens[$level])) { + while ($token = array_pop($closingTokens[$level])) { + $tokens[] = $token; + } + } + } while ($level > 0); + return $tokens; + } +} diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php new file mode 100644 index 0000000..c7b17cf --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php @@ -0,0 +1,148 @@ +doConstruct($attr_types, $modules); + } + + public function doConstruct($attr_types, $modules) + { + // load extensions from the modules + foreach ($modules as $module) { + foreach ($module->attr_collections as $coll_i => $coll) { + if (!isset($this->info[$coll_i])) { + $this->info[$coll_i] = array(); + } + foreach ($coll as $attr_i => $attr) { + if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) { + // merge in includes + $this->info[$coll_i][$attr_i] = array_merge( + $this->info[$coll_i][$attr_i], + $attr + ); + continue; + } + $this->info[$coll_i][$attr_i] = $attr; + } + } + } + // perform internal expansions and inclusions + foreach ($this->info as $name => $attr) { + // merge attribute collections that include others + $this->performInclusions($this->info[$name]); + // replace string identifiers with actual attribute objects + $this->expandIdentifiers($this->info[$name], $attr_types); + } + } + + /** + * Takes a reference to an attribute associative array and performs + * all inclusions specified by the zero index. + * @param array &$attr Reference to attribute array + */ + public function performInclusions(&$attr) + { + if (!isset($attr[0])) { + return; + } + $merge = $attr[0]; + $seen = array(); // recursion guard + // loop through all the inclusions + for ($i = 0; isset($merge[$i]); $i++) { + if (isset($seen[$merge[$i]])) { + continue; + } + $seen[$merge[$i]] = true; + // foreach attribute of the inclusion, copy it over + if (!isset($this->info[$merge[$i]])) { + continue; + } + foreach ($this->info[$merge[$i]] as $key => $value) { + if (isset($attr[$key])) { + continue; + } // also catches more inclusions + $attr[$key] = $value; + } + if (isset($this->info[$merge[$i]][0])) { + // recursion + $merge = array_merge($merge, $this->info[$merge[$i]][0]); + } + } + unset($attr[0]); + } + + /** + * Expands all string identifiers in an attribute array by replacing + * them with the appropriate values inside HTMLPurifier_AttrTypes + * @param array &$attr Reference to attribute array + * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance + */ + public function expandIdentifiers(&$attr, $attr_types) + { + // because foreach will process new elements we add, make sure we + // skip duplicates + $processed = array(); + + foreach ($attr as $def_i => $def) { + // skip inclusions + if ($def_i === 0) { + continue; + } + + if (isset($processed[$def_i])) { + continue; + } + + // determine whether or not attribute is required + if ($required = (strpos($def_i, '*') !== false)) { + // rename the definition + unset($attr[$def_i]); + $def_i = trim($def_i, '*'); + $attr[$def_i] = $def; + } + + $processed[$def_i] = true; + + // if we've already got a literal object, move on + if (is_object($def)) { + // preserve previous required + $attr[$def_i]->required = ($required || $attr[$def_i]->required); + continue; + } + + if ($def === false) { + unset($attr[$def_i]); + continue; + } + + if ($t = $attr_types->get($def)) { + $attr[$def_i] = $t; + $attr[$def_i]->required = $required; + } else { + unset($attr[$def_i]); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php new file mode 100644 index 0000000..739646f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php @@ -0,0 +1,144 @@ + by removing + * leading and trailing whitespace, ignoring line feeds, and replacing + * carriage returns and tabs with spaces. While most useful for HTML + * attributes specified as CDATA, it can also be applied to most CSS + * values. + * + * @note This method is not entirely standards compliant, as trim() removes + * more types of whitespace than specified in the spec. In practice, + * this is rarely a problem, as those extra characters usually have + * already been removed by HTMLPurifier_Encoder. + * + * @warning This processing is inconsistent with XML's whitespace handling + * as specified by section 3.3.3 and referenced XHTML 1.0 section + * 4.7. However, note that we are NOT necessarily + * parsing XML, thus, this behavior may still be correct. We + * assume that newlines have been normalized. + */ + public function parseCDATA($string) + { + $string = trim($string); + $string = str_replace(array("\n", "\t", "\r"), ' ', $string); + return $string; + } + + /** + * Factory method for creating this class from a string. + * @param string $string String construction info + * @return HTMLPurifier_AttrDef Created AttrDef object corresponding to $string + */ + public function make($string) + { + // default implementation, return a flyweight of this object. + // If $string has an effect on the returned object (i.e. you + // need to overload this method), it is best + // to clone or instantiate new copies. (Instantiation is safer.) + return $this; + } + + /** + * Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work + * properly. THIS IS A HACK! + * @param string $string a CSS colour definition + * @return string + */ + protected function mungeRgb($string) + { + $p = '\s*(\d+(\.\d+)?([%]?))\s*'; + + if (preg_match('/(rgba|hsla)\(/', $string)) { + return preg_replace('/(rgba|hsla)\('.$p.','.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8,\11)', $string); + } + + return preg_replace('/(rgb|hsl)\('.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8)', $string); + } + + /** + * Parses a possibly escaped CSS string and returns the "pure" + * version of it. + */ + protected function expandCSSEscape($string) + { + // flexibly parse it + $ret = ''; + for ($i = 0, $c = strlen($string); $i < $c; $i++) { + if ($string[$i] === '\\') { + $i++; + if ($i >= $c) { + $ret .= '\\'; + break; + } + if (ctype_xdigit($string[$i])) { + $code = $string[$i]; + for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) { + if (!ctype_xdigit($string[$i])) { + break; + } + $code .= $string[$i]; + } + // We have to be extremely careful when adding + // new characters, to make sure we're not breaking + // the encoding. + $char = HTMLPurifier_Encoder::unichr(hexdec($code)); + if (HTMLPurifier_Encoder::cleanUTF8($char) === '') { + continue; + } + $ret .= $char; + if ($i < $c && trim($string[$i]) !== '') { + $i--; + } + continue; + } + if ($string[$i] === "\n") { + continue; + } + } + $ret .= $string[$i]; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php new file mode 100644 index 0000000..ad2cb90 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php @@ -0,0 +1,136 @@ +parseCDATA($css); + + $definition = $config->getCSSDefinition(); + $allow_duplicates = $config->get("CSS.AllowDuplicates"); + + + // According to the CSS2.1 spec, the places where a + // non-delimiting semicolon can appear are in strings + // escape sequences. So here is some dumb hack to + // handle quotes. + $len = strlen($css); + $accum = ""; + $declarations = array(); + $quoted = false; + for ($i = 0; $i < $len; $i++) { + $c = strcspn($css, ";'\"", $i); + $accum .= substr($css, $i, $c); + $i += $c; + if ($i == $len) break; + $d = $css[$i]; + if ($quoted) { + $accum .= $d; + if ($d == $quoted) { + $quoted = false; + } + } else { + if ($d == ";") { + $declarations[] = $accum; + $accum = ""; + } else { + $accum .= $d; + $quoted = $d; + } + } + } + if ($accum != "") $declarations[] = $accum; + + $propvalues = array(); + $new_declarations = ''; + + /** + * Name of the current CSS property being validated. + */ + $property = false; + $context->register('CurrentCSSProperty', $property); + + foreach ($declarations as $declaration) { + if (!$declaration) { + continue; + } + if (!strpos($declaration, ':')) { + continue; + } + list($property, $value) = explode(':', $declaration, 2); + $property = trim($property); + $value = trim($value); + $ok = false; + do { + if (isset($definition->info[$property])) { + $ok = true; + break; + } + if (ctype_lower($property)) { + break; + } + $property = strtolower($property); + if (isset($definition->info[$property])) { + $ok = true; + break; + } + } while (0); + if (!$ok) { + continue; + } + // inefficient call, since the validator will do this again + if (strtolower(trim($value)) !== 'inherit') { + // inherit works for everything (but only on the base property) + $result = $definition->info[$property]->validate( + $value, + $config, + $context + ); + } else { + $result = 'inherit'; + } + if ($result === false) { + continue; + } + if ($allow_duplicates) { + $new_declarations .= "$property:$result;"; + } else { + $propvalues[$property] = $result; + } + } + + $context->destroy('CurrentCSSProperty'); + + // procedure does not write the new CSS simultaneously, so it's + // slightly inefficient, but it's the only way of getting rid of + // duplicates. Perhaps config to optimize it, but not now. + + foreach ($propvalues as $prop => $value) { + $new_declarations .= "$prop:$value;"; + } + + return $new_declarations ? $new_declarations : false; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php new file mode 100644 index 0000000..af2b83d --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php @@ -0,0 +1,34 @@ + 1.0) { + $result = '1'; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php new file mode 100644 index 0000000..7f1ea3b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php @@ -0,0 +1,111 @@ +getCSSDefinition(); + $this->info['background-color'] = $def->info['background-color']; + $this->info['background-image'] = $def->info['background-image']; + $this->info['background-repeat'] = $def->info['background-repeat']; + $this->info['background-attachment'] = $def->info['background-attachment']; + $this->info['background-position'] = $def->info['background-position']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') { + return false; + } + + // munge rgb() decl if necessary + $string = $this->mungeRgb($string); + + // assumes URI doesn't have spaces in it + $bits = explode(' ', $string); // bits to process + + $caught = array(); + $caught['color'] = false; + $caught['image'] = false; + $caught['repeat'] = false; + $caught['attachment'] = false; + $caught['position'] = false; + + $i = 0; // number of catches + + foreach ($bits as $bit) { + if ($bit === '') { + continue; + } + foreach ($caught as $key => $status) { + if ($key != 'position') { + if ($status !== false) { + continue; + } + $r = $this->info['background-' . $key]->validate($bit, $config, $context); + } else { + $r = $bit; + } + if ($r === false) { + continue; + } + if ($key == 'position') { + if ($caught[$key] === false) { + $caught[$key] = ''; + } + $caught[$key] .= $r . ' '; + } else { + $caught[$key] = $r; + } + $i++; + break; + } + } + + if (!$i) { + return false; + } + if ($caught['position'] !== false) { + $caught['position'] = $this->info['background-position']-> + validate($caught['position'], $config, $context); + } + + $ret = array(); + foreach ($caught as $value) { + if ($value === false) { + continue; + } + $ret[] = $value; + } + + if (empty($ret)) { + return false; + } + return implode(' ', $ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php new file mode 100644 index 0000000..4580ef5 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php @@ -0,0 +1,157 @@ + | | left | center | right + ] + [ + | | top | center | bottom + ]? + ] | + [ // this signifies that the vertical and horizontal adjectives + // can be arbitrarily ordered, however, there can only be two, + // one of each, or none at all + [ + left | center | right + ] || + [ + top | center | bottom + ] + ] + top, left = 0% + center, (none) = 50% + bottom, right = 100% +*/ + +/* QuirksMode says: + keyword + length/percentage must be ordered correctly, as per W3C + + Internet Explorer and Opera, however, support arbitrary ordering. We + should fix it up. + + Minor issue though, not strictly necessary. +*/ + +// control freaks may appreciate the ability to convert these to +// percentages or something, but it's not necessary + +/** + * Validates the value of background-position. + */ +class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef +{ + + /** + * @type HTMLPurifier_AttrDef_CSS_Length + */ + protected $length; + + /** + * @type HTMLPurifier_AttrDef_CSS_Percentage + */ + protected $percentage; + + public function __construct() + { + $this->length = new HTMLPurifier_AttrDef_CSS_Length(); + $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage(); + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + $bits = explode(' ', $string); + + $keywords = array(); + $keywords['h'] = false; // left, right + $keywords['v'] = false; // top, bottom + $keywords['ch'] = false; // center (first word) + $keywords['cv'] = false; // center (second word) + $measures = array(); + + $i = 0; + + $lookup = array( + 'top' => 'v', + 'bottom' => 'v', + 'left' => 'h', + 'right' => 'h', + 'center' => 'c' + ); + + foreach ($bits as $bit) { + if ($bit === '') { + continue; + } + + // test for keyword + $lbit = ctype_lower($bit) ? $bit : strtolower($bit); + if (isset($lookup[$lbit])) { + $status = $lookup[$lbit]; + if ($status == 'c') { + if ($i == 0) { + $status = 'ch'; + } else { + $status = 'cv'; + } + } + $keywords[$status] = $lbit; + $i++; + } + + // test for length + $r = $this->length->validate($bit, $config, $context); + if ($r !== false) { + $measures[] = $r; + $i++; + } + + // test for percentage + $r = $this->percentage->validate($bit, $config, $context); + if ($r !== false) { + $measures[] = $r; + $i++; + } + } + + if (!$i) { + return false; + } // no valid values were caught + + $ret = array(); + + // first keyword + if ($keywords['h']) { + $ret[] = $keywords['h']; + } elseif ($keywords['ch']) { + $ret[] = $keywords['ch']; + $keywords['cv'] = false; // prevent re-use: center = center center + } elseif (count($measures)) { + $ret[] = array_shift($measures); + } + + if ($keywords['v']) { + $ret[] = $keywords['v']; + } elseif ($keywords['cv']) { + $ret[] = $keywords['cv']; + } elseif (count($measures)) { + $ret[] = array_shift($measures); + } + + if (empty($ret)) { + return false; + } + return implode(' ', $ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php new file mode 100644 index 0000000..16243ba --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php @@ -0,0 +1,56 @@ +getCSSDefinition(); + $this->info['border-width'] = $def->info['border-width']; + $this->info['border-style'] = $def->info['border-style']; + $this->info['border-top-color'] = $def->info['border-top-color']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + $string = $this->mungeRgb($string); + $bits = explode(' ', $string); + $done = array(); // segments we've finished + $ret = ''; // return value + foreach ($bits as $bit) { + foreach ($this->info as $propname => $validator) { + if (isset($done[$propname])) { + continue; + } + $r = $validator->validate($bit, $config, $context); + if ($r !== false) { + $ret .= $r . ' '; + $done[$propname] = true; + break; + } + } + } + return rtrim($ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php new file mode 100644 index 0000000..d7287a0 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php @@ -0,0 +1,161 @@ +alpha = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + } + + /** + * @param string $color + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($color, $config, $context) + { + static $colors = null; + if ($colors === null) { + $colors = $config->get('Core.ColorKeywords'); + } + + $color = trim($color); + if ($color === '') { + return false; + } + + $lower = strtolower($color); + if (isset($colors[$lower])) { + return $colors[$lower]; + } + + if (preg_match('#(rgb|rgba|hsl|hsla)\(#', $color, $matches) === 1) { + $length = strlen($color); + if (strpos($color, ')') !== $length - 1) { + return false; + } + + // get used function : rgb, rgba, hsl or hsla + $function = $matches[1]; + + $parameters_size = 3; + $alpha_channel = false; + if (substr($function, -1) === 'a') { + $parameters_size = 4; + $alpha_channel = true; + } + + /* + * Allowed types for values : + * parameter_position => [type => max_value] + */ + $allowed_types = array( + 1 => array('percentage' => 100, 'integer' => 255), + 2 => array('percentage' => 100, 'integer' => 255), + 3 => array('percentage' => 100, 'integer' => 255), + ); + $allow_different_types = false; + + if (strpos($function, 'hsl') !== false) { + $allowed_types = array( + 1 => array('integer' => 360), + 2 => array('percentage' => 100), + 3 => array('percentage' => 100), + ); + $allow_different_types = true; + } + + $values = trim(str_replace($function, '', $color), ' ()'); + + $parts = explode(',', $values); + if (count($parts) !== $parameters_size) { + return false; + } + + $type = false; + $new_parts = array(); + $i = 0; + + foreach ($parts as $part) { + $i++; + $part = trim($part); + + if ($part === '') { + return false; + } + + // different check for alpha channel + if ($alpha_channel === true && $i === count($parts)) { + $result = $this->alpha->validate($part, $config, $context); + + if ($result === false) { + return false; + } + + $new_parts[] = (string)$result; + continue; + } + + if (substr($part, -1) === '%') { + $current_type = 'percentage'; + } else { + $current_type = 'integer'; + } + + if (!array_key_exists($current_type, $allowed_types[$i])) { + return false; + } + + if (!$type) { + $type = $current_type; + } + + if ($allow_different_types === false && $type != $current_type) { + return false; + } + + $max_value = $allowed_types[$i][$current_type]; + + if ($current_type == 'integer') { + // Return value between range 0 -> $max_value + $new_parts[] = (int)max(min($part, $max_value), 0); + } elseif ($current_type == 'percentage') { + $new_parts[] = (float)max(min(rtrim($part, '%'), $max_value), 0) . '%'; + } + } + + $new_values = implode(',', $new_parts); + + $color = $function . '(' . $new_values . ')'; + } else { + // hexadecimal handling + if ($color[0] === '#') { + $hex = substr($color, 1); + } else { + $hex = $color; + $color = '#' . $color; + } + $length = strlen($hex); + if ($length !== 3 && $length !== 6) { + return false; + } + if (!ctype_xdigit($hex)) { + return false; + } + } + return $color; + } + +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php new file mode 100644 index 0000000..9c17505 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php @@ -0,0 +1,48 @@ +defs = $defs; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + foreach ($this->defs as $i => $def) { + $result = $this->defs[$i]->validate($string, $config, $context); + if ($result !== false) { + return $result; + } + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php new file mode 100644 index 0000000..9d77cc9 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php @@ -0,0 +1,44 @@ +def = $def; + $this->element = $element; + } + + /** + * Checks if CurrentToken is set and equal to $this->element + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $token = $context->get('CurrentToken', true); + if ($token && $token->name == $this->element) { + return false; + } + return $this->def->validate($string, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php new file mode 100644 index 0000000..bde4c33 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php @@ -0,0 +1,77 @@ +intValidator = new HTMLPurifier_AttrDef_Integer(); + } + + /** + * @param string $value + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($value, $config, $context) + { + $value = $this->parseCDATA($value); + if ($value === 'none') { + return $value; + } + // if we looped this we could support multiple filters + $function_length = strcspn($value, '('); + $function = trim(substr($value, 0, $function_length)); + if ($function !== 'alpha' && + $function !== 'Alpha' && + $function !== 'progid:DXImageTransform.Microsoft.Alpha' + ) { + return false; + } + $cursor = $function_length + 1; + $parameters_length = strcspn($value, ')', $cursor); + $parameters = substr($value, $cursor, $parameters_length); + $params = explode(',', $parameters); + $ret_params = array(); + $lookup = array(); + foreach ($params as $param) { + list($key, $value) = explode('=', $param); + $key = trim($key); + $value = trim($value); + if (isset($lookup[$key])) { + continue; + } + if ($key !== 'opacity') { + continue; + } + $value = $this->intValidator->validate($value, $config, $context); + if ($value === false) { + continue; + } + $int = (int)$value; + if ($int > 100) { + $value = '100'; + } + if ($int < 0) { + $value = '0'; + } + $ret_params[] = "$key=$value"; + $lookup[$key] = true; + } + $ret_parameters = implode(',', $ret_params); + $ret_function = "$function($ret_parameters)"; + return $ret_function; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php new file mode 100644 index 0000000..579b97e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php @@ -0,0 +1,176 @@ +getCSSDefinition(); + $this->info['font-style'] = $def->info['font-style']; + $this->info['font-variant'] = $def->info['font-variant']; + $this->info['font-weight'] = $def->info['font-weight']; + $this->info['font-size'] = $def->info['font-size']; + $this->info['line-height'] = $def->info['line-height']; + $this->info['font-family'] = $def->info['font-family']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + static $system_fonts = array( + 'caption' => true, + 'icon' => true, + 'menu' => true, + 'message-box' => true, + 'small-caption' => true, + 'status-bar' => true + ); + + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') { + return false; + } + + // check if it's one of the keywords + $lowercase_string = strtolower($string); + if (isset($system_fonts[$lowercase_string])) { + return $lowercase_string; + } + + $bits = explode(' ', $string); // bits to process + $stage = 0; // this indicates what we're looking for + $caught = array(); // which stage 0 properties have we caught? + $stage_1 = array('font-style', 'font-variant', 'font-weight'); + $final = ''; // output + + for ($i = 0, $size = count($bits); $i < $size; $i++) { + if ($bits[$i] === '') { + continue; + } + switch ($stage) { + case 0: // attempting to catch font-style, font-variant or font-weight + foreach ($stage_1 as $validator_name) { + if (isset($caught[$validator_name])) { + continue; + } + $r = $this->info[$validator_name]->validate( + $bits[$i], + $config, + $context + ); + if ($r !== false) { + $final .= $r . ' '; + $caught[$validator_name] = true; + break; + } + } + // all three caught, continue on + if (count($caught) >= 3) { + $stage = 1; + } + if ($r !== false) { + break; + } + case 1: // attempting to catch font-size and perhaps line-height + $found_slash = false; + if (strpos($bits[$i], '/') !== false) { + list($font_size, $line_height) = + explode('/', $bits[$i]); + if ($line_height === '') { + // ooh, there's a space after the slash! + $line_height = false; + $found_slash = true; + } + } else { + $font_size = $bits[$i]; + $line_height = false; + } + $r = $this->info['font-size']->validate( + $font_size, + $config, + $context + ); + if ($r !== false) { + $final .= $r; + // attempt to catch line-height + if ($line_height === false) { + // we need to scroll forward + for ($j = $i + 1; $j < $size; $j++) { + if ($bits[$j] === '') { + continue; + } + if ($bits[$j] === '/') { + if ($found_slash) { + return false; + } else { + $found_slash = true; + continue; + } + } + $line_height = $bits[$j]; + break; + } + } else { + // slash already found + $found_slash = true; + $j = $i; + } + if ($found_slash) { + $i = $j; + $r = $this->info['line-height']->validate( + $line_height, + $config, + $context + ); + if ($r !== false) { + $final .= '/' . $r; + } + } + $final .= ' '; + $stage = 2; + break; + } + return false; + case 2: // attempting to catch font-family + $font_family = + implode(' ', array_slice($bits, $i, $size - $i)); + $r = $this->info['font-family']->validate( + $font_family, + $config, + $context + ); + if ($r !== false) { + $final .= $r . ' '; + // processing completed successfully + return rtrim($final); + } + return false; + } + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php new file mode 100644 index 0000000..74e24c8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php @@ -0,0 +1,219 @@ +mask = '_- '; + for ($c = 'a'; $c <= 'z'; $c++) { + $this->mask .= $c; + } + for ($c = 'A'; $c <= 'Z'; $c++) { + $this->mask .= $c; + } + for ($c = '0'; $c <= '9'; $c++) { + $this->mask .= $c; + } // cast-y, but should be fine + // special bytes used by UTF-8 + for ($i = 0x80; $i <= 0xFF; $i++) { + // We don't bother excluding invalid bytes in this range, + // because the our restriction of well-formed UTF-8 will + // prevent these from ever occurring. + $this->mask .= chr($i); + } + + /* + PHP's internal strcspn implementation is + O(length of string * length of mask), making it inefficient + for large masks. However, it's still faster than + preg_match 8) + for (p = s1;;) { + spanp = s2; + do { + if (*spanp == c || p == s1_end) { + return p - s1; + } + } while (spanp++ < (s2_end - 1)); + c = *++p; + } + */ + // possible optimization: invert the mask. + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + static $generic_names = array( + 'serif' => true, + 'sans-serif' => true, + 'monospace' => true, + 'fantasy' => true, + 'cursive' => true + ); + $allowed_fonts = $config->get('CSS.AllowedFonts'); + + // assume that no font names contain commas in them + $fonts = explode(',', $string); + $final = ''; + foreach ($fonts as $font) { + $font = trim($font); + if ($font === '') { + continue; + } + // match a generic name + if (isset($generic_names[$font])) { + if ($allowed_fonts === null || isset($allowed_fonts[$font])) { + $final .= $font . ', '; + } + continue; + } + // match a quoted name + if ($font[0] === '"' || $font[0] === "'") { + $length = strlen($font); + if ($length <= 2) { + continue; + } + $quote = $font[0]; + if ($font[$length - 1] !== $quote) { + continue; + } + $font = substr($font, 1, $length - 2); + } + + $font = $this->expandCSSEscape($font); + + // $font is a pure representation of the font name + + if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) { + continue; + } + + if (ctype_alnum($font) && $font !== '') { + // very simple font, allow it in unharmed + $final .= $font . ', '; + continue; + } + + // bugger out on whitespace. form feed (0C) really + // shouldn't show up regardless + $font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font); + + // Here, there are various classes of characters which need + // to be treated differently: + // - Alphanumeric characters are essentially safe. We + // handled these above. + // - Spaces require quoting, though most parsers will do + // the right thing if there aren't any characters that + // can be misinterpreted + // - Dashes rarely occur, but they fairly unproblematic + // for parsing/rendering purposes. + // The above characters cover the majority of Western font + // names. + // - Arbitrary Unicode characters not in ASCII. Because + // most parsers give little thought to Unicode, treatment + // of these codepoints is basically uniform, even for + // punctuation-like codepoints. These characters can + // show up in non-Western pages and are supported by most + // major browsers, for example: "MS 明朝" is a + // legitimate font-name + // . See + // the CSS3 spec for more examples: + // + // You can see live samples of these on the Internet: + // + // However, most of these fonts have ASCII equivalents: + // for example, 'MS Mincho', and it's considered + // professional to use ASCII font names instead of + // Unicode font names. Thanks Takeshi Terada for + // providing this information. + // The following characters, to my knowledge, have not been + // used to name font names. + // - Single quote. While theoretically you might find a + // font name that has a single quote in its name (serving + // as an apostrophe, e.g. Dave's Scribble), I haven't + // been able to find any actual examples of this. + // Internet Explorer's cssText translation (which I + // believe is invoked by innerHTML) normalizes any + // quoting to single quotes, and fails to escape single + // quotes. (Note that this is not IE's behavior for all + // CSS properties, just some sort of special casing for + // font-family). So a single quote *cannot* be used + // safely in the font-family context if there will be an + // innerHTML/cssText translation. Note that Firefox 3.x + // does this too. + // - Double quote. In IE, these get normalized to + // single-quotes, no matter what the encoding. (Fun + // fact, in IE8, the 'content' CSS property gained + // support, where they special cased to preserve encoded + // double quotes, but still translate unadorned double + // quotes into single quotes.) So, because their + // fixpoint behavior is identical to single quotes, they + // cannot be allowed either. Firefox 3.x displays + // single-quote style behavior. + // - Backslashes are reduced by one (so \\ -> \) every + // iteration, so they cannot be used safely. This shows + // up in IE7, IE8 and FF3 + // - Semicolons, commas and backticks are handled properly. + // - The rest of the ASCII punctuation is handled properly. + // We haven't checked what browsers do to unadorned + // versions, but this is not important as long as the + // browser doesn't /remove/ surrounding quotes (as IE does + // for HTML). + // + // With these results in hand, we conclude that there are + // various levels of safety: + // - Paranoid: alphanumeric, spaces and dashes(?) + // - International: Paranoid + non-ASCII Unicode + // - Edgy: Everything except quotes, backslashes + // - NoJS: Standards compliance, e.g. sod IE. Note that + // with some judicious character escaping (since certain + // types of escaping doesn't work) this is theoretically + // OK as long as innerHTML/cssText is not called. + // We believe that international is a reasonable default + // (that we will implement now), and once we do more + // extensive research, we may feel comfortable with dropping + // it down to edgy. + + // Edgy: alphanumeric, spaces, dashes, underscores and Unicode. Use of + // str(c)spn assumes that the string was already well formed + // Unicode (which of course it is). + if (strspn($font, $this->mask) !== strlen($font)) { + continue; + } + + // Historical: + // In the absence of innerHTML/cssText, these ugly + // transforms don't pose a security risk (as \\ and \" + // might--these escapes are not supported by most browsers). + // We could try to be clever and use single-quote wrapping + // when there is a double quote present, but I have choosen + // not to implement that. (NOTE: you can reduce the amount + // of escapes by one depending on what quoting style you use) + // $font = str_replace('\\', '\\5C ', $font); + // $font = str_replace('"', '\\22 ', $font); + // $font = str_replace("'", '\\27 ', $font); + + // font possibly with spaces, requires quoting + $final .= "'$font', "; + } + $final = rtrim($final, ', '); + if ($final === '') { + return false; + } + return $final; + } + +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php new file mode 100644 index 0000000..973002c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php @@ -0,0 +1,32 @@ +def = $def; + $this->allow = $allow; + } + + /** + * Intercepts and removes !important if necessary + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + // test for ! and important tokens + $string = trim($string); + $is_important = false; + // :TODO: optimization: test directly for !important and ! important + if (strlen($string) >= 9 && substr($string, -9) === 'important') { + $temp = rtrim(substr($string, 0, -9)); + // use a temp, because we might want to restore important + if (strlen($temp) >= 1 && substr($temp, -1) === '!') { + $string = rtrim(substr($temp, 0, -1)); + $is_important = true; + } + } + $string = $this->def->validate($string, $config, $context); + if ($this->allow && $is_important) { + $string .= ' !important'; + } + return $string; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php new file mode 100644 index 0000000..f12453a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php @@ -0,0 +1,77 @@ +min = $min !== null ? HTMLPurifier_Length::make($min) : null; + $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + + // Optimizations + if ($string === '') { + return false; + } + if ($string === '0') { + return '0'; + } + if (strlen($string) === 1) { + return false; + } + + $length = HTMLPurifier_Length::make($string); + if (!$length->isValid()) { + return false; + } + + if ($this->min) { + $c = $length->compareTo($this->min); + if ($c === false) { + return false; + } + if ($c < 0) { + return false; + } + } + if ($this->max) { + $c = $length->compareTo($this->max); + if ($c === false) { + return false; + } + if ($c > 0) { + return false; + } + } + return $length->toString(); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php new file mode 100644 index 0000000..e74d426 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php @@ -0,0 +1,112 @@ +getCSSDefinition(); + $this->info['list-style-type'] = $def->info['list-style-type']; + $this->info['list-style-position'] = $def->info['list-style-position']; + $this->info['list-style-image'] = $def->info['list-style-image']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') { + return false; + } + + // assumes URI doesn't have spaces in it + $bits = explode(' ', strtolower($string)); // bits to process + + $caught = array(); + $caught['type'] = false; + $caught['position'] = false; + $caught['image'] = false; + + $i = 0; // number of catches + $none = false; + + foreach ($bits as $bit) { + if ($i >= 3) { + return; + } // optimization bit + if ($bit === '') { + continue; + } + foreach ($caught as $key => $status) { + if ($status !== false) { + continue; + } + $r = $this->info['list-style-' . $key]->validate($bit, $config, $context); + if ($r === false) { + continue; + } + if ($r === 'none') { + if ($none) { + continue; + } else { + $none = true; + } + if ($key == 'image') { + continue; + } + } + $caught[$key] = $r; + $i++; + break; + } + } + + if (!$i) { + return false; + } + + $ret = array(); + + // construct type + if ($caught['type']) { + $ret[] = $caught['type']; + } + + // construct image + if ($caught['image']) { + $ret[] = $caught['image']; + } + + // construct position + if ($caught['position']) { + $ret[] = $caught['position']; + } + + if (empty($ret)) { + return false; + } + return implode(' ', $ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php new file mode 100644 index 0000000..e707f87 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php @@ -0,0 +1,71 @@ +single = $single; + $this->max = $max; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->mungeRgb($this->parseCDATA($string)); + if ($string === '') { + return false; + } + $parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n + $length = count($parts); + $final = ''; + for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) { + if (ctype_space($parts[$i])) { + continue; + } + $result = $this->single->validate($parts[$i], $config, $context); + if ($result !== false) { + $final .= $result . ' '; + $num++; + } + } + if ($final === '') { + return false; + } + return rtrim($final); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php new file mode 100644 index 0000000..ef49d20 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php @@ -0,0 +1,90 @@ +non_negative = $non_negative; + } + + /** + * @param string $number + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string|bool + * @warning Some contexts do not pass $config, $context. These + * variables should not be used without checking HTMLPurifier_Length + */ + public function validate($number, $config, $context) + { + $number = $this->parseCDATA($number); + + if ($number === '') { + return false; + } + if ($number === '0') { + return '0'; + } + + $sign = ''; + switch ($number[0]) { + case '-': + if ($this->non_negative) { + return false; + } + $sign = '-'; + case '+': + $number = substr($number, 1); + } + + if (ctype_digit($number)) { + $number = ltrim($number, '0'); + return $number ? $sign . $number : '0'; + } + + // Period is the only non-numeric character allowed + if (strpos($number, '.') === false) { + return false; + } + + list($left, $right) = explode('.', $number, 2); + + if ($left === '' && $right === '') { + return false; + } + if ($left !== '' && !ctype_digit($left)) { + return false; + } + + // Remove leading zeros until positive number or a zero stays left + if (ltrim($left, '0') != '') { + $left = ltrim($left, '0'); + } else { + $left = '0'; + } + + $right = rtrim($right, '0'); + + if ($right === '') { + return $left ? $sign . $left : '0'; + } elseif (!ctype_digit($right)) { + return false; + } + return $sign . $left . '.' . $right; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php new file mode 100644 index 0000000..f0f25c5 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php @@ -0,0 +1,54 @@ +number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative); + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + + if ($string === '') { + return false; + } + $length = strlen($string); + if ($length === 1) { + return false; + } + if ($string[$length - 1] !== '%') { + return false; + } + + $number = substr($string, 0, $length - 1); + $number = $this->number_def->validate($number, $config, $context); + + if ($number === false) { + return false; + } + return "$number%"; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php new file mode 100644 index 0000000..5fd4b7f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php @@ -0,0 +1,46 @@ + true, + 'overline' => true, + 'underline' => true, + ); + + $string = strtolower($this->parseCDATA($string)); + + if ($string === 'none') { + return $string; + } + + $parts = explode(' ', $string); + $final = ''; + foreach ($parts as $part) { + if (isset($allowed_values[$part])) { + $final .= $part . ' '; + } + } + $final = rtrim($final); + if ($final === '') { + return false; + } + return $final; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php new file mode 100644 index 0000000..6617aca --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php @@ -0,0 +1,77 @@ +parseCDATA($uri_string); + if (strpos($uri_string, 'url(') !== 0) { + return false; + } + $uri_string = substr($uri_string, 4); + if (strlen($uri_string) == 0) { + return false; + } + $new_length = strlen($uri_string) - 1; + if ($uri_string[$new_length] != ')') { + return false; + } + $uri = trim(substr($uri_string, 0, $new_length)); + + if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) { + $quote = $uri[0]; + $new_length = strlen($uri) - 1; + if ($uri[$new_length] !== $quote) { + return false; + } + $uri = substr($uri, 1, $new_length - 1); + } + + $uri = $this->expandCSSEscape($uri); + + $result = parent::validate($uri, $config, $context); + + if ($result === false) { + return false; + } + + // extra sanity check; should have been done by URI + $result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result); + + // suspicious characters are ()'; we're going to percent encode + // them for safety. + $result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result); + + // there's an extra bug where ampersands lose their escaping on + // an innerHTML cycle, so a very unlucky query parameter could + // then change the meaning of the URL. Unfortunately, there's + // not much we can do about that... + return "url(\"$result\")"; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php new file mode 100644 index 0000000..6698a00 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php @@ -0,0 +1,44 @@ +clone = $clone; + } + + /** + * @param string $v + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($v, $config, $context) + { + return $this->clone->validate($v, $config, $context); + } + + /** + * @param string $string + * @return HTMLPurifier_AttrDef + */ + public function make($string) + { + return clone $this->clone; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php new file mode 100644 index 0000000..8abda7f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php @@ -0,0 +1,73 @@ +valid_values = array_flip($valid_values); + $this->case_sensitive = $case_sensitive; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = trim($string); + if (!$this->case_sensitive) { + // we may want to do full case-insensitive libraries + $string = ctype_lower($string) ? $string : strtolower($string); + } + $result = isset($this->valid_values[$string]); + + return $result ? $string : false; + } + + /** + * @param string $string In form of comma-delimited list of case-insensitive + * valid values. Example: "foo,bar,baz". Prepend "s:" to make + * case sensitive + * @return HTMLPurifier_AttrDef_Enum + */ + public function make($string) + { + if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') { + $string = substr($string, 2); + $sensitive = true; + } else { + $sensitive = false; + } + $values = explode(',', $string); + return new HTMLPurifier_AttrDef_Enum($values, $sensitive); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php new file mode 100644 index 0000000..be3bbc8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php @@ -0,0 +1,48 @@ +name = $name; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + return $this->name; + } + + /** + * @param string $string Name of attribute + * @return HTMLPurifier_AttrDef_HTML_Bool + */ + public function make($string) + { + return new HTMLPurifier_AttrDef_HTML_Bool($string); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php new file mode 100644 index 0000000..d501348 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php @@ -0,0 +1,48 @@ +getDefinition('HTML')->doctype->name; + if ($name == "XHTML 1.1" || $name == "XHTML 2.0") { + return parent::split($string, $config, $context); + } else { + return preg_split('/\s+/', $string); + } + } + + /** + * @param array $tokens + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + protected function filter($tokens, $config, $context) + { + $allowed = $config->get('Attr.AllowedClasses'); + $forbidden = $config->get('Attr.ForbiddenClasses'); + $ret = array(); + foreach ($tokens as $token) { + if (($allowed === null || isset($allowed[$token])) && + !isset($forbidden[$token]) && + // We need this O(n) check because of PHP's array + // implementation that casts -0 to 0. + !in_array($token, $ret, true) + ) { + $ret[] = $token; + } + } + return $ret; + } +} diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php new file mode 100644 index 0000000..946ebb7 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php @@ -0,0 +1,51 @@ +get('Core.ColorKeywords'); + } + + $string = trim($string); + + if (empty($string)) { + return false; + } + $lower = strtolower($string); + if (isset($colors[$lower])) { + return $colors[$lower]; + } + if ($string[0] === '#') { + $hex = substr($string, 1); + } else { + $hex = $string; + } + + $length = strlen($hex); + if ($length !== 3 && $length !== 6) { + return false; + } + if (!ctype_xdigit($hex)) { + return false; + } + if ($length === 3) { + $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; + } + return "#$hex"; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php new file mode 100644 index 0000000..d79ba12 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php @@ -0,0 +1,38 @@ +valid_values === false) { + $this->valid_values = $config->get('Attr.AllowedFrameTargets'); + } + return parent::validate($string, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php new file mode 100644 index 0000000..4ba4561 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php @@ -0,0 +1,113 @@ +selector = $selector; + } + + /** + * @param string $id + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($id, $config, $context) + { + if (!$this->selector && !$config->get('Attr.EnableID')) { + return false; + } + + $id = trim($id); // trim it first + + if ($id === '') { + return false; + } + + $prefix = $config->get('Attr.IDPrefix'); + if ($prefix !== '') { + $prefix .= $config->get('Attr.IDPrefixLocal'); + // prevent re-appending the prefix + if (strpos($id, $prefix) !== 0) { + $id = $prefix . $id; + } + } elseif ($config->get('Attr.IDPrefixLocal') !== '') { + trigger_error( + '%Attr.IDPrefixLocal cannot be used unless ' . + '%Attr.IDPrefix is set', + E_USER_WARNING + ); + } + + if (!$this->selector) { + $id_accumulator =& $context->get('IDAccumulator'); + if (isset($id_accumulator->ids[$id])) { + return false; + } + } + + // we purposely avoid using regex, hopefully this is faster + + if ($config->get('Attr.ID.HTML5') === true) { + if (preg_match('/[\t\n\x0b\x0c ]/', $id)) { + return false; + } + } else { + if (ctype_alpha($id)) { + // OK + } else { + if (!ctype_alpha(@$id[0])) { + return false; + } + // primitive style of regexps, I suppose + $trim = trim( + $id, + 'A..Za..z0..9:-._' + ); + if ($trim !== '') { + return false; + } + } + } + + $regexp = $config->get('Attr.IDBlacklistRegexp'); + if ($regexp && preg_match($regexp, $id)) { + return false; + } + + if (!$this->selector) { + $id_accumulator->add($id); + } + + // if no change was made to the ID, return the result + // else, return the new id if stripping whitespace made it + // valid, or return false. + return $id; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php new file mode 100644 index 0000000..1c4006f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php @@ -0,0 +1,56 @@ + 100) { + return '100%'; + } + return ((string)$points) . '%'; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php new file mode 100644 index 0000000..63fa04c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php @@ -0,0 +1,72 @@ + 'AllowedRel', + 'rev' => 'AllowedRev' + ); + if (!isset($configLookup[$name])) { + trigger_error( + 'Unrecognized attribute name for link ' . + 'relationship.', + E_USER_ERROR + ); + return; + } + $this->name = $configLookup[$name]; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $allowed = $config->get('Attr.' . $this->name); + if (empty($allowed)) { + return false; + } + + $string = $this->parseCDATA($string); + $parts = explode(' ', $string); + + // lookup to prevent duplicates + $ret_lookup = array(); + foreach ($parts as $part) { + $part = strtolower(trim($part)); + if (!isset($allowed[$part])) { + continue; + } + $ret_lookup[$part] = true; + } + + if (empty($ret_lookup)) { + return false; + } + $string = implode(' ', array_keys($ret_lookup)); + return $string; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php new file mode 100644 index 0000000..bbb20f2 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php @@ -0,0 +1,60 @@ +split($string, $config, $context); + $tokens = $this->filter($tokens, $config, $context); + if (empty($tokens)) { + return false; + } + return implode(' ', $tokens); + } + + /** + * Splits a space separated list of tokens into its constituent parts. + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + protected function split($string, $config, $context) + { + // OPTIMIZABLE! + // do the preg_match, capture all subpatterns for reformulation + + // we don't support U+00A1 and up codepoints or + // escaping because I don't know how to do that with regexps + // and plus it would complicate optimization efforts (you never + // see that anyway). + $pattern = '/(?:(?<=\s)|\A)' . // look behind for space or string start + '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)' . + '(?:(?=\s)|\z)/'; // look ahead for space or string end + preg_match_all($pattern, $string, $matches); + return $matches[1]; + } + + /** + * Template method for removing certain tokens based on arbitrary criteria. + * @note If we wanted to be really functional, we'd do an array_filter + * with a callback. But... we're not. + * @param array $tokens + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + protected function filter($tokens, $config, $context) + { + return $tokens; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php new file mode 100644 index 0000000..a1d019e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php @@ -0,0 +1,76 @@ +max = $max; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = trim($string); + if ($string === '0') { + return $string; + } + if ($string === '') { + return false; + } + $length = strlen($string); + if (substr($string, $length - 2) == 'px') { + $string = substr($string, 0, $length - 2); + } + if (!is_numeric($string)) { + return false; + } + $int = (int)$string; + + if ($int < 0) { + return '0'; + } + + // upper-bound value, extremely high values can + // crash operating systems, see + // WARNING, above link WILL crash you if you're using Windows + + if ($this->max !== null && $int > $this->max) { + return (string)$this->max; + } + return (string)$int; + } + + /** + * @param string $string + * @return HTMLPurifier_AttrDef + */ + public function make($string) + { + if ($string === '') { + $max = null; + } else { + $max = (int)$string; + } + $class = get_class($this); + return new $class($max); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php new file mode 100644 index 0000000..400e707 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php @@ -0,0 +1,91 @@ +negative = $negative; + $this->zero = $zero; + $this->positive = $positive; + } + + /** + * @param string $integer + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($integer, $config, $context) + { + $integer = $this->parseCDATA($integer); + if ($integer === '') { + return false; + } + + // we could possibly simply typecast it to integer, but there are + // certain fringe cases that must not return an integer. + + // clip leading sign + if ($this->negative && $integer[0] === '-') { + $digits = substr($integer, 1); + if ($digits === '0') { + $integer = '0'; + } // rm minus sign for zero + } elseif ($this->positive && $integer[0] === '+') { + $digits = $integer = substr($integer, 1); // rm unnecessary plus + } else { + $digits = $integer; + } + + // test if it's numeric + if (!ctype_digit($digits)) { + return false; + } + + // perform scope tests + if (!$this->zero && $integer == 0) { + return false; + } + if (!$this->positive && $integer > 0) { + return false; + } + if (!$this->negative && $integer < 0) { + return false; + } + + return $integer; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php new file mode 100644 index 0000000..2a55cea --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php @@ -0,0 +1,86 @@ + 8 || !ctype_alnum($subtags[1])) { + return $new_string; + } + if (!ctype_lower($subtags[1])) { + $subtags[1] = strtolower($subtags[1]); + } + + $new_string .= '-' . $subtags[1]; + if ($num_subtags == 2) { + return $new_string; + } + + // process all other subtags, index 2 and up + for ($i = 2; $i < $num_subtags; $i++) { + $length = strlen($subtags[$i]); + if ($length == 0 || $length > 8 || !ctype_alnum($subtags[$i])) { + return $new_string; + } + if (!ctype_lower($subtags[$i])) { + $subtags[$i] = strtolower($subtags[$i]); + } + $new_string .= '-' . $subtags[$i]; + } + return $new_string; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php new file mode 100644 index 0000000..c7eb319 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php @@ -0,0 +1,53 @@ +tag = $tag; + $this->withTag = $with_tag; + $this->withoutTag = $without_tag; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $token = $context->get('CurrentToken', true); + if (!$token || $token->name !== $this->tag) { + return $this->withoutTag->validate($string, $config, $context); + } else { + return $this->withTag->validate($string, $config, $context); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php new file mode 100644 index 0000000..4553a4e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php @@ -0,0 +1,21 @@ +parseCDATA($string); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php new file mode 100644 index 0000000..c1cd897 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php @@ -0,0 +1,111 @@ +parser = new HTMLPurifier_URIParser(); + $this->embedsResource = (bool)$embeds_resource; + } + + /** + * @param string $string + * @return HTMLPurifier_AttrDef_URI + */ + public function make($string) + { + $embeds = ($string === 'embedded'); + return new HTMLPurifier_AttrDef_URI($embeds); + } + + /** + * @param string $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($uri, $config, $context) + { + if ($config->get('URI.Disable')) { + return false; + } + + $uri = $this->parseCDATA($uri); + + // parse the URI + $uri = $this->parser->parse($uri); + if ($uri === false) { + return false; + } + + // add embedded flag to context for validators + $context->register('EmbeddedURI', $this->embedsResource); + + $ok = false; + do { + + // generic validation + $result = $uri->validate($config, $context); + if (!$result) { + break; + } + + // chained filtering + $uri_def = $config->getDefinition('URI'); + $result = $uri_def->filter($uri, $config, $context); + if (!$result) { + break; + } + + // scheme-specific validation + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) { + break; + } + if ($this->embedsResource && !$scheme_obj->browsable) { + break; + } + $result = $scheme_obj->validate($uri, $config, $context); + if (!$result) { + break; + } + + // Post chained filtering + $result = $uri_def->postFilter($uri, $config, $context); + if (!$result) { + break; + } + + // survived gauntlet + $ok = true; + + } while (false); + + $context->destroy('EmbeddedURI'); + if (!$ok) { + return false; + } + // back to string + return $uri->toString(); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php new file mode 100644 index 0000000..daf32b7 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php @@ -0,0 +1,20 @@ +" + // that needs more percent encoding to be done + if ($string == '') { + return false; + } + $string = trim($string); + $result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string); + return $result ? $string : false; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php new file mode 100644 index 0000000..1beeaa5 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php @@ -0,0 +1,142 @@ +ipv4 = new HTMLPurifier_AttrDef_URI_IPv4(); + $this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6(); + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $length = strlen($string); + // empty hostname is OK; it's usually semantically equivalent: + // the default host as defined by a URI scheme is used: + // + // If the URI scheme defines a default for host, then that + // default applies when the host subcomponent is undefined + // or when the registered name is empty (zero length). + if ($string === '') { + return ''; + } + if ($length > 1 && $string[0] === '[' && $string[$length - 1] === ']') { + //IPv6 + $ip = substr($string, 1, $length - 2); + $valid = $this->ipv6->validate($ip, $config, $context); + if ($valid === false) { + return false; + } + return '[' . $valid . ']'; + } + + // need to do checks on unusual encodings too + $ipv4 = $this->ipv4->validate($string, $config, $context); + if ($ipv4 !== false) { + return $ipv4; + } + + // A regular domain name. + + // This doesn't match I18N domain names, but we don't have proper IRI support, + // so force users to insert Punycode. + + // There is not a good sense in which underscores should be + // allowed, since it's technically not! (And if you go as + // far to allow everything as specified by the DNS spec... + // well, that's literally everything, modulo some space limits + // for the components and the overall name (which, by the way, + // we are NOT checking!). So we (arbitrarily) decide this: + // let's allow underscores wherever we would have allowed + // hyphens, if they are enabled. This is a pretty good match + // for browser behavior, for example, a large number of browsers + // cannot handle foo_.example.com, but foo_bar.example.com is + // fairly well supported. + $underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : ''; + + // Based off of RFC 1738, but amended so that + // as per RFC 3696, the top label need only not be all numeric. + // The productions describing this are: + $a = '[a-z]'; // alpha + $an = '[a-z0-9]'; // alphanum + $and = "[a-z0-9-$underscore]"; // alphanum | "-" + // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum + $domainlabel = "$an(?:$and*$an)?"; + // AMENDED as per RFC 3696 + // toplabel = alphanum | alphanum *( alphanum | "-" ) alphanum + // side condition: not all numeric + $toplabel = "$an(?:$and*$an)?"; + // hostname = *( domainlabel "." ) toplabel [ "." ] + if (preg_match("/^(?:$domainlabel\.)*($toplabel)\.?$/i", $string, $matches)) { + if (!ctype_digit($matches[1])) { + return $string; + } + } + + // PHP 5.3 and later support this functionality natively + if (function_exists('idn_to_ascii')) { + if (defined('IDNA_NONTRANSITIONAL_TO_ASCII') && defined('INTL_IDNA_VARIANT_UTS46')) { + $string = idn_to_ascii($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); + } else { + $string = idn_to_ascii($string); + } + + // If we have Net_IDNA2 support, we can support IRIs by + // punycoding them. (This is the most portable thing to do, + // since otherwise we have to assume browsers support + } elseif ($config->get('Core.EnableIDNA')) { + $idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true)); + // we need to encode each period separately + $parts = explode('.', $string); + try { + $new_parts = array(); + foreach ($parts as $part) { + $encodable = false; + for ($i = 0, $c = strlen($part); $i < $c; $i++) { + if (ord($part[$i]) > 0x7a) { + $encodable = true; + break; + } + } + if (!$encodable) { + $new_parts[] = $part; + } else { + $new_parts[] = $idna->encode($part); + } + } + $string = implode('.', $new_parts); + } catch (Exception $e) { + // XXX error reporting + } + } + // Try again + if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) { + return $string; + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php new file mode 100644 index 0000000..30ac16c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php @@ -0,0 +1,45 @@ +ip4) { + $this->_loadRegex(); + } + + if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) { + return $aIP; + } + return false; + } + + /** + * Lazy load function to prevent regex from being stuffed in + * cache. + */ + protected function _loadRegex() + { + $oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255 + $this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})"; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php new file mode 100644 index 0000000..f243793 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php @@ -0,0 +1,89 @@ +ip4) { + $this->_loadRegex(); + } + + $original = $aIP; + + $hex = '[0-9a-fA-F]'; + $blk = '(?:' . $hex . '{1,4})'; + $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128 + + // prefix check + if (strpos($aIP, '/') !== false) { + if (preg_match('#' . $pre . '$#s', $aIP, $find)) { + $aIP = substr($aIP, 0, 0 - strlen($find[0])); + unset($find); + } else { + return false; + } + } + + // IPv4-compatiblity check + if (preg_match('#(?<=:' . ')' . $this->ip4 . '$#s', $aIP, $find)) { + $aIP = substr($aIP, 0, 0 - strlen($find[0])); + $ip = explode('.', $find[0]); + $ip = array_map('dechex', $ip); + $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3]; + unset($find, $ip); + } + + // compression check + $aIP = explode('::', $aIP); + $c = count($aIP); + if ($c > 2) { + return false; + } elseif ($c == 2) { + list($first, $second) = $aIP; + $first = explode(':', $first); + $second = explode(':', $second); + + if (count($first) + count($second) > 8) { + return false; + } + + while (count($first) < 8) { + array_push($first, '0'); + } + + array_splice($first, 8 - count($second), 8, $second); + $aIP = $first; + unset($first, $second); + } else { + $aIP = explode(':', $aIP[0]); + } + $c = count($aIP); + + if ($c != 8) { + return false; + } + + // All the pieces should be 16-bit hex strings. Are they? + foreach ($aIP as $piece) { + if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) { + return false; + } + } + return $original; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php new file mode 100644 index 0000000..b428331 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php @@ -0,0 +1,60 @@ +confiscateAttr($attr, 'background'); + // some validation should happen here + + $this->prependCSS($attr, "background-image:url($background);"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php new file mode 100644 index 0000000..d66c04a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php @@ -0,0 +1,27 @@ +get('Attr.DefaultTextDir'); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php new file mode 100644 index 0000000..0f51fd2 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php @@ -0,0 +1,28 @@ +confiscateAttr($attr, 'bgcolor'); + // some validation should happen here + + $this->prependCSS($attr, "background-color:$bgcolor;"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php new file mode 100644 index 0000000..f25cd01 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php @@ -0,0 +1,47 @@ +attr = $attr; + $this->css = $css; + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->attr])) { + return $attr; + } + unset($attr[$this->attr]); + $this->prependCSS($attr, $this->css); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php new file mode 100644 index 0000000..057dc01 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php @@ -0,0 +1,26 @@ +confiscateAttr($attr, 'border'); + // some validation should happen here + $this->prependCSS($attr, "border:{$border_width}px solid;"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php new file mode 100644 index 0000000..7ccd0e3 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php @@ -0,0 +1,68 @@ +attr = $attr; + $this->enumToCSS = $enum_to_css; + $this->caseSensitive = (bool)$case_sensitive; + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->attr])) { + return $attr; + } + + $value = trim($attr[$this->attr]); + unset($attr[$this->attr]); + + if (!$this->caseSensitive) { + $value = strtolower($value); + } + + if (!isset($this->enumToCSS[$value])) { + return $attr; + } + $this->prependCSS($attr, $this->enumToCSS[$value]); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php new file mode 100644 index 0000000..235ebb3 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php @@ -0,0 +1,47 @@ +get('Core.RemoveInvalidImg')) { + return $attr; + } + $attr['src'] = $config->get('Attr.DefaultInvalidImage'); + $src = false; + } + + if (!isset($attr['alt'])) { + if ($src) { + $alt = $config->get('Attr.DefaultImageAlt'); + if ($alt === null) { + $attr['alt'] = basename($attr['src']); + } else { + $attr['alt'] = $alt; + } + } else { + $attr['alt'] = $config->get('Attr.DefaultInvalidImageAlt'); + } + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php new file mode 100644 index 0000000..350b335 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php @@ -0,0 +1,61 @@ + array('left', 'right'), + 'vspace' => array('top', 'bottom') + ); + + /** + * @param string $attr + */ + public function __construct($attr) + { + $this->attr = $attr; + if (!isset($this->css[$attr])) { + trigger_error(htmlspecialchars($attr) . ' is not valid space attribute'); + } + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->attr])) { + return $attr; + } + + $width = $this->confiscateAttr($attr, $this->attr); + // some validation could happen here + + if (!isset($this->css[$this->attr])) { + return $attr; + } + + $style = ''; + foreach ($this->css[$this->attr] as $suffix) { + $property = "margin-$suffix"; + $style .= "$property:{$width}px;"; + } + $this->prependCSS($attr, $style); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php new file mode 100644 index 0000000..3ab47ed --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php @@ -0,0 +1,56 @@ +pixels = new HTMLPurifier_AttrDef_HTML_Pixels(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['type'])) { + $t = 'text'; + } else { + $t = strtolower($attr['type']); + } + if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') { + unset($attr['checked']); + } + if (isset($attr['maxlength']) && $t !== 'text' && $t !== 'password') { + unset($attr['maxlength']); + } + if (isset($attr['size']) && $t !== 'text' && $t !== 'password') { + $result = $this->pixels->validate($attr['size'], $config, $context); + if ($result === false) { + unset($attr['size']); + } else { + $attr['size'] = $result; + } + } + if (isset($attr['src']) && $t !== 'image') { + unset($attr['src']); + } + if (!isset($attr['value']) && ($t === 'radio' || $t === 'checkbox')) { + $attr['value'] = ''; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php new file mode 100644 index 0000000..5b0aff0 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php @@ -0,0 +1,31 @@ +name = $name; + $this->cssName = $css_name ? $css_name : $name; + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->name])) { + return $attr; + } + $length = $this->confiscateAttr($attr, $this->name); + if (ctype_digit($length)) { + $length .= 'px'; + } + $this->prependCSS($attr, $this->cssName . ":$length;"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php new file mode 100644 index 0000000..63cce68 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php @@ -0,0 +1,33 @@ +get('HTML.Attr.Name.UseCDATA')) { + return $attr; + } + if (!isset($attr['name'])) { + return $attr; + } + $id = $this->confiscateAttr($attr, 'name'); + if (isset($attr['id'])) { + return $attr; + } + $attr['id'] = $id; + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php new file mode 100644 index 0000000..36079b7 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php @@ -0,0 +1,41 @@ +idDef = new HTMLPurifier_AttrDef_HTML_ID(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['name'])) { + return $attr; + } + $name = $attr['name']; + if (isset($attr['id']) && $attr['id'] === $name) { + return $attr; + } + $result = $this->idDef->validate($name, $config, $context); + if ($result === false) { + unset($attr['name']); + } else { + $attr['name'] = $result; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php new file mode 100644 index 0000000..1057ebe --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php @@ -0,0 +1,52 @@ +parser = new HTMLPurifier_URIParser(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['href'])) { + return $attr; + } + + // XXX Kind of inefficient + $url = $this->parser->parse($attr['href']); + $scheme = $url->getSchemeObj($config, $context); + + if ($scheme->browsable && !$url->isLocal($config, $context)) { + if (isset($attr['rel'])) { + $rels = explode(' ', $attr['rel']); + if (!in_array('nofollow', $rels)) { + $rels[] = 'nofollow'; + } + $attr['rel'] = implode(' ', $rels); + } else { + $attr['rel'] = 'nofollow'; + } + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php new file mode 100644 index 0000000..231c81a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php @@ -0,0 +1,25 @@ +uri = new HTMLPurifier_AttrDef_URI(true); // embedded + $this->wmode = new HTMLPurifier_AttrDef_Enum(array('window', 'opaque', 'transparent')); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + // If we add support for other objects, we'll need to alter the + // transforms. + switch ($attr['name']) { + // application/x-shockwave-flash + // Keep this synchronized with Injector/SafeObject.php + case 'allowScriptAccess': + $attr['value'] = 'never'; + break; + case 'allowNetworking': + $attr['value'] = 'internal'; + break; + case 'allowFullScreen': + if ($config->get('HTML.FlashAllowFullScreen')) { + $attr['value'] = ($attr['value'] == 'true') ? 'true' : 'false'; + } else { + $attr['value'] = 'false'; + } + break; + case 'wmode': + $attr['value'] = $this->wmode->validate($attr['value'], $config, $context); + break; + case 'movie': + case 'src': + $attr['name'] = "movie"; + $attr['value'] = $this->uri->validate($attr['value'], $config, $context); + break; + case 'flashvars': + // we're going to allow arbitrary inputs to the SWF, on + // the reasoning that it could only hack the SWF, not us. + break; + // add other cases to support other param name/value pairs + default: + $attr['name'] = $attr['value'] = null; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php new file mode 100644 index 0000000..b7057bb --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php @@ -0,0 +1,23 @@ + + */ +class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform +{ + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['type'])) { + $attr['type'] = 'text/javascript'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php new file mode 100644 index 0000000..dd63ea8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php @@ -0,0 +1,45 @@ +parser = new HTMLPurifier_URIParser(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['href'])) { + return $attr; + } + + // XXX Kind of inefficient + $url = $this->parser->parse($attr['href']); + $scheme = $url->getSchemeObj($config, $context); + + if ($scheme->browsable && !$url->isBenign($config, $context)) { + $attr['target'] = '_blank'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetNoopener.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetNoopener.php new file mode 100644 index 0000000..1db3c6c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetNoopener.php @@ -0,0 +1,37 @@ + + */ +class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform +{ + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + // Calculated from Firefox + if (!isset($attr['cols'])) { + $attr['cols'] = '22'; + } + if (!isset($attr['rows'])) { + $attr['rows'] = '3'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php new file mode 100644 index 0000000..3b70520 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php @@ -0,0 +1,96 @@ +info['Enum'] = new HTMLPurifier_AttrDef_Enum(); + $this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool(); + + $this->info['CDATA'] = new HTMLPurifier_AttrDef_Text(); + $this->info['ID'] = new HTMLPurifier_AttrDef_HTML_ID(); + $this->info['Length'] = new HTMLPurifier_AttrDef_HTML_Length(); + $this->info['MultiLength'] = new HTMLPurifier_AttrDef_HTML_MultiLength(); + $this->info['NMTOKENS'] = new HTMLPurifier_AttrDef_HTML_Nmtokens(); + $this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels(); + $this->info['Text'] = new HTMLPurifier_AttrDef_Text(); + $this->info['URI'] = new HTMLPurifier_AttrDef_URI(); + $this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang(); + $this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color(); + $this->info['IAlign'] = self::makeEnum('top,middle,bottom,left,right'); + $this->info['LAlign'] = self::makeEnum('top,bottom,left,right'); + $this->info['FrameTarget'] = new HTMLPurifier_AttrDef_HTML_FrameTarget(); + + // unimplemented aliases + $this->info['ContentType'] = new HTMLPurifier_AttrDef_Text(); + $this->info['ContentTypes'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Charsets'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Character'] = new HTMLPurifier_AttrDef_Text(); + + // "proprietary" types + $this->info['Class'] = new HTMLPurifier_AttrDef_HTML_Class(); + + // number is really a positive integer (one or more digits) + // FIXME: ^^ not always, see start and value of list items + $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); + } + + private static function makeEnum($in) + { + return new HTMLPurifier_AttrDef_Clone(new HTMLPurifier_AttrDef_Enum(explode(',', $in))); + } + + /** + * Retrieves a type + * @param string $type String type name + * @return HTMLPurifier_AttrDef Object AttrDef for type + */ + public function get($type) + { + // determine if there is any extra info tacked on + if (strpos($type, '#') !== false) { + list($type, $string) = explode('#', $type, 2); + } else { + $string = ''; + } + + if (!isset($this->info[$type])) { + trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR); + return; + } + return $this->info[$type]->make($string); + } + + /** + * Sets a new implementation for a type + * @param string $type String type name + * @param HTMLPurifier_AttrDef $impl Object AttrDef for type + */ + public function set($type, $impl) + { + $this->info[$type] = $impl; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php new file mode 100644 index 0000000..f97dc93 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php @@ -0,0 +1,178 @@ +getHTMLDefinition(); + $e =& $context->get('ErrorCollector', true); + + // initialize IDAccumulator if necessary + $ok =& $context->get('IDAccumulator', true); + if (!$ok) { + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + } + + // initialize CurrentToken if necessary + $current_token =& $context->get('CurrentToken', true); + if (!$current_token) { + $context->register('CurrentToken', $token); + } + + if (!$token instanceof HTMLPurifier_Token_Start && + !$token instanceof HTMLPurifier_Token_Empty + ) { + return; + } + + // create alias to global definition array, see also $defs + // DEFINITION CALL + $d_defs = $definition->info_global_attr; + + // don't update token until the very end, to ensure an atomic update + $attr = $token->attr; + + // do global transformations (pre) + // nothing currently utilizes this + foreach ($definition->info_attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // do local transformations only applicable to this element (pre) + // ex.

to

+ foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // create alias to this element's attribute definition array, see + // also $d_defs (global attribute definition array) + // DEFINITION CALL + $defs = $definition->info[$token->name]->attr; + + $attr_key = false; + $context->register('CurrentAttr', $attr_key); + + // iterate through all the attribute keypairs + // Watch out for name collisions: $key has previously been used + foreach ($attr as $attr_key => $value) { + + // call the definition + if (isset($defs[$attr_key])) { + // there is a local definition defined + if ($defs[$attr_key] === false) { + // We've explicitly been told not to allow this element. + // This is usually when there's a global definition + // that must be overridden. + // Theoretically speaking, we could have a + // AttrDef_DenyAll, but this is faster! + $result = false; + } else { + // validate according to the element's definition + $result = $defs[$attr_key]->validate( + $value, + $config, + $context + ); + } + } elseif (isset($d_defs[$attr_key])) { + // there is a global definition defined, validate according + // to the global definition + $result = $d_defs[$attr_key]->validate( + $value, + $config, + $context + ); + } else { + // system never heard of the attribute? DELETE! + $result = false; + } + + // put the results into effect + if ($result === false || $result === null) { + // this is a generic error message that should replaced + // with more specific ones when possible + if ($e) { + $e->send(E_ERROR, 'AttrValidator: Attribute removed'); + } + + // remove the attribute + unset($attr[$attr_key]); + } elseif (is_string($result)) { + // generally, if a substitution is happening, there + // was some sort of implicit correction going on. We'll + // delegate it to the attribute classes to say exactly what. + + // simple substitution + $attr[$attr_key] = $result; + } else { + // nothing happens + } + + // we'd also want slightly more complicated substitution + // involving an array as the return value, + // although we're not sure how colliding attributes would + // resolve (certain ones would be completely overriden, + // others would prepend themselves). + } + + $context->destroy('CurrentAttr'); + + // post transforms + + // global (error reporting untested) + foreach ($definition->info_attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // local (error reporting untested) + foreach ($definition->info[$token->name]->attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + $token->attr = $attr; + + // destroy CurrentToken if we made it ourselves + if (!$current_token) { + $context->destroy('CurrentToken'); + } + + } + + +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php new file mode 100644 index 0000000..707122b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php @@ -0,0 +1,124 @@ + +if (!defined('PHP_EOL')) { + switch (strtoupper(substr(PHP_OS, 0, 3))) { + case 'WIN': + define('PHP_EOL', "\r\n"); + break; + case 'DAR': + define('PHP_EOL', "\r"); + break; + default: + define('PHP_EOL', "\n"); + } +} + +/** + * Bootstrap class that contains meta-functionality for HTML Purifier such as + * the autoload function. + * + * @note + * This class may be used without any other files from HTML Purifier. + */ +class HTMLPurifier_Bootstrap +{ + + /** + * Autoload function for HTML Purifier + * @param string $class Class to load + * @return bool + */ + public static function autoload($class) + { + $file = HTMLPurifier_Bootstrap::getPath($class); + if (!$file) { + return false; + } + // Technically speaking, it should be ok and more efficient to + // just do 'require', but Antonio Parraga reports that with + // Zend extensions such as Zend debugger and APC, this invariant + // may be broken. Since we have efficient alternatives, pay + // the cost here and avoid the bug. + require_once HTMLPURIFIER_PREFIX . '/' . $file; + return true; + } + + /** + * Returns the path for a specific class. + * @param string $class Class path to get + * @return string + */ + public static function getPath($class) + { + if (strncmp('HTMLPurifier', $class, 12) !== 0) { + return false; + } + // Custom implementations + if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) { + $code = str_replace('_', '-', substr($class, 22)); + $file = 'HTMLPurifier/Language/classes/' . $code . '.php'; + } else { + $file = str_replace('_', '/', $class) . '.php'; + } + if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) { + return false; + } + return $file; + } + + /** + * "Pre-registers" our autoloader on the SPL stack. + */ + public static function registerAutoload() + { + $autoload = array('HTMLPurifier_Bootstrap', 'autoload'); + if (($funcs = spl_autoload_functions()) === false) { + spl_autoload_register($autoload); + } elseif (function_exists('spl_autoload_unregister')) { + if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + // prepend flag exists, no need for shenanigans + spl_autoload_register($autoload, true, true); + } else { + $buggy = version_compare(PHP_VERSION, '5.2.11', '<'); + $compat = version_compare(PHP_VERSION, '5.1.2', '<=') && + version_compare(PHP_VERSION, '5.1.0', '>='); + foreach ($funcs as $func) { + if ($buggy && is_array($func)) { + // :TRICKY: There are some compatibility issues and some + // places where we need to error out + $reflector = new ReflectionMethod($func[0], $func[1]); + if (!$reflector->isStatic()) { + throw new Exception( + 'HTML Purifier autoloader registrar is not compatible + with non-static object methods due to PHP Bug #44144; + Please do not use HTMLPurifier.autoload.php (or any + file that includes this file); instead, place the code: + spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\')) + after your own autoloaders.' + ); + } + // Suprisingly, spl_autoload_register supports the + // Class::staticMethod callback format, although call_user_func doesn't + if ($compat) { + $func = implode('::', $func); + } + } + spl_autoload_unregister($func); + } + spl_autoload_register($autoload); + foreach ($funcs as $func) { + spl_autoload_register($func); + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php new file mode 100644 index 0000000..21f1a58 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php @@ -0,0 +1,533 @@ +info['text-align'] = new HTMLPurifier_AttrDef_Enum( + array('left', 'right', 'center', 'justify'), + false + ); + + $border_style = + $this->info['border-bottom-style'] = + $this->info['border-right-style'] = + $this->info['border-left-style'] = + $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum( + array( + 'none', + 'hidden', + 'dotted', + 'dashed', + 'solid', + 'double', + 'groove', + 'ridge', + 'inset', + 'outset' + ), + false + ); + + $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style); + + $this->info['clear'] = new HTMLPurifier_AttrDef_Enum( + array('none', 'left', 'right', 'both'), + false + ); + $this->info['float'] = new HTMLPurifier_AttrDef_Enum( + array('none', 'left', 'right'), + false + ); + $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum( + array('normal', 'italic', 'oblique'), + false + ); + $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum( + array('normal', 'small-caps'), + false + ); + + $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('none')), + new HTMLPurifier_AttrDef_CSS_URI() + ) + ); + + $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum( + array('inside', 'outside'), + false + ); + $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum( + array( + 'disc', + 'circle', + 'square', + 'decimal', + 'lower-roman', + 'upper-roman', + 'lower-alpha', + 'upper-alpha', + 'none' + ), + false + ); + $this->info['list-style-image'] = $uri_or_none; + + $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config); + + $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( + array('capitalize', 'uppercase', 'lowercase', 'none'), + false + ); + $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + $this->info['background-image'] = $uri_or_none; + $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum( + array('repeat', 'repeat-x', 'repeat-y', 'no-repeat') + ); + $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum( + array('scroll', 'fixed') + ); + $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); + + $border_color = + $this->info['border-top-color'] = + $this->info['border-bottom-color'] = + $this->info['border-left-color'] = + $this->info['border-right-color'] = + $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('transparent')), + new HTMLPurifier_AttrDef_CSS_Color() + ) + ); + + $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config); + + $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color); + + $border_width = + $this->info['border-top-width'] = + $this->info['border-bottom-width'] = + $this->info['border-left-width'] = + $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')), + new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative + ) + ); + + $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width); + + $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('normal')), + new HTMLPurifier_AttrDef_CSS_Length() + ) + ); + + $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('normal')), + new HTMLPurifier_AttrDef_CSS_Length() + ) + ); + + $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum( + array( + 'xx-small', + 'x-small', + 'small', + 'medium', + 'large', + 'x-large', + 'xx-large', + 'larger', + 'smaller' + ) + ), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_CSS_Length() + ) + ); + + $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum(array('normal')), + new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + ) + ); + + $margin = + $this->info['margin-top'] = + $this->info['margin-bottom'] = + $this->info['margin-left'] = + $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(array('auto')) + ) + ); + + $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin); + + // non-negative + $padding = + $this->info['padding-top'] = + $this->info['padding-bottom'] = + $this->info['padding-left'] = + $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + ) + ); + + $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding); + + $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + ) + ); + + $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(array('auto', 'initial', 'inherit')) + ) + ); + $trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit')) + ) + ); + $trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit')) + ) + ); + $max = $config->get('CSS.MaxImgLength'); + + $this->info['width'] = + $this->info['height'] = + $max === null ? + $trusted_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(array('auto')) + ) + ), + // For everyone else: + $trusted_wh + ); + $this->info['min-width'] = + $this->info['min-height'] = + $max === null ? + $trusted_min_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(array('initial', 'inherit')) + ) + ), + // For everyone else: + $trusted_min_wh + ); + $this->info['max-width'] = + $this->info['max-height'] = + $max === null ? + $trusted_max_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(array('none', 'initial', 'inherit')) + ) + ), + // For everyone else: + $trusted_max_wh + ); + + $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); + + $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily(); + + // this could use specialized code + $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum( + array( + 'normal', + 'bold', + 'bolder', + 'lighter', + '100', + '200', + '300', + '400', + '500', + '600', + '700', + '800', + '900' + ), + false + ); + + // MUST be called after other font properties, as it references + // a CSSDefinition object + $this->info['font'] = new HTMLPurifier_AttrDef_CSS_Font($config); + + // same here + $this->info['border'] = + $this->info['border-bottom'] = + $this->info['border-top'] = + $this->info['border-left'] = + $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config); + + $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum( + array('collapse', 'separate') + ); + + $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum( + array('top', 'bottom') + ); + + $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum( + array('auto', 'fixed') + ); + + $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Enum( + array( + 'baseline', + 'sub', + 'super', + 'top', + 'text-top', + 'middle', + 'bottom', + 'text-bottom' + ) + ), + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + ) + ); + + $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2); + + // These CSS properties don't work on many browsers, but we live + // in THE FUTURE! + $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum( + array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line') + ); + + if ($config->get('CSS.Proprietary')) { + $this->doSetupProprietary($config); + } + + if ($config->get('CSS.AllowTricky')) { + $this->doSetupTricky($config); + } + + if ($config->get('CSS.Trusted')) { + $this->doSetupTrusted($config); + } + + $allow_important = $config->get('CSS.AllowImportant'); + // wrap all attr-defs with decorator that handles !important + foreach ($this->info as $k => $v) { + $this->info[$k] = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($v, $allow_important); + } + + $this->setupConfigStuff($config); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupProprietary($config) + { + // Internet Explorer only scrollbar colors + $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + // vendor specific prefixes of opacity + $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + + // only opacity, for now + $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter(); + + // more CSS3 + $this->info['page-break-after'] = + $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum( + array( + 'auto', + 'always', + 'avoid', + 'left', + 'right' + ) + ); + $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid')); + + $border_radius = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Percentage(true), // disallow negative + new HTMLPurifier_AttrDef_CSS_Length('0') // disallow negative + )); + + $this->info['border-top-left-radius'] = + $this->info['border-top-right-radius'] = + $this->info['border-bottom-right-radius'] = + $this->info['border-bottom-left-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 2); + // TODO: support SLASH syntax + $this->info['border-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 4); + + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupTricky($config) + { + $this->info['display'] = new HTMLPurifier_AttrDef_Enum( + array( + 'inline', + 'block', + 'list-item', + 'run-in', + 'compact', + 'marker', + 'table', + 'inline-block', + 'inline-table', + 'table-row-group', + 'table-header-group', + 'table-footer-group', + 'table-row', + 'table-column-group', + 'table-column', + 'table-cell', + 'table-caption', + 'none' + ) + ); + $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum( + array('visible', 'hidden', 'collapse') + ); + $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll')); + $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupTrusted($config) + { + $this->info['position'] = new HTMLPurifier_AttrDef_Enum( + array('static', 'relative', 'absolute', 'fixed') + ); + $this->info['top'] = + $this->info['left'] = + $this->info['right'] = + $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(array('auto')), + ) + ); + $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite( + array( + new HTMLPurifier_AttrDef_Integer(), + new HTMLPurifier_AttrDef_Enum(array('auto')), + ) + ); + } + + /** + * Performs extra config-based processing. Based off of + * HTMLPurifier_HTMLDefinition. + * @param HTMLPurifier_Config $config + * @todo Refactor duplicate elements into common class (probably using + * composition, not inheritance). + */ + protected function setupConfigStuff($config) + { + // setup allowed elements + $support = "(for information on implementing this, see the " . + "support forums) "; + $allowed_properties = $config->get('CSS.AllowedProperties'); + if ($allowed_properties !== null) { + foreach ($this->info as $name => $d) { + if (!isset($allowed_properties[$name])) { + unset($this->info[$name]); + } + unset($allowed_properties[$name]); + } + // emit errors + foreach ($allowed_properties as $name => $d) { + // :TODO: Is this htmlspecialchars() call really necessary? + $name = htmlspecialchars($name); + trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING); + } + } + + $forbidden_properties = $config->get('CSS.ForbiddenProperties'); + if ($forbidden_properties !== null) { + foreach ($this->info as $name => $d) { + if (isset($forbidden_properties[$name])) { + unset($this->info[$name]); + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php new file mode 100644 index 0000000..8eb17b8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php @@ -0,0 +1,52 @@ +elements; + } + + /** + * Validates nodes according to definition and returns modification. + * + * @param HTMLPurifier_Node[] $children Array of HTMLPurifier_Node + * @param HTMLPurifier_Config $config HTMLPurifier_Config object + * @param HTMLPurifier_Context $context HTMLPurifier_Context object + * @return bool|array true to leave nodes as is, false to remove parent node, array of replacement children + */ + abstract public function validateChildren($children, $config, $context); +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php new file mode 100644 index 0000000..7439be2 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php @@ -0,0 +1,67 @@ +inline = new HTMLPurifier_ChildDef_Optional($inline); + $this->block = new HTMLPurifier_ChildDef_Optional($block); + $this->elements = $this->block->elements; + } + + /** + * @param HTMLPurifier_Node[] $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function validateChildren($children, $config, $context) + { + if ($context->get('IsInline') === false) { + return $this->block->validateChildren( + $children, + $config, + $context + ); + } else { + return $this->inline->validateChildren( + $children, + $config, + $context + ); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php new file mode 100644 index 0000000..f515888 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php @@ -0,0 +1,102 @@ +dtd_regex = $dtd_regex; + $this->_compileRegex(); + } + + /** + * Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex) + */ + protected function _compileRegex() + { + $raw = str_replace(' ', '', $this->dtd_regex); + if ($raw[0] != '(') { + $raw = "($raw)"; + } + $el = '[#a-zA-Z0-9_.-]+'; + $reg = $raw; + + // COMPLICATED! AND MIGHT BE BUGGY! I HAVE NO CLUE WHAT I'M + // DOING! Seriously: if there's problems, please report them. + + // collect all elements into the $elements array + preg_match_all("/$el/", $reg, $matches); + foreach ($matches[0] as $match) { + $this->elements[$match] = true; + } + + // setup all elements as parentheticals with leading commas + $reg = preg_replace("/$el/", '(,\\0)', $reg); + + // remove commas when they were not solicited + $reg = preg_replace("/([^,(|]\(+),/", '\\1', $reg); + + // remove all non-paranthetical commas: they are handled by first regex + $reg = preg_replace("/,\(/", '(', $reg); + + $this->_pcre_regex = $reg; + } + + /** + * @param HTMLPurifier_Node[] $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function validateChildren($children, $config, $context) + { + $list_of_children = ''; + $nesting = 0; // depth into the nest + foreach ($children as $node) { + if (!empty($node->is_whitespace)) { + continue; + } + $list_of_children .= $node->name . ','; + } + // add leading comma to deal with stray comma declarations + $list_of_children = ',' . rtrim($list_of_children, ','); + $okay = + preg_match( + '/^,?' . $this->_pcre_regex . '$/', + $list_of_children + ); + return (bool)$okay; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php new file mode 100644 index 0000000..a8a6cbd --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php @@ -0,0 +1,38 @@ + true, 'ul' => true, 'ol' => true); + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + // Flag for subclasses + $this->whitespace = false; + + // if there are no tokens, delete parent node + if (empty($children)) { + return false; + } + + // if li is not allowed, delete parent node + if (!isset($config->getHTMLDefinition()->info['li'])) { + trigger_error("Cannot allow ul/ol without allowing li", E_USER_WARNING); + return false; + } + + // the new set of children + $result = array(); + + // a little sanity check to make sure it's not ALL whitespace + $all_whitespace = true; + + $current_li = null; + + foreach ($children as $node) { + if (!empty($node->is_whitespace)) { + $result[] = $node; + continue; + } + $all_whitespace = false; // phew, we're not talking about whitespace + + if ($node->name === 'li') { + // good + $current_li = $node; + $result[] = $node; + } else { + // we want to tuck this into the previous li + // Invariant: we expect the node to be ol/ul + // ToDo: Make this more robust in the case of not ol/ul + // by distinguishing between existing li and li created + // to handle non-list elements; non-list elements should + // not be appended to an existing li; only li created + // for non-list. This distinction is not currently made. + if ($current_li === null) { + $current_li = new HTMLPurifier_Node_Element('li'); + $result[] = $current_li; + } + $current_li->children[] = $node; + $current_li->empty = false; // XXX fascinating! Check for this error elsewhere ToDo + } + } + if (empty($result)) { + return false; + } + if ($all_whitespace) { + return false; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php new file mode 100644 index 0000000..b946806 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php @@ -0,0 +1,45 @@ +whitespace) { + return $children; + } else { + return array(); + } + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php new file mode 100644 index 0000000..0d1c8f5 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php @@ -0,0 +1,118 @@ + $x) { + $elements[$i] = true; + if (empty($i)) { + unset($elements[$i]); + } // remove blank + } + } + $this->elements = $elements; + } + + /** + * @type bool + */ + public $allow_empty = false; + + /** + * @type string + */ + public $type = 'required'; + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + // Flag for subclasses + $this->whitespace = false; + + // if there are no tokens, delete parent node + if (empty($children)) { + return false; + } + + // the new set of children + $result = array(); + + // whether or not parsed character data is allowed + // this controls whether or not we silently drop a tag + // or generate escaped HTML from it + $pcdata_allowed = isset($this->elements['#PCDATA']); + + // a little sanity check to make sure it's not ALL whitespace + $all_whitespace = true; + + $stack = array_reverse($children); + while (!empty($stack)) { + $node = array_pop($stack); + if (!empty($node->is_whitespace)) { + $result[] = $node; + continue; + } + $all_whitespace = false; // phew, we're not talking about whitespace + + if (!isset($this->elements[$node->name])) { + // special case text + // XXX One of these ought to be redundant or something + if ($pcdata_allowed && $node instanceof HTMLPurifier_Node_Text) { + $result[] = $node; + continue; + } + // spill the child contents in + // ToDo: Make configurable + if ($node instanceof HTMLPurifier_Node_Element) { + for ($i = count($node->children) - 1; $i >= 0; $i--) { + $stack[] = $node->children[$i]; + } + continue; + } + continue; + } + $result[] = $node; + } + if (empty($result)) { + return false; + } + if ($all_whitespace) { + $this->whitespace = true; + return false; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php new file mode 100644 index 0000000..3270a46 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php @@ -0,0 +1,110 @@ +init($config); + return $this->fake_elements; + } + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + $this->init($config); + + // trick the parent class into thinking it allows more + $this->elements = $this->fake_elements; + $result = parent::validateChildren($children, $config, $context); + $this->elements = $this->real_elements; + + if ($result === false) { + return array(); + } + if ($result === true) { + $result = $children; + } + + $def = $config->getHTMLDefinition(); + $block_wrap_name = $def->info_block_wrapper; + $block_wrap = false; + $ret = array(); + + foreach ($result as $node) { + if ($block_wrap === false) { + if (($node instanceof HTMLPurifier_Node_Text && !$node->is_whitespace) || + ($node instanceof HTMLPurifier_Node_Element && !isset($this->elements[$node->name]))) { + $block_wrap = new HTMLPurifier_Node_Element($def->info_block_wrapper); + $ret[] = $block_wrap; + } + } else { + if ($node instanceof HTMLPurifier_Node_Element && isset($this->elements[$node->name])) { + $block_wrap = false; + + } + } + if ($block_wrap) { + $block_wrap->children[] = $node; + } else { + $ret[] = $node; + } + } + return $ret; + } + + /** + * @param HTMLPurifier_Config $config + */ + private function init($config) + { + if (!$this->init) { + $def = $config->getHTMLDefinition(); + // allow all inline elements + $this->real_elements = $this->elements; + $this->fake_elements = $def->info_content_sets['Flow']; + $this->fake_elements['#PCDATA'] = true; + $this->init = true; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php new file mode 100644 index 0000000..cb6b3e6 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php @@ -0,0 +1,224 @@ + true, + 'tbody' => true, + 'thead' => true, + 'tfoot' => true, + 'caption' => true, + 'colgroup' => true, + 'col' => true + ); + + public function __construct() + { + } + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + if (empty($children)) { + return false; + } + + // only one of these elements is allowed in a table + $caption = false; + $thead = false; + $tfoot = false; + + // whitespace + $initial_ws = array(); + $after_caption_ws = array(); + $after_thead_ws = array(); + $after_tfoot_ws = array(); + + // as many of these as you want + $cols = array(); + $content = array(); + + $tbody_mode = false; // if true, then we need to wrap any stray + // s with a . + + $ws_accum =& $initial_ws; + + foreach ($children as $node) { + if ($node instanceof HTMLPurifier_Node_Comment) { + $ws_accum[] = $node; + continue; + } + switch ($node->name) { + case 'tbody': + $tbody_mode = true; + // fall through + case 'tr': + $content[] = $node; + $ws_accum =& $content; + break; + case 'caption': + // there can only be one caption! + if ($caption !== false) break; + $caption = $node; + $ws_accum =& $after_caption_ws; + break; + case 'thead': + $tbody_mode = true; + // XXX This breaks rendering properties with + // Firefox, which never floats a to + // the top. Ever. (Our scheme will float the + // first to the top.) So maybe + // s that are not first should be + // turned into ? Very tricky, indeed. + if ($thead === false) { + $thead = $node; + $ws_accum =& $after_thead_ws; + } else { + // Oops, there's a second one! What + // should we do? Current behavior is to + // transmutate the first and last entries into + // tbody tags, and then put into content. + // Maybe a better idea is to *attach + // it* to the existing thead or tfoot? + // We don't do this, because Firefox + // doesn't float an extra tfoot to the + // bottom like it does for the first one. + $node->name = 'tbody'; + $content[] = $node; + $ws_accum =& $content; + } + break; + case 'tfoot': + // see above for some aveats + $tbody_mode = true; + if ($tfoot === false) { + $tfoot = $node; + $ws_accum =& $after_tfoot_ws; + } else { + $node->name = 'tbody'; + $content[] = $node; + $ws_accum =& $content; + } + break; + case 'colgroup': + case 'col': + $cols[] = $node; + $ws_accum =& $cols; + break; + case '#PCDATA': + // How is whitespace handled? We treat is as sticky to + // the *end* of the previous element. So all of the + // nonsense we have worked on is to keep things + // together. + if (!empty($node->is_whitespace)) { + $ws_accum[] = $node; + } + break; + } + } + + if (empty($content)) { + return false; + } + + $ret = $initial_ws; + if ($caption !== false) { + $ret[] = $caption; + $ret = array_merge($ret, $after_caption_ws); + } + if ($cols !== false) { + $ret = array_merge($ret, $cols); + } + if ($thead !== false) { + $ret[] = $thead; + $ret = array_merge($ret, $after_thead_ws); + } + if ($tfoot !== false) { + $ret[] = $tfoot; + $ret = array_merge($ret, $after_tfoot_ws); + } + + if ($tbody_mode) { + // we have to shuffle tr into tbody + $current_tr_tbody = null; + + foreach($content as $node) { + switch ($node->name) { + case 'tbody': + $current_tr_tbody = null; + $ret[] = $node; + break; + case 'tr': + if ($current_tr_tbody === null) { + $current_tr_tbody = new HTMLPurifier_Node_Element('tbody'); + $ret[] = $current_tr_tbody; + } + $current_tr_tbody->children[] = $node; + break; + case '#PCDATA': + //assert($node->is_whitespace); + if ($current_tr_tbody === null) { + $ret[] = $node; + } else { + $current_tr_tbody->children[] = $node; + } + break; + } + } + } else { + $ret = array_merge($ret, $content); + } + + return $ret; + + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php new file mode 100644 index 0000000..3133d8a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php @@ -0,0 +1,920 @@ +defaultPlist; + $this->plist = new HTMLPurifier_PropertyList($parent); + $this->def = $definition; // keep a copy around for checking + $this->parser = new HTMLPurifier_VarParser_Flexible(); + } + + /** + * Convenience constructor that creates a config object based on a mixed var + * @param mixed $config Variable that defines the state of the config + * object. Can be: a HTMLPurifier_Config() object, + * an array of directives based on loadArray(), + * or a string filename of an ini file. + * @param HTMLPurifier_ConfigSchema $schema Schema object + * @return HTMLPurifier_Config Configured object + */ + public static function create($config, $schema = null) + { + if ($config instanceof HTMLPurifier_Config) { + // pass-through + return $config; + } + if (!$schema) { + $ret = HTMLPurifier_Config::createDefault(); + } else { + $ret = new HTMLPurifier_Config($schema); + } + if (is_string($config)) { + $ret->loadIni($config); + } elseif (is_array($config)) $ret->loadArray($config); + return $ret; + } + + /** + * Creates a new config object that inherits from a previous one. + * @param HTMLPurifier_Config $config Configuration object to inherit from. + * @return HTMLPurifier_Config object with $config as its parent. + */ + public static function inherit(HTMLPurifier_Config $config) + { + return new HTMLPurifier_Config($config->def, $config->plist); + } + + /** + * Convenience constructor that creates a default configuration object. + * @return HTMLPurifier_Config default object. + */ + public static function createDefault() + { + $definition = HTMLPurifier_ConfigSchema::instance(); + $config = new HTMLPurifier_Config($definition); + return $config; + } + + /** + * Retrieves a value from the configuration. + * + * @param string $key String key + * @param mixed $a + * + * @return mixed + */ + public function get($key, $a = null) + { + if ($a !== null) { + $this->triggerError( + "Using deprecated API: use \$config->get('$key.$a') instead", + E_USER_WARNING + ); + $key = "$key.$a"; + } + if (!$this->finalized) { + $this->autoFinalize(); + } + if (!isset($this->def->info[$key])) { + // can't add % due to SimpleTest bug + $this->triggerError( + 'Cannot retrieve value of undefined directive ' . htmlspecialchars($key), + E_USER_WARNING + ); + return; + } + if (isset($this->def->info[$key]->isAlias)) { + $d = $this->def->info[$key]; + $this->triggerError( + 'Cannot get value from aliased directive, use real name ' . $d->key, + E_USER_ERROR + ); + return; + } + if ($this->lock) { + list($ns) = explode('.', $key); + if ($ns !== $this->lock) { + $this->triggerError( + 'Cannot get value of namespace ' . $ns . ' when lock for ' . + $this->lock . + ' is active, this probably indicates a Definition setup method ' . + 'is accessing directives that are not within its namespace', + E_USER_ERROR + ); + return; + } + } + return $this->plist->get($key); + } + + /** + * Retrieves an array of directives to values from a given namespace + * + * @param string $namespace String namespace + * + * @return array + */ + public function getBatch($namespace) + { + if (!$this->finalized) { + $this->autoFinalize(); + } + $full = $this->getAll(); + if (!isset($full[$namespace])) { + $this->triggerError( + 'Cannot retrieve undefined namespace ' . + htmlspecialchars($namespace), + E_USER_WARNING + ); + return; + } + return $full[$namespace]; + } + + /** + * Returns a SHA-1 signature of a segment of the configuration object + * that uniquely identifies that particular configuration + * + * @param string $namespace Namespace to get serial for + * + * @return string + * @note Revision is handled specially and is removed from the batch + * before processing! + */ + public function getBatchSerial($namespace) + { + if (empty($this->serials[$namespace])) { + $batch = $this->getBatch($namespace); + unset($batch['DefinitionRev']); + $this->serials[$namespace] = sha1(serialize($batch)); + } + return $this->serials[$namespace]; + } + + /** + * Returns a SHA-1 signature for the entire configuration object + * that uniquely identifies that particular configuration + * + * @return string + */ + public function getSerial() + { + if (empty($this->serial)) { + $this->serial = sha1(serialize($this->getAll())); + } + return $this->serial; + } + + /** + * Retrieves all directives, organized by namespace + * + * @warning This is a pretty inefficient function, avoid if you can + */ + public function getAll() + { + if (!$this->finalized) { + $this->autoFinalize(); + } + $ret = array(); + foreach ($this->plist->squash() as $name => $value) { + list($ns, $key) = explode('.', $name, 2); + $ret[$ns][$key] = $value; + } + return $ret; + } + + /** + * Sets a value to configuration. + * + * @param string $key key + * @param mixed $value value + * @param mixed $a + */ + public function set($key, $value, $a = null) + { + if (strpos($key, '.') === false) { + $namespace = $key; + $directive = $value; + $value = $a; + $key = "$key.$directive"; + $this->triggerError("Using deprecated API: use \$config->set('$key', ...) instead", E_USER_NOTICE); + } else { + list($namespace) = explode('.', $key); + } + if ($this->isFinalized('Cannot set directive after finalization')) { + return; + } + if (!isset($this->def->info[$key])) { + $this->triggerError( + 'Cannot set undefined directive ' . htmlspecialchars($key) . ' to value', + E_USER_WARNING + ); + return; + } + $def = $this->def->info[$key]; + + if (isset($def->isAlias)) { + if ($this->aliasMode) { + $this->triggerError( + 'Double-aliases not allowed, please fix '. + 'ConfigSchema bug with' . $key, + E_USER_ERROR + ); + return; + } + $this->aliasMode = true; + $this->set($def->key, $value); + $this->aliasMode = false; + $this->triggerError("$key is an alias, preferred directive name is {$def->key}", E_USER_NOTICE); + return; + } + + // Raw type might be negative when using the fully optimized form + // of stdClass, which indicates allow_null == true + $rtype = is_int($def) ? $def : $def->type; + if ($rtype < 0) { + $type = -$rtype; + $allow_null = true; + } else { + $type = $rtype; + $allow_null = isset($def->allow_null); + } + + try { + $value = $this->parser->parse($value, $type, $allow_null); + } catch (HTMLPurifier_VarParserException $e) { + $this->triggerError( + 'Value for ' . $key . ' is of invalid type, should be ' . + HTMLPurifier_VarParser::getTypeName($type), + E_USER_WARNING + ); + return; + } + if (is_string($value) && is_object($def)) { + // resolve value alias if defined + if (isset($def->aliases[$value])) { + $value = $def->aliases[$value]; + } + // check to see if the value is allowed + if (isset($def->allowed) && !isset($def->allowed[$value])) { + $this->triggerError( + 'Value not supported, valid values are: ' . + $this->_listify($def->allowed), + E_USER_WARNING + ); + return; + } + } + $this->plist->set($key, $value); + + // reset definitions if the directives they depend on changed + // this is a very costly process, so it's discouraged + // with finalization + if ($namespace == 'HTML' || $namespace == 'CSS' || $namespace == 'URI') { + $this->definitions[$namespace] = null; + } + + $this->serials[$namespace] = false; + } + + /** + * Convenience function for error reporting + * + * @param array $lookup + * + * @return string + */ + private function _listify($lookup) + { + $list = array(); + foreach ($lookup as $name => $b) { + $list[] = $name; + } + return implode(', ', $list); + } + + /** + * Retrieves object reference to the HTML definition. + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawHTMLDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_HTMLDefinition|null + */ + public function getHTMLDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('HTML', $raw, $optimized); + } + + /** + * Retrieves object reference to the CSS definition + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawCSSDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_CSSDefinition|null + */ + public function getCSSDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('CSS', $raw, $optimized); + } + + /** + * Retrieves object reference to the URI definition + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawURIDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_URIDefinition|null + */ + public function getURIDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('URI', $raw, $optimized); + } + + /** + * Retrieves a definition + * + * @param string $type Type of definition: HTML, CSS, etc + * @param bool $raw Whether or not definition should be returned raw + * @param bool $optimized Only has an effect when $raw is true. Whether + * or not to return null if the result is already present in + * the cache. This is off by default for backwards + * compatibility reasons, but you need to do things this + * way in order to ensure that caching is done properly. + * Check out enduser-customize.html for more details. + * We probably won't ever change this default, as much as the + * maybe semantics is the "right thing to do." + * + * @throws HTMLPurifier_Exception + * @return HTMLPurifier_Definition|null + */ + public function getDefinition($type, $raw = false, $optimized = false) + { + if ($optimized && !$raw) { + throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false"); + } + if (!$this->finalized) { + $this->autoFinalize(); + } + // temporarily suspend locks, so we can handle recursive definition calls + $lock = $this->lock; + $this->lock = null; + $factory = HTMLPurifier_DefinitionCacheFactory::instance(); + $cache = $factory->create($type, $this); + $this->lock = $lock; + if (!$raw) { + // full definition + // --------------- + // check if definition is in memory + if (!empty($this->definitions[$type])) { + $def = $this->definitions[$type]; + // check if the definition is setup + if ($def->setup) { + return $def; + } else { + $def->setup($this); + if ($def->optimized) { + $cache->add($def, $this); + } + return $def; + } + } + // check if definition is in cache + $def = $cache->get($this); + if ($def) { + // definition in cache, save to memory and return it + $this->definitions[$type] = $def; + return $def; + } + // initialize it + $def = $this->initDefinition($type); + // set it up + $this->lock = $type; + $def->setup($this); + $this->lock = null; + // save in cache + $cache->add($def, $this); + // return it + return $def; + } else { + // raw definition + // -------------- + // check preconditions + $def = null; + if ($optimized) { + if (is_null($this->get($type . '.DefinitionID'))) { + // fatally error out if definition ID not set + throw new HTMLPurifier_Exception( + "Cannot retrieve raw version without specifying %$type.DefinitionID" + ); + } + } + if (!empty($this->definitions[$type])) { + $def = $this->definitions[$type]; + if ($def->setup && !$optimized) { + $extra = $this->chatty ? + " (try moving this code block earlier in your initialization)" : + ""; + throw new HTMLPurifier_Exception( + "Cannot retrieve raw definition after it has already been setup" . + $extra + ); + } + if ($def->optimized === null) { + $extra = $this->chatty ? " (try flushing your cache)" : ""; + throw new HTMLPurifier_Exception( + "Optimization status of definition is unknown" . $extra + ); + } + if ($def->optimized !== $optimized) { + $msg = $optimized ? "optimized" : "unoptimized"; + $extra = $this->chatty ? + " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)" + : ""; + throw new HTMLPurifier_Exception( + "Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra + ); + } + } + // check if definition was in memory + if ($def) { + if ($def->setup) { + // invariant: $optimized === true (checked above) + return null; + } else { + return $def; + } + } + // if optimized, check if definition was in cache + // (because we do the memory check first, this formulation + // is prone to cache slamming, but I think + // guaranteeing that either /all/ of the raw + // setup code or /none/ of it is run is more important.) + if ($optimized) { + // This code path only gets run once; once we put + // something in $definitions (which is guaranteed by the + // trailing code), we always short-circuit above. + $def = $cache->get($this); + if ($def) { + // save the full definition for later, but don't + // return it yet + $this->definitions[$type] = $def; + return null; + } + } + // check invariants for creation + if (!$optimized) { + if (!is_null($this->get($type . '.DefinitionID'))) { + if ($this->chatty) { + $this->triggerError( + 'Due to a documentation error in previous version of HTML Purifier, your ' . + 'definitions are not being cached. If this is OK, you can remove the ' . + '%$type.DefinitionRev and %$type.DefinitionID declaration. Otherwise, ' . + 'modify your code to use maybeGetRawDefinition, and test if the returned ' . + 'value is null before making any edits (if it is null, that means that a ' . + 'cached version is available, and no raw operations are necessary). See ' . + '' . + 'Customize for more details', + E_USER_WARNING + ); + } else { + $this->triggerError( + "Useless DefinitionID declaration", + E_USER_WARNING + ); + } + } + } + // initialize it + $def = $this->initDefinition($type); + $def->optimized = $optimized; + return $def; + } + throw new HTMLPurifier_Exception("The impossible happened!"); + } + + /** + * Initialise definition + * + * @param string $type What type of definition to create + * + * @return HTMLPurifier_CSSDefinition|HTMLPurifier_HTMLDefinition|HTMLPurifier_URIDefinition + * @throws HTMLPurifier_Exception + */ + private function initDefinition($type) + { + // quick checks failed, let's create the object + if ($type == 'HTML') { + $def = new HTMLPurifier_HTMLDefinition(); + } elseif ($type == 'CSS') { + $def = new HTMLPurifier_CSSDefinition(); + } elseif ($type == 'URI') { + $def = new HTMLPurifier_URIDefinition(); + } else { + throw new HTMLPurifier_Exception( + "Definition of $type type not supported" + ); + } + $this->definitions[$type] = $def; + return $def; + } + + public function maybeGetRawDefinition($name) + { + return $this->getDefinition($name, true, true); + } + + /** + * @return HTMLPurifier_HTMLDefinition|null + */ + public function maybeGetRawHTMLDefinition() + { + return $this->getDefinition('HTML', true, true); + } + + /** + * @return HTMLPurifier_CSSDefinition|null + */ + public function maybeGetRawCSSDefinition() + { + return $this->getDefinition('CSS', true, true); + } + + /** + * @return HTMLPurifier_URIDefinition|null + */ + public function maybeGetRawURIDefinition() + { + return $this->getDefinition('URI', true, true); + } + + /** + * Loads configuration values from an array with the following structure: + * Namespace.Directive => Value + * + * @param array $config_array Configuration associative array + */ + public function loadArray($config_array) + { + if ($this->isFinalized('Cannot load directives after finalization')) { + return; + } + foreach ($config_array as $key => $value) { + $key = str_replace('_', '.', $key); + if (strpos($key, '.') !== false) { + $this->set($key, $value); + } else { + $namespace = $key; + $namespace_values = $value; + foreach ($namespace_values as $directive => $value2) { + $this->set($namespace .'.'. $directive, $value2); + } + } + } + } + + /** + * Returns a list of array(namespace, directive) for all directives + * that are allowed in a web-form context as per an allowed + * namespaces/directives list. + * + * @param array $allowed List of allowed namespaces/directives + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return array + */ + public static function getAllowedDirectivesForForm($allowed, $schema = null) + { + if (!$schema) { + $schema = HTMLPurifier_ConfigSchema::instance(); + } + if ($allowed !== true) { + if (is_string($allowed)) { + $allowed = array($allowed); + } + $allowed_ns = array(); + $allowed_directives = array(); + $blacklisted_directives = array(); + foreach ($allowed as $ns_or_directive) { + if (strpos($ns_or_directive, '.') !== false) { + // directive + if ($ns_or_directive[0] == '-') { + $blacklisted_directives[substr($ns_or_directive, 1)] = true; + } else { + $allowed_directives[$ns_or_directive] = true; + } + } else { + // namespace + $allowed_ns[$ns_or_directive] = true; + } + } + } + $ret = array(); + foreach ($schema->info as $key => $def) { + list($ns, $directive) = explode('.', $key, 2); + if ($allowed !== true) { + if (isset($blacklisted_directives["$ns.$directive"])) { + continue; + } + if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) { + continue; + } + } + if (isset($def->isAlias)) { + continue; + } + if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') { + continue; + } + $ret[] = array($ns, $directive); + } + return $ret; + } + + /** + * Loads configuration values from $_GET/$_POST that were posted + * via ConfigForm + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return mixed + */ + public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) + { + $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema); + $config = HTMLPurifier_Config::create($ret, $schema); + return $config; + } + + /** + * Merges in configuration values from $_GET/$_POST to object. NOT STATIC. + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + */ + public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) + { + $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def); + $this->loadArray($ret); + } + + /** + * Prepares an array from a form into something usable for the more + * strict parts of HTMLPurifier_Config + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return array + */ + public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) + { + if ($index !== false) { + $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); + } + $mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema); + $ret = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $skey = "$ns.$directive"; + if (!empty($array["Null_$skey"])) { + $ret[$ns][$directive] = null; + continue; + } + if (!isset($array[$skey])) { + continue; + } + $value = $mq ? stripslashes($array[$skey]) : $array[$skey]; + $ret[$ns][$directive] = $value; + } + return $ret; + } + + /** + * Loads configuration values from an ini file + * + * @param string $filename Name of ini file + */ + public function loadIni($filename) + { + if ($this->isFinalized('Cannot load directives after finalization')) { + return; + } + $array = parse_ini_file($filename, true); + $this->loadArray($array); + } + + /** + * Checks whether or not the configuration object is finalized. + * + * @param string|bool $error String error message, or false for no error + * + * @return bool + */ + public function isFinalized($error = false) + { + if ($this->finalized && $error) { + $this->triggerError($error, E_USER_ERROR); + } + return $this->finalized; + } + + /** + * Finalizes configuration only if auto finalize is on and not + * already finalized + */ + public function autoFinalize() + { + if ($this->autoFinalize) { + $this->finalize(); + } else { + $this->plist->squash(true); + } + } + + /** + * Finalizes a configuration object, prohibiting further change + */ + public function finalize() + { + $this->finalized = true; + $this->parser = null; + } + + /** + * Produces a nicely formatted error message by supplying the + * stack frame information OUTSIDE of HTMLPurifier_Config. + * + * @param string $msg An error message + * @param int $no An error number + */ + protected function triggerError($msg, $no) + { + // determine previous stack frame + $extra = ''; + if ($this->chatty) { + $trace = debug_backtrace(); + // zip(tail(trace), trace) -- but PHP is not Haskell har har + for ($i = 0, $c = count($trace); $i < $c - 1; $i++) { + // XXX this is not correct on some versions of HTML Purifier + if (isset($trace[$i + 1]['class']) && $trace[$i + 1]['class'] === 'HTMLPurifier_Config') { + continue; + } + $frame = $trace[$i]; + $extra = " invoked on line {$frame['line']} in file {$frame['file']}"; + break; + } + } + trigger_error($msg . $extra, $no); + } + + /** + * Returns a serialized form of the configuration object that can + * be reconstituted. + * + * @return string + */ + public function serialize() + { + $this->getDefinition('HTML'); + $this->getDefinition('CSS'); + $this->getDefinition('URI'); + return serialize($this); + } + +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php new file mode 100644 index 0000000..c3fe8cd --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php @@ -0,0 +1,176 @@ + array( + * 'Directive' => new stdClass(), + * ) + * ) + * + * The stdClass may have the following properties: + * + * - If isAlias isn't set: + * - type: Integer type of directive, see HTMLPurifier_VarParser for definitions + * - allow_null: If set, this directive allows null values + * - aliases: If set, an associative array of value aliases to real values + * - allowed: If set, a lookup array of allowed (string) values + * - If isAlias is set: + * - namespace: Namespace this directive aliases to + * - name: Directive name this directive aliases to + * + * In certain degenerate cases, stdClass will actually be an integer. In + * that case, the value is equivalent to an stdClass with the type + * property set to the integer. If the integer is negative, type is + * equal to the absolute value of integer, and allow_null is true. + * + * This class is friendly with HTMLPurifier_Config. If you need introspection + * about the schema, you're better of using the ConfigSchema_Interchange, + * which uses more memory but has much richer information. + * @type array + */ + public $info = array(); + + /** + * Application-wide singleton + * @type HTMLPurifier_ConfigSchema + */ + protected static $singleton; + + public function __construct() + { + $this->defaultPlist = new HTMLPurifier_PropertyList(); + } + + /** + * Unserializes the default ConfigSchema. + * @return HTMLPurifier_ConfigSchema + */ + public static function makeFromSerial() + { + $contents = file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser'); + $r = unserialize($contents); + if (!$r) { + $hash = sha1($contents); + trigger_error("Unserialization of configuration schema failed, sha1 of file was $hash", E_USER_ERROR); + } + return $r; + } + + /** + * Retrieves an instance of the application-wide configuration definition. + * @param HTMLPurifier_ConfigSchema $prototype + * @return HTMLPurifier_ConfigSchema + */ + public static function instance($prototype = null) + { + if ($prototype !== null) { + HTMLPurifier_ConfigSchema::$singleton = $prototype; + } elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) { + HTMLPurifier_ConfigSchema::$singleton = HTMLPurifier_ConfigSchema::makeFromSerial(); + } + return HTMLPurifier_ConfigSchema::$singleton; + } + + /** + * Defines a directive for configuration + * @warning Will fail of directive's namespace is defined. + * @warning This method's signature is slightly different from the legacy + * define() static method! Beware! + * @param string $key Name of directive + * @param mixed $default Default value of directive + * @param string $type Allowed type of the directive. See + * HTMLPurifier_VarParser::$types for allowed values + * @param bool $allow_null Whether or not to allow null values + */ + public function add($key, $default, $type, $allow_null) + { + $obj = new stdClass(); + $obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type]; + if ($allow_null) { + $obj->allow_null = true; + } + $this->info[$key] = $obj; + $this->defaults[$key] = $default; + $this->defaultPlist->set($key, $default); + } + + /** + * Defines a directive value alias. + * + * Directive value aliases are convenient for developers because it lets + * them set a directive to several values and get the same result. + * @param string $key Name of Directive + * @param array $aliases Hash of aliased values to the real alias + */ + public function addValueAliases($key, $aliases) + { + if (!isset($this->info[$key]->aliases)) { + $this->info[$key]->aliases = array(); + } + foreach ($aliases as $alias => $real) { + $this->info[$key]->aliases[$alias] = $real; + } + } + + /** + * Defines a set of allowed values for a directive. + * @warning This is slightly different from the corresponding static + * method definition. + * @param string $key Name of directive + * @param array $allowed Lookup array of allowed values + */ + public function addAllowedValues($key, $allowed) + { + $this->info[$key]->allowed = $allowed; + } + + /** + * Defines a directive alias for backwards compatibility + * @param string $key Directive that will be aliased + * @param string $new_key Directive that the alias will be to + */ + public function addAlias($key, $new_key) + { + $obj = new stdClass; + $obj->key = $new_key; + $obj->isAlias = true; + $this->info[$key] = $obj; + } + + /** + * Replaces any stdClass that only has the type property with type integer. + */ + public function postProcess() + { + foreach ($this->info as $key => $v) { + if (count((array) $v) == 1) { + $this->info[$key] = $v->type; + } elseif (count((array) $v) == 2 && isset($v->allow_null)) { + $this->info[$key] = -$v->type; + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php new file mode 100644 index 0000000..d5906cd --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php @@ -0,0 +1,48 @@ +directives as $d) { + $schema->add( + $d->id->key, + $d->default, + $d->type, + $d->typeAllowsNull + ); + if ($d->allowed !== null) { + $schema->addAllowedValues( + $d->id->key, + $d->allowed + ); + } + foreach ($d->aliases as $alias) { + $schema->addAlias( + $alias->key, + $d->id->key + ); + } + if ($d->valueAliases !== null) { + $schema->addValueAliases( + $d->id->key, + $d->valueAliases + ); + } + } + $schema->postProcess(); + return $schema; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php new file mode 100644 index 0000000..5fa56f7 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php @@ -0,0 +1,144 @@ +startElement('div'); + + $purifier = HTMLPurifier::getInstance(); + $html = $purifier->purify($html); + $this->writeAttribute('xmlns', 'http://www.w3.org/1999/xhtml'); + $this->writeRaw($html); + + $this->endElement(); // div + } + + /** + * @param mixed $var + * @return string + */ + protected function export($var) + { + if ($var === array()) { + return 'array()'; + } + return var_export($var, true); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + */ + public function build($interchange) + { + // global access, only use as last resort + $this->interchange = $interchange; + + $this->setIndent(true); + $this->startDocument('1.0', 'UTF-8'); + $this->startElement('configdoc'); + $this->writeElement('title', $interchange->name); + + foreach ($interchange->directives as $directive) { + $this->buildDirective($directive); + } + + if ($this->namespace) { + $this->endElement(); + } // namespace + + $this->endElement(); // configdoc + $this->flush(); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive + */ + public function buildDirective($directive) + { + // Kludge, although I suppose having a notion of a "root namespace" + // certainly makes things look nicer when documentation is built. + // Depends on things being sorted. + if (!$this->namespace || $this->namespace !== $directive->id->getRootNamespace()) { + if ($this->namespace) { + $this->endElement(); + } // namespace + $this->namespace = $directive->id->getRootNamespace(); + $this->startElement('namespace'); + $this->writeAttribute('id', $this->namespace); + $this->writeElement('name', $this->namespace); + } + + $this->startElement('directive'); + $this->writeAttribute('id', $directive->id->toString()); + + $this->writeElement('name', $directive->id->getDirective()); + + $this->startElement('aliases'); + foreach ($directive->aliases as $alias) { + $this->writeElement('alias', $alias->toString()); + } + $this->endElement(); // aliases + + $this->startElement('constraints'); + if ($directive->version) { + $this->writeElement('version', $directive->version); + } + $this->startElement('type'); + if ($directive->typeAllowsNull) { + $this->writeAttribute('allow-null', 'yes'); + } + $this->text($directive->type); + $this->endElement(); // type + if ($directive->allowed) { + $this->startElement('allowed'); + foreach ($directive->allowed as $value => $x) { + $this->writeElement('value', $value); + } + $this->endElement(); // allowed + } + $this->writeElement('default', $this->export($directive->default)); + $this->writeAttribute('xml:space', 'preserve'); + if ($directive->external) { + $this->startElement('external'); + foreach ($directive->external as $project) { + $this->writeElement('project', $project); + } + $this->endElement(); + } + $this->endElement(); // constraints + + if ($directive->deprecatedVersion) { + $this->startElement('deprecated'); + $this->writeElement('version', $directive->deprecatedVersion); + $this->writeElement('use', $directive->deprecatedUse->toString()); + $this->endElement(); // deprecated + } + + $this->startElement('description'); + $this->writeHTMLDiv($directive->description); + $this->endElement(); // description + + $this->endElement(); // directive + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php new file mode 100644 index 0000000..2671516 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php @@ -0,0 +1,11 @@ + array(directive info) + * @type HTMLPurifier_ConfigSchema_Interchange_Directive[] + */ + public $directives = array(); + + /** + * Adds a directive array to $directives + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive + * @throws HTMLPurifier_ConfigSchema_Exception + */ + public function addDirective($directive) + { + if (isset($this->directives[$i = $directive->id->toString()])) { + throw new HTMLPurifier_ConfigSchema_Exception("Cannot redefine directive '$i'"); + } + $this->directives[$i] = $directive; + } + + /** + * Convenience function to perform standard validation. Throws exception + * on failed validation. + */ + public function validate() + { + $validator = new HTMLPurifier_ConfigSchema_Validator(); + return $validator->validate($this); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php new file mode 100644 index 0000000..127a39a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php @@ -0,0 +1,89 @@ + true). + * Null if all values are allowed. + * @type array + */ + public $allowed; + + /** + * List of aliases for the directive. + * e.g. array(new HTMLPurifier_ConfigSchema_Interchange_Id('Ns', 'Dir'))). + * @type HTMLPurifier_ConfigSchema_Interchange_Id[] + */ + public $aliases = array(); + + /** + * Hash of value aliases, e.g. array('alt' => 'real'). Null if value + * aliasing is disabled (necessary for non-scalar types). + * @type array + */ + public $valueAliases; + + /** + * Version of HTML Purifier the directive was introduced, e.g. '1.3.1'. + * Null if the directive has always existed. + * @type string + */ + public $version; + + /** + * ID of directive that supercedes this old directive. + * Null if not deprecated. + * @type HTMLPurifier_ConfigSchema_Interchange_Id + */ + public $deprecatedUse; + + /** + * Version of HTML Purifier this directive was deprecated. Null if not + * deprecated. + * @type string + */ + public $deprecatedVersion; + + /** + * List of external projects this directive depends on, e.g. array('CSSTidy'). + * @type array + */ + public $external = array(); +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php new file mode 100644 index 0000000..126f09d --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php @@ -0,0 +1,58 @@ +key = $key; + } + + /** + * @return string + * @warning This is NOT magic, to ensure that people don't abuse SPL and + * cause problems for PHP 5.0 support. + */ + public function toString() + { + return $this->key; + } + + /** + * @return string + */ + public function getRootNamespace() + { + return substr($this->key, 0, strpos($this->key, ".")); + } + + /** + * @return string + */ + public function getDirective() + { + return substr($this->key, strpos($this->key, ".") + 1); + } + + /** + * @param string $id + * @return HTMLPurifier_ConfigSchema_Interchange_Id + */ + public static function make($id) + { + return new HTMLPurifier_ConfigSchema_Interchange_Id($id); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php new file mode 100644 index 0000000..655e6dd --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php @@ -0,0 +1,226 @@ +varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native(); + } + + /** + * @param string $dir + * @return HTMLPurifier_ConfigSchema_Interchange + */ + public static function buildFromDirectory($dir = null) + { + $builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder(); + $interchange = new HTMLPurifier_ConfigSchema_Interchange(); + return $builder->buildDir($interchange, $dir); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @param string $dir + * @return HTMLPurifier_ConfigSchema_Interchange + */ + public function buildDir($interchange, $dir = null) + { + if (!$dir) { + $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema'; + } + if (file_exists($dir . '/info.ini')) { + $info = parse_ini_file($dir . '/info.ini'); + $interchange->name = $info['name']; + } + + $files = array(); + $dh = opendir($dir); + while (false !== ($file = readdir($dh))) { + if (!$file || $file[0] == '.' || strrchr($file, '.') !== '.txt') { + continue; + } + $files[] = $file; + } + closedir($dh); + + sort($files); + foreach ($files as $file) { + $this->buildFile($interchange, $dir . '/' . $file); + } + return $interchange; + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @param string $file + */ + public function buildFile($interchange, $file) + { + $parser = new HTMLPurifier_StringHashParser(); + $this->build( + $interchange, + new HTMLPurifier_StringHash($parser->parseFile($file)) + ); + } + + /** + * Builds an interchange object based on a hash. + * @param HTMLPurifier_ConfigSchema_Interchange $interchange HTMLPurifier_ConfigSchema_Interchange object to build + * @param HTMLPurifier_StringHash $hash source data + * @throws HTMLPurifier_ConfigSchema_Exception + */ + public function build($interchange, $hash) + { + if (!$hash instanceof HTMLPurifier_StringHash) { + $hash = new HTMLPurifier_StringHash($hash); + } + if (!isset($hash['ID'])) { + throw new HTMLPurifier_ConfigSchema_Exception('Hash does not have any ID'); + } + if (strpos($hash['ID'], '.') === false) { + if (count($hash) == 2 && isset($hash['DESCRIPTION'])) { + $hash->offsetGet('DESCRIPTION'); // prevent complaining + } else { + throw new HTMLPurifier_ConfigSchema_Exception('All directives must have a namespace'); + } + } else { + $this->buildDirective($interchange, $hash); + } + $this->_findUnused($hash); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @param HTMLPurifier_StringHash $hash + * @throws HTMLPurifier_ConfigSchema_Exception + */ + public function buildDirective($interchange, $hash) + { + $directive = new HTMLPurifier_ConfigSchema_Interchange_Directive(); + + // These are required elements: + $directive->id = $this->id($hash->offsetGet('ID')); + $id = $directive->id->toString(); // convenience + + if (isset($hash['TYPE'])) { + $type = explode('/', $hash->offsetGet('TYPE')); + if (isset($type[1])) { + $directive->typeAllowsNull = true; + } + $directive->type = $type[0]; + } else { + throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined"); + } + + if (isset($hash['DEFAULT'])) { + try { + $directive->default = $this->varParser->parse( + $hash->offsetGet('DEFAULT'), + $directive->type, + $directive->typeAllowsNull + ); + } catch (HTMLPurifier_VarParserException $e) { + throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'"); + } + } + + if (isset($hash['DESCRIPTION'])) { + $directive->description = $hash->offsetGet('DESCRIPTION'); + } + + if (isset($hash['ALLOWED'])) { + $directive->allowed = $this->lookup($this->evalArray($hash->offsetGet('ALLOWED'))); + } + + if (isset($hash['VALUE-ALIASES'])) { + $directive->valueAliases = $this->evalArray($hash->offsetGet('VALUE-ALIASES')); + } + + if (isset($hash['ALIASES'])) { + $raw_aliases = trim($hash->offsetGet('ALIASES')); + $aliases = preg_split('/\s*,\s*/', $raw_aliases); + foreach ($aliases as $alias) { + $directive->aliases[] = $this->id($alias); + } + } + + if (isset($hash['VERSION'])) { + $directive->version = $hash->offsetGet('VERSION'); + } + + if (isset($hash['DEPRECATED-USE'])) { + $directive->deprecatedUse = $this->id($hash->offsetGet('DEPRECATED-USE')); + } + + if (isset($hash['DEPRECATED-VERSION'])) { + $directive->deprecatedVersion = $hash->offsetGet('DEPRECATED-VERSION'); + } + + if (isset($hash['EXTERNAL'])) { + $directive->external = preg_split('/\s*,\s*/', trim($hash->offsetGet('EXTERNAL'))); + } + + $interchange->addDirective($directive); + } + + /** + * Evaluates an array PHP code string without array() wrapper + * @param string $contents + */ + protected function evalArray($contents) + { + return eval('return array(' . $contents . ');'); + } + + /** + * Converts an array list into a lookup array. + * @param array $array + * @return array + */ + protected function lookup($array) + { + $ret = array(); + foreach ($array as $val) { + $ret[$val] = true; + } + return $ret; + } + + /** + * Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id + * object based on a string Id. + * @param string $id + * @return HTMLPurifier_ConfigSchema_Interchange_Id + */ + protected function id($id) + { + return HTMLPurifier_ConfigSchema_Interchange_Id::make($id); + } + + /** + * Triggers errors for any unused keys passed in the hash; such keys + * may indicate typos, missing values, etc. + * @param HTMLPurifier_StringHash $hash Hash to check. + */ + protected function _findUnused($hash) + { + $accessed = $hash->getAccessed(); + foreach ($hash as $k => $v) { + if (!isset($accessed[$k])) { + trigger_error("String hash key '$k' not used by builder", E_USER_NOTICE); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php new file mode 100644 index 0000000..fb31277 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php @@ -0,0 +1,248 @@ +parser = new HTMLPurifier_VarParser(); + } + + /** + * Validates a fully-formed interchange object. + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @return bool + */ + public function validate($interchange) + { + $this->interchange = $interchange; + $this->aliases = array(); + // PHP is a bit lax with integer <=> string conversions in + // arrays, so we don't use the identical !== comparison + foreach ($interchange->directives as $i => $directive) { + $id = $directive->id->toString(); + if ($i != $id) { + $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'"); + } + $this->validateDirective($directive); + } + return true; + } + + /** + * Validates a HTMLPurifier_ConfigSchema_Interchange_Id object. + * @param HTMLPurifier_ConfigSchema_Interchange_Id $id + */ + public function validateId($id) + { + $id_string = $id->toString(); + $this->context[] = "id '$id_string'"; + if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) { + // handled by InterchangeBuilder + $this->error(false, 'is not an instance of HTMLPurifier_ConfigSchema_Interchange_Id'); + } + // keys are now unconstrained (we might want to narrow down to A-Za-z0-9.) + // we probably should check that it has at least one namespace + $this->with($id, 'key') + ->assertNotEmpty() + ->assertIsString(); // implicit assertIsString handled by InterchangeBuilder + array_pop($this->context); + } + + /** + * Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirective($d) + { + $id = $d->id->toString(); + $this->context[] = "directive '$id'"; + $this->validateId($d->id); + + $this->with($d, 'description') + ->assertNotEmpty(); + + // BEGIN - handled by InterchangeBuilder + $this->with($d, 'type') + ->assertNotEmpty(); + $this->with($d, 'typeAllowsNull') + ->assertIsBool(); + try { + // This also tests validity of $d->type + $this->parser->parse($d->default, $d->type, $d->typeAllowsNull); + } catch (HTMLPurifier_VarParserException $e) { + $this->error('default', 'had error: ' . $e->getMessage()); + } + // END - handled by InterchangeBuilder + + if (!is_null($d->allowed) || !empty($d->valueAliases)) { + // allowed and valueAliases require that we be dealing with + // strings, so check for that early. + $d_int = HTMLPurifier_VarParser::$types[$d->type]; + if (!isset(HTMLPurifier_VarParser::$stringTypes[$d_int])) { + $this->error('type', 'must be a string type when used with allowed or value aliases'); + } + } + + $this->validateDirectiveAllowed($d); + $this->validateDirectiveValueAliases($d); + $this->validateDirectiveAliases($d); + + array_pop($this->context); + } + + /** + * Extra validation if $allowed member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirectiveAllowed($d) + { + if (is_null($d->allowed)) { + return; + } + $this->with($d, 'allowed') + ->assertNotEmpty() + ->assertIsLookup(); // handled by InterchangeBuilder + if (is_string($d->default) && !isset($d->allowed[$d->default])) { + $this->error('default', 'must be an allowed value'); + } + $this->context[] = 'allowed'; + foreach ($d->allowed as $val => $x) { + if (!is_string($val)) { + $this->error("value $val", 'must be a string'); + } + } + array_pop($this->context); + } + + /** + * Extra validation if $valueAliases member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirectiveValueAliases($d) + { + if (is_null($d->valueAliases)) { + return; + } + $this->with($d, 'valueAliases') + ->assertIsArray(); // handled by InterchangeBuilder + $this->context[] = 'valueAliases'; + foreach ($d->valueAliases as $alias => $real) { + if (!is_string($alias)) { + $this->error("alias $alias", 'must be a string'); + } + if (!is_string($real)) { + $this->error("alias target $real from alias '$alias'", 'must be a string'); + } + if ($alias === $real) { + $this->error("alias '$alias'", "must not be an alias to itself"); + } + } + if (!is_null($d->allowed)) { + foreach ($d->valueAliases as $alias => $real) { + if (isset($d->allowed[$alias])) { + $this->error("alias '$alias'", 'must not be an allowed value'); + } elseif (!isset($d->allowed[$real])) { + $this->error("alias '$alias'", 'must be an alias to an allowed value'); + } + } + } + array_pop($this->context); + } + + /** + * Extra validation if $aliases member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirectiveAliases($d) + { + $this->with($d, 'aliases') + ->assertIsArray(); // handled by InterchangeBuilder + $this->context[] = 'aliases'; + foreach ($d->aliases as $alias) { + $this->validateId($alias); + $s = $alias->toString(); + if (isset($this->interchange->directives[$s])) { + $this->error("alias '$s'", 'collides with another directive'); + } + if (isset($this->aliases[$s])) { + $other_directive = $this->aliases[$s]; + $this->error("alias '$s'", "collides with alias for directive '$other_directive'"); + } + $this->aliases[$s] = $d->id->toString(); + } + array_pop($this->context); + } + + // protected helper functions + + /** + * Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom + * for validating simple member variables of objects. + * @param $obj + * @param $member + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + protected function with($obj, $member) + { + return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member); + } + + /** + * Emits an error, providing helpful context. + * @throws HTMLPurifier_ConfigSchema_Exception + */ + protected function error($target, $msg) + { + if ($target !== false) { + $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext(); + } else { + $prefix = ucfirst($this->getFormattedContext()); + } + throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg)); + } + + /** + * Returns a formatted context string. + * @return string + */ + protected function getFormattedContext() + { + return implode(' in ', array_reverse($this->context)); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php new file mode 100644 index 0000000..c9aa364 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php @@ -0,0 +1,130 @@ +context = $context; + $this->obj = $obj; + $this->member = $member; + $this->contents =& $obj->$member; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsString() + { + if (!is_string($this->contents)) { + $this->error('must be a string'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsBool() + { + if (!is_bool($this->contents)) { + $this->error('must be a boolean'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsArray() + { + if (!is_array($this->contents)) { + $this->error('must be an array'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertNotNull() + { + if ($this->contents === null) { + $this->error('must not be null'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertAlnum() + { + $this->assertIsString(); + if (!ctype_alnum($this->contents)) { + $this->error('must be alphanumeric'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertNotEmpty() + { + if (empty($this->contents)) { + $this->error('must not be empty'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsLookup() + { + $this->assertIsArray(); + foreach ($this->contents as $v) { + if ($v !== true) { + $this->error('must be a lookup array'); + } + } + return $this; + } + + /** + * @param string $msg + * @throws HTMLPurifier_ConfigSchema_Exception + */ + protected function error($msg) + { + throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser new file mode 100644 index 0000000..a5426c7 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser @@ -0,0 +1 @@ +O:25:"HTMLPurifier_ConfigSchema":3:{s:8:"defaults";a:127:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:12:"defaultPlist";O:25:"HTMLPurifier_PropertyList":3:{s:7:"*data";a:127:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:9:"*parent";N;s:8:"*cache";N;}s:4:"info";a:140:{s:19:"Attr.AllowedClasses";i:-8;s:24:"Attr.AllowedFrameTargets";i:8;s:15:"Attr.AllowedRel";i:8;s:15:"Attr.AllowedRev";i:8;s:18:"Attr.ClassUseCDATA";i:-7;s:20:"Attr.DefaultImageAlt";i:-1;s:24:"Attr.DefaultInvalidImage";i:1;s:27:"Attr.DefaultInvalidImageAlt";i:1;s:19:"Attr.DefaultTextDir";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:2:{s:3:"ltr";b:1;s:3:"rtl";b:1;}}s:13:"Attr.EnableID";i:7;s:17:"HTML.EnableAttrID";O:8:"stdClass":2:{s:3:"key";s:13:"Attr.EnableID";s:7:"isAlias";b:1;}s:21:"Attr.ForbiddenClasses";i:8;s:13:"Attr.ID.HTML5";i:-7;s:16:"Attr.IDBlacklist";i:9;s:22:"Attr.IDBlacklistRegexp";i:-1;s:13:"Attr.IDPrefix";i:1;s:18:"Attr.IDPrefixLocal";i:1;s:24:"AutoFormat.AutoParagraph";i:7;s:17:"AutoFormat.Custom";i:9;s:25:"AutoFormat.DisplayLinkURI";i:7;s:18:"AutoFormat.Linkify";i:7;s:33:"AutoFormat.PurifierLinkify.DocURL";i:1;s:37:"AutoFormatParam.PurifierLinkifyDocURL";O:8:"stdClass":2:{s:3:"key";s:33:"AutoFormat.PurifierLinkify.DocURL";s:7:"isAlias";b:1;}s:26:"AutoFormat.PurifierLinkify";i:7;s:32:"AutoFormat.RemoveEmpty.Predicate";i:10;s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";i:8;s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";i:7;s:22:"AutoFormat.RemoveEmpty";i:7;s:39:"AutoFormat.RemoveSpansWithoutAttributes";i:7;s:19:"CSS.AllowDuplicates";i:7;s:18:"CSS.AllowImportant";i:7;s:15:"CSS.AllowTricky";i:7;s:16:"CSS.AllowedFonts";i:-8;s:21:"CSS.AllowedProperties";i:-8;s:17:"CSS.DefinitionRev";i:5;s:23:"CSS.ForbiddenProperties";i:8;s:16:"CSS.MaxImgLength";i:-1;s:15:"CSS.Proprietary";i:7;s:11:"CSS.Trusted";i:7;s:20:"Cache.DefinitionImpl";i:-1;s:20:"Core.DefinitionCache";O:8:"stdClass":2:{s:3:"key";s:20:"Cache.DefinitionImpl";s:7:"isAlias";b:1;}s:20:"Cache.SerializerPath";i:-1;s:27:"Cache.SerializerPermissions";i:-5;s:22:"Core.AggressivelyFixLt";i:7;s:29:"Core.AggressivelyRemoveScript";i:7;s:28:"Core.AllowHostnameUnderscore";i:7;s:23:"Core.AllowParseManyTags";i:7;s:18:"Core.CollectErrors";i:7;s:18:"Core.ColorKeywords";i:10;s:30:"Core.ConvertDocumentToFragment";i:7;s:24:"Core.AcceptFullDocuments";O:8:"stdClass":2:{s:3:"key";s:30:"Core.ConvertDocumentToFragment";s:7:"isAlias";b:1;}s:36:"Core.DirectLexLineNumberSyncInterval";i:5;s:20:"Core.DisableExcludes";i:7;s:15:"Core.EnableIDNA";i:7;s:13:"Core.Encoding";i:2;s:26:"Core.EscapeInvalidChildren";i:7;s:22:"Core.EscapeInvalidTags";i:7;s:29:"Core.EscapeNonASCIICharacters";i:7;s:19:"Core.HiddenElements";i:8;s:13:"Core.Language";i:1;s:24:"Core.LegacyEntityDecoder";i:7;s:14:"Core.LexerImpl";i:-11;s:24:"Core.MaintainLineNumbers";i:-7;s:22:"Core.NormalizeNewlines";i:7;s:21:"Core.RemoveInvalidImg";i:7;s:33:"Core.RemoveProcessingInstructions";i:7;s:25:"Core.RemoveScriptContents";i:-7;s:13:"Filter.Custom";i:9;s:34:"Filter.ExtractStyleBlocks.Escaping";i:7;s:33:"Filter.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:38:"FilterParam.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:31:"Filter.ExtractStyleBlocks.Scope";i:-1;s:30:"Filter.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:35:"FilterParam.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:34:"Filter.ExtractStyleBlocks.TidyImpl";i:-11;s:38:"FilterParam.ExtractStyleBlocksTidyImpl";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.TidyImpl";s:7:"isAlias";b:1;}s:25:"Filter.ExtractStyleBlocks";i:7;s:14:"Filter.YouTube";i:7;s:12:"HTML.Allowed";i:-4;s:22:"HTML.AllowedAttributes";i:-8;s:20:"HTML.AllowedComments";i:8;s:26:"HTML.AllowedCommentsRegexp";i:-1;s:20:"HTML.AllowedElements";i:-8;s:19:"HTML.AllowedModules";i:-8;s:23:"HTML.Attr.Name.UseCDATA";i:7;s:17:"HTML.BlockWrapper";i:1;s:16:"HTML.CoreModules";i:8;s:18:"HTML.CustomDoctype";i:-1;s:17:"HTML.DefinitionID";i:-1;s:18:"HTML.DefinitionRev";i:5;s:12:"HTML.Doctype";O:8:"stdClass":3:{s:4:"type";i:1;s:10:"allow_null";b:1;s:7:"allowed";a:5:{s:22:"HTML 4.01 Transitional";b:1;s:16:"HTML 4.01 Strict";b:1;s:22:"XHTML 1.0 Transitional";b:1;s:16:"XHTML 1.0 Strict";b:1;s:9:"XHTML 1.1";b:1;}}s:25:"HTML.FlashAllowFullScreen";i:7;s:24:"HTML.ForbiddenAttributes";i:8;s:22:"HTML.ForbiddenElements";i:8;s:10:"HTML.Forms";i:7;s:17:"HTML.MaxImgLength";i:-5;s:13:"HTML.Nofollow";i:7;s:11:"HTML.Parent";i:1;s:16:"HTML.Proprietary";i:7;s:14:"HTML.SafeEmbed";i:7;s:15:"HTML.SafeIframe";i:7;s:15:"HTML.SafeObject";i:7;s:18:"HTML.SafeScripting";i:8;s:11:"HTML.Strict";i:7;s:16:"HTML.TargetBlank";i:7;s:19:"HTML.TargetNoopener";i:7;s:21:"HTML.TargetNoreferrer";i:7;s:12:"HTML.TidyAdd";i:8;s:14:"HTML.TidyLevel";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:4:{s:4:"none";b:1;s:5:"light";b:1;s:6:"medium";b:1;s:5:"heavy";b:1;}}s:15:"HTML.TidyRemove";i:8;s:12:"HTML.Trusted";i:7;s:10:"HTML.XHTML";i:7;s:10:"Core.XHTML";O:8:"stdClass":2:{s:3:"key";s:10:"HTML.XHTML";s:7:"isAlias";b:1;}s:28:"Output.CommentScriptContents";i:7;s:26:"Core.CommentScriptContents";O:8:"stdClass":2:{s:3:"key";s:28:"Output.CommentScriptContents";s:7:"isAlias";b:1;}s:19:"Output.FixInnerHTML";i:7;s:18:"Output.FlashCompat";i:7;s:14:"Output.Newline";i:-1;s:15:"Output.SortAttr";i:7;s:17:"Output.TidyFormat";i:7;s:15:"Core.TidyFormat";O:8:"stdClass":2:{s:3:"key";s:17:"Output.TidyFormat";s:7:"isAlias";b:1;}s:17:"Test.ForceNoIconv";i:7;s:18:"URI.AllowedSchemes";i:8;s:8:"URI.Base";i:-1;s:17:"URI.DefaultScheme";i:-1;s:16:"URI.DefinitionID";i:-1;s:17:"URI.DefinitionRev";i:5;s:11:"URI.Disable";i:7;s:15:"Attr.DisableURI";O:8:"stdClass":2:{s:3:"key";s:11:"URI.Disable";s:7:"isAlias";b:1;}s:19:"URI.DisableExternal";i:7;s:28:"URI.DisableExternalResources";i:7;s:20:"URI.DisableResources";i:7;s:8:"URI.Host";i:-1;s:17:"URI.HostBlacklist";i:9;s:16:"URI.MakeAbsolute";i:7;s:9:"URI.Munge";i:-1;s:18:"URI.MungeResources";i:7;s:18:"URI.MungeSecretKey";i:-1;s:26:"URI.OverrideAllowedSchemes";i:7;s:20:"URI.SafeIframeRegexp";i:-1;}} \ No newline at end of file diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt new file mode 100644 index 0000000..0517fed --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt @@ -0,0 +1,8 @@ +Attr.AllowedClasses +TYPE: lookup/null +VERSION: 4.0.0 +DEFAULT: null +--DESCRIPTION-- +List of allowed class values in the class attribute. By default, this is null, +which means all classes are allowed. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt new file mode 100644 index 0000000..249edd6 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt @@ -0,0 +1,12 @@ +Attr.AllowedFrameTargets +TYPE: lookup +DEFAULT: array() +--DESCRIPTION-- +Lookup table of all allowed link frame targets. Some commonly used link +targets include _blank, _self, _parent and _top. Values should be +lowercase, as validation will be done in a case-sensitive manner despite +W3C's recommendation. XHTML 1.0 Strict does not permit the target attribute +so this directive will have no effect in that doctype. XHTML 1.1 does not +enable the Target module by default, you will have to manually enable it +(see the module documentation for more details.) +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt new file mode 100644 index 0000000..9a8fa6a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt @@ -0,0 +1,9 @@ +Attr.AllowedRel +TYPE: lookup +VERSION: 1.6.0 +DEFAULT: array() +--DESCRIPTION-- +List of allowed forward document relationships in the rel attribute. Common +values may be nofollow or print. By default, this is empty, meaning that no +document relationships are allowed. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt new file mode 100644 index 0000000..b017883 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt @@ -0,0 +1,9 @@ +Attr.AllowedRev +TYPE: lookup +VERSION: 1.6.0 +DEFAULT: array() +--DESCRIPTION-- +List of allowed reverse document relationships in the rev attribute. This +attribute is a bit of an edge-case; if you don't know what it is for, stay +away. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt new file mode 100644 index 0000000..e774b82 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt @@ -0,0 +1,19 @@ +Attr.ClassUseCDATA +TYPE: bool/null +DEFAULT: null +VERSION: 4.0.0 +--DESCRIPTION-- +If null, class will auto-detect the doctype and, if matching XHTML 1.1 or +XHTML 2.0, will use the restrictive NMTOKENS specification of class. Otherwise, +it will use a relaxed CDATA definition. If true, the relaxed CDATA definition +is forced; if false, the NMTOKENS definition is forced. To get behavior +of HTML Purifier prior to 4.0.0, set this directive to false. + +Some rational behind the auto-detection: +in previous versions of HTML Purifier, it was assumed that the form of +class was NMTOKENS, as specified by the XHTML Modularization (representing +XHTML 1.1 and XHTML 2.0). The DTDs for HTML 4.01 and XHTML 1.0, however +specify class as CDATA. HTML 5 effectively defines it as CDATA, but +with the additional constraint that each name should be unique (this is not +explicitly outlined in previous specifications). +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt new file mode 100644 index 0000000..533165e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt @@ -0,0 +1,11 @@ +Attr.DefaultImageAlt +TYPE: string/null +DEFAULT: null +VERSION: 3.2.0 +--DESCRIPTION-- +This is the content of the alt tag of an image if the user had not +previously specified an alt attribute. This applies to all images without +a valid alt attribute, as opposed to %Attr.DefaultInvalidImageAlt, which +only applies to invalid images, and overrides in the case of an invalid image. +Default behavior with null is to use the basename of the src tag for the alt. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt new file mode 100644 index 0000000..9eb7e38 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt @@ -0,0 +1,9 @@ +Attr.DefaultInvalidImage +TYPE: string +DEFAULT: '' +--DESCRIPTION-- +This is the default image an img tag will be pointed to if it does not have +a valid src attribute. In future versions, we may allow the image tag to +be removed completely, but due to design issues, this is not possible right +now. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt new file mode 100644 index 0000000..2f17bf4 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt @@ -0,0 +1,8 @@ +Attr.DefaultInvalidImageAlt +TYPE: string +DEFAULT: 'Invalid image' +--DESCRIPTION-- +This is the content of the alt tag of an invalid image if the user had not +previously specified an alt attribute. It has no effect when the image is +valid but there was no alt attribute present. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt new file mode 100644 index 0000000..52654b5 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt @@ -0,0 +1,10 @@ +Attr.DefaultTextDir +TYPE: string +DEFAULT: 'ltr' +--DESCRIPTION-- +Defines the default text direction (ltr or rtl) of the document being +parsed. This generally is the same as the value of the dir attribute in +HTML, or ltr if that is not specified. +--ALLOWED-- +'ltr', 'rtl' +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt new file mode 100644 index 0000000..6440d21 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt @@ -0,0 +1,16 @@ +Attr.EnableID +TYPE: bool +DEFAULT: false +VERSION: 1.2.0 +--DESCRIPTION-- +Allows the ID attribute in HTML. This is disabled by default due to the +fact that without proper configuration user input can easily break the +validation of a webpage by specifying an ID that is already on the +surrounding HTML. If you don't mind throwing caution to the wind, enable +this directive, but I strongly recommend you also consider blacklisting IDs +you use (%Attr.IDBlacklist) or prefixing all user supplied IDs +(%Attr.IDPrefix). When set to true HTML Purifier reverts to the behavior of +pre-1.2.0 versions. +--ALIASES-- +HTML.EnableAttrID +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt new file mode 100644 index 0000000..f31d226 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt @@ -0,0 +1,8 @@ +Attr.ForbiddenClasses +TYPE: lookup +VERSION: 4.0.0 +DEFAULT: array() +--DESCRIPTION-- +List of forbidden class values in the class attribute. By default, this is +empty, which means that no classes are forbidden. See also %Attr.AllowedClasses. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ID.HTML5.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ID.HTML5.txt new file mode 100644 index 0000000..735d4b7 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ID.HTML5.txt @@ -0,0 +1,10 @@ +Attr.ID.HTML5 +TYPE: bool/null +DEFAULT: null +VERSION: 4.8.0 +--DESCRIPTION-- +In HTML5, restrictions on the format of the id attribute have been significantly +relaxed, such that any string is valid so long as it contains no spaces and +is at least one character. In lieu of a general HTML5 compatibility flag, +set this configuration directive to true to use the relaxed rules. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt new file mode 100644 index 0000000..5f2b5e3 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt @@ -0,0 +1,5 @@ +Attr.IDBlacklist +TYPE: list +DEFAULT: array() +DESCRIPTION: Array of IDs not allowed in the document. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt new file mode 100644 index 0000000..6f58245 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt @@ -0,0 +1,9 @@ +Attr.IDBlacklistRegexp +TYPE: string/null +VERSION: 1.6.0 +DEFAULT: NULL +--DESCRIPTION-- +PCRE regular expression to be matched against all IDs. If the expression is +matches, the ID is rejected. Use this with care: may cause significant +degradation. ID matching is done after all other validation. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt new file mode 100644 index 0000000..cc49d43 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt @@ -0,0 +1,12 @@ +Attr.IDPrefix +TYPE: string +VERSION: 1.2.0 +DEFAULT: '' +--DESCRIPTION-- +String to prefix to IDs. If you have no idea what IDs your pages may use, +you may opt to simply add a prefix to all user-submitted ID attributes so +that they are still usable, but will not conflict with core page IDs. +Example: setting the directive to 'user_' will result in a user submitted +'foo' to become 'user_foo' Be sure to set %HTML.EnableAttrID to true +before using this. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt new file mode 100644 index 0000000..2c5924a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt @@ -0,0 +1,14 @@ +Attr.IDPrefixLocal +TYPE: string +VERSION: 1.2.0 +DEFAULT: '' +--DESCRIPTION-- +Temporary prefix for IDs used in conjunction with %Attr.IDPrefix. If you +need to allow multiple sets of user content on web page, you may need to +have a seperate prefix that changes with each iteration. This way, +seperately submitted user content displayed on the same page doesn't +clobber each other. Ideal values are unique identifiers for the content it +represents (i.e. the id of the row in the database). Be sure to add a +seperator (like an underscore) at the end. Warning: this directive will +not work unless %Attr.IDPrefix is set to a non-empty value! +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt new file mode 100644 index 0000000..d5caa1b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt @@ -0,0 +1,31 @@ +AutoFormat.AutoParagraph +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ This directive turns on auto-paragraphing, where double newlines are + converted in to paragraphs whenever possible. Auto-paragraphing: +

+
    +
  • Always applies to inline elements or text in the root node,
  • +
  • Applies to inline elements or text with double newlines in nodes + that allow paragraph tags,
  • +
  • Applies to double newlines in paragraph tags
  • +
+

+ p tags must be allowed for this directive to take effect. + We do not use br tags for paragraphing, as that is + semantically incorrect. +

+

+ To prevent auto-paragraphing as a content-producer, refrain from using + double-newlines except to specify a new paragraph or in contexts where + it has special meaning (whitespace usually has no meaning except in + tags like pre, so this should not be difficult.) To prevent + the paragraphing of inline text adjacent to block elements, wrap them + in div tags (the behavior is slightly different outside of + the root node.) +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt new file mode 100644 index 0000000..2a47648 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt @@ -0,0 +1,12 @@ +AutoFormat.Custom +TYPE: list +VERSION: 2.0.1 +DEFAULT: array() +--DESCRIPTION-- + +

+ This directive can be used to add custom auto-format injectors. + Specify an array of injector names (class name minus the prefix) + or concrete implementations. Injector class must exist. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt new file mode 100644 index 0000000..663064a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt @@ -0,0 +1,11 @@ +AutoFormat.DisplayLinkURI +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ This directive turns on the in-text display of URIs in <a> tags, and disables + those links. For example, example becomes + example (http://example.com). +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt new file mode 100644 index 0000000..3a48ba9 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt @@ -0,0 +1,12 @@ +AutoFormat.Linkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ This directive turns on linkification, auto-linking http, ftp and + https URLs. a tags with the href attribute + must be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt new file mode 100644 index 0000000..db58b13 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify.DocURL +TYPE: string +VERSION: 2.0.1 +DEFAULT: '#%s' +ALIASES: AutoFormatParam.PurifierLinkifyDocURL +--DESCRIPTION-- +

+ Location of configuration documentation to link to, let %s substitute + into the configuration's namespace and directive names sans the percent + sign. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt new file mode 100644 index 0000000..7996488 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ Internal auto-formatter that converts configuration directives in + syntax %Namespace.Directive to links. a tags + with the href attribute must be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt new file mode 100644 index 0000000..6367fe2 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt @@ -0,0 +1,14 @@ +AutoFormat.RemoveEmpty.Predicate +TYPE: hash +VERSION: 4.7.0 +DEFAULT: array('colgroup' => array(), 'th' => array(), 'td' => array(), 'iframe' => array('src')) +--DESCRIPTION-- +

+ Given that an element has no contents, it will be removed by default, unless + this predicate dictates otherwise. The predicate can either be an associative + map from tag name to list of attributes that must be present for the element + to be considered preserved: thus, the default always preserves colgroup, + th and td, and also iframe if it + has a src. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt new file mode 100644 index 0000000..35c393b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt @@ -0,0 +1,11 @@ +AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions +TYPE: lookup +VERSION: 4.0.0 +DEFAULT: array('td' => true, 'th' => true) +--DESCRIPTION-- +

+ When %AutoFormat.RemoveEmpty and %AutoFormat.RemoveEmpty.RemoveNbsp + are enabled, this directive defines what HTML elements should not be + removede if they have only a non-breaking space in them. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt new file mode 100644 index 0000000..9228dee --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt @@ -0,0 +1,15 @@ +AutoFormat.RemoveEmpty.RemoveNbsp +TYPE: bool +VERSION: 4.0.0 +DEFAULT: false +--DESCRIPTION-- +

+ When enabled, HTML Purifier will treat any elements that contain only + non-breaking spaces as well as regular whitespace as empty, and remove + them when %AutoFormat.RemoveEmpty is enabled. +

+

+ See %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions for a list of elements + that don't have this behavior applied to them. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt new file mode 100644 index 0000000..34657ba --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt @@ -0,0 +1,46 @@ +AutoFormat.RemoveEmpty +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ When enabled, HTML Purifier will attempt to remove empty elements that + contribute no semantic information to the document. The following types + of nodes will be removed: +

+
  • + Tags with no attributes and no content, and that are not empty + elements (remove <a></a> but not + <br />), and +
  • +
  • + Tags with no content, except for:
      +
    • The colgroup element, or
    • +
    • + Elements with the id or name attribute, + when those attributes are permitted on those elements. +
    • +
  • +
+

+ Please be very careful when using this functionality; while it may not + seem that empty elements contain useful information, they can alter the + layout of a document given appropriate styling. This directive is most + useful when you are processing machine-generated HTML, please avoid using + it on regular user HTML. +

+

+ Elements that contain only whitespace will be treated as empty. Non-breaking + spaces, however, do not count as whitespace. See + %AutoFormat.RemoveEmpty.RemoveNbsp for alternate behavior. +

+

+ This algorithm is not perfect; you may still notice some empty tags, + particularly if a node had elements, but those elements were later removed + because they were not permitted in that context, or tags that, after + being auto-closed by another tag, where empty. This is for safety reasons + to prevent clever code from breaking validation. The general rule of thumb: + if a tag looked empty on the way in, it will get removed; if HTML Purifier + made it empty, it will stay. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt new file mode 100644 index 0000000..dde990a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt @@ -0,0 +1,11 @@ +AutoFormat.RemoveSpansWithoutAttributes +TYPE: bool +VERSION: 4.0.1 +DEFAULT: false +--DESCRIPTION-- +

+ This directive causes span tags without any attributes + to be removed. It will also remove spans that had all attributes + removed during processing. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowDuplicates.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowDuplicates.txt new file mode 100644 index 0000000..4d054b1 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowDuplicates.txt @@ -0,0 +1,11 @@ +CSS.AllowDuplicates +TYPE: bool +DEFAULT: false +VERSION: 4.8.0 +--DESCRIPTION-- +

+ By default, HTML Purifier removes duplicate CSS properties, + like color:red; color:blue. If this is set to + true, duplicate properties are allowed. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt new file mode 100644 index 0000000..b324608 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt @@ -0,0 +1,8 @@ +CSS.AllowImportant +TYPE: bool +DEFAULT: false +VERSION: 3.1.0 +--DESCRIPTION-- +This parameter determines whether or not !important cascade modifiers should +be allowed in user CSS. If false, !important will stripped. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt new file mode 100644 index 0000000..748be0e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt @@ -0,0 +1,11 @@ +CSS.AllowTricky +TYPE: bool +DEFAULT: false +VERSION: 3.1.0 +--DESCRIPTION-- +This parameter determines whether or not to allow "tricky" CSS properties and +values. Tricky CSS properties/values can drastically modify page layout or +be used for deceptive practices but do not directly constitute a security risk. +For example, display:none; is considered a tricky property that +will only be allowed if this directive is set to true. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt new file mode 100644 index 0000000..3fd4654 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt @@ -0,0 +1,12 @@ +CSS.AllowedFonts +TYPE: lookup/null +VERSION: 4.3.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ Allows you to manually specify a set of allowed fonts. If + NULL, all fonts are allowed. This directive + affects generic names (serif, sans-serif, monospace, cursive, + fantasy) as well as specific font families. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt new file mode 100644 index 0000000..460112e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt @@ -0,0 +1,18 @@ +CSS.AllowedProperties +TYPE: lookup/null +VERSION: 3.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If HTML Purifier's style attributes set is unsatisfactory for your needs, + you can overload it with your own list of tags to allow. Note that this + method is subtractive: it does its job by taking away from HTML Purifier + usual feature set, so you cannot add an attribute that HTML Purifier never + supported in the first place. +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt new file mode 100644 index 0000000..5cb7dda --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt @@ -0,0 +1,11 @@ +CSS.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt new file mode 100644 index 0000000..f1f5c5f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt @@ -0,0 +1,13 @@ +CSS.ForbiddenProperties +TYPE: lookup +VERSION: 4.2.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This is the logical inverse of %CSS.AllowedProperties, and it will + override that directive or any other directive. If possible, + %CSS.AllowedProperties is recommended over this directive, + because it can sometimes be difficult to tell whether or not you've + forbidden all of the CSS properties you truly would like to disallow. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt new file mode 100644 index 0000000..7a32914 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt @@ -0,0 +1,16 @@ +CSS.MaxImgLength +TYPE: string/null +DEFAULT: '1200px' +VERSION: 3.1.1 +--DESCRIPTION-- +

+ This parameter sets the maximum allowed length on img tags, + effectively the width and height properties. + Only absolute units of measurement (in, pt, pc, mm, cm) and pixels (px) are allowed. This is + in place to prevent imagecrash attacks, disable with null at your own risk. + This directive is similar to %HTML.MaxImgLength, and both should be + concurrently edited, although there are + subtle differences in the input format (the CSS max is a number with + a unit). +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt new file mode 100644 index 0000000..148eedb --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt @@ -0,0 +1,10 @@ +CSS.Proprietary +TYPE: bool +VERSION: 3.0.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Whether or not to allow safe, proprietary CSS values. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt new file mode 100644 index 0000000..e733a61 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt @@ -0,0 +1,9 @@ +CSS.Trusted +TYPE: bool +VERSION: 4.2.1 +DEFAULT: false +--DESCRIPTION-- +Indicates whether or not the user's CSS input is trusted or not. If the +input is trusted, a more expansive set of allowed properties. See +also %HTML.Trusted. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt new file mode 100644 index 0000000..c486724 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt @@ -0,0 +1,14 @@ +Cache.DefinitionImpl +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: 'Serializer' +--DESCRIPTION-- + +This directive defines which method to use when caching definitions, +the complex data-type that makes HTML Purifier tick. Set to null +to disable caching (not recommended, as you will see a definite +performance degradation). + +--ALIASES-- +Core.DefinitionCache +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt new file mode 100644 index 0000000..5403650 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt @@ -0,0 +1,13 @@ +Cache.SerializerPath +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Absolute path with no trailing slash to store serialized definitions in. + Default is within the + HTML Purifier library inside DefinitionCache/Serializer. This + path must be writable by the webserver. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt new file mode 100644 index 0000000..2e0cc81 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt @@ -0,0 +1,16 @@ +Cache.SerializerPermissions +TYPE: int/null +VERSION: 4.3.0 +DEFAULT: 0755 +--DESCRIPTION-- + +

+ Directory permissions of the files and directories created inside + the DefinitionCache/Serializer or other custom serializer path. +

+

+ In HTML Purifier 4.8.0, this also supports NULL, + which means that no chmod'ing or directory creation shall + occur. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt new file mode 100644 index 0000000..568cbf3 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt @@ -0,0 +1,18 @@ +Core.AggressivelyFixLt +TYPE: bool +VERSION: 2.1.0 +DEFAULT: true +--DESCRIPTION-- +

+ This directive enables aggressive pre-filter fixes HTML Purifier can + perform in order to ensure that open angled-brackets do not get killed + during parsing stage. Enabling this will result in two preg_replace_callback + calls and at least two preg_replace calls for every HTML document parsed; + if your users make very well-formed HTML, you can set this directive false. + This has no effect when DirectLex is used. +

+

+ Notice: This directive's default turned from false to true + in HTML Purifier 3.2.0. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt new file mode 100644 index 0000000..b2b6ab1 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt @@ -0,0 +1,16 @@ +Core.AggressivelyRemoveScript +TYPE: bool +VERSION: 4.9.0 +DEFAULT: true +--DESCRIPTION-- +

+ This directive enables aggressive pre-filter removal of + script tags. This is not necessary for security, + but it can help work around a bug in libxml where embedded + HTML elements inside script sections cause the parser to + choke. To revert to pre-4.9.0 behavior, set this to false. + This directive has no effect if %Core.Trusted is true, + %Core.RemoveScriptContents is false, or %Core.HiddenElements + does not contain script. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt new file mode 100644 index 0000000..2c910cc --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt @@ -0,0 +1,16 @@ +Core.AllowHostnameUnderscore +TYPE: bool +VERSION: 4.6.0 +DEFAULT: false +--DESCRIPTION-- +

+ By RFC 1123, underscores are not permitted in host names. + (This is in contrast to the specification for DNS, RFC + 2181, which allows underscores.) + However, most browsers do the right thing when faced with + an underscore in the host name, and so some poorly written + websites are written with the expectation this should work. + Setting this parameter to true relaxes our allowed character + check so that underscores are permitted. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt new file mode 100644 index 0000000..06278f8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt @@ -0,0 +1,12 @@ +Core.AllowParseManyTags +TYPE: bool +DEFAULT: false +VERSION: 4.10.1 +--DESCRIPTION-- +

+ This directive allows parsing of many nested tags. + If you set true, relaxes any hardcoded limit from the parser. + However, in that case it may cause a Dos attack. + Be careful when enabling it. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt new file mode 100644 index 0000000..d731791 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt @@ -0,0 +1,12 @@ +Core.CollectErrors +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- + +Whether or not to collect errors found while filtering the document. This +is a useful way to give feedback to your users. Warning: +Currently this feature is very patchy and experimental, with lots of +possible error messages not yet implemented. It will not cause any +problems, but it may not help your users either. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt new file mode 100644 index 0000000..a75844c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt @@ -0,0 +1,160 @@ +Core.ColorKeywords +TYPE: hash +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'aliceblue' => '#F0F8FF', + 'antiquewhite' => '#FAEBD7', + 'aqua' => '#00FFFF', + 'aquamarine' => '#7FFFD4', + 'azure' => '#F0FFFF', + 'beige' => '#F5F5DC', + 'bisque' => '#FFE4C4', + 'black' => '#000000', + 'blanchedalmond' => '#FFEBCD', + 'blue' => '#0000FF', + 'blueviolet' => '#8A2BE2', + 'brown' => '#A52A2A', + 'burlywood' => '#DEB887', + 'cadetblue' => '#5F9EA0', + 'chartreuse' => '#7FFF00', + 'chocolate' => '#D2691E', + 'coral' => '#FF7F50', + 'cornflowerblue' => '#6495ED', + 'cornsilk' => '#FFF8DC', + 'crimson' => '#DC143C', + 'cyan' => '#00FFFF', + 'darkblue' => '#00008B', + 'darkcyan' => '#008B8B', + 'darkgoldenrod' => '#B8860B', + 'darkgray' => '#A9A9A9', + 'darkgrey' => '#A9A9A9', + 'darkgreen' => '#006400', + 'darkkhaki' => '#BDB76B', + 'darkmagenta' => '#8B008B', + 'darkolivegreen' => '#556B2F', + 'darkorange' => '#FF8C00', + 'darkorchid' => '#9932CC', + 'darkred' => '#8B0000', + 'darksalmon' => '#E9967A', + 'darkseagreen' => '#8FBC8F', + 'darkslateblue' => '#483D8B', + 'darkslategray' => '#2F4F4F', + 'darkslategrey' => '#2F4F4F', + 'darkturquoise' => '#00CED1', + 'darkviolet' => '#9400D3', + 'deeppink' => '#FF1493', + 'deepskyblue' => '#00BFFF', + 'dimgray' => '#696969', + 'dimgrey' => '#696969', + 'dodgerblue' => '#1E90FF', + 'firebrick' => '#B22222', + 'floralwhite' => '#FFFAF0', + 'forestgreen' => '#228B22', + 'fuchsia' => '#FF00FF', + 'gainsboro' => '#DCDCDC', + 'ghostwhite' => '#F8F8FF', + 'gold' => '#FFD700', + 'goldenrod' => '#DAA520', + 'gray' => '#808080', + 'grey' => '#808080', + 'green' => '#008000', + 'greenyellow' => '#ADFF2F', + 'honeydew' => '#F0FFF0', + 'hotpink' => '#FF69B4', + 'indianred' => '#CD5C5C', + 'indigo' => '#4B0082', + 'ivory' => '#FFFFF0', + 'khaki' => '#F0E68C', + 'lavender' => '#E6E6FA', + 'lavenderblush' => '#FFF0F5', + 'lawngreen' => '#7CFC00', + 'lemonchiffon' => '#FFFACD', + 'lightblue' => '#ADD8E6', + 'lightcoral' => '#F08080', + 'lightcyan' => '#E0FFFF', + 'lightgoldenrodyellow' => '#FAFAD2', + 'lightgray' => '#D3D3D3', + 'lightgrey' => '#D3D3D3', + 'lightgreen' => '#90EE90', + 'lightpink' => '#FFB6C1', + 'lightsalmon' => '#FFA07A', + 'lightseagreen' => '#20B2AA', + 'lightskyblue' => '#87CEFA', + 'lightslategray' => '#778899', + 'lightslategrey' => '#778899', + 'lightsteelblue' => '#B0C4DE', + 'lightyellow' => '#FFFFE0', + 'lime' => '#00FF00', + 'limegreen' => '#32CD32', + 'linen' => '#FAF0E6', + 'magenta' => '#FF00FF', + 'maroon' => '#800000', + 'mediumaquamarine' => '#66CDAA', + 'mediumblue' => '#0000CD', + 'mediumorchid' => '#BA55D3', + 'mediumpurple' => '#9370DB', + 'mediumseagreen' => '#3CB371', + 'mediumslateblue' => '#7B68EE', + 'mediumspringgreen' => '#00FA9A', + 'mediumturquoise' => '#48D1CC', + 'mediumvioletred' => '#C71585', + 'midnightblue' => '#191970', + 'mintcream' => '#F5FFFA', + 'mistyrose' => '#FFE4E1', + 'moccasin' => '#FFE4B5', + 'navajowhite' => '#FFDEAD', + 'navy' => '#000080', + 'oldlace' => '#FDF5E6', + 'olive' => '#808000', + 'olivedrab' => '#6B8E23', + 'orange' => '#FFA500', + 'orangered' => '#FF4500', + 'orchid' => '#DA70D6', + 'palegoldenrod' => '#EEE8AA', + 'palegreen' => '#98FB98', + 'paleturquoise' => '#AFEEEE', + 'palevioletred' => '#DB7093', + 'papayawhip' => '#FFEFD5', + 'peachpuff' => '#FFDAB9', + 'peru' => '#CD853F', + 'pink' => '#FFC0CB', + 'plum' => '#DDA0DD', + 'powderblue' => '#B0E0E6', + 'purple' => '#800080', + 'rebeccapurple' => '#663399', + 'red' => '#FF0000', + 'rosybrown' => '#BC8F8F', + 'royalblue' => '#4169E1', + 'saddlebrown' => '#8B4513', + 'salmon' => '#FA8072', + 'sandybrown' => '#F4A460', + 'seagreen' => '#2E8B57', + 'seashell' => '#FFF5EE', + 'sienna' => '#A0522D', + 'silver' => '#C0C0C0', + 'skyblue' => '#87CEEB', + 'slateblue' => '#6A5ACD', + 'slategray' => '#708090', + 'slategrey' => '#708090', + 'snow' => '#FFFAFA', + 'springgreen' => '#00FF7F', + 'steelblue' => '#4682B4', + 'tan' => '#D2B48C', + 'teal' => '#008080', + 'thistle' => '#D8BFD8', + 'tomato' => '#FF6347', + 'turquoise' => '#40E0D0', + 'violet' => '#EE82EE', + 'wheat' => '#F5DEB3', + 'white' => '#FFFFFF', + 'whitesmoke' => '#F5F5F5', + 'yellow' => '#FFFF00', + 'yellowgreen' => '#9ACD32' +) +--DESCRIPTION-- + +Lookup array of color names to six digit hexadecimal number corresponding +to color, with preceding hash mark. Used when parsing colors. The lookup +is done in a case-insensitive manner. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt new file mode 100644 index 0000000..64b114f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt @@ -0,0 +1,14 @@ +Core.ConvertDocumentToFragment +TYPE: bool +DEFAULT: true +--DESCRIPTION-- + +This parameter determines whether or not the filter should convert +input that is a full document with html and body tags to a fragment +of just the contents of a body tag. This parameter is simply something +HTML Purifier can do during an edge-case: for most inputs, this +processing is not necessary. + +--ALIASES-- +Core.AcceptFullDocuments +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt new file mode 100644 index 0000000..36f16e0 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt @@ -0,0 +1,17 @@ +Core.DirectLexLineNumberSyncInterval +TYPE: int +VERSION: 2.0.0 +DEFAULT: 0 +--DESCRIPTION-- + +

+ Specifies the number of tokens the DirectLex line number tracking + implementations should process before attempting to resyncronize the + current line count by manually counting all previous new-lines. When + at 0, this functionality is disabled. Lower values will decrease + performance, and this is only strictly necessary if the counting + algorithm is buggy (in which case you should report it as a bug). + This has no effect when %Core.MaintainLineNumbers is disabled or DirectLex is + not being used. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt new file mode 100644 index 0000000..1cd4c2c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt @@ -0,0 +1,14 @@ +Core.DisableExcludes +TYPE: bool +DEFAULT: false +VERSION: 4.5.0 +--DESCRIPTION-- +

+ This directive disables SGML-style exclusions, e.g. the exclusion of + <object> in any descendant of a + <pre> tag. Disabling excludes will allow some + invalid documents to pass through HTML Purifier, but HTML Purifier + will also be less likely to accidentally remove large documents during + processing. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt new file mode 100644 index 0000000..ce243c3 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt @@ -0,0 +1,9 @@ +Core.EnableIDNA +TYPE: bool +DEFAULT: false +VERSION: 4.4.0 +--DESCRIPTION-- +Allows international domain names in URLs. This configuration option +requires the PEAR Net_IDNA2 module to be installed. It operates by +punycoding any internationalized host names for maximum portability. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt new file mode 100644 index 0000000..8bfb47c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt @@ -0,0 +1,15 @@ +Core.Encoding +TYPE: istring +DEFAULT: 'utf-8' +--DESCRIPTION-- +If for some reason you are unable to convert all webpages to UTF-8, you can +use this directive as a stop-gap compatibility change to let HTML Purifier +deal with non UTF-8 input. This technique has notable deficiencies: +absolutely no characters outside of the selected character encoding will be +preserved, not even the ones that have been ampersand escaped (this is due +to a UTF-8 specific feature that automatically resolves all +entities), making it pretty useless for anything except the most I18N-blind +applications, although %Core.EscapeNonASCIICharacters offers fixes this +trouble with another tradeoff. This directive only accepts ISO-8859-1 if +iconv is not enabled. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt new file mode 100644 index 0000000..a3881be --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt @@ -0,0 +1,12 @@ +Core.EscapeInvalidChildren +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +

Warning: this configuration option is no longer does anything as of 4.6.0.

+ +

When true, a child is found that is not allowed in the context of the +parent element will be transformed into text as if it were ASCII. When +false, that element and all internal tags will be dropped, though text will +be preserved. There is no option for dropping the element but preserving +child nodes.

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt new file mode 100644 index 0000000..a7a5b24 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt @@ -0,0 +1,7 @@ +Core.EscapeInvalidTags +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When true, invalid tags will be written back to the document as plain text. +Otherwise, they are silently dropped. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt new file mode 100644 index 0000000..abb4999 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt @@ -0,0 +1,13 @@ +Core.EscapeNonASCIICharacters +TYPE: bool +VERSION: 1.4.0 +DEFAULT: false +--DESCRIPTION-- +This directive overcomes a deficiency in %Core.Encoding by blindly +converting all non-ASCII characters into decimal numeric entities before +converting it to its native encoding. This means that even characters that +can be expressed in the non-UTF-8 encoding will be entity-ized, which can +be a real downer for encodings like Big5. It also assumes that the ASCII +repetoire is available, although this is the case for almost all encodings. +Anyway, use UTF-8! +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt new file mode 100644 index 0000000..915391e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt @@ -0,0 +1,19 @@ +Core.HiddenElements +TYPE: lookup +--DEFAULT-- +array ( + 'script' => true, + 'style' => true, +) +--DESCRIPTION-- + +

+ This directive is a lookup array of elements which should have their + contents removed when they are not allowed by the HTML definition. + For example, the contents of a script tag are not + normally shown in a document, so if script tags are to be removed, + their contents should be removed to. This is opposed to a b + tag, which defines some presentational changes but does not hide its + contents. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt new file mode 100644 index 0000000..233fca1 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt @@ -0,0 +1,10 @@ +Core.Language +TYPE: string +VERSION: 2.0.0 +DEFAULT: 'en' +--DESCRIPTION-- + +ISO 639 language code for localizable things in HTML Purifier to use, +which is mainly error reporting. There is currently only an English (en) +translation, so this directive is currently useless. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt new file mode 100644 index 0000000..392b436 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt @@ -0,0 +1,36 @@ +Core.LegacyEntityDecoder +TYPE: bool +VERSION: 4.9.0 +DEFAULT: false +--DESCRIPTION-- +

+ Prior to HTML Purifier 4.9.0, entities were decoded by performing + a global search replace for all entities whose decoded versions + did not have special meanings under HTML, and replaced them with + their decoded versions. We would match all entities, even if they did + not have a trailing semicolon, but only if there weren't any trailing + alphanumeric characters. +

+ + + + + + +
OriginalTextAttribute
&yen;¥¥
&yen¥¥
&yena&yena&yena
&yen=¥=¥=
+

+ In HTML Purifier 4.9.0, we changed the behavior of entity parsing + to match entities that had missing trailing semicolons in less + cases, to more closely match HTML5 parsing behavior: +

+ + + + + + +
OriginalTextAttribute
&yen;¥¥
&yen¥¥
&yena¥a&yena
&yen=¥=&yen=
+

+ This flag reverts back to pre-HTML Purifier 4.9.0 behavior. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt new file mode 100644 index 0000000..8983e2c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt @@ -0,0 +1,34 @@ +Core.LexerImpl +TYPE: mixed/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ This parameter determines what lexer implementation can be used. The + valid values are: +

+
+
null
+
+ Recommended, the lexer implementation will be auto-detected based on + your PHP-version and configuration. +
+
string lexer identifier
+
+ This is a slim way of manually overridding the implementation. + Currently recognized values are: DOMLex (the default PHP5 +implementation) + and DirectLex (the default PHP4 implementation). Only use this if + you know what you are doing: usually, the auto-detection will + manage things for cases you aren't even aware of. +
+
object lexer instance
+
+ Super-advanced: you can specify your own, custom, implementation that + implements the interface defined by HTMLPurifier_Lexer. + I may remove this option simply because I don't expect anyone + to use it. +
+
+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt new file mode 100644 index 0000000..eb841a7 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt @@ -0,0 +1,16 @@ +Core.MaintainLineNumbers +TYPE: bool/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If true, HTML Purifier will add line number information to all tokens. + This is useful when error reporting is turned on, but can result in + significant performance degradation and should not be used when + unnecessary. This directive must be used with the DirectLex lexer, + as the DOMLex lexer does not (yet) support this functionality. + If the value is null, an appropriate value will be selected based + on other configuration. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt new file mode 100644 index 0000000..d77f536 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt @@ -0,0 +1,11 @@ +Core.NormalizeNewlines +TYPE: bool +VERSION: 4.2.0 +DEFAULT: true +--DESCRIPTION-- +

+ Whether or not to normalize newlines to the operating + system default. When false, HTML Purifier + will attempt to preserve mixed newline files. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt new file mode 100644 index 0000000..4070c2a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt @@ -0,0 +1,12 @@ +Core.RemoveInvalidImg +TYPE: bool +DEFAULT: true +VERSION: 1.3.0 +--DESCRIPTION-- + +

+ This directive enables pre-emptive URI checking in img + tags, as the attribute validation strategy is not authorized to + remove elements from the document. Revert to pre-1.3.0 behavior by setting to false. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt new file mode 100644 index 0000000..3397d9f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt @@ -0,0 +1,11 @@ +Core.RemoveProcessingInstructions +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +Instead of escaping processing instructions in the form <? ... +?>, remove it out-right. This may be useful if the HTML +you are validating contains XML processing instruction gunk, however, +it can also be user-unfriendly for people attempting to post PHP +snippets. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt new file mode 100644 index 0000000..a4cd966 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt @@ -0,0 +1,12 @@ +Core.RemoveScriptContents +TYPE: bool/null +DEFAULT: NULL +VERSION: 2.0.0 +DEPRECATED-VERSION: 2.1.0 +DEPRECATED-USE: Core.HiddenElements +--DESCRIPTION-- +

+ This directive enables HTML Purifier to remove not only script tags + but all of their contents. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt new file mode 100644 index 0000000..3db50ef --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt @@ -0,0 +1,11 @@ +Filter.Custom +TYPE: list +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This directive can be used to add custom filters; it is nearly the + equivalent of the now deprecated HTMLPurifier->addFilter() + method. Specify an array of concrete implementations. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt new file mode 100644 index 0000000..16829bc --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt @@ -0,0 +1,14 @@ +Filter.ExtractStyleBlocks.Escaping +TYPE: bool +VERSION: 3.0.0 +DEFAULT: true +ALIASES: Filter.ExtractStyleBlocksEscaping, FilterParam.ExtractStyleBlocksEscaping +--DESCRIPTION-- + +

+ Whether or not to escape the dangerous characters <, > and & + as \3C, \3E and \26, respectively. This is can be safely set to false + if the contents of StyleBlocks will be placed in an external stylesheet, + where there is no risk of it being interpreted as HTML. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt new file mode 100644 index 0000000..7f95f54 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt @@ -0,0 +1,29 @@ +Filter.ExtractStyleBlocks.Scope +TYPE: string/null +VERSION: 3.0.0 +DEFAULT: NULL +ALIASES: Filter.ExtractStyleBlocksScope, FilterParam.ExtractStyleBlocksScope +--DESCRIPTION-- + +

+ If you would like users to be able to define external stylesheets, but + only allow them to specify CSS declarations for a specific node and + prevent them from fiddling with other elements, use this directive. + It accepts any valid CSS selector, and will prepend this to any + CSS declaration extracted from the document. For example, if this + directive is set to #user-content and a user uses the + selector a:hover, the final selector will be + #user-content a:hover. +

+

+ The comma shorthand may be used; consider the above example, with + #user-content, #user-content2, the final selector will + be #user-content a:hover, #user-content2 a:hover. +

+

+ Warning: It is possible for users to bypass this measure + using a naughty + selector. This is a bug in CSS Tidy 1.3, not HTML + Purifier, and I am working to get it fixed. Until then, HTML Purifier + performs a basic check to prevent this. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt new file mode 100644 index 0000000..6c231b2 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt @@ -0,0 +1,16 @@ +Filter.ExtractStyleBlocks.TidyImpl +TYPE: mixed/null +VERSION: 3.1.0 +DEFAULT: NULL +ALIASES: FilterParam.ExtractStyleBlocksTidyImpl +--DESCRIPTION-- +

+ If left NULL, HTML Purifier will attempt to instantiate a csstidy + class to use for internal cleaning. This will usually be good enough. +

+

+ However, for trusted user input, you can set this to false to + disable cleaning. In addition, you can supply your own concrete implementation + of Tidy's interface to use, although I don't know why you'd want to do that. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt new file mode 100644 index 0000000..078d087 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt @@ -0,0 +1,74 @@ +Filter.ExtractStyleBlocks +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +EXTERNAL: CSSTidy +--DESCRIPTION-- +

+ This directive turns on the style block extraction filter, which removes + style blocks from input HTML, cleans them up with CSSTidy, + and places them in the StyleBlocks context variable, for further + use by you, usually to be placed in an external stylesheet, or a + style block in the head of your document. +

+

+ Sample usage: +

+
';
+?>
+
+
+
+  Filter.ExtractStyleBlocks
+body {color:#F00;} Some text';
+
+    $config = HTMLPurifier_Config::createDefault();
+    $config->set('Filter', 'ExtractStyleBlocks', true);
+    $purifier = new HTMLPurifier($config);
+
+    $html = $purifier->purify($dirty);
+
+    // This implementation writes the stylesheets to the styles/ directory.
+    // You can also echo the styles inside the document, but it's a bit
+    // more difficult to make sure they get interpreted properly by
+    // browsers; try the usual CSS armoring techniques.
+    $styles = $purifier->context->get('StyleBlocks');
+    $dir = 'styles/';
+    if (!is_dir($dir)) mkdir($dir);
+    $hash = sha1($_GET['html']);
+    foreach ($styles as $i => $style) {
+        file_put_contents($name = $dir . $hash . "_$i");
+        echo '';
+    }
+?>
+
+
+  
+ +
+ + +]]>
+

+ Warning: It is possible for a user to mount an + imagecrash attack using this CSS. Counter-measures are difficult; + it is not simply enough to limit the range of CSS lengths (using + relative lengths with many nesting levels allows for large values + to be attained without actually specifying them in the stylesheet), + and the flexible nature of selectors makes it difficult to selectively + disable lengths on image tags (HTML Purifier, however, does disable + CSS width and height in inline styling). There are probably two effective + counter measures: an explicit width and height set to auto in all + images in your document (unlikely) or the disabling of width and + height (somewhat reasonable). Whether or not these measures should be + used is left to the reader. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt new file mode 100644 index 0000000..321eaa2 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt @@ -0,0 +1,16 @@ +Filter.YouTube +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ Warning: Deprecated in favor of %HTML.SafeObject and + %Output.FlashCompat (turn both on to allow YouTube videos and other + Flash content). +

+

+ This directive enables YouTube video embedding in HTML Purifier. Check + this document + on embedding videos for more information on what this filter does. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt new file mode 100644 index 0000000..0b2c106 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt @@ -0,0 +1,25 @@ +HTML.Allowed +TYPE: itext/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ This is a preferred convenience directive that combines + %HTML.AllowedElements and %HTML.AllowedAttributes. + Specify elements and attributes that are allowed using: + element1[attr1|attr2],element2.... For example, + if you would like to only allow paragraphs and links, specify + a[href],p. You can specify attributes that apply + to all elements using an asterisk, e.g. *[lang]. + You can also use newlines instead of commas to separate elements. +

+

+ Warning: + All of the constraints on the component directives are still enforced. + The syntax is a subset of TinyMCE's valid_elements + whitelist: directly copy-pasting it here will probably result in + broken whitelists. If %HTML.AllowedElements or %HTML.AllowedAttributes + are set, this directive has no effect. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt new file mode 100644 index 0000000..fcf093f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt @@ -0,0 +1,19 @@ +HTML.AllowedAttributes +TYPE: lookup/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If HTML Purifier's attribute set is unsatisfactory, overload it! + The syntax is "tag.attr" or "*.attr" for the global attributes + (style, id, class, dir, lang, xml:lang). +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. For + example, %HTML.EnableAttrID will take precedence over *.id in this + directive. You must set that directive to true before you can use + IDs at all. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt new file mode 100644 index 0000000..140e214 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt @@ -0,0 +1,10 @@ +HTML.AllowedComments +TYPE: lookup +VERSION: 4.4.0 +DEFAULT: array() +--DESCRIPTION-- +A whitelist which indicates what explicit comment bodies should be +allowed, modulo leading and trailing whitespace. See also %HTML.AllowedCommentsRegexp +(these directives are union'ed together, so a comment is considered +valid if any directive deems it valid.) +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt new file mode 100644 index 0000000..f22e977 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt @@ -0,0 +1,15 @@ +HTML.AllowedCommentsRegexp +TYPE: string/null +VERSION: 4.4.0 +DEFAULT: NULL +--DESCRIPTION-- +A regexp, which if it matches the body of a comment, indicates that +it should be allowed. Trailing and leading spaces are removed prior +to running this regular expression. +Warning: Make sure you specify +correct anchor metacharacters ^regex$, otherwise you may accept +comments that you did not mean to! In particular, the regex /foo|bar/ +is probably not sufficiently strict, since it also allows foobar. +See also %HTML.AllowedComments (these directives are union'ed together, +so a comment is considered valid if any directive deems it valid.) +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt new file mode 100644 index 0000000..1d3fa79 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt @@ -0,0 +1,23 @@ +HTML.AllowedElements +TYPE: lookup/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ If HTML Purifier's tag set is unsatisfactory for your needs, you can + overload it with your own list of tags to allow. If you change + this, you probably also want to change %HTML.AllowedAttributes; see + also %HTML.Allowed which lets you set allowed elements and + attributes at the same time. +

+

+ If you attempt to allow an element that HTML Purifier does not know + about, HTML Purifier will raise an error. You will need to manually + tell HTML Purifier about this element by using the + advanced customization features. +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt new file mode 100644 index 0000000..5a59a55 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt @@ -0,0 +1,20 @@ +HTML.AllowedModules +TYPE: lookup/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ A doctype comes with a set of usual modules to use. Without having + to mucking about with the doctypes, you can quickly activate or + disable these modules by specifying which modules you wish to allow + with this directive. This is most useful for unit testing specific + modules, although end users may find it useful for their own ends. +

+

+ If you specify a module that does not exist, the manager will silently + fail to use it, so be careful! User-defined modules are not affected + by this directive. Modules defined in %HTML.CoreModules are not + affected by this directive. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt new file mode 100644 index 0000000..151fb7b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt @@ -0,0 +1,11 @@ +HTML.Attr.Name.UseCDATA +TYPE: bool +DEFAULT: false +VERSION: 4.0.0 +--DESCRIPTION-- +The W3C specification DTD defines the name attribute to be CDATA, not ID, due +to limitations of DTD. In certain documents, this relaxed behavior is desired, +whether it is to specify duplicate names, or to specify names that would be +illegal IDs (for example, names that begin with a digit.) Set this configuration +directive to true to use the relaxed parsing rules. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt new file mode 100644 index 0000000..45ae469 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt @@ -0,0 +1,18 @@ +HTML.BlockWrapper +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'p' +--DESCRIPTION-- + +

+ String name of element to wrap inline elements that are inside a block + context. This only occurs in the children of blockquote in strict mode. +

+

+ Example: by default value, + <blockquote>Foo</blockquote> would become + <blockquote><p>Foo</p></blockquote>. + The <p> tags can be replaced with whatever you desire, + as long as it is a block level element. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt new file mode 100644 index 0000000..5246188 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt @@ -0,0 +1,23 @@ +HTML.CoreModules +TYPE: lookup +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'Structure' => true, + 'Text' => true, + 'Hypertext' => true, + 'List' => true, + 'NonXMLCommonAttributes' => true, + 'XMLCommonAttributes' => true, + 'CommonAttributes' => true, +) +--DESCRIPTION-- + +

+ Certain modularized doctypes (XHTML, namely), have certain modules + that must be included for the doctype to be an conforming document + type: put those modules here. By default, XHTML's core modules + are used. You can set this to a blank array to disable core module + protection, but this is not recommended. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt new file mode 100644 index 0000000..6ed70b5 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt @@ -0,0 +1,9 @@ +HTML.CustomDoctype +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +A custom doctype for power-users who defined their own document +type. This directive only applies when %HTML.Doctype is blank. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt new file mode 100644 index 0000000..103db75 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt @@ -0,0 +1,33 @@ +HTML.DefinitionID +TYPE: string/null +DEFAULT: NULL +VERSION: 2.0.0 +--DESCRIPTION-- + +

+ Unique identifier for a custom-built HTML definition. If you edit + the raw version of the HTMLDefinition, introducing changes that the + configuration object does not reflect, you must specify this variable. + If you change your custom edits, you should change this directive, or + clear your cache. Example: +

+
+$config = HTMLPurifier_Config::createDefault();
+$config->set('HTML', 'DefinitionID', '1');
+$def = $config->getHTMLDefinition();
+$def->addAttribute('a', 'tabindex', 'Number');
+
+

+ In the above example, the configuration is still at the defaults, but + using the advanced API, an extra attribute has been added. The + configuration object normally has no way of knowing that this change + has taken place, so it needs an extra directive: %HTML.DefinitionID. + If someone else attempts to use the default configuration, these two + pieces of code will not clobber each other in the cache, since one has + an extra directive attached to it. +

+

+ You must specify a value to this directive to use the + advanced API features. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt new file mode 100644 index 0000000..229ae02 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt @@ -0,0 +1,16 @@ +HTML.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition specified in + %HTML.DefinitionID. This serves the same purpose: uniquely identifying + your custom definition, but this one does so in a chronological + context: revision 3 is more up-to-date then revision 2. Thus, when + this gets incremented, the cache handling is smart enough to clean + up any older revisions of your definition as well as flush the + cache. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt new file mode 100644 index 0000000..9dab497 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt @@ -0,0 +1,11 @@ +HTML.Doctype +TYPE: string/null +DEFAULT: NULL +--DESCRIPTION-- +Doctype to use during filtering. Technically speaking this is not actually +a doctype (as it does not identify a corresponding DTD), but we are using +this name for sake of simplicity. When non-blank, this will override any +older directives like %HTML.XHTML or %HTML.Strict. +--ALLOWED-- +'HTML 4.01 Transitional', 'HTML 4.01 Strict', 'XHTML 1.0 Transitional', 'XHTML 1.0 Strict', 'XHTML 1.1' +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt new file mode 100644 index 0000000..7878dc0 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt @@ -0,0 +1,11 @@ +HTML.FlashAllowFullScreen +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit embedded Flash content from + %HTML.SafeObject to expand to the full screen. Corresponds to + the allowFullScreen parameter. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt new file mode 100644 index 0000000..57358f9 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt @@ -0,0 +1,21 @@ +HTML.ForbiddenAttributes +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ While this directive is similar to %HTML.AllowedAttributes, for + forwards-compatibility with XML, this attribute has a different syntax. Instead of + tag.attr, use tag@attr. To disallow href + attributes in a tags, set this directive to + a@href. You can also disallow an attribute globally with + attr or *@attr (either syntax is fine; the latter + is provided for consistency with %HTML.AllowedAttributes). +

+

+ Warning: This directive complements %HTML.ForbiddenElements, + accordingly, check + out that directive for a discussion of why you + should think twice before using this directive. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt new file mode 100644 index 0000000..93a53e1 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt @@ -0,0 +1,20 @@ +HTML.ForbiddenElements +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This was, perhaps, the most requested feature ever in HTML + Purifier. Please don't abuse it! This is the logical inverse of + %HTML.AllowedElements, and it will override that directive, or any + other directive. +

+

+ If possible, %HTML.Allowed is recommended over this directive, because it + can sometimes be difficult to tell whether or not you've forbidden all of + the behavior you would like to disallow. If you forbid img + with the expectation of preventing images on your site, you'll be in for + a nasty surprise when people start using the background-image + CSS property. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Forms.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Forms.txt new file mode 100644 index 0000000..4a432d8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Forms.txt @@ -0,0 +1,11 @@ +HTML.Forms +TYPE: bool +VERSION: 4.13.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit form elements in the user input, regardless of + %HTML.Trusted value. Please be very careful when using this functionality, as + enabling forms in untrusted documents may allow for phishing attacks. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt new file mode 100644 index 0000000..e424c38 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt @@ -0,0 +1,14 @@ +HTML.MaxImgLength +TYPE: int/null +DEFAULT: 1200 +VERSION: 3.1.1 +--DESCRIPTION-- +

+ This directive controls the maximum number of pixels in the width and + height attributes in img tags. This is + in place to prevent imagecrash attacks, disable with null at your own risk. + This directive is similar to %CSS.MaxImgLength, and both should be + concurrently edited, although there are + subtle differences in the input format (the HTML max is an integer). +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt new file mode 100644 index 0000000..700b309 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt @@ -0,0 +1,7 @@ +HTML.Nofollow +TYPE: bool +VERSION: 4.3.0 +DEFAULT: FALSE +--DESCRIPTION-- +If enabled, nofollow rel attributes are added to all outgoing links. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt new file mode 100644 index 0000000..62e8e16 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt @@ -0,0 +1,12 @@ +HTML.Parent +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'div' +--DESCRIPTION-- + +

+ String name of element that HTML fragment passed to library will be + inserted in. An interesting variation would be using span as the + parent element, meaning that only inline tags would be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt new file mode 100644 index 0000000..dfb7204 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt @@ -0,0 +1,12 @@ +HTML.Proprietary +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to allow proprietary elements and attributes in your + documents, as per HTMLPurifier_HTMLModule_Proprietary. + Warning: This can cause your documents to stop + validating! +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt new file mode 100644 index 0000000..cdda09a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt @@ -0,0 +1,13 @@ +HTML.SafeEmbed +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit embed tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to embed tags. Embed is a proprietary + element and will cause your website to stop validating; you should + see if you can use %Output.FlashCompat with %HTML.SafeObject instead + first.

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt new file mode 100644 index 0000000..5eb6ec2 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt @@ -0,0 +1,13 @@ +HTML.SafeIframe +TYPE: bool +VERSION: 4.4.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit iframe tags in untrusted documents. This + directive must be accompanied by a whitelist of permitted iframes, + such as %URI.SafeIframeRegexp, otherwise it will fatally error. + This directive has no effect on strict doctypes, as iframes are not + valid. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt new file mode 100644 index 0000000..ceb342e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt @@ -0,0 +1,13 @@ +HTML.SafeObject +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit object tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to object tags. You should also enable + %Output.FlashCompat in order to generate Internet Explorer + compatibility code for your object tags. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt new file mode 100644 index 0000000..5ebc7a1 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt @@ -0,0 +1,10 @@ +HTML.SafeScripting +TYPE: lookup +VERSION: 4.5.0 +DEFAULT: array() +--DESCRIPTION-- +

+ Whether or not to permit script tags to external scripts in documents. + Inline scripting is not allowed, and the script must match an explicit whitelist. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt new file mode 100644 index 0000000..a8b1de5 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt @@ -0,0 +1,9 @@ +HTML.Strict +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not to use Transitional (loose) or Strict rulesets. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt new file mode 100644 index 0000000..587a167 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt @@ -0,0 +1,8 @@ +HTML.TargetBlank +TYPE: bool +VERSION: 4.4.0 +DEFAULT: FALSE +--DESCRIPTION-- +If enabled, target=blank attributes are added to all outgoing links. +(This includes links from an HTTPS version of a page to an HTTP version.) +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt new file mode 100644 index 0000000..dd514c0 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt @@ -0,0 +1,10 @@ +--# vim: et sw=4 sts=4 +HTML.TargetNoopener +TYPE: bool +VERSION: 4.8.0 +DEFAULT: TRUE +--DESCRIPTION-- +If enabled, noopener rel attributes are added to links which have +a target attribute associated with them. This prevents malicious +destinations from overwriting the original window. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt new file mode 100644 index 0000000..cb5a0b0 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt @@ -0,0 +1,9 @@ +HTML.TargetNoreferrer +TYPE: bool +VERSION: 4.8.0 +DEFAULT: TRUE +--DESCRIPTION-- +If enabled, noreferrer rel attributes are added to links which have +a target attribute associated with them. This prevents malicious +destinations from overwriting the original window. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt new file mode 100644 index 0000000..b4c271b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt @@ -0,0 +1,8 @@ +HTML.TidyAdd +TYPE: lookup +VERSION: 2.0.0 +DEFAULT: array() +--DESCRIPTION-- + +Fixes to add to the default set of Tidy fixes as per your level. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt new file mode 100644 index 0000000..4186ccd --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt @@ -0,0 +1,24 @@ +HTML.TidyLevel +TYPE: string +VERSION: 2.0.0 +DEFAULT: 'medium' +--DESCRIPTION-- + +

General level of cleanliness the Tidy module should enforce. +There are four allowed values:

+
+
none
+
No extra tidying should be done
+
light
+
Only fix elements that would be discarded otherwise due to + lack of support in doctype
+
medium
+
Enforce best practices
+
heavy
+
Transform all deprecated elements and attributes to standards + compliant equivalents
+
+ +--ALLOWED-- +'none', 'light', 'medium', 'heavy' +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt new file mode 100644 index 0000000..996762b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt @@ -0,0 +1,8 @@ +HTML.TidyRemove +TYPE: lookup +VERSION: 2.0.0 +DEFAULT: array() +--DESCRIPTION-- + +Fixes to remove from the default set of Tidy fixes as per your level. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt new file mode 100644 index 0000000..1db9237 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt @@ -0,0 +1,9 @@ +HTML.Trusted +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- +Indicates whether or not the user input is trusted or not. If the input is +trusted, a more expansive set of allowed tags and attributes will be used. +See also %CSS.Trusted. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt new file mode 100644 index 0000000..2a47e38 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt @@ -0,0 +1,11 @@ +HTML.XHTML +TYPE: bool +DEFAULT: true +VERSION: 1.1.0 +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not output is XHTML 1.0 or HTML 4.01 flavor. +--ALIASES-- +Core.XHTML +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt new file mode 100644 index 0000000..08921fd --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt @@ -0,0 +1,10 @@ +Output.CommentScriptContents +TYPE: bool +VERSION: 2.0.0 +DEFAULT: true +--DESCRIPTION-- +Determines whether or not HTML Purifier should attempt to fix up the +contents of script tags for legacy browsers with comments. +--ALIASES-- +Core.CommentScriptContents +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt new file mode 100644 index 0000000..d6f0d9f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt @@ -0,0 +1,15 @@ +Output.FixInnerHTML +TYPE: bool +VERSION: 4.3.0 +DEFAULT: true +--DESCRIPTION-- +

+ If true, HTML Purifier will protect against Internet Explorer's + mishandling of the innerHTML attribute by appending + a space to any attribute that does not contain angled brackets, spaces + or quotes, but contains a backtick. This slightly changes the + semantics of any given attribute, so if this is unacceptable and + you do not use innerHTML on any of your pages, you can + turn this directive off. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt new file mode 100644 index 0000000..93398e8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt @@ -0,0 +1,11 @@ +Output.FlashCompat +TYPE: bool +VERSION: 4.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ If true, HTML Purifier will generate Internet Explorer compatibility + code for all object code. This is highly recommended if you enable + %HTML.SafeObject. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt new file mode 100644 index 0000000..79f8ad8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt @@ -0,0 +1,13 @@ +Output.Newline +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Newline string to format final output with. If left null, HTML Purifier + will auto-detect the default newline type of the system and use that; + you can manually override it here. Remember, \r\n is Windows, \r + is Mac, and \n is Unix. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt new file mode 100644 index 0000000..232b023 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt @@ -0,0 +1,14 @@ +Output.SortAttr +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ If true, HTML Purifier will sort attributes by name before writing them back + to the document, converting a tag like: <el b="" a="" c="" /> + to <el a="" b="" c="" />. This is a workaround for + a bug in FCKeditor which causes it to swap attributes order, adding noise + to text diffs. If you're not seeing this bug, chances are, you don't need + this directive. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt new file mode 100644 index 0000000..06bab00 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt @@ -0,0 +1,25 @@ +Output.TidyFormat +TYPE: bool +VERSION: 1.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Determines whether or not to run Tidy on the final output for pretty + formatting reasons, such as indentation and wrap. +

+

+ This can greatly improve readability for editors who are hand-editing + the HTML, but is by no means necessary as HTML Purifier has already + fixed all major errors the HTML may have had. Tidy is a non-default + extension, and this directive will silently fail if Tidy is not + available. +

+

+ If you are looking to make the overall look of your page's source + better, I recommend running Tidy on the entire page rather than just + user-content (after all, the indentation relative to the containing + blocks will be incorrect). +

+--ALIASES-- +Core.TidyFormat +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt new file mode 100644 index 0000000..071bc02 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt @@ -0,0 +1,7 @@ +Test.ForceNoIconv +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When set to true, HTMLPurifier_Encoder will act as if iconv does not exist +and use only pure PHP implementations. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt new file mode 100644 index 0000000..eb97307 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt @@ -0,0 +1,18 @@ +URI.AllowedSchemes +TYPE: lookup +--DEFAULT-- +array ( + 'http' => true, + 'https' => true, + 'mailto' => true, + 'ftp' => true, + 'nntp' => true, + 'news' => true, + 'tel' => true, +) +--DESCRIPTION-- +Whitelist that defines the schemes that a URI is allowed to have. This +prevents XSS attacks from using pseudo-schemes like javascript or mocha. +There is also support for the data and file +URI schemes, but they are not enabled by default. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt new file mode 100644 index 0000000..876f068 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt @@ -0,0 +1,17 @@ +URI.Base +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ The base URI is the URI of the document this purified HTML will be + inserted into. This information is important if HTML Purifier needs + to calculate absolute URIs from relative URIs, such as when %URI.MakeAbsolute + is on. You may use a non-absolute URI for this value, but behavior + may vary (%URI.MakeAbsolute deals nicely with both absolute and + relative paths, but forwards-compatibility is not guaranteed). + Warning: If set, the scheme on this URI + overrides the one specified by %URI.DefaultScheme. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt new file mode 100644 index 0000000..834bc08 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt @@ -0,0 +1,15 @@ +URI.DefaultScheme +TYPE: string/null +DEFAULT: 'http' +--DESCRIPTION-- + +

+ Defines through what scheme the output will be served, in order to + select the proper object validator when no scheme information is present. +

+ +

+ Starting with HTML Purifier 4.9.0, the default scheme can be null, in + which case we reject all URIs which do not have explicit schemes. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt new file mode 100644 index 0000000..f05312b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt @@ -0,0 +1,11 @@ +URI.DefinitionID +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Unique identifier for a custom-built URI definition. If you want + to add custom URIFilters, you must specify this value. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt new file mode 100644 index 0000000..80cfea9 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt @@ -0,0 +1,11 @@ +URI.DefinitionRev +TYPE: int +VERSION: 2.1.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt new file mode 100644 index 0000000..71ce025 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt @@ -0,0 +1,14 @@ +URI.Disable +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Disables all URIs in all forms. Not sure why you'd want to do that + (after all, the Internet's founded on the notion of a hyperlink). +

+ +--ALIASES-- +Attr.DisableURI +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt new file mode 100644 index 0000000..13c122c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt @@ -0,0 +1,11 @@ +URI.DisableExternal +TYPE: bool +VERSION: 1.2.0 +DEFAULT: false +--DESCRIPTION-- +Disables links to external websites. This is a highly effective anti-spam +and anti-pagerank-leech measure, but comes at a hefty price: nolinks or +images outside of your domain will be allowed. Non-linkified URIs will +still be preserved. If you want to be able to link to subdomains or use +absolute URIs, specify %URI.Host for your website. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt new file mode 100644 index 0000000..abcc1ef --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt @@ -0,0 +1,13 @@ +URI.DisableExternalResources +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- +Disables the embedding of external resources, preventing users from +embedding things like images from other hosts. This prevents access +tracking (good for email viewers), bandwidth leeching, cross-site request +forging, goatse.cx posting, and other nasties, but also results in a loss +of end-user functionality (they can't directly post a pic they posted from +Flickr anymore). Use it if you don't have a robust user-content moderation +team. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt new file mode 100644 index 0000000..f891de4 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt @@ -0,0 +1,15 @@ +URI.DisableResources +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ Disables embedding resources, essentially meaning no pictures. You can + still link to them though. See %URI.DisableExternalResources for why + this might be a good idea. +

+

+ Note: While this directive has been available since 1.3.0, + it didn't actually start doing anything until 4.2.0. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt new file mode 100644 index 0000000..ee83b12 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt @@ -0,0 +1,19 @@ +URI.Host +TYPE: string/null +VERSION: 1.2.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Defines the domain name of the server, so we can determine whether or + an absolute URI is from your website or not. Not strictly necessary, + as users should be using relative URIs to reference resources on your + website. It will, however, let you use absolute URIs to link to + subdomains of the domain you post here: i.e. example.com will allow + sub.example.com. However, higher up domains will still be excluded: + if you set %URI.Host to sub.example.com, example.com will be blocked. + Note: This directive overrides %URI.Base because + a given page may be on a sub-domain, but you wish HTML Purifier to be + more relaxed and allow some of the parent domains too. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt new file mode 100644 index 0000000..0b6df76 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt @@ -0,0 +1,9 @@ +URI.HostBlacklist +TYPE: list +VERSION: 1.3.0 +DEFAULT: array() +--DESCRIPTION-- +List of strings that are forbidden in the host of any URI. Use it to kill +domain names of spam, etc. Note that it will catch anything in the domain, +so moo.com will catch moo.com.example.com. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt new file mode 100644 index 0000000..4214900 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt @@ -0,0 +1,13 @@ +URI.MakeAbsolute +TYPE: bool +VERSION: 2.1.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Converts all URIs into absolute forms. This is useful when the HTML + being filtered assumes a specific base path, but will actually be + viewed in a different context (and setting an alternate base URI is + not possible). %URI.Base must be set for this directive to work. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt new file mode 100644 index 0000000..58c81dc --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt @@ -0,0 +1,83 @@ +URI.Munge +TYPE: string/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Munges all browsable (usually http, https and ftp) + absolute URIs into another URI, usually a URI redirection service. + This directive accepts a URI, formatted with a %s where + the url-encoded original URI should be inserted (sample: + http://www.google.com/url?q=%s). +

+

+ Uses for this directive: +

+
    +
  • + Prevent PageRank leaks, while being fairly transparent + to users (you may also want to add some client side JavaScript to + override the text in the statusbar). Notice: + Many security experts believe that this form of protection does not deter spam-bots. +
  • +
  • + Redirect users to a splash page telling them they are leaving your + website. While this is poor usability practice, it is often mandated + in corporate environments. +
  • +
+

+ Prior to HTML Purifier 3.1.1, this directive also enabled the munging + of browsable external resources, which could break things if your redirection + script was a splash page or used meta tags. To revert to + previous behavior, please use %URI.MungeResources. +

+

+ You may want to also use %URI.MungeSecretKey along with this directive + in order to enforce what URIs your redirector script allows. Open + redirector scripts can be a security risk and negatively affect the + reputation of your domain name. +

+

+ Starting with HTML Purifier 3.1.1, there is also these substitutions: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescriptionExample <a href="">
%r1 - The URI embeds a resource
(blank) - The URI is merely a link
%nThe name of the tag this URI came froma
%mThe name of the attribute this URI came fromhref
%pThe name of the CSS property this URI came from, or blank if irrelevant
+

+ Admittedly, these letters are somewhat arbitrary; the only stipulation + was that they couldn't be a through f. r is for resource (I would have preferred + e, but you take what you can get), n is for name, m + was picked because it came after n (and I couldn't use a), p is for + property. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt new file mode 100644 index 0000000..6fce0fd --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt @@ -0,0 +1,17 @@ +URI.MungeResources +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ If true, any URI munging directives like %URI.Munge + will also apply to embedded resources, such as <img src="">. + Be careful enabling this directive if you have a redirector script + that does not use the Location HTTP header; all of your images + and other embedded resources will break. +

+

+ Warning: It is strongly advised you use this in conjunction + %URI.MungeSecretKey to mitigate the security risk of an open redirector. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt new file mode 100644 index 0000000..1e17c1d --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt @@ -0,0 +1,30 @@ +URI.MungeSecretKey +TYPE: string/null +VERSION: 3.1.1 +DEFAULT: NULL +--DESCRIPTION-- +

+ This directive enables secure checksum generation along with %URI.Munge. + It should be set to a secure key that is not shared with anyone else. + The checksum can be placed in the URI using %t. Use of this checksum + affords an additional level of protection by allowing a redirector + to check if a URI has passed through HTML Purifier with this line: +

+ +
$checksum === hash_hmac("sha256", $url, $secret_key)
+ +

+ If the output is TRUE, the redirector script should accept the URI. +

+ +

+ Please note that it would still be possible for an attacker to procure + secure hashes en-mass by abusing your website's Preview feature or the + like, but this service affords an additional level of protection + that should be combined with website blacklisting. +

+ +

+ Remember this has no effect if %URI.Munge is not on. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt new file mode 100644 index 0000000..23331a4 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt @@ -0,0 +1,9 @@ +URI.OverrideAllowedSchemes +TYPE: bool +DEFAULT: true +--DESCRIPTION-- +If this is set to true (which it is by default), you can override +%URI.AllowedSchemes by simply registering a HTMLPurifier_URIScheme to the +registry. If false, you will also have to update that directive in order +to add more schemes. +--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt new file mode 100644 index 0000000..7908483 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt @@ -0,0 +1,22 @@ +URI.SafeIframeRegexp +TYPE: string/null +VERSION: 4.4.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ A PCRE regular expression that will be matched against an iframe URI. This is + a relatively inflexible scheme, but works well enough for the most common + use-case of iframes: embedded video. This directive only has an effect if + %HTML.SafeIframe is enabled. Here are some example values: +

+
    +
  • %^http://www.youtube.com/embed/% - Allow YouTube videos
  • +
  • %^http://player.vimeo.com/video/% - Allow Vimeo videos
  • +
  • %^http://(www.youtube.com/embed/|player.vimeo.com/video/)% - Allow both
  • +
+

+ Note that this directive does not give you enough granularity to, say, disable + all autoplay videos. Pipe up on the HTML Purifier forums if this + is a capability you want. +

+--# vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini new file mode 100644 index 0000000..5de4505 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini @@ -0,0 +1,3 @@ +name = "HTML Purifier" + +; vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php new file mode 100644 index 0000000..543e3f8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php @@ -0,0 +1,170 @@ + true) indexed by name. + * @type array + * @note This is in HTMLPurifier_HTMLDefinition->info_content_sets + */ + public $lookup = array(); + + /** + * Synchronized list of defined content sets (keys of info). + * @type array + */ + protected $keys = array(); + /** + * Synchronized list of defined content values (values of info). + * @type array + */ + protected $values = array(); + + /** + * Merges in module's content sets, expands identifiers in the content + * sets and populates the keys, values and lookup member variables. + * @param HTMLPurifier_HTMLModule[] $modules List of HTMLPurifier_HTMLModule + */ + public function __construct($modules) + { + if (!is_array($modules)) { + $modules = array($modules); + } + // populate content_sets based on module hints + // sorry, no way of overloading + foreach ($modules as $module) { + foreach ($module->content_sets as $key => $value) { + $temp = $this->convertToLookup($value); + if (isset($this->lookup[$key])) { + // add it into the existing content set + $this->lookup[$key] = array_merge($this->lookup[$key], $temp); + } else { + $this->lookup[$key] = $temp; + } + } + } + $old_lookup = false; + while ($old_lookup !== $this->lookup) { + $old_lookup = $this->lookup; + foreach ($this->lookup as $i => $set) { + $add = array(); + foreach ($set as $element => $x) { + if (isset($this->lookup[$element])) { + $add += $this->lookup[$element]; + unset($this->lookup[$i][$element]); + } + } + $this->lookup[$i] += $add; + } + } + + foreach ($this->lookup as $key => $lookup) { + $this->info[$key] = implode(' | ', array_keys($lookup)); + } + $this->keys = array_keys($this->info); + $this->values = array_values($this->info); + } + + /** + * Accepts a definition; generates and assigns a ChildDef for it + * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef reference + * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef + */ + public function generateChildDef(&$def, $module) + { + if (!empty($def->child)) { // already done! + return; + } + $content_model = $def->content_model; + if (is_string($content_model)) { + // Assume that $this->keys is alphanumeric + $def->content_model = preg_replace_callback( + '/\b(' . implode('|', $this->keys) . ')\b/', + array($this, 'generateChildDefCallback'), + $content_model + ); + //$def->content_model = str_replace( + // $this->keys, $this->values, $content_model); + } + $def->child = $this->getChildDef($def, $module); + } + + public function generateChildDefCallback($matches) + { + return $this->info[$matches[0]]; + } + + /** + * Instantiates a ChildDef based on content_model and content_model_type + * member variables in HTMLPurifier_ElementDef + * @note This will also defer to modules for custom HTMLPurifier_ChildDef + * subclasses that need content set expansion + * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef to have ChildDef extracted + * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef + * @return HTMLPurifier_ChildDef corresponding to ElementDef + */ + public function getChildDef($def, $module) + { + $value = $def->content_model; + if (is_object($value)) { + trigger_error( + 'Literal object child definitions should be stored in '. + 'ElementDef->child not ElementDef->content_model', + E_USER_NOTICE + ); + return $value; + } + switch ($def->content_model_type) { + case 'required': + return new HTMLPurifier_ChildDef_Required($value); + case 'optional': + return new HTMLPurifier_ChildDef_Optional($value); + case 'empty': + return new HTMLPurifier_ChildDef_Empty(); + case 'custom': + return new HTMLPurifier_ChildDef_Custom($value); + } + // defer to its module + $return = false; + if ($module->defines_child_def) { // save a func call + $return = $module->getChildDef($def); + } + if ($return !== false) { + return $return; + } + // error-out + trigger_error( + 'Could not determine which ChildDef class to instantiate', + E_USER_ERROR + ); + return false; + } + + /** + * Converts a string list of elements separated by pipes into + * a lookup array. + * @param string $string List of elements + * @return array Lookup array of elements + */ + protected function convertToLookup($string) + { + $array = explode('|', str_replace(' ', '', $string)); + $ret = array(); + foreach ($array as $k) { + $ret[$k] = true; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php new file mode 100644 index 0000000..00e509c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php @@ -0,0 +1,95 @@ +_storage)) { + trigger_error( + "Name $name produces collision, cannot re-register", + E_USER_ERROR + ); + return; + } + $this->_storage[$name] =& $ref; + } + + /** + * Retrieves a variable reference from the context. + * @param string $name String name + * @param bool $ignore_error Boolean whether or not to ignore error + * @return mixed + */ + public function &get($name, $ignore_error = false) + { + if (!array_key_exists($name, $this->_storage)) { + if (!$ignore_error) { + trigger_error( + "Attempted to retrieve non-existent variable $name", + E_USER_ERROR + ); + } + $var = null; // so we can return by reference + return $var; + } + return $this->_storage[$name]; + } + + /** + * Destroys a variable in the context. + * @param string $name String name + */ + public function destroy($name) + { + if (!array_key_exists($name, $this->_storage)) { + trigger_error( + "Attempted to destroy non-existent variable $name", + E_USER_ERROR + ); + return; + } + unset($this->_storage[$name]); + } + + /** + * Checks whether or not the variable exists. + * @param string $name String name + * @return bool + */ + public function exists($name) + { + return array_key_exists($name, $this->_storage); + } + + /** + * Loads a series of variables from an associative array + * @param array $context_array Assoc array of variables to load + */ + public function loadArray($context_array) + { + foreach ($context_array as $key => $discard) { + $this->register($key, $context_array[$key]); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php new file mode 100644 index 0000000..bc6d433 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php @@ -0,0 +1,55 @@ +setup) { + return; + } + $this->setup = true; + $this->doSetup($config); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php new file mode 100644 index 0000000..9aa8ff3 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php @@ -0,0 +1,129 @@ +type = $type; + } + + /** + * Generates a unique identifier for a particular configuration + * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config + * @return string + */ + public function generateKey($config) + { + return $config->version . ',' . // possibly replace with function calls + $config->getBatchSerial($this->type) . ',' . + $config->get($this->type . '.DefinitionRev'); + } + + /** + * Tests whether or not a key is old with respect to the configuration's + * version and revision number. + * @param string $key Key to test + * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config to test against + * @return bool + */ + public function isOld($key, $config) + { + if (substr_count($key, ',') < 2) { + return true; + } + list($version, $hash, $revision) = explode(',', $key, 3); + $compare = version_compare($version, $config->version); + // version mismatch, is always old + if ($compare != 0) { + return true; + } + // versions match, ids match, check revision number + if ($hash == $config->getBatchSerial($this->type) && + $revision < $config->get($this->type . '.DefinitionRev')) { + return true; + } + return false; + } + + /** + * Checks if a definition's type jives with the cache's type + * @note Throws an error on failure + * @param HTMLPurifier_Definition $def Definition object to check + * @return bool true if good, false if not + */ + public function checkDefType($def) + { + if ($def->type !== $this->type) { + trigger_error("Cannot use definition of type {$def->type} in cache for {$this->type}"); + return false; + } + return true; + } + + /** + * Adds a definition object to the cache + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + */ + abstract public function add($def, $config); + + /** + * Unconditionally saves a definition object to the cache + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + */ + abstract public function set($def, $config); + + /** + * Replace an object in the cache + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + */ + abstract public function replace($def, $config); + + /** + * Retrieves a definition object from the cache + * @param HTMLPurifier_Config $config + */ + abstract public function get($config); + + /** + * Removes a definition object to the cache + * @param HTMLPurifier_Config $config + */ + abstract public function remove($config); + + /** + * Clears all objects from cache + * @param HTMLPurifier_Config $config + */ + abstract public function flush($config); + + /** + * Clears all expired (older version or revision) objects from cache + * @note Be careful implementing this method as flush. Flush must + * not interfere with other Definition types, and cleanup() + * should not be repeatedly called by userland code. + * @param HTMLPurifier_Config $config + */ + abstract public function cleanup($config); +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php new file mode 100644 index 0000000..b57a51b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php @@ -0,0 +1,112 @@ +copy(); + // reference is necessary for mocks in PHP 4 + $decorator->cache =& $cache; + $decorator->type = $cache->type; + return $decorator; + } + + /** + * Cross-compatible clone substitute + * @return HTMLPurifier_DefinitionCache_Decorator + */ + public function copy() + { + return new HTMLPurifier_DefinitionCache_Decorator(); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function add($def, $config) + { + return $this->cache->add($def, $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function set($def, $config) + { + return $this->cache->set($def, $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function replace($def, $config) + { + return $this->cache->replace($def, $config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function get($config) + { + return $this->cache->get($config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function remove($config) + { + return $this->cache->remove($config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function flush($config) + { + return $this->cache->flush($config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function cleanup($config) + { + return $this->cache->cleanup($config); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php new file mode 100644 index 0000000..4991777 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php @@ -0,0 +1,78 @@ +definitions[$this->generateKey($config)] = $def; + } + return $status; + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function set($def, $config) + { + $status = parent::set($def, $config); + if ($status) { + $this->definitions[$this->generateKey($config)] = $def; + } + return $status; + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function replace($def, $config) + { + $status = parent::replace($def, $config); + if ($status) { + $this->definitions[$this->generateKey($config)] = $def; + } + return $status; + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function get($config) + { + $key = $this->generateKey($config); + if (isset($this->definitions[$key])) { + return $this->definitions[$key]; + } + $this->definitions[$key] = parent::get($config); + return $this->definitions[$key]; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in new file mode 100644 index 0000000..b1fec8d --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in @@ -0,0 +1,82 @@ +checkDefType($def)) { + return; + } + $file = $this->generateFilePath($config); + if (file_exists($file)) { + return false; + } + if (!$this->_prepareDir($config)) { + return false; + } + return $this->_write($file, serialize($def), $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return int|bool + */ + public function set($def, $config) + { + if (!$this->checkDefType($def)) { + return; + } + $file = $this->generateFilePath($config); + if (!$this->_prepareDir($config)) { + return false; + } + return $this->_write($file, serialize($def), $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return int|bool + */ + public function replace($def, $config) + { + if (!$this->checkDefType($def)) { + return; + } + $file = $this->generateFilePath($config); + if (!file_exists($file)) { + return false; + } + if (!$this->_prepareDir($config)) { + return false; + } + return $this->_write($file, serialize($def), $config); + } + + /** + * @param HTMLPurifier_Config $config + * @return bool|HTMLPurifier_Config + */ + public function get($config) + { + $file = $this->generateFilePath($config); + if (!file_exists($file)) { + return false; + } + return unserialize(file_get_contents($file)); + } + + /** + * @param HTMLPurifier_Config $config + * @return bool + */ + public function remove($config) + { + $file = $this->generateFilePath($config); + if (!file_exists($file)) { + return false; + } + return unlink($file); + } + + /** + * @param HTMLPurifier_Config $config + * @return bool + */ + public function flush($config) + { + if (!$this->_prepareDir($config)) { + return false; + } + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + // Apparently, on some versions of PHP, readdir will return + // an empty string if you pass an invalid argument to readdir. + // So you need this test. See #49. + if (false === $dh) { + return false; + } + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) { + continue; + } + if ($filename[0] === '.') { + continue; + } + unlink($dir . '/' . $filename); + } + closedir($dh); + return true; + } + + /** + * @param HTMLPurifier_Config $config + * @return bool + */ + public function cleanup($config) + { + if (!$this->_prepareDir($config)) { + return false; + } + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + // See #49 (and above). + if (false === $dh) { + return false; + } + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) { + continue; + } + if ($filename[0] === '.') { + continue; + } + $key = substr($filename, 0, strlen($filename) - 4); + if ($this->isOld($key, $config)) { + unlink($dir . '/' . $filename); + } + } + closedir($dh); + return true; + } + + /** + * Generates the file path to the serial file corresponding to + * the configuration and definition name + * @param HTMLPurifier_Config $config + * @return string + * @todo Make protected + */ + public function generateFilePath($config) + { + $key = $this->generateKey($config); + return $this->generateDirectoryPath($config) . '/' . $key . '.ser'; + } + + /** + * Generates the path to the directory contain this cache's serial files + * @param HTMLPurifier_Config $config + * @return string + * @note No trailing slash + * @todo Make protected + */ + public function generateDirectoryPath($config) + { + $base = $this->generateBaseDirectoryPath($config); + return $base . '/' . $this->type; + } + + /** + * Generates path to base directory that contains all definition type + * serials + * @param HTMLPurifier_Config $config + * @return mixed|string + * @todo Make protected + */ + public function generateBaseDirectoryPath($config) + { + $base = $config->get('Cache.SerializerPath'); + $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base; + return $base; + } + + /** + * Convenience wrapper function for file_put_contents + * @param string $file File name to write to + * @param string $data Data to write into file + * @param HTMLPurifier_Config $config + * @return int|bool Number of bytes written if success, or false if failure. + */ + private function _write($file, $data, $config) + { + $result = file_put_contents($file, $data); + if ($result !== false) { + // set permissions of the new file (no execute) + $chmod = $config->get('Cache.SerializerPermissions'); + if ($chmod !== null) { + chmod($file, $chmod & 0666); + } + } + return $result; + } + + /** + * Prepares the directory that this type stores the serials in + * @param HTMLPurifier_Config $config + * @return bool True if successful + */ + private function _prepareDir($config) + { + $directory = $this->generateDirectoryPath($config); + $chmod = $config->get('Cache.SerializerPermissions'); + if ($chmod === null) { + if (!@mkdir($directory) && !is_dir($directory)) { + trigger_error( + 'Could not create directory ' . $directory . '', + E_USER_WARNING + ); + return false; + } + return true; + } + if (!is_dir($directory)) { + $base = $this->generateBaseDirectoryPath($config); + if (!is_dir($base)) { + trigger_error( + 'Base directory ' . $base . ' does not exist, + please create or change using %Cache.SerializerPath', + E_USER_WARNING + ); + return false; + } elseif (!$this->_testPermissions($base, $chmod)) { + return false; + } + if (!@mkdir($directory, $chmod) && !is_dir($directory)) { + trigger_error( + 'Could not create directory ' . $directory . '', + E_USER_WARNING + ); + return false; + } + if (!$this->_testPermissions($directory, $chmod)) { + return false; + } + } elseif (!$this->_testPermissions($directory, $chmod)) { + return false; + } + return true; + } + + /** + * Tests permissions on a directory and throws out friendly + * error messages and attempts to chmod it itself if possible + * @param string $dir Directory path + * @param int $chmod Permissions + * @return bool True if directory is writable + */ + private function _testPermissions($dir, $chmod) + { + // early abort, if it is writable, everything is hunky-dory + if (is_writable($dir)) { + return true; + } + if (!is_dir($dir)) { + // generally, you'll want to handle this beforehand + // so a more specific error message can be given + trigger_error( + 'Directory ' . $dir . ' does not exist', + E_USER_WARNING + ); + return false; + } + if (function_exists('posix_getuid') && $chmod !== null) { + // POSIX system, we can give more specific advice + if (fileowner($dir) === posix_getuid()) { + // we can chmod it ourselves + $chmod = $chmod | 0700; + if (chmod($dir, $chmod)) { + return true; + } + } elseif (filegroup($dir) === posix_getgid()) { + $chmod = $chmod | 0070; + } else { + // PHP's probably running as nobody, so we'll + // need to give global permissions + $chmod = $chmod | 0777; + } + trigger_error( + 'Directory ' . $dir . ' not writable, ' . + 'please chmod to ' . decoct($chmod), + E_USER_WARNING + ); + } else { + // generic error message + trigger_error( + 'Directory ' . $dir . ' not writable, ' . + 'please alter file permissions', + E_USER_WARNING + ); + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/HTML/4.13.0,f474c0a322b208e83d22d3aef33ecb184bc71d31,1.ser b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/HTML/4.13.0,f474c0a322b208e83d22d3aef33ecb184bc71d31,1.ser new file mode 100644 index 0000000..b265e01 Binary files /dev/null and b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/HTML/4.13.0,f474c0a322b208e83d22d3aef33ecb184bc71d31,1.ser differ diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README new file mode 100644 index 0000000..2e35c1c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README @@ -0,0 +1,3 @@ +This is a dummy file to prevent Git from ignoring this empty directory. + + vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php new file mode 100644 index 0000000..fd1cc9b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php @@ -0,0 +1,106 @@ + array()); + + /** + * @type array + */ + protected $implementations = array(); + + /** + * @type HTMLPurifier_DefinitionCache_Decorator[] + */ + protected $decorators = array(); + + /** + * Initialize default decorators + */ + public function setup() + { + $this->addDecorator('Cleanup'); + } + + /** + * Retrieves an instance of global definition cache factory. + * @param HTMLPurifier_DefinitionCacheFactory $prototype + * @return HTMLPurifier_DefinitionCacheFactory + */ + public static function instance($prototype = null) + { + static $instance; + if ($prototype !== null) { + $instance = $prototype; + } elseif ($instance === null || $prototype === true) { + $instance = new HTMLPurifier_DefinitionCacheFactory(); + $instance->setup(); + } + return $instance; + } + + /** + * Registers a new definition cache object + * @param string $short Short name of cache object, for reference + * @param string $long Full class name of cache object, for construction + */ + public function register($short, $long) + { + $this->implementations[$short] = $long; + } + + /** + * Factory method that creates a cache object based on configuration + * @param string $type Name of definitions handled by cache + * @param HTMLPurifier_Config $config Config instance + * @return mixed + */ + public function create($type, $config) + { + $method = $config->get('Cache.DefinitionImpl'); + if ($method === null) { + return new HTMLPurifier_DefinitionCache_Null($type); + } + if (!empty($this->caches[$method][$type])) { + return $this->caches[$method][$type]; + } + if (isset($this->implementations[$method]) && + class_exists($class = $this->implementations[$method], false)) { + $cache = new $class($type); + } else { + if ($method != 'Serializer') { + trigger_error("Unrecognized DefinitionCache $method, using Serializer instead", E_USER_WARNING); + } + $cache = new HTMLPurifier_DefinitionCache_Serializer($type); + } + foreach ($this->decorators as $decorator) { + $new_cache = $decorator->decorate($cache); + // prevent infinite recursion in PHP 4 + unset($cache); + $cache = $new_cache; + } + $this->caches[$method][$type] = $cache; + return $this->caches[$method][$type]; + } + + /** + * Registers a decorator to add to all new cache objects + * @param HTMLPurifier_DefinitionCache_Decorator|string $decorator An instance or the name of a decorator + */ + public function addDecorator($decorator) + { + if (is_string($decorator)) { + $class = "HTMLPurifier_DefinitionCache_Decorator_$decorator"; + $decorator = new $class; + } + $this->decorators[$decorator->name] = $decorator; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php new file mode 100644 index 0000000..4acd06e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php @@ -0,0 +1,73 @@ +renderDoctype. + * If structure changes, please update that function. + */ +class HTMLPurifier_Doctype +{ + /** + * Full name of doctype + * @type string + */ + public $name; + + /** + * List of standard modules (string identifiers or literal objects) + * that this doctype uses + * @type array + */ + public $modules = array(); + + /** + * List of modules to use for tidying up code + * @type array + */ + public $tidyModules = array(); + + /** + * Is the language derived from XML (i.e. XHTML)? + * @type bool + */ + public $xml = true; + + /** + * List of aliases for this doctype + * @type array + */ + public $aliases = array(); + + /** + * Public DTD identifier + * @type string + */ + public $dtdPublic; + + /** + * System DTD identifier + * @type string + */ + public $dtdSystem; + + public function __construct( + $name = null, + $xml = true, + $modules = array(), + $tidyModules = array(), + $aliases = array(), + $dtd_public = null, + $dtd_system = null + ) { + $this->name = $name; + $this->xml = $xml; + $this->modules = $modules; + $this->tidyModules = $tidyModules; + $this->aliases = $aliases; + $this->dtdPublic = $dtd_public; + $this->dtdSystem = $dtd_system; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php new file mode 100644 index 0000000..acc1d64 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php @@ -0,0 +1,142 @@ +doctypes[$doctype->name] = $doctype; + $name = $doctype->name; + // hookup aliases + foreach ($doctype->aliases as $alias) { + if (isset($this->doctypes[$alias])) { + continue; + } + $this->aliases[$alias] = $name; + } + // remove old aliases + if (isset($this->aliases[$name])) { + unset($this->aliases[$name]); + } + return $doctype; + } + + /** + * Retrieves reference to a doctype of a certain name + * @note This function resolves aliases + * @note When possible, use the more fully-featured make() + * @param string $doctype Name of doctype + * @return HTMLPurifier_Doctype Editable doctype object + */ + public function get($doctype) + { + if (isset($this->aliases[$doctype])) { + $doctype = $this->aliases[$doctype]; + } + if (!isset($this->doctypes[$doctype])) { + trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR); + $anon = new HTMLPurifier_Doctype($doctype); + return $anon; + } + return $this->doctypes[$doctype]; + } + + /** + * Creates a doctype based on a configuration object, + * will perform initialization on the doctype + * @note Use this function to get a copy of doctype that config + * can hold on to (this is necessary in order to tell + * Generator whether or not the current document is XML + * based or not). + * @param HTMLPurifier_Config $config + * @return HTMLPurifier_Doctype + */ + public function make($config) + { + return clone $this->get($this->getDoctypeFromConfig($config)); + } + + /** + * Retrieves the doctype from the configuration object + * @param HTMLPurifier_Config $config + * @return string + */ + public function getDoctypeFromConfig($config) + { + // recommended test + $doctype = $config->get('HTML.Doctype'); + if (!empty($doctype)) { + return $doctype; + } + $doctype = $config->get('HTML.CustomDoctype'); + if (!empty($doctype)) { + return $doctype; + } + // backwards-compatibility + if ($config->get('HTML.XHTML')) { + $doctype = 'XHTML 1.0'; + } else { + $doctype = 'HTML 4.01'; + } + if ($config->get('HTML.Strict')) { + $doctype .= ' Strict'; + } else { + $doctype .= ' Transitional'; + } + return $doctype; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php new file mode 100644 index 0000000..d5311ce --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php @@ -0,0 +1,216 @@ +setup(), this array may also + * contain an array at index 0 that indicates which attribute + * collections to load into the full array. It may also + * contain string indentifiers in lieu of HTMLPurifier_AttrDef, + * see HTMLPurifier_AttrTypes on how they are expanded during + * HTMLPurifier_HTMLDefinition->setup() processing. + */ + public $attr = array(); + + // XXX: Design note: currently, it's not possible to override + // previously defined AttrTransforms without messing around with + // the final generated config. This is by design; a previous version + // used an associated list of attr_transform, but it was extremely + // easy to accidentally override other attribute transforms by + // forgetting to specify an index (and just using 0.) While we + // could check this by checking the index number and complaining, + // there is a second problem which is that it is not at all easy to + // tell when something is getting overridden. Combine this with a + // codebase where this isn't really being used, and it's perfect for + // nuking. + + /** + * List of tags HTMLPurifier_AttrTransform to be done before validation. + * @type array + */ + public $attr_transform_pre = array(); + + /** + * List of tags HTMLPurifier_AttrTransform to be done after validation. + * @type array + */ + public $attr_transform_post = array(); + + /** + * HTMLPurifier_ChildDef of this tag. + * @type HTMLPurifier_ChildDef + */ + public $child; + + /** + * Abstract string representation of internal ChildDef rules. + * @see HTMLPurifier_ContentSets for how this is parsed and then transformed + * into an HTMLPurifier_ChildDef. + * @warning This is a temporary variable that is not available after + * being processed by HTMLDefinition + * @type string + */ + public $content_model; + + /** + * Value of $child->type, used to determine which ChildDef to use, + * used in combination with $content_model. + * @warning This must be lowercase + * @warning This is a temporary variable that is not available after + * being processed by HTMLDefinition + * @type string + */ + public $content_model_type; + + /** + * Does the element have a content model (#PCDATA | Inline)*? This + * is important for chameleon ins and del processing in + * HTMLPurifier_ChildDef_Chameleon. Dynamically set: modules don't + * have to worry about this one. + * @type bool + */ + public $descendants_are_inline = false; + + /** + * List of the names of required attributes this element has. + * Dynamically populated by HTMLPurifier_HTMLDefinition::getElement() + * @type array + */ + public $required_attr = array(); + + /** + * Lookup table of tags excluded from all descendants of this tag. + * @type array + * @note SGML permits exclusions for all descendants, but this is + * not possible with DTDs or XML Schemas. W3C has elected to + * use complicated compositions of content_models to simulate + * exclusion for children, but we go the simpler, SGML-style + * route of flat-out exclusions, which correctly apply to + * all descendants and not just children. Note that the XHTML + * Modularization Abstract Modules are blithely unaware of such + * distinctions. + */ + public $excludes = array(); + + /** + * This tag is explicitly auto-closed by the following tags. + * @type array + */ + public $autoclose = array(); + + /** + * If a foreign element is found in this element, test if it is + * allowed by this sub-element; if it is, instead of closing the + * current element, place it inside this element. + * @type string + */ + public $wrap; + + /** + * Whether or not this is a formatting element affected by the + * "Active Formatting Elements" algorithm. + * @type bool + */ + public $formatting; + + /** + * Low-level factory constructor for creating new standalone element defs + */ + public static function create($content_model, $content_model_type, $attr) + { + $def = new HTMLPurifier_ElementDef(); + $def->content_model = $content_model; + $def->content_model_type = $content_model_type; + $def->attr = $attr; + return $def; + } + + /** + * Merges the values of another element definition into this one. + * Values from the new element def take precedence if a value is + * not mergeable. + * @param HTMLPurifier_ElementDef $def + */ + public function mergeIn($def) + { + // later keys takes precedence + foreach ($def->attr as $k => $v) { + if ($k === 0) { + // merge in the includes + // sorry, no way to override an include + foreach ($v as $v2) { + $this->attr[0][] = $v2; + } + continue; + } + if ($v === false) { + if (isset($this->attr[$k])) { + unset($this->attr[$k]); + } + continue; + } + $this->attr[$k] = $v; + } + $this->_mergeAssocArray($this->excludes, $def->excludes); + $this->attr_transform_pre = array_merge($this->attr_transform_pre, $def->attr_transform_pre); + $this->attr_transform_post = array_merge($this->attr_transform_post, $def->attr_transform_post); + + if (!empty($def->content_model)) { + $this->content_model = + str_replace("#SUPER", $this->content_model, $def->content_model); + $this->child = false; + } + if (!empty($def->content_model_type)) { + $this->content_model_type = $def->content_model_type; + $this->child = false; + } + if (!is_null($def->child)) { + $this->child = $def->child; + } + if (!is_null($def->formatting)) { + $this->formatting = $def->formatting; + } + if ($def->descendants_are_inline) { + $this->descendants_are_inline = $def->descendants_are_inline; + } + } + + /** + * Merges one array into another, removes values which equal false + * @param $a1 Array by reference that is merged into + * @param $a2 Array that merges into $a1 + */ + private function _mergeAssocArray(&$a1, $a2) + { + foreach ($a2 as $k => $v) { + if ($v === false) { + if (isset($a1[$k])) { + unset($a1[$k]); + } + continue; + } + $a1[$k] = $v; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php new file mode 100644 index 0000000..40a2426 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php @@ -0,0 +1,617 @@ += $c) { + $r .= self::unsafeIconv($in, $out, substr($text, $i)); + break; + } + // wibble the boundary + if (0x80 != (0xC0 & ord($text[$i + $max_chunk_size]))) { + $chunk_size = $max_chunk_size; + } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 1]))) { + $chunk_size = $max_chunk_size - 1; + } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 2]))) { + $chunk_size = $max_chunk_size - 2; + } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 3]))) { + $chunk_size = $max_chunk_size - 3; + } else { + return false; // rather confusing UTF-8... + } + $chunk = substr($text, $i, $chunk_size); // substr doesn't mind overlong lengths + $r .= self::unsafeIconv($in, $out, $chunk); + $i += $chunk_size; + } + return $r; + } else { + return false; + } + } else { + return false; + } + } + + /** + * Cleans a UTF-8 string for well-formedness and SGML validity + * + * It will parse according to UTF-8 and return a valid UTF8 string, with + * non-SGML codepoints excluded. + * + * Specifically, it will permit: + * \x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF} + * Source: https://www.w3.org/TR/REC-xml/#NT-Char + * Arguably this function should be modernized to the HTML5 set + * of allowed characters: + * https://www.w3.org/TR/html5/syntax.html#preprocessing-the-input-stream + * which simultaneously expand and restrict the set of allowed characters. + * + * @param string $str The string to clean + * @param bool $force_php + * @return string + * + * @note Just for reference, the non-SGML code points are 0 to 31 and + * 127 to 159, inclusive. However, we allow code points 9, 10 + * and 13, which are the tab, line feed and carriage return + * respectively. 128 and above the code points map to multibyte + * UTF-8 representations. + * + * @note Fallback code adapted from utf8ToUnicode by Henri Sivonen and + * hsivonen@iki.fi at under the + * LGPL license. Notes on what changed are inside, but in general, + * the original code transformed UTF-8 text into an array of integer + * Unicode codepoints. Understandably, transforming that back to + * a string would be somewhat expensive, so the function was modded to + * directly operate on the string. However, this discourages code + * reuse, and the logic enumerated here would be useful for any + * function that needs to be able to understand UTF-8 characters. + * As of right now, only smart lossless character encoding converters + * would need that, and I'm probably not going to implement them. + */ + public static function cleanUTF8($str, $force_php = false) + { + // UTF-8 validity is checked since PHP 4.3.5 + // This is an optimization: if the string is already valid UTF-8, no + // need to do PHP stuff. 99% of the time, this will be the case. + if (preg_match( + '/^[\x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]*$/Du', + $str + )) { + return $str; + } + + $mState = 0; // cached expected number of octets after the current octet + // until the beginning of the next UTF8 character sequence + $mUcs4 = 0; // cached Unicode character + $mBytes = 1; // cached expected number of octets in the current sequence + + // original code involved an $out that was an array of Unicode + // codepoints. Instead of having to convert back into UTF-8, we've + // decided to directly append valid UTF-8 characters onto a string + // $out once they're done. $char accumulates raw bytes, while $mUcs4 + // turns into the Unicode code point, so there's some redundancy. + + $out = ''; + $char = ''; + + $len = strlen($str); + for ($i = 0; $i < $len; $i++) { + $in = ord($str[$i]); + $char .= $str[$i]; // append byte to char + if (0 == $mState) { + // When mState is zero we expect either a US-ASCII character + // or a multi-octet sequence. + if (0 == (0x80 & ($in))) { + // US-ASCII, pass straight through. + if (($in <= 31 || $in == 127) && + !($in == 9 || $in == 13 || $in == 10) // save \r\t\n + ) { + // control characters, remove + } else { + $out .= $char; + } + // reset + $char = ''; + $mBytes = 1; + } elseif (0xC0 == (0xE0 & ($in))) { + // First octet of 2 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x1F) << 6; + $mState = 1; + $mBytes = 2; + } elseif (0xE0 == (0xF0 & ($in))) { + // First octet of 3 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x0F) << 12; + $mState = 2; + $mBytes = 3; + } elseif (0xF0 == (0xF8 & ($in))) { + // First octet of 4 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x07) << 18; + $mState = 3; + $mBytes = 4; + } elseif (0xF8 == (0xFC & ($in))) { + // First octet of 5 octet sequence. + // + // This is illegal because the encoded codepoint must be + // either: + // (a) not the shortest form or + // (b) outside the Unicode range of 0-0x10FFFF. + // Rather than trying to resynchronize, we will carry on + // until the end of the sequence and let the later error + // handling code catch it. + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x03) << 24; + $mState = 4; + $mBytes = 5; + } elseif (0xFC == (0xFE & ($in))) { + // First octet of 6 octet sequence, see comments for 5 + // octet sequence. + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 1) << 30; + $mState = 5; + $mBytes = 6; + } else { + // Current octet is neither in the US-ASCII range nor a + // legal first octet of a multi-octet sequence. + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char = ''; + } + } else { + // When mState is non-zero, we expect a continuation of the + // multi-octet sequence + if (0x80 == (0xC0 & ($in))) { + // Legal continuation. + $shift = ($mState - 1) * 6; + $tmp = $in; + $tmp = ($tmp & 0x0000003F) << $shift; + $mUcs4 |= $tmp; + + if (0 == --$mState) { + // End of the multi-octet sequence. mUcs4 now contains + // the final Unicode codepoint to be output + + // Check for illegal sequences and codepoints. + + // From Unicode 3.1, non-shortest form is illegal + if (((2 == $mBytes) && ($mUcs4 < 0x0080)) || + ((3 == $mBytes) && ($mUcs4 < 0x0800)) || + ((4 == $mBytes) && ($mUcs4 < 0x10000)) || + (4 < $mBytes) || + // From Unicode 3.2, surrogate characters = illegal + (($mUcs4 & 0xFFFFF800) == 0xD800) || + // Codepoints outside the Unicode range are illegal + ($mUcs4 > 0x10FFFF) + ) { + + } elseif (0xFEFF != $mUcs4 && // omit BOM + // check for valid Char unicode codepoints + ( + 0x9 == $mUcs4 || + 0xA == $mUcs4 || + 0xD == $mUcs4 || + (0x20 <= $mUcs4 && 0x7E >= $mUcs4) || + // 7F-9F is not strictly prohibited by XML, + // but it is non-SGML, and thus we don't allow it + (0xA0 <= $mUcs4 && 0xD7FF >= $mUcs4) || + (0xE000 <= $mUcs4 && 0xFFFD >= $mUcs4) || + (0x10000 <= $mUcs4 && 0x10FFFF >= $mUcs4) + ) + ) { + $out .= $char; + } + // initialize UTF8 cache (reset) + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char = ''; + } + } else { + // ((0xC0 & (*in) != 0x80) && (mState != 0)) + // Incomplete multi-octet sequence. + // used to result in complete fail, but we'll reset + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char =''; + } + } + } + return $out; + } + + /** + * Translates a Unicode codepoint into its corresponding UTF-8 character. + * @note Based on Feyd's function at + * , + * which is in public domain. + * @note While we're going to do code point parsing anyway, a good + * optimization would be to refuse to translate code points that + * are non-SGML characters. However, this could lead to duplication. + * @note This is very similar to the unichr function in + * maintenance/generate-entity-file.php (although this is superior, + * due to its sanity checks). + */ + + // +----------+----------+----------+----------+ + // | 33222222 | 22221111 | 111111 | | + // | 10987654 | 32109876 | 54321098 | 76543210 | bit + // +----------+----------+----------+----------+ + // | | | | 0xxxxxxx | 1 byte 0x00000000..0x0000007F + // | | | 110yyyyy | 10xxxxxx | 2 byte 0x00000080..0x000007FF + // | | 1110zzzz | 10yyyyyy | 10xxxxxx | 3 byte 0x00000800..0x0000FFFF + // | 11110www | 10wwzzzz | 10yyyyyy | 10xxxxxx | 4 byte 0x00010000..0x0010FFFF + // +----------+----------+----------+----------+ + // | 00000000 | 00011111 | 11111111 | 11111111 | Theoretical upper limit of legal scalars: 2097151 (0x001FFFFF) + // | 00000000 | 00010000 | 11111111 | 11111111 | Defined upper limit of legal scalar codes + // +----------+----------+----------+----------+ + + public static function unichr($code) + { + if ($code > 1114111 or $code < 0 or + ($code >= 55296 and $code <= 57343) ) { + // bits are set outside the "valid" range as defined + // by UNICODE 4.1.0 + return ''; + } + + $x = $y = $z = $w = 0; + if ($code < 128) { + // regular ASCII character + $x = $code; + } else { + // set up bits for UTF-8 + $x = ($code & 63) | 128; + if ($code < 2048) { + $y = (($code & 2047) >> 6) | 192; + } else { + $y = (($code & 4032) >> 6) | 128; + if ($code < 65536) { + $z = (($code >> 12) & 15) | 224; + } else { + $z = (($code >> 12) & 63) | 128; + $w = (($code >> 18) & 7) | 240; + } + } + } + // set up the actual character + $ret = ''; + if ($w) { + $ret .= chr($w); + } + if ($z) { + $ret .= chr($z); + } + if ($y) { + $ret .= chr($y); + } + $ret .= chr($x); + + return $ret; + } + + /** + * @return bool + */ + public static function iconvAvailable() + { + static $iconv = null; + if ($iconv === null) { + $iconv = function_exists('iconv') && self::testIconvTruncateBug() != self::ICONV_UNUSABLE; + } + return $iconv; + } + + /** + * Convert a string to UTF-8 based on configuration. + * @param string $str The string to convert + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public static function convertToUTF8($str, $config, $context) + { + $encoding = $config->get('Core.Encoding'); + if ($encoding === 'utf-8') { + return $str; + } + static $iconv = null; + if ($iconv === null) { + $iconv = self::iconvAvailable(); + } + if ($iconv && !$config->get('Test.ForceNoIconv')) { + // unaffected by bugs, since UTF-8 support all characters + $str = self::unsafeIconv($encoding, 'utf-8//IGNORE', $str); + if ($str === false) { + // $encoding is not a valid encoding + trigger_error('Invalid encoding ' . $encoding, E_USER_ERROR); + return ''; + } + // If the string is bjorked by Shift_JIS or a similar encoding + // that doesn't support all of ASCII, convert the naughty + // characters to their true byte-wise ASCII/UTF-8 equivalents. + $str = strtr($str, self::testEncodingSupportsASCII($encoding)); + return $str; + } elseif ($encoding === 'iso-8859-1') { + $str = utf8_encode($str); + return $str; + } + $bug = HTMLPurifier_Encoder::testIconvTruncateBug(); + if ($bug == self::ICONV_OK) { + trigger_error('Encoding not supported, please install iconv', E_USER_ERROR); + } else { + trigger_error( + 'You have a buggy version of iconv, see https://bugs.php.net/bug.php?id=48147 ' . + 'and http://sourceware.org/bugzilla/show_bug.cgi?id=13541', + E_USER_ERROR + ); + } + } + + /** + * Converts a string from UTF-8 based on configuration. + * @param string $str The string to convert + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + * @note Currently, this is a lossy conversion, with unexpressable + * characters being omitted. + */ + public static function convertFromUTF8($str, $config, $context) + { + $encoding = $config->get('Core.Encoding'); + if ($escape = $config->get('Core.EscapeNonASCIICharacters')) { + $str = self::convertToASCIIDumbLossless($str); + } + if ($encoding === 'utf-8') { + return $str; + } + static $iconv = null; + if ($iconv === null) { + $iconv = self::iconvAvailable(); + } + if ($iconv && !$config->get('Test.ForceNoIconv')) { + // Undo our previous fix in convertToUTF8, otherwise iconv will barf + $ascii_fix = self::testEncodingSupportsASCII($encoding); + if (!$escape && !empty($ascii_fix)) { + $clear_fix = array(); + foreach ($ascii_fix as $utf8 => $native) { + $clear_fix[$utf8] = ''; + } + $str = strtr($str, $clear_fix); + } + $str = strtr($str, array_flip($ascii_fix)); + // Normal stuff + $str = self::iconv('utf-8', $encoding . '//IGNORE', $str); + return $str; + } elseif ($encoding === 'iso-8859-1') { + $str = utf8_decode($str); + return $str; + } + trigger_error('Encoding not supported', E_USER_ERROR); + // You might be tempted to assume that the ASCII representation + // might be OK, however, this is *not* universally true over all + // encodings. So we take the conservative route here, rather + // than forcibly turn on %Core.EscapeNonASCIICharacters + } + + /** + * Lossless (character-wise) conversion of HTML to ASCII + * @param string $str UTF-8 string to be converted to ASCII + * @return string ASCII encoded string with non-ASCII character entity-ized + * @warning Adapted from MediaWiki, claiming fair use: this is a common + * algorithm. If you disagree with this license fudgery, + * implement it yourself. + * @note Uses decimal numeric entities since they are best supported. + * @note This is a DUMB function: it has no concept of keeping + * character entities that the projected character encoding + * can allow. We could possibly implement a smart version + * but that would require it to also know which Unicode + * codepoints the charset supported (not an easy task). + * @note Sort of with cleanUTF8() but it assumes that $str is + * well-formed UTF-8 + */ + public static function convertToASCIIDumbLossless($str) + { + $bytesleft = 0; + $result = ''; + $working = 0; + $len = strlen($str); + for ($i = 0; $i < $len; $i++) { + $bytevalue = ord($str[$i]); + if ($bytevalue <= 0x7F) { //0xxx xxxx + $result .= chr($bytevalue); + $bytesleft = 0; + } elseif ($bytevalue <= 0xBF) { //10xx xxxx + $working = $working << 6; + $working += ($bytevalue & 0x3F); + $bytesleft--; + if ($bytesleft <= 0) { + $result .= "&#" . $working . ";"; + } + } elseif ($bytevalue <= 0xDF) { //110x xxxx + $working = $bytevalue & 0x1F; + $bytesleft = 1; + } elseif ($bytevalue <= 0xEF) { //1110 xxxx + $working = $bytevalue & 0x0F; + $bytesleft = 2; + } else { //1111 0xxx + $working = $bytevalue & 0x07; + $bytesleft = 3; + } + } + return $result; + } + + /** No bugs detected in iconv. */ + const ICONV_OK = 0; + + /** Iconv truncates output if converting from UTF-8 to another + * character set with //IGNORE, and a non-encodable character is found */ + const ICONV_TRUNCATES = 1; + + /** Iconv does not support //IGNORE, making it unusable for + * transcoding purposes */ + const ICONV_UNUSABLE = 2; + + /** + * glibc iconv has a known bug where it doesn't handle the magic + * //IGNORE stanza correctly. In particular, rather than ignore + * characters, it will return an EILSEQ after consuming some number + * of characters, and expect you to restart iconv as if it were + * an E2BIG. Old versions of PHP did not respect the errno, and + * returned the fragment, so as a result you would see iconv + * mysteriously truncating output. We can work around this by + * manually chopping our input into segments of about 8000 + * characters, as long as PHP ignores the error code. If PHP starts + * paying attention to the error code, iconv becomes unusable. + * + * @return int Error code indicating severity of bug. + */ + public static function testIconvTruncateBug() + { + static $code = null; + if ($code === null) { + // better not use iconv, otherwise infinite loop! + $r = self::unsafeIconv('utf-8', 'ascii//IGNORE', "\xCE\xB1" . str_repeat('a', 9000)); + if ($r === false) { + $code = self::ICONV_UNUSABLE; + } elseif (($c = strlen($r)) < 9000) { + $code = self::ICONV_TRUNCATES; + } elseif ($c > 9000) { + trigger_error( + 'Your copy of iconv is extremely buggy. Please notify HTML Purifier maintainers: ' . + 'include your iconv version as per phpversion()', + E_USER_ERROR + ); + } else { + $code = self::ICONV_OK; + } + } + return $code; + } + + /** + * This expensive function tests whether or not a given character + * encoding supports ASCII. 7/8-bit encodings like Shift_JIS will + * fail this test, and require special processing. Variable width + * encodings shouldn't ever fail. + * + * @param string $encoding Encoding name to test, as per iconv format + * @param bool $bypass Whether or not to bypass the precompiled arrays. + * @return Array of UTF-8 characters to their corresponding ASCII, + * which can be used to "undo" any overzealous iconv action. + */ + public static function testEncodingSupportsASCII($encoding, $bypass = false) + { + // All calls to iconv here are unsafe, proof by case analysis: + // If ICONV_OK, no difference. + // If ICONV_TRUNCATE, all calls involve one character inputs, + // so bug is not triggered. + // If ICONV_UNUSABLE, this call is irrelevant + static $encodings = array(); + if (!$bypass) { + if (isset($encodings[$encoding])) { + return $encodings[$encoding]; + } + $lenc = strtolower($encoding); + switch ($lenc) { + case 'shift_jis': + return array("\xC2\xA5" => '\\', "\xE2\x80\xBE" => '~'); + case 'johab': + return array("\xE2\x82\xA9" => '\\'); + } + if (strpos($lenc, 'iso-8859-') === 0) { + return array(); + } + } + $ret = array(); + if (self::unsafeIconv('UTF-8', $encoding, 'a') === false) { + return false; + } + for ($i = 0x20; $i <= 0x7E; $i++) { // all printable ASCII chars + $c = chr($i); // UTF-8 char + $r = self::unsafeIconv('UTF-8', "$encoding//IGNORE", $c); // initial conversion + if ($r === '' || + // This line is needed for iconv implementations that do not + // omit characters that do not exist in the target character set + ($r === $c && self::unsafeIconv($encoding, 'UTF-8//IGNORE', $r) !== $c) + ) { + // Reverse engineer: what's the UTF-8 equiv of this byte + // sequence? This assumes that there's no variable width + // encoding that doesn't support ASCII. + $ret[self::unsafeIconv($encoding, 'UTF-8//IGNORE', $c)] = $c; + } + } + $encodings[$encoding] = $ret; + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php new file mode 100644 index 0000000..f12ff13 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php @@ -0,0 +1,48 @@ +table = unserialize(file_get_contents($file)); + } + + /** + * Retrieves sole instance of the object. + * @param bool|HTMLPurifier_EntityLookup $prototype Optional prototype of custom lookup table to overload with. + * @return HTMLPurifier_EntityLookup + */ + public static function instance($prototype = false) + { + // no references, since PHP doesn't copy unless modified + static $instance = null; + if ($prototype) { + $instance = $prototype; + } elseif (!$instance) { + $instance = new HTMLPurifier_EntityLookup(); + $instance->setup(); + } + return $instance; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser new file mode 100644 index 0000000..e8b0812 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser @@ -0,0 +1 @@ +a:253:{s:4:"fnof";s:2:"ƒ";s:5:"Alpha";s:2:"Α";s:4:"Beta";s:2:"Β";s:5:"Gamma";s:2:"Γ";s:5:"Delta";s:2:"Δ";s:7:"Epsilon";s:2:"Ε";s:4:"Zeta";s:2:"Ζ";s:3:"Eta";s:2:"Η";s:5:"Theta";s:2:"Θ";s:4:"Iota";s:2:"Ι";s:5:"Kappa";s:2:"Κ";s:6:"Lambda";s:2:"Λ";s:2:"Mu";s:2:"Μ";s:2:"Nu";s:2:"Ν";s:2:"Xi";s:2:"Ξ";s:7:"Omicron";s:2:"Ο";s:2:"Pi";s:2:"Π";s:3:"Rho";s:2:"Ρ";s:5:"Sigma";s:2:"Σ";s:3:"Tau";s:2:"Τ";s:7:"Upsilon";s:2:"Υ";s:3:"Phi";s:2:"Φ";s:3:"Chi";s:2:"Χ";s:3:"Psi";s:2:"Ψ";s:5:"Omega";s:2:"Ω";s:5:"alpha";s:2:"α";s:4:"beta";s:2:"β";s:5:"gamma";s:2:"γ";s:5:"delta";s:2:"δ";s:7:"epsilon";s:2:"ε";s:4:"zeta";s:2:"ζ";s:3:"eta";s:2:"η";s:5:"theta";s:2:"θ";s:4:"iota";s:2:"ι";s:5:"kappa";s:2:"κ";s:6:"lambda";s:2:"λ";s:2:"mu";s:2:"μ";s:2:"nu";s:2:"ν";s:2:"xi";s:2:"ξ";s:7:"omicron";s:2:"ο";s:2:"pi";s:2:"π";s:3:"rho";s:2:"ρ";s:6:"sigmaf";s:2:"ς";s:5:"sigma";s:2:"σ";s:3:"tau";s:2:"τ";s:7:"upsilon";s:2:"υ";s:3:"phi";s:2:"φ";s:3:"chi";s:2:"χ";s:3:"psi";s:2:"ψ";s:5:"omega";s:2:"ω";s:8:"thetasym";s:2:"ϑ";s:5:"upsih";s:2:"ϒ";s:3:"piv";s:2:"ϖ";s:4:"bull";s:3:"•";s:6:"hellip";s:3:"…";s:5:"prime";s:3:"′";s:5:"Prime";s:3:"″";s:5:"oline";s:3:"‾";s:5:"frasl";s:3:"⁄";s:6:"weierp";s:3:"℘";s:5:"image";s:3:"ℑ";s:4:"real";s:3:"ℜ";s:5:"trade";s:3:"™";s:7:"alefsym";s:3:"ℵ";s:4:"larr";s:3:"←";s:4:"uarr";s:3:"↑";s:4:"rarr";s:3:"→";s:4:"darr";s:3:"↓";s:4:"harr";s:3:"↔";s:5:"crarr";s:3:"↵";s:4:"lArr";s:3:"⇐";s:4:"uArr";s:3:"⇑";s:4:"rArr";s:3:"⇒";s:4:"dArr";s:3:"⇓";s:4:"hArr";s:3:"⇔";s:6:"forall";s:3:"∀";s:4:"part";s:3:"∂";s:5:"exist";s:3:"∃";s:5:"empty";s:3:"∅";s:5:"nabla";s:3:"∇";s:4:"isin";s:3:"∈";s:5:"notin";s:3:"∉";s:2:"ni";s:3:"∋";s:4:"prod";s:3:"∏";s:3:"sum";s:3:"∑";s:5:"minus";s:3:"−";s:6:"lowast";s:3:"∗";s:5:"radic";s:3:"√";s:4:"prop";s:3:"∝";s:5:"infin";s:3:"∞";s:3:"ang";s:3:"∠";s:3:"and";s:3:"∧";s:2:"or";s:3:"∨";s:3:"cap";s:3:"∩";s:3:"cup";s:3:"∪";s:3:"int";s:3:"∫";s:6:"there4";s:3:"∴";s:3:"sim";s:3:"∼";s:4:"cong";s:3:"≅";s:5:"asymp";s:3:"≈";s:2:"ne";s:3:"≠";s:5:"equiv";s:3:"≡";s:2:"le";s:3:"≤";s:2:"ge";s:3:"≥";s:3:"sub";s:3:"⊂";s:3:"sup";s:3:"⊃";s:4:"nsub";s:3:"⊄";s:4:"sube";s:3:"⊆";s:4:"supe";s:3:"⊇";s:5:"oplus";s:3:"⊕";s:6:"otimes";s:3:"⊗";s:4:"perp";s:3:"⊥";s:4:"sdot";s:3:"⋅";s:5:"lceil";s:3:"⌈";s:5:"rceil";s:3:"⌉";s:6:"lfloor";s:3:"⌊";s:6:"rfloor";s:3:"⌋";s:4:"lang";s:3:"〈";s:4:"rang";s:3:"〉";s:3:"loz";s:3:"◊";s:6:"spades";s:3:"♠";s:5:"clubs";s:3:"♣";s:6:"hearts";s:3:"♥";s:5:"diams";s:3:"♦";s:4:"quot";s:1:""";s:3:"amp";s:1:"&";s:2:"lt";s:1:"<";s:2:"gt";s:1:">";s:4:"apos";s:1:"'";s:5:"OElig";s:2:"Œ";s:5:"oelig";s:2:"œ";s:6:"Scaron";s:2:"Š";s:6:"scaron";s:2:"š";s:4:"Yuml";s:2:"Ÿ";s:4:"circ";s:2:"ˆ";s:5:"tilde";s:2:"˜";s:4:"ensp";s:3:" ";s:4:"emsp";s:3:" ";s:6:"thinsp";s:3:" ";s:4:"zwnj";s:3:"‌";s:3:"zwj";s:3:"‍";s:3:"lrm";s:3:"‎";s:3:"rlm";s:3:"‏";s:5:"ndash";s:3:"–";s:5:"mdash";s:3:"—";s:5:"lsquo";s:3:"‘";s:5:"rsquo";s:3:"’";s:5:"sbquo";s:3:"‚";s:5:"ldquo";s:3:"“";s:5:"rdquo";s:3:"”";s:5:"bdquo";s:3:"„";s:6:"dagger";s:3:"†";s:6:"Dagger";s:3:"‡";s:6:"permil";s:3:"‰";s:6:"lsaquo";s:3:"‹";s:6:"rsaquo";s:3:"›";s:4:"euro";s:3:"€";s:4:"nbsp";s:2:" ";s:5:"iexcl";s:2:"¡";s:4:"cent";s:2:"¢";s:5:"pound";s:2:"£";s:6:"curren";s:2:"¤";s:3:"yen";s:2:"¥";s:6:"brvbar";s:2:"¦";s:4:"sect";s:2:"§";s:3:"uml";s:2:"¨";s:4:"copy";s:2:"©";s:4:"ordf";s:2:"ª";s:5:"laquo";s:2:"«";s:3:"not";s:2:"¬";s:3:"shy";s:2:"­";s:3:"reg";s:2:"®";s:4:"macr";s:2:"¯";s:3:"deg";s:2:"°";s:6:"plusmn";s:2:"±";s:4:"sup2";s:2:"²";s:4:"sup3";s:2:"³";s:5:"acute";s:2:"´";s:5:"micro";s:2:"µ";s:4:"para";s:2:"¶";s:6:"middot";s:2:"·";s:5:"cedil";s:2:"¸";s:4:"sup1";s:2:"¹";s:4:"ordm";s:2:"º";s:5:"raquo";s:2:"»";s:6:"frac14";s:2:"¼";s:6:"frac12";s:2:"½";s:6:"frac34";s:2:"¾";s:6:"iquest";s:2:"¿";s:6:"Agrave";s:2:"À";s:6:"Aacute";s:2:"Á";s:5:"Acirc";s:2:"Â";s:6:"Atilde";s:2:"Ã";s:4:"Auml";s:2:"Ä";s:5:"Aring";s:2:"Å";s:5:"AElig";s:2:"Æ";s:6:"Ccedil";s:2:"Ç";s:6:"Egrave";s:2:"È";s:6:"Eacute";s:2:"É";s:5:"Ecirc";s:2:"Ê";s:4:"Euml";s:2:"Ë";s:6:"Igrave";s:2:"Ì";s:6:"Iacute";s:2:"Í";s:5:"Icirc";s:2:"Î";s:4:"Iuml";s:2:"Ï";s:3:"ETH";s:2:"Ð";s:6:"Ntilde";s:2:"Ñ";s:6:"Ograve";s:2:"Ò";s:6:"Oacute";s:2:"Ó";s:5:"Ocirc";s:2:"Ô";s:6:"Otilde";s:2:"Õ";s:4:"Ouml";s:2:"Ö";s:5:"times";s:2:"×";s:6:"Oslash";s:2:"Ø";s:6:"Ugrave";s:2:"Ù";s:6:"Uacute";s:2:"Ú";s:5:"Ucirc";s:2:"Û";s:4:"Uuml";s:2:"Ü";s:6:"Yacute";s:2:"Ý";s:5:"THORN";s:2:"Þ";s:5:"szlig";s:2:"ß";s:6:"agrave";s:2:"à";s:6:"aacute";s:2:"á";s:5:"acirc";s:2:"â";s:6:"atilde";s:2:"ã";s:4:"auml";s:2:"ä";s:5:"aring";s:2:"å";s:5:"aelig";s:2:"æ";s:6:"ccedil";s:2:"ç";s:6:"egrave";s:2:"è";s:6:"eacute";s:2:"é";s:5:"ecirc";s:2:"ê";s:4:"euml";s:2:"ë";s:6:"igrave";s:2:"ì";s:6:"iacute";s:2:"í";s:5:"icirc";s:2:"î";s:4:"iuml";s:2:"ï";s:3:"eth";s:2:"ð";s:6:"ntilde";s:2:"ñ";s:6:"ograve";s:2:"ò";s:6:"oacute";s:2:"ó";s:5:"ocirc";s:2:"ô";s:6:"otilde";s:2:"õ";s:4:"ouml";s:2:"ö";s:6:"divide";s:2:"÷";s:6:"oslash";s:2:"ø";s:6:"ugrave";s:2:"ù";s:6:"uacute";s:2:"ú";s:5:"ucirc";s:2:"û";s:4:"uuml";s:2:"ü";s:6:"yacute";s:2:"ý";s:5:"thorn";s:2:"þ";s:4:"yuml";s:2:"ÿ";} \ No newline at end of file diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php new file mode 100644 index 0000000..3ef2d09 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php @@ -0,0 +1,285 @@ +_semiOptionalPrefixRegex = "/&()()()($semi_optional)/"; + + $this->_textEntitiesRegex = + '/&(?:'. + // hex + '[#]x([a-fA-F0-9]+);?|'. + // dec + '[#]0*(\d+);?|'. + // string (mandatory semicolon) + // NB: order matters: match semicolon preferentially + '([A-Za-z_:][A-Za-z0-9.\-_:]*);|'. + // string (optional semicolon) + "($semi_optional)". + ')/'; + + $this->_attrEntitiesRegex = + '/&(?:'. + // hex + '[#]x([a-fA-F0-9]+);?|'. + // dec + '[#]0*(\d+);?|'. + // string (mandatory semicolon) + // NB: order matters: match semicolon preferentially + '([A-Za-z_:][A-Za-z0-9.\-_:]*);|'. + // string (optional semicolon) + // don't match if trailing is equals or alphanumeric (URL + // like) + "($semi_optional)(?![=;A-Za-z0-9])". + ')/'; + + } + + /** + * Substitute entities with the parsed equivalents. Use this on + * textual data in an HTML document (as opposed to attributes.) + * + * @param string $string String to have entities parsed. + * @return string Parsed string. + */ + public function substituteTextEntities($string) + { + return preg_replace_callback( + $this->_textEntitiesRegex, + array($this, 'entityCallback'), + $string + ); + } + + /** + * Substitute entities with the parsed equivalents. Use this on + * attribute contents in documents. + * + * @param string $string String to have entities parsed. + * @return string Parsed string. + */ + public function substituteAttrEntities($string) + { + return preg_replace_callback( + $this->_attrEntitiesRegex, + array($this, 'entityCallback'), + $string + ); + } + + /** + * Callback function for substituteNonSpecialEntities() that does the work. + * + * @param array $matches PCRE matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @return string Replacement string. + */ + + protected function entityCallback($matches) + { + $entity = $matches[0]; + $hex_part = @$matches[1]; + $dec_part = @$matches[2]; + $named_part = empty($matches[3]) ? (empty($matches[4]) ? "" : $matches[4]) : $matches[3]; + if ($hex_part !== NULL && $hex_part !== "") { + return HTMLPurifier_Encoder::unichr(hexdec($hex_part)); + } elseif ($dec_part !== NULL && $dec_part !== "") { + return HTMLPurifier_Encoder::unichr((int) $dec_part); + } else { + if (!$this->_entity_lookup) { + $this->_entity_lookup = HTMLPurifier_EntityLookup::instance(); + } + if (isset($this->_entity_lookup->table[$named_part])) { + return $this->_entity_lookup->table[$named_part]; + } else { + // exact match didn't match anything, so test if + // any of the semicolon optional match the prefix. + // Test that this is an EXACT match is important to + // prevent infinite loop + if (!empty($matches[3])) { + return preg_replace_callback( + $this->_semiOptionalPrefixRegex, + array($this, 'entityCallback'), + $entity + ); + } + return $entity; + } + } + } + + // LEGACY CODE BELOW + + /** + * Callback regex string for parsing entities. + * @type string + */ + protected $_substituteEntitiesRegex = + '/&(?:[#]x([a-fA-F0-9]+)|[#]0*(\d+)|([A-Za-z_:][A-Za-z0-9.\-_:]*));?/'; + // 1. hex 2. dec 3. string (XML style) + + /** + * Decimal to parsed string conversion table for special entities. + * @type array + */ + protected $_special_dec2str = + array( + 34 => '"', + 38 => '&', + 39 => "'", + 60 => '<', + 62 => '>' + ); + + /** + * Stripped entity names to decimal conversion table for special entities. + * @type array + */ + protected $_special_ent2dec = + array( + 'quot' => 34, + 'amp' => 38, + 'lt' => 60, + 'gt' => 62 + ); + + /** + * Substitutes non-special entities with their parsed equivalents. Since + * running this whenever you have parsed character is t3h 5uck, we run + * it before everything else. + * + * @param string $string String to have non-special entities parsed. + * @return string Parsed string. + */ + public function substituteNonSpecialEntities($string) + { + // it will try to detect missing semicolons, but don't rely on it + return preg_replace_callback( + $this->_substituteEntitiesRegex, + array($this, 'nonSpecialEntityCallback'), + $string + ); + } + + /** + * Callback function for substituteNonSpecialEntities() that does the work. + * + * @param array $matches PCRE matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @return string Replacement string. + */ + + protected function nonSpecialEntityCallback($matches) + { + // replaces all but big five + $entity = $matches[0]; + $is_num = (@$matches[0][1] === '#'); + if ($is_num) { + $is_hex = (@$entity[2] === 'x'); + $code = $is_hex ? hexdec($matches[1]) : (int) $matches[2]; + // abort for special characters + if (isset($this->_special_dec2str[$code])) { + return $entity; + } + return HTMLPurifier_Encoder::unichr($code); + } else { + if (isset($this->_special_ent2dec[$matches[3]])) { + return $entity; + } + if (!$this->_entity_lookup) { + $this->_entity_lookup = HTMLPurifier_EntityLookup::instance(); + } + if (isset($this->_entity_lookup->table[$matches[3]])) { + return $this->_entity_lookup->table[$matches[3]]; + } else { + return $entity; + } + } + } + + /** + * Substitutes only special entities with their parsed equivalents. + * + * @notice We try to avoid calling this function because otherwise, it + * would have to be called a lot (for every parsed section). + * + * @param string $string String to have non-special entities parsed. + * @return string Parsed string. + */ + public function substituteSpecialEntities($string) + { + return preg_replace_callback( + $this->_substituteEntitiesRegex, + array($this, 'specialEntityCallback'), + $string + ); + } + + /** + * Callback function for substituteSpecialEntities() that does the work. + * + * This callback has same syntax as nonSpecialEntityCallback(). + * + * @param array $matches PCRE-style matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @return string Replacement string. + */ + protected function specialEntityCallback($matches) + { + $entity = $matches[0]; + $is_num = (@$matches[0][1] === '#'); + if ($is_num) { + $is_hex = (@$entity[2] === 'x'); + $int = $is_hex ? hexdec($matches[1]) : (int) $matches[2]; + return isset($this->_special_dec2str[$int]) ? + $this->_special_dec2str[$int] : + $entity; + } else { + return isset($this->_special_ent2dec[$matches[3]]) ? + $this->_special_dec2str[$this->_special_ent2dec[$matches[3]]] : + $entity; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php new file mode 100644 index 0000000..d47e3f2 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php @@ -0,0 +1,244 @@ +locale =& $context->get('Locale'); + $this->context = $context; + $this->_current =& $this->_stacks[0]; + $this->errors =& $this->_stacks[0]; + } + + /** + * Sends an error message to the collector for later use + * @param int $severity Error severity, PHP error style (don't use E_USER_) + * @param string $msg Error message text + */ + public function send($severity, $msg) + { + $args = array(); + if (func_num_args() > 2) { + $args = func_get_args(); + array_shift($args); + unset($args[0]); + } + + $token = $this->context->get('CurrentToken', true); + $line = $token ? $token->line : $this->context->get('CurrentLine', true); + $col = $token ? $token->col : $this->context->get('CurrentCol', true); + $attr = $this->context->get('CurrentAttr', true); + + // perform special substitutions, also add custom parameters + $subst = array(); + if (!is_null($token)) { + $args['CurrentToken'] = $token; + } + if (!is_null($attr)) { + $subst['$CurrentAttr.Name'] = $attr; + if (isset($token->attr[$attr])) { + $subst['$CurrentAttr.Value'] = $token->attr[$attr]; + } + } + + if (empty($args)) { + $msg = $this->locale->getMessage($msg); + } else { + $msg = $this->locale->formatMessage($msg, $args); + } + + if (!empty($subst)) { + $msg = strtr($msg, $subst); + } + + // (numerically indexed) + $error = array( + self::LINENO => $line, + self::SEVERITY => $severity, + self::MESSAGE => $msg, + self::CHILDREN => array() + ); + $this->_current[] = $error; + + // NEW CODE BELOW ... + // Top-level errors are either: + // TOKEN type, if $value is set appropriately, or + // "syntax" type, if $value is null + $new_struct = new HTMLPurifier_ErrorStruct(); + $new_struct->type = HTMLPurifier_ErrorStruct::TOKEN; + if ($token) { + $new_struct->value = clone $token; + } + if (is_int($line) && is_int($col)) { + if (isset($this->lines[$line][$col])) { + $struct = $this->lines[$line][$col]; + } else { + $struct = $this->lines[$line][$col] = $new_struct; + } + // These ksorts may present a performance problem + ksort($this->lines[$line], SORT_NUMERIC); + } else { + if (isset($this->lines[-1])) { + $struct = $this->lines[-1]; + } else { + $struct = $this->lines[-1] = $new_struct; + } + } + ksort($this->lines, SORT_NUMERIC); + + // Now, check if we need to operate on a lower structure + if (!empty($attr)) { + $struct = $struct->getChild(HTMLPurifier_ErrorStruct::ATTR, $attr); + if (!$struct->value) { + $struct->value = array($attr, 'PUT VALUE HERE'); + } + } + if (!empty($cssprop)) { + $struct = $struct->getChild(HTMLPurifier_ErrorStruct::CSSPROP, $cssprop); + if (!$struct->value) { + // if we tokenize CSS this might be a little more difficult to do + $struct->value = array($cssprop, 'PUT VALUE HERE'); + } + } + + // Ok, structs are all setup, now time to register the error + $struct->addError($severity, $msg); + } + + /** + * Retrieves raw error data for custom formatter to use + */ + public function getRaw() + { + return $this->errors; + } + + /** + * Default HTML formatting implementation for error messages + * @param HTMLPurifier_Config $config Configuration, vital for HTML output nature + * @param array $errors Errors array to display; used for recursion. + * @return string + */ + public function getHTMLFormatted($config, $errors = null) + { + $ret = array(); + + $this->generator = new HTMLPurifier_Generator($config, $this->context); + if ($errors === null) { + $errors = $this->errors; + } + + // 'At line' message needs to be removed + + // generation code for new structure goes here. It needs to be recursive. + foreach ($this->lines as $line => $col_array) { + if ($line == -1) { + continue; + } + foreach ($col_array as $col => $struct) { + $this->_renderStruct($ret, $struct, $line, $col); + } + } + if (isset($this->lines[-1])) { + $this->_renderStruct($ret, $this->lines[-1]); + } + + if (empty($errors)) { + return '

' . $this->locale->getMessage('ErrorCollector: No errors') . '

'; + } else { + return '
  • ' . implode('
  • ', $ret) . '
'; + } + + } + + private function _renderStruct(&$ret, $struct, $line = null, $col = null) + { + $stack = array($struct); + $context_stack = array(array()); + while ($current = array_pop($stack)) { + $context = array_pop($context_stack); + foreach ($current->errors as $error) { + list($severity, $msg) = $error; + $string = ''; + $string .= '
'; + // W3C uses an icon to indicate the severity of the error. + $error = $this->locale->getErrorName($severity); + $string .= "$error "; + if (!is_null($line) && !is_null($col)) { + $string .= "Line $line, Column $col: "; + } else { + $string .= 'End of Document: '; + } + $string .= '' . $this->generator->escape($msg) . ' '; + $string .= '
'; + // Here, have a marker for the character on the column appropriate. + // Be sure to clip extremely long lines. + //$string .= '
';
+                //$string .= '';
+                //$string .= '
'; + $ret[] = $string; + } + foreach ($current->children as $array) { + $context[] = $current; + $stack = array_merge($stack, array_reverse($array, true)); + for ($i = count($array); $i > 0; $i--) { + $context_stack[] = $context; + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php new file mode 100644 index 0000000..cf869d3 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php @@ -0,0 +1,74 @@ +children[$type][$id])) { + $this->children[$type][$id] = new HTMLPurifier_ErrorStruct(); + $this->children[$type][$id]->type = $type; + } + return $this->children[$type][$id]; + } + + /** + * @param int $severity + * @param string $message + */ + public function addError($severity, $message) + { + $this->errors[] = array($severity, $message); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php new file mode 100644 index 0000000..be85b4c --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php @@ -0,0 +1,12 @@ +preFilter, + * 2->preFilter, 3->preFilter, purify, 3->postFilter, 2->postFilter, + * 1->postFilter. + * + * @note Methods are not declared abstract as it is perfectly legitimate + * for an implementation not to want anything to happen on a step + */ + +class HTMLPurifier_Filter +{ + + /** + * Name of the filter for identification purposes. + * @type string + */ + public $name; + + /** + * Pre-processor function, handles HTML before HTML Purifier + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function preFilter($html, $config, $context) + { + return $html; + } + + /** + * Post-processor function, handles HTML after HTML Purifier + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + return $html; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php new file mode 100644 index 0000000..66f70b0 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php @@ -0,0 +1,341 @@ + blocks from input HTML, cleans them up + * using CSSTidy, and then places them in $purifier->context->get('StyleBlocks') + * so they can be used elsewhere in the document. + * + * @note + * See tests/HTMLPurifier/Filter/ExtractStyleBlocksTest.php for + * sample usage. + * + * @note + * This filter can also be used on stylesheets not included in the + * document--something purists would probably prefer. Just directly + * call HTMLPurifier_Filter_ExtractStyleBlocks->cleanCSS() + */ +class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter +{ + /** + * @type string + */ + public $name = 'ExtractStyleBlocks'; + + /** + * @type array + */ + private $_styleMatches = array(); + + /** + * @type csstidy + */ + private $_tidy; + + /** + * @type HTMLPurifier_AttrDef_HTML_ID + */ + private $_id_attrdef; + + /** + * @type HTMLPurifier_AttrDef_CSS_Ident + */ + private $_class_attrdef; + + /** + * @type HTMLPurifier_AttrDef_Enum + */ + private $_enum_attrdef; + + public function __construct() + { + $this->_tidy = new csstidy(); + $this->_tidy->set_cfg('lowercase_s', false); + $this->_id_attrdef = new HTMLPurifier_AttrDef_HTML_ID(true); + $this->_class_attrdef = new HTMLPurifier_AttrDef_CSS_Ident(); + $this->_enum_attrdef = new HTMLPurifier_AttrDef_Enum( + array( + 'first-child', + 'link', + 'visited', + 'active', + 'hover', + 'focus' + ) + ); + } + + /** + * Save the contents of CSS blocks to style matches + * @param array $matches preg_replace style $matches array + */ + protected function styleCallback($matches) + { + $this->_styleMatches[] = $matches[1]; + } + + /** + * Removes inline + // we must not grab foo in a font-family prop). + if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { + $css = str_replace( + array('<', '>', '&'), + array('\3C ', '\3E ', '\26 '), + $css + ); + } + return $css; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php new file mode 100644 index 0000000..276d836 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php @@ -0,0 +1,65 @@ +]+>.+?' . + '(?:http:)?//www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?
#s'; + $pre_replace = '\1'; + return preg_replace($pre_regex, $pre_replace, $html); + } + + /** + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + $post_regex = '#((?:v|cp)/[A-Za-z0-9\-_=]+)#'; + return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); + } + + /** + * @param $url + * @return string + */ + protected function armorUrl($url) + { + return str_replace('--', '--', $url); + } + + /** + * @param array $matches + * @return string + */ + protected function postFilterCallback($matches) + { + $url = $this->armorUrl($matches[1]); + return '' . + '' . + '' . + ''; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php new file mode 100644 index 0000000..eb56e2d --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php @@ -0,0 +1,286 @@ + tags. + * @type bool + */ + private $_scriptFix = false; + + /** + * Cache of HTMLDefinition during HTML output to determine whether or + * not attributes should be minimized. + * @type HTMLPurifier_HTMLDefinition + */ + private $_def; + + /** + * Cache of %Output.SortAttr. + * @type bool + */ + private $_sortAttr; + + /** + * Cache of %Output.FlashCompat. + * @type bool + */ + private $_flashCompat; + + /** + * Cache of %Output.FixInnerHTML. + * @type bool + */ + private $_innerHTMLFix; + + /** + * Stack for keeping track of object information when outputting IE + * compatibility code. + * @type array + */ + private $_flashStack = array(); + + /** + * Configuration for the generator + * @type HTMLPurifier_Config + */ + protected $config; + + /** + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + */ + public function __construct($config, $context) + { + $this->config = $config; + $this->_scriptFix = $config->get('Output.CommentScriptContents'); + $this->_innerHTMLFix = $config->get('Output.FixInnerHTML'); + $this->_sortAttr = $config->get('Output.SortAttr'); + $this->_flashCompat = $config->get('Output.FlashCompat'); + $this->_def = $config->getHTMLDefinition(); + $this->_xhtml = $this->_def->doctype->xml; + } + + /** + * Generates HTML from an array of tokens. + * @param HTMLPurifier_Token[] $tokens Array of HTMLPurifier_Token + * @return string Generated HTML + */ + public function generateFromTokens($tokens) + { + if (!$tokens) { + return ''; + } + + // Basic algorithm + $html = ''; + for ($i = 0, $size = count($tokens); $i < $size; $i++) { + if ($this->_scriptFix && $tokens[$i]->name === 'script' + && $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) { + // script special case + // the contents of the script block must be ONE token + // for this to work. + $html .= $this->generateFromToken($tokens[$i++]); + $html .= $this->generateScriptFromToken($tokens[$i++]); + } + $html .= $this->generateFromToken($tokens[$i]); + } + + // Tidy cleanup + if (extension_loaded('tidy') && $this->config->get('Output.TidyFormat')) { + $tidy = new Tidy; + $tidy->parseString( + $html, + array( + 'indent'=> true, + 'output-xhtml' => $this->_xhtml, + 'show-body-only' => true, + 'indent-spaces' => 2, + 'wrap' => 68, + ), + 'utf8' + ); + $tidy->cleanRepair(); + $html = (string) $tidy; // explicit cast necessary + } + + // Normalize newlines to system defined value + if ($this->config->get('Core.NormalizeNewlines')) { + $nl = $this->config->get('Output.Newline'); + if ($nl === null) { + $nl = PHP_EOL; + } + if ($nl !== "\n") { + $html = str_replace("\n", $nl, $html); + } + } + return $html; + } + + /** + * Generates HTML from a single token. + * @param HTMLPurifier_Token $token HTMLPurifier_Token object. + * @return string Generated HTML + */ + public function generateFromToken($token) + { + if (!$token instanceof HTMLPurifier_Token) { + trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING); + return ''; + + } elseif ($token instanceof HTMLPurifier_Token_Start) { + $attr = $this->generateAttributes($token->attr, $token->name); + if ($this->_flashCompat) { + if ($token->name == "object") { + $flash = new stdClass(); + $flash->attr = $token->attr; + $flash->param = array(); + $this->_flashStack[] = $flash; + } + } + return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_End) { + $_extra = ''; + if ($this->_flashCompat) { + if ($token->name == "object" && !empty($this->_flashStack)) { + // doesn't do anything for now + } + } + return $_extra . 'name . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + if ($this->_flashCompat && $token->name == "param" && !empty($this->_flashStack)) { + $this->_flashStack[count($this->_flashStack)-1]->param[$token->attr['name']] = $token->attr['value']; + } + $attr = $this->generateAttributes($token->attr, $token->name); + return '<' . $token->name . ($attr ? ' ' : '') . $attr . + ( $this->_xhtml ? ' /': '' ) //
v.
+ . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Text) { + return $this->escape($token->data, ENT_NOQUOTES); + + } elseif ($token instanceof HTMLPurifier_Token_Comment) { + return ''; + } else { + return ''; + + } + } + + /** + * Special case processor for the contents of script tags + * @param HTMLPurifier_Token $token HTMLPurifier_Token object. + * @return string + * @warning This runs into problems if there's already a literal + * --> somewhere inside the script contents. + */ + public function generateScriptFromToken($token) + { + if (!$token instanceof HTMLPurifier_Token_Text) { + return $this->generateFromToken($token); + } + // Thanks + $data = preg_replace('#//\s*$#', '', $token->data); + return ''; + } + + /** + * Generates attribute declarations from attribute array. + * @note This does not include the leading or trailing space. + * @param array $assoc_array_of_attributes Attribute array + * @param string $element Name of element attributes are for, used to check + * attribute minimization. + * @return string Generated HTML fragment for insertion. + */ + public function generateAttributes($assoc_array_of_attributes, $element = '') + { + $html = ''; + if ($this->_sortAttr) { + ksort($assoc_array_of_attributes); + } + foreach ($assoc_array_of_attributes as $key => $value) { + if (!$this->_xhtml) { + // Remove namespaced attributes + if (strpos($key, ':') !== false) { + continue; + } + // Check if we should minimize the attribute: val="val" -> val + if ($element && !empty($this->_def->info[$element]->attr[$key]->minimized)) { + $html .= $key . ' '; + continue; + } + } + // Workaround for Internet Explorer innerHTML bug. + // Essentially, Internet Explorer, when calculating + // innerHTML, omits quotes if there are no instances of + // angled brackets, quotes or spaces. However, when parsing + // HTML (for example, when you assign to innerHTML), it + // treats backticks as quotes. Thus, + // `` + // becomes + // `` + // becomes + // + // Fortunately, all we need to do is trigger an appropriate + // quoting style, which we do by adding an extra space. + // This also is consistent with the W3C spec, which states + // that user agents may ignore leading or trailing + // whitespace (in fact, most don't, at least for attributes + // like alt, but an extra space at the end is barely + // noticeable). Still, we have a configuration knob for + // this, since this transformation is not necesary if you + // don't process user input with innerHTML or you don't plan + // on supporting Internet Explorer. + if ($this->_innerHTMLFix) { + if (strpos($value, '`') !== false) { + // check if correct quoting style would not already be + // triggered + if (strcspn($value, '"\' <>') === strlen($value)) { + // protect! + $value .= ' '; + } + } + } + $html .= $key.'="'.$this->escape($value).'" '; + } + return rtrim($html); + } + + /** + * Escapes raw text data. + * @todo This really ought to be protected, but until we have a facility + * for properly generating HTML here w/o using tokens, it stays + * public. + * @param string $string String data to escape for HTML. + * @param int $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is + * permissible for non-attribute output. + * @return string escaped data. + */ + public function escape($string, $quote = null) + { + // Workaround for APC bug on Mac Leopard reported by sidepodcast + // http://htmlpurifier.org/phorum/read.php?3,4823,4846 + if ($quote === null) { + $quote = ENT_COMPAT; + } + return htmlspecialchars($string, $quote, 'UTF-8'); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php new file mode 100644 index 0000000..9b7b334 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php @@ -0,0 +1,493 @@ +getAnonymousModule(); + if (!isset($module->info[$element_name])) { + $element = $module->addBlankElement($element_name); + } else { + $element = $module->info[$element_name]; + } + $element->attr[$attr_name] = $def; + } + + /** + * Adds a custom element to your HTML definition + * @see HTMLPurifier_HTMLModule::addElement() for detailed + * parameter and return value descriptions. + */ + public function addElement($element_name, $type, $contents, $attr_collections, $attributes = array()) + { + $module = $this->getAnonymousModule(); + // assume that if the user is calling this, the element + // is safe. This may not be a good idea + $element = $module->addElement($element_name, $type, $contents, $attr_collections, $attributes); + return $element; + } + + /** + * Adds a blank element to your HTML definition, for overriding + * existing behavior + * @param string $element_name + * @return HTMLPurifier_ElementDef + * @see HTMLPurifier_HTMLModule::addBlankElement() for detailed + * parameter and return value descriptions. + */ + public function addBlankElement($element_name) + { + $module = $this->getAnonymousModule(); + $element = $module->addBlankElement($element_name); + return $element; + } + + /** + * Retrieves a reference to the anonymous module, so you can + * bust out advanced features without having to make your own + * module. + * @return HTMLPurifier_HTMLModule + */ + public function getAnonymousModule() + { + if (!$this->_anonModule) { + $this->_anonModule = new HTMLPurifier_HTMLModule(); + $this->_anonModule->name = 'Anonymous'; + } + return $this->_anonModule; + } + + private $_anonModule = null; + + // PUBLIC BUT INTERNAL VARIABLES -------------------------------------- + + /** + * @type string + */ + public $type = 'HTML'; + + /** + * @type HTMLPurifier_HTMLModuleManager + */ + public $manager; + + /** + * Performs low-cost, preliminary initialization. + */ + public function __construct() + { + $this->manager = new HTMLPurifier_HTMLModuleManager(); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetup($config) + { + $this->processModules($config); + $this->setupConfigStuff($config); + unset($this->manager); + + // cleanup some of the element definitions + foreach ($this->info as $k => $v) { + unset($this->info[$k]->content_model); + unset($this->info[$k]->content_model_type); + } + } + + /** + * Extract out the information from the manager + * @param HTMLPurifier_Config $config + */ + protected function processModules($config) + { + if ($this->_anonModule) { + // for user specific changes + // this is late-loaded so we don't have to deal with PHP4 + // reference wonky-ness + $this->manager->addModule($this->_anonModule); + unset($this->_anonModule); + } + + $this->manager->setup($config); + $this->doctype = $this->manager->doctype; + + foreach ($this->manager->modules as $module) { + foreach ($module->info_tag_transform as $k => $v) { + if ($v === false) { + unset($this->info_tag_transform[$k]); + } else { + $this->info_tag_transform[$k] = $v; + } + } + foreach ($module->info_attr_transform_pre as $k => $v) { + if ($v === false) { + unset($this->info_attr_transform_pre[$k]); + } else { + $this->info_attr_transform_pre[$k] = $v; + } + } + foreach ($module->info_attr_transform_post as $k => $v) { + if ($v === false) { + unset($this->info_attr_transform_post[$k]); + } else { + $this->info_attr_transform_post[$k] = $v; + } + } + foreach ($module->info_injector as $k => $v) { + if ($v === false) { + unset($this->info_injector[$k]); + } else { + $this->info_injector[$k] = $v; + } + } + } + $this->info = $this->manager->getElements(); + $this->info_content_sets = $this->manager->contentSets->lookup; + } + + /** + * Sets up stuff based on config. We need a better way of doing this. + * @param HTMLPurifier_Config $config + */ + protected function setupConfigStuff($config) + { + $block_wrapper = $config->get('HTML.BlockWrapper'); + if (isset($this->info_content_sets['Block'][$block_wrapper])) { + $this->info_block_wrapper = $block_wrapper; + } else { + trigger_error( + 'Cannot use non-block element as block wrapper', + E_USER_ERROR + ); + } + + $parent = $config->get('HTML.Parent'); + $def = $this->manager->getElement($parent, true); + if ($def) { + $this->info_parent = $parent; + $this->info_parent_def = $def; + } else { + trigger_error( + 'Cannot use unrecognized element as parent', + E_USER_ERROR + ); + $this->info_parent_def = $this->manager->getElement($this->info_parent, true); + } + + // support template text + $support = "(for information on implementing this, see the support forums) "; + + // setup allowed elements ----------------------------------------- + + $allowed_elements = $config->get('HTML.AllowedElements'); + $allowed_attributes = $config->get('HTML.AllowedAttributes'); // retrieve early + + if (!is_array($allowed_elements) && !is_array($allowed_attributes)) { + $allowed = $config->get('HTML.Allowed'); + if (is_string($allowed)) { + list($allowed_elements, $allowed_attributes) = $this->parseTinyMCEAllowedList($allowed); + } + } + + if (is_array($allowed_elements)) { + foreach ($this->info as $name => $d) { + if (!isset($allowed_elements[$name])) { + unset($this->info[$name]); + } + unset($allowed_elements[$name]); + } + // emit errors + foreach ($allowed_elements as $element => $d) { + $element = htmlspecialchars($element); // PHP doesn't escape errors, be careful! + trigger_error("Element '$element' is not supported $support", E_USER_WARNING); + } + } + + // setup allowed attributes --------------------------------------- + + $allowed_attributes_mutable = $allowed_attributes; // by copy! + if (is_array($allowed_attributes)) { + // This actually doesn't do anything, since we went away from + // global attributes. It's possible that userland code uses + // it, but HTMLModuleManager doesn't! + foreach ($this->info_global_attr as $attr => $x) { + $keys = array($attr, "*@$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) { + unset($this->info_global_attr[$attr]); + } + } + + foreach ($this->info as $tag => $info) { + foreach ($info->attr as $attr => $x) { + $keys = array("$tag@$attr", $attr, "*@$attr", "$tag.$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) { + if ($this->info[$tag]->attr[$attr]->required) { + trigger_error( + "Required attribute '$attr' in element '$tag' " . + "was not allowed, which means '$tag' will not be allowed either", + E_USER_WARNING + ); + } + unset($this->info[$tag]->attr[$attr]); + } + } + } + // emit errors + foreach ($allowed_attributes_mutable as $elattr => $d) { + $bits = preg_split('/[.@]/', $elattr, 2); + $c = count($bits); + switch ($c) { + case 2: + if ($bits[0] !== '*') { + $element = htmlspecialchars($bits[0]); + $attribute = htmlspecialchars($bits[1]); + if (!isset($this->info[$element])) { + trigger_error( + "Cannot allow attribute '$attribute' if element " . + "'$element' is not allowed/supported $support" + ); + } else { + trigger_error( + "Attribute '$attribute' in element '$element' not supported $support", + E_USER_WARNING + ); + } + break; + } + // otherwise fall through + case 1: + $attribute = htmlspecialchars($bits[0]); + trigger_error( + "Global attribute '$attribute' is not ". + "supported in any elements $support", + E_USER_WARNING + ); + break; + } + } + } + + // setup forbidden elements --------------------------------------- + + $forbidden_elements = $config->get('HTML.ForbiddenElements'); + $forbidden_attributes = $config->get('HTML.ForbiddenAttributes'); + + foreach ($this->info as $tag => $info) { + if (isset($forbidden_elements[$tag])) { + unset($this->info[$tag]); + continue; + } + foreach ($info->attr as $attr => $x) { + if (isset($forbidden_attributes["$tag@$attr"]) || + isset($forbidden_attributes["*@$attr"]) || + isset($forbidden_attributes[$attr]) + ) { + unset($this->info[$tag]->attr[$attr]); + continue; + } elseif (isset($forbidden_attributes["$tag.$attr"])) { // this segment might get removed eventually + // $tag.$attr are not user supplied, so no worries! + trigger_error( + "Error with $tag.$attr: tag.attr syntax not supported for " . + "HTML.ForbiddenAttributes; use tag@attr instead", + E_USER_WARNING + ); + } + } + } + foreach ($forbidden_attributes as $key => $v) { + if (strlen($key) < 2) { + continue; + } + if ($key[0] != '*') { + continue; + } + if ($key[1] == '.') { + trigger_error( + "Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead", + E_USER_WARNING + ); + } + } + + // setup injectors ----------------------------------------------------- + foreach ($this->info_injector as $i => $injector) { + if ($injector->checkNeeded($config) !== false) { + // remove injector that does not have it's required + // elements/attributes present, and is thus not needed. + unset($this->info_injector[$i]); + } + } + } + + /** + * Parses a TinyMCE-flavored Allowed Elements and Attributes list into + * separate lists for processing. Format is element[attr1|attr2],element2... + * @warning Although it's largely drawn from TinyMCE's implementation, + * it is different, and you'll probably have to modify your lists + * @param array $list String list to parse + * @return array + * @todo Give this its own class, probably static interface + */ + public function parseTinyMCEAllowedList($list) + { + $list = str_replace(array(' ', "\t"), '', $list); + + $elements = array(); + $attributes = array(); + + $chunks = preg_split('/(,|[\n\r]+)/', $list); + foreach ($chunks as $chunk) { + if (empty($chunk)) { + continue; + } + // remove TinyMCE element control characters + if (!strpos($chunk, '[')) { + $element = $chunk; + $attr = false; + } else { + list($element, $attr) = explode('[', $chunk); + } + if ($element !== '*') { + $elements[$element] = true; + } + if (!$attr) { + continue; + } + $attr = substr($attr, 0, strlen($attr) - 1); // remove trailing ] + $attr = explode('|', $attr); + foreach ($attr as $key) { + $attributes["$element.$key"] = true; + } + } + return array($elements, $attributes); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php new file mode 100644 index 0000000..6d898f8 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php @@ -0,0 +1,284 @@ +info, since the object's data is only info, + * with extra behavior associated with it. + * @type array + */ + public $attr_collections = array(); + + /** + * Associative array of deprecated tag name to HTMLPurifier_TagTransform. + * @type array + */ + public $info_tag_transform = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed before validation. + * @type array + */ + public $info_attr_transform_pre = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed after validation. + * @type array + */ + public $info_attr_transform_post = array(); + + /** + * List of HTMLPurifier_Injector to be performed during well-formedness fixing. + * An injector will only be invoked if all of it's pre-requisites are met; + * if an injector fails setup, there will be no error; it will simply be + * silently disabled. + * @type array + */ + public $info_injector = array(); + + /** + * Boolean flag that indicates whether or not getChildDef is implemented. + * For optimization reasons: may save a call to a function. Be sure + * to set it if you do implement getChildDef(), otherwise it will have + * no effect! + * @type bool + */ + public $defines_child_def = false; + + /** + * Boolean flag whether or not this module is safe. If it is not safe, all + * of its members are unsafe. Modules are safe by default (this might be + * slightly dangerous, but it doesn't make much sense to force HTML Purifier, + * which is based off of safe HTML, to explicitly say, "This is safe," even + * though there are modules which are "unsafe") + * + * @type bool + * @note Previously, safety could be applied at an element level granularity. + * We've removed this ability, so in order to add "unsafe" elements + * or attributes, a dedicated module with this property set to false + * must be used. + */ + public $safe = true; + + /** + * Retrieves a proper HTMLPurifier_ChildDef subclass based on + * content_model and content_model_type member variables of + * the HTMLPurifier_ElementDef class. There is a similar function + * in HTMLPurifier_HTMLDefinition. + * @param HTMLPurifier_ElementDef $def + * @return HTMLPurifier_ChildDef subclass + */ + public function getChildDef($def) + { + return false; + } + + // -- Convenience ----------------------------------------------------- + + /** + * Convenience function that sets up a new element + * @param string $element Name of element to add + * @param string|bool $type What content set should element be registered to? + * Set as false to skip this step. + * @param string|HTMLPurifier_ChildDef $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @param array|string $attr_includes What attribute collections to register to + * element? + * @param array $attr What unique attributes does the element define? + * @see HTMLPurifier_ElementDef:: for in-depth descriptions of these parameters. + * @return HTMLPurifier_ElementDef Created element definition object, so you + * can set advanced parameters + */ + public function addElement($element, $type, $contents, $attr_includes = array(), $attr = array()) + { + $this->elements[] = $element; + // parse content_model + list($content_model_type, $content_model) = $this->parseContents($contents); + // merge in attribute inclusions + $this->mergeInAttrIncludes($attr, $attr_includes); + // add element to content sets + if ($type) { + $this->addElementToContentSet($element, $type); + } + // create element + $this->info[$element] = HTMLPurifier_ElementDef::create( + $content_model, + $content_model_type, + $attr + ); + // literal object $contents means direct child manipulation + if (!is_string($contents)) { + $this->info[$element]->child = $contents; + } + return $this->info[$element]; + } + + /** + * Convenience function that creates a totally blank, non-standalone + * element. + * @param string $element Name of element to create + * @return HTMLPurifier_ElementDef Created element + */ + public function addBlankElement($element) + { + if (!isset($this->info[$element])) { + $this->elements[] = $element; + $this->info[$element] = new HTMLPurifier_ElementDef(); + $this->info[$element]->standalone = false; + } else { + trigger_error("Definition for $element already exists in module, cannot redefine"); + } + return $this->info[$element]; + } + + /** + * Convenience function that registers an element to a content set + * @param string $element Element to register + * @param string $type Name content set (warning: case sensitive, usually upper-case + * first letter) + */ + public function addElementToContentSet($element, $type) + { + if (!isset($this->content_sets[$type])) { + $this->content_sets[$type] = ''; + } else { + $this->content_sets[$type] .= ' | '; + } + $this->content_sets[$type] .= $element; + } + + /** + * Convenience function that transforms single-string contents + * into separate content model and content model type + * @param string $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @return array + * @note If contents is an object, an array of two nulls will be + * returned, and the callee needs to take the original $contents + * and use it directly. + */ + public function parseContents($contents) + { + if (!is_string($contents)) { + return array(null, null); + } // defer + switch ($contents) { + // check for shorthand content model forms + case 'Empty': + return array('empty', ''); + case 'Inline': + return array('optional', 'Inline | #PCDATA'); + case 'Flow': + return array('optional', 'Flow | #PCDATA'); + } + list($content_model_type, $content_model) = explode(':', $contents); + $content_model_type = strtolower(trim($content_model_type)); + $content_model = trim($content_model); + return array($content_model_type, $content_model); + } + + /** + * Convenience function that merges a list of attribute includes into + * an attribute array. + * @param array $attr Reference to attr array to modify + * @param array $attr_includes Array of includes / string include to merge in + */ + public function mergeInAttrIncludes(&$attr, $attr_includes) + { + if (!is_array($attr_includes)) { + if (empty($attr_includes)) { + $attr_includes = array(); + } else { + $attr_includes = array($attr_includes); + } + } + $attr[0] = $attr_includes; + } + + /** + * Convenience function that generates a lookup table with boolean + * true as value. + * @param string $list List of values to turn into a lookup + * @note You can also pass an arbitrary number of arguments in + * place of the regular argument + * @return array array equivalent of list + */ + public function makeLookup($list) + { + if (is_string($list)) { + $list = func_get_args(); + } + $ret = array(); + foreach ($list as $value) { + if (is_null($value)) { + continue; + } + $ret[$value] = true; + } + return $ret; + } + + /** + * Lazy load construction of the module after determining whether + * or not it's needed, and also when a finalized configuration object + * is available. + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php new file mode 100644 index 0000000..1e67c79 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php @@ -0,0 +1,44 @@ + array('dir' => false) + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $bdo = $this->addElement( + 'bdo', + 'Inline', + 'Inline', + array('Core', 'Lang'), + array( + 'dir' => 'Enum#ltr,rtl', // required + // The Abstract Module specification has the attribute + // inclusions wrong for bdo: bdo allows Lang + ) + ); + $bdo->attr_transform_post[] = new HTMLPurifier_AttrTransform_BdoDir(); + + $this->attr_collections['I18N']['dir'] = 'Enum#ltr,rtl'; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php new file mode 100644 index 0000000..a96ab1b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php @@ -0,0 +1,31 @@ + array( + 0 => array('Style'), + // 'xml:space' => false, + 'class' => 'Class', + 'id' => 'ID', + 'title' => 'CDATA', + ), + 'Lang' => array(), + 'I18N' => array( + 0 => array('Lang'), // proprietary, for xml:lang/lang + ), + 'Common' => array( + 0 => array('Core', 'I18N') + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php new file mode 100644 index 0000000..a9042a3 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php @@ -0,0 +1,55 @@ + 'URI', + // 'datetime' => 'Datetime', // not implemented + ); + $this->addElement('del', 'Inline', $contents, 'Common', $attr); + $this->addElement('ins', 'Inline', $contents, 'Common', $attr); + } + + // HTML 4.01 specifies that ins/del must not contain block + // elements when used in an inline context, chameleon is + // a complicated workaround to acheive this effect + + // Inline context ! Block context (exclamation mark is + // separator, see getChildDef for parsing) + + /** + * @type bool + */ + public $defines_child_def = true; + + /** + * @param HTMLPurifier_ElementDef $def + * @return HTMLPurifier_ChildDef_Chameleon + */ + public function getChildDef($def) + { + if ($def->content_model_type != 'chameleon') { + return false; + } + $value = explode('!', $def->content_model); + return new HTMLPurifier_ChildDef_Chameleon($value[0], $value[1]); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php new file mode 100644 index 0000000..eb0edcf --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php @@ -0,0 +1,194 @@ + 'Form', + 'Inline' => 'Formctrl', + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + if ($config->get('HTML.Forms')) { + $this->safe = true; + } + + $form = $this->addElement( + 'form', + 'Form', + 'Required: Heading | List | Block | fieldset', + 'Common', + array( + 'accept' => 'ContentTypes', + 'accept-charset' => 'Charsets', + 'action*' => 'URI', + 'method' => 'Enum#get,post', + // really ContentType, but these two are the only ones used today + 'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data', + ) + ); + $form->excludes = array('form' => true); + + $input = $this->addElement( + 'input', + 'Formctrl', + 'Empty', + 'Common', + array( + 'accept' => 'ContentTypes', + 'accesskey' => 'Character', + 'alt' => 'Text', + 'checked' => 'Bool#checked', + 'disabled' => 'Bool#disabled', + 'maxlength' => 'Number', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'size' => 'Number', + 'src' => 'URI#embedded', + 'tabindex' => 'Number', + 'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image', + 'value' => 'CDATA', + ) + ); + $input->attr_transform_post[] = new HTMLPurifier_AttrTransform_Input(); + + $this->addElement( + 'select', + 'Formctrl', + 'Required: optgroup | option', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'multiple' => 'Bool#multiple', + 'name' => 'CDATA', + 'size' => 'Number', + 'tabindex' => 'Number', + ) + ); + + $this->addElement( + 'option', + false, + 'Optional: #PCDATA', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'label' => 'Text', + 'selected' => 'Bool#selected', + 'value' => 'CDATA', + ) + ); + // It's illegal for there to be more than one selected, but not + // be multiple. Also, no selected means undefined behavior. This might + // be difficult to implement; perhaps an injector, or a context variable. + + $textarea = $this->addElement( + 'textarea', + 'Formctrl', + 'Optional: #PCDATA', + 'Common', + array( + 'accesskey' => 'Character', + 'cols*' => 'Number', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'rows*' => 'Number', + 'tabindex' => 'Number', + ) + ); + $textarea->attr_transform_pre[] = new HTMLPurifier_AttrTransform_Textarea(); + + $button = $this->addElement( + 'button', + 'Formctrl', + 'Optional: #PCDATA | Heading | List | Block | Inline', + 'Common', + array( + 'accesskey' => 'Character', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'tabindex' => 'Number', + 'type' => 'Enum#button,submit,reset', + 'value' => 'CDATA', + ) + ); + + // For exclusions, ideally we'd specify content sets, not literal elements + $button->excludes = $this->makeLookup( + 'form', + 'fieldset', // Form + 'input', + 'select', + 'textarea', + 'label', + 'button', // Formctrl + 'a', // as per HTML 4.01 spec, this is omitted by modularization + 'isindex', + 'iframe' // legacy items + ); + + // Extra exclusion: img usemap="" is not permitted within this element. + // We'll omit this for now, since we don't have any good way of + // indicating it yet. + + // This is HIGHLY user-unfriendly; we need a custom child-def for this + $this->addElement('fieldset', 'Form', 'Custom: (#WS?,legend,(Flow|#PCDATA)*)', 'Common'); + + $label = $this->addElement( + 'label', + 'Formctrl', + 'Optional: #PCDATA | Inline', + 'Common', + array( + 'accesskey' => 'Character', + // 'for' => 'IDREF', // IDREF not implemented, cannot allow + ) + ); + $label->excludes = array('label' => true); + + $this->addElement( + 'legend', + false, + 'Optional: #PCDATA | Inline', + 'Common', + array( + 'accesskey' => 'Character', + ) + ); + + $this->addElement( + 'optgroup', + false, + 'Required: option', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'label*' => 'Text', + ) + ); + // Don't forget an injector for . This one's a little complex + // because it maps to multiple elements. + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php new file mode 100644 index 0000000..72d7a31 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php @@ -0,0 +1,40 @@ +addElement( + 'a', + 'Inline', + 'Inline', + 'Common', + array( + // 'accesskey' => 'Character', + // 'charset' => 'Charset', + 'href' => 'URI', + // 'hreflang' => 'LanguageCode', + 'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'), + 'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'), + // 'tabindex' => 'Number', + // 'type' => 'ContentType', + ) + ); + $a->formatting = true; + $a->excludes = array('a' => true); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php new file mode 100644 index 0000000..f7e7c91 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php @@ -0,0 +1,51 @@ +get('HTML.SafeIframe')) { + $this->safe = true; + } + $this->addElement( + 'iframe', + 'Inline', + 'Flow', + 'Common', + array( + 'src' => 'URI#embedded', + 'width' => 'Length', + 'height' => 'Length', + 'name' => 'ID', + 'scrolling' => 'Enum#yes,no,auto', + 'frameborder' => 'Enum#0,1', + 'longdesc' => 'URI', + 'marginheight' => 'Pixels', + 'marginwidth' => 'Pixels', + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php new file mode 100644 index 0000000..0f5fdb3 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php @@ -0,0 +1,49 @@ +get('HTML.MaxImgLength'); + $img = $this->addElement( + 'img', + 'Inline', + 'Empty', + 'Common', + array( + 'alt*' => 'Text', + // According to the spec, it's Length, but percents can + // be abused, so we allow only Pixels. + 'height' => 'Pixels#' . $max, + 'width' => 'Pixels#' . $max, + 'longdesc' => 'URI', + 'src*' => new HTMLPurifier_AttrDef_URI(true), // embedded + ) + ); + if ($max === null || $config->get('HTML.Trusted')) { + $img->attr['height'] = + $img->attr['width'] = 'Length'; + } + + // kind of strange, but splitting things up would be inefficient + $img->attr_transform_pre[] = + $img->attr_transform_post[] = + new HTMLPurifier_AttrTransform_ImgRequired(); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php new file mode 100644 index 0000000..86b5299 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php @@ -0,0 +1,186 @@ +addElement( + 'basefont', + 'Inline', + 'Empty', + null, + array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + 'id' => 'ID' + ) + ); + $this->addElement('center', 'Block', 'Flow', 'Common'); + $this->addElement( + 'dir', + 'Block', + 'Required: li', + 'Common', + array( + 'compact' => 'Bool#compact' + ) + ); + $this->addElement( + 'font', + 'Inline', + 'Inline', + array('Core', 'I18N'), + array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + ) + ); + $this->addElement( + 'menu', + 'Block', + 'Required: li', + 'Common', + array( + 'compact' => 'Bool#compact' + ) + ); + + $s = $this->addElement('s', 'Inline', 'Inline', 'Common'); + $s->formatting = true; + + $strike = $this->addElement('strike', 'Inline', 'Inline', 'Common'); + $strike->formatting = true; + + $u = $this->addElement('u', 'Inline', 'Inline', 'Common'); + $u->formatting = true; + + // setup modifications to old elements + + $align = 'Enum#left,right,center,justify'; + + $address = $this->addBlankElement('address'); + $address->content_model = 'Inline | #PCDATA | p'; + $address->content_model_type = 'optional'; + $address->child = false; + + $blockquote = $this->addBlankElement('blockquote'); + $blockquote->content_model = 'Flow | #PCDATA'; + $blockquote->content_model_type = 'optional'; + $blockquote->child = false; + + $br = $this->addBlankElement('br'); + $br->attr['clear'] = 'Enum#left,all,right,none'; + + $caption = $this->addBlankElement('caption'); + $caption->attr['align'] = 'Enum#top,bottom,left,right'; + + $div = $this->addBlankElement('div'); + $div->attr['align'] = $align; + + $dl = $this->addBlankElement('dl'); + $dl->attr['compact'] = 'Bool#compact'; + + for ($i = 1; $i <= 6; $i++) { + $h = $this->addBlankElement("h$i"); + $h->attr['align'] = $align; + } + + $hr = $this->addBlankElement('hr'); + $hr->attr['align'] = $align; + $hr->attr['noshade'] = 'Bool#noshade'; + $hr->attr['size'] = 'Pixels'; + $hr->attr['width'] = 'Length'; + + $img = $this->addBlankElement('img'); + $img->attr['align'] = 'IAlign'; + $img->attr['border'] = 'Pixels'; + $img->attr['hspace'] = 'Pixels'; + $img->attr['vspace'] = 'Pixels'; + + // figure out this integer business + + $li = $this->addBlankElement('li'); + $li->attr['value'] = new HTMLPurifier_AttrDef_Integer(); + $li->attr['type'] = 'Enum#s:1,i,I,a,A,disc,square,circle'; + + $ol = $this->addBlankElement('ol'); + $ol->attr['compact'] = 'Bool#compact'; + $ol->attr['start'] = new HTMLPurifier_AttrDef_Integer(); + $ol->attr['type'] = 'Enum#s:1,i,I,a,A'; + + $p = $this->addBlankElement('p'); + $p->attr['align'] = $align; + + $pre = $this->addBlankElement('pre'); + $pre->attr['width'] = 'Number'; + + // script omitted + + $table = $this->addBlankElement('table'); + $table->attr['align'] = 'Enum#left,center,right'; + $table->attr['bgcolor'] = 'Color'; + + $tr = $this->addBlankElement('tr'); + $tr->attr['bgcolor'] = 'Color'; + + $th = $this->addBlankElement('th'); + $th->attr['bgcolor'] = 'Color'; + $th->attr['height'] = 'Length'; + $th->attr['nowrap'] = 'Bool#nowrap'; + $th->attr['width'] = 'Length'; + + $td = $this->addBlankElement('td'); + $td->attr['bgcolor'] = 'Color'; + $td->attr['height'] = 'Length'; + $td->attr['nowrap'] = 'Bool#nowrap'; + $td->attr['width'] = 'Length'; + + $ul = $this->addBlankElement('ul'); + $ul->attr['compact'] = 'Bool#compact'; + $ul->attr['type'] = 'Enum#square,disc,circle'; + + // "safe" modifications to "unsafe" elements + // WARNING: If you want to add support for an unsafe, legacy + // attribute, make a new TrustedLegacy module with the trusted + // bit set appropriately + + $form = $this->addBlankElement('form'); + $form->content_model = 'Flow | #PCDATA'; + $form->content_model_type = 'optional'; + $form->attr['target'] = 'FrameTarget'; + + $input = $this->addBlankElement('input'); + $input->attr['align'] = 'IAlign'; + + $legend = $this->addBlankElement('legend'); + $legend->attr['align'] = 'LAlign'; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php new file mode 100644 index 0000000..7a20ff7 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php @@ -0,0 +1,51 @@ + 'List'); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $ol = $this->addElement('ol', 'List', new HTMLPurifier_ChildDef_List(), 'Common'); + $ul = $this->addElement('ul', 'List', new HTMLPurifier_ChildDef_List(), 'Common'); + // XXX The wrap attribute is handled by MakeWellFormed. This is all + // quite unsatisfactory, because we generated this + // *specifically* for lists, and now a big chunk of the handling + // is done properly by the List ChildDef. So actually, we just + // want enough information to make autoclosing work properly, + // and then hand off the tricky stuff to the ChildDef. + $ol->wrap = 'li'; + $ul->wrap = 'li'; + $this->addElement('dl', 'List', 'Required: dt | dd', 'Common'); + + $this->addElement('li', false, 'Flow', 'Common'); + + $this->addElement('dd', false, 'Flow', 'Common'); + $this->addElement('dt', false, 'Inline', 'Common'); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php new file mode 100644 index 0000000..60c0545 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php @@ -0,0 +1,26 @@ +addBlankElement($name); + $element->attr['name'] = 'CDATA'; + if (!$config->get('HTML.Attr.Name.UseCDATA')) { + $element->attr_transform_post[] = new HTMLPurifier_AttrTransform_NameSync(); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php new file mode 100644 index 0000000..dc9410a --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php @@ -0,0 +1,25 @@ +addBlankElement('a'); + $a->attr_transform_post[] = new HTMLPurifier_AttrTransform_Nofollow(); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php new file mode 100644 index 0000000..da72225 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php @@ -0,0 +1,20 @@ + array( + 'lang' => 'LanguageCode', + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php new file mode 100644 index 0000000..2f9efc5 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php @@ -0,0 +1,62 @@ + to cater to legacy browsers: this + * module does not allow this sort of behavior + */ +class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule +{ + /** + * @type string + */ + public $name = 'Object'; + + /** + * @type bool + */ + public $safe = false; + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $this->addElement( + 'object', + 'Inline', + 'Optional: #PCDATA | Flow | param', + 'Common', + array( + 'archive' => 'URI', + 'classid' => 'URI', + 'codebase' => 'URI', + 'codetype' => 'Text', + 'data' => 'URI', + 'declare' => 'Bool#declare', + 'height' => 'Length', + 'name' => 'CDATA', + 'standby' => 'Text', + 'tabindex' => 'Number', + 'type' => 'ContentType', + 'width' => 'Length' + ) + ); + + $this->addElement( + 'param', + false, + 'Empty', + null, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'type' => 'Text', + 'value' => 'Text', + 'valuetype' => 'Enum#data,ref,object' + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php new file mode 100644 index 0000000..6458ce9 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php @@ -0,0 +1,42 @@ +addElement('hr', 'Block', 'Empty', 'Common'); + $this->addElement('sub', 'Inline', 'Inline', 'Common'); + $this->addElement('sup', 'Inline', 'Inline', 'Common'); + $b = $this->addElement('b', 'Inline', 'Inline', 'Common'); + $b->formatting = true; + $big = $this->addElement('big', 'Inline', 'Inline', 'Common'); + $big->formatting = true; + $i = $this->addElement('i', 'Inline', 'Inline', 'Common'); + $i->formatting = true; + $small = $this->addElement('small', 'Inline', 'Inline', 'Common'); + $small->formatting = true; + $tt = $this->addElement('tt', 'Inline', 'Inline', 'Common'); + $tt->formatting = true; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php new file mode 100644 index 0000000..5ee3c8e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php @@ -0,0 +1,40 @@ +addElement( + 'marquee', + 'Inline', + 'Flow', + 'Common', + array( + 'direction' => 'Enum#left,right,up,down', + 'behavior' => 'Enum#alternate', + 'width' => 'Length', + 'height' => 'Length', + 'scrolldelay' => 'Number', + 'scrollamount' => 'Number', + 'loop' => 'Number', + 'bgcolor' => 'Color', + 'hspace' => 'Pixels', + 'vspace' => 'Pixels', + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php new file mode 100644 index 0000000..a0d4892 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php @@ -0,0 +1,36 @@ +addElement( + 'ruby', + 'Inline', + 'Custom: ((rb, (rt | (rp, rt, rp))) | (rbc, rtc, rtc?))', + 'Common' + ); + $this->addElement('rbc', false, 'Required: rb', 'Common'); + $this->addElement('rtc', false, 'Required: rt', 'Common'); + $rb = $this->addElement('rb', false, 'Inline', 'Common'); + $rb->excludes = array('ruby' => true); + $rt = $this->addElement('rt', false, 'Inline', 'Common', array('rbspan' => 'Number')); + $rt->excludes = array('ruby' => true); + $this->addElement('rp', false, 'Optional: #PCDATA', 'Common'); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php new file mode 100644 index 0000000..04e6689 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php @@ -0,0 +1,40 @@ +get('HTML.MaxImgLength'); + $embed = $this->addElement( + 'embed', + 'Inline', + 'Empty', + 'Common', + array( + 'src*' => 'URI#embedded', + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'allowscriptaccess' => 'Enum#never', + 'allownetworking' => 'Enum#internal', + 'flashvars' => 'Text', + 'wmode' => 'Enum#window,transparent,opaque', + 'name' => 'ID', + ) + ); + $embed->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeEmbed(); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php new file mode 100644 index 0000000..1297f80 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php @@ -0,0 +1,62 @@ +get('HTML.MaxImgLength'); + $object = $this->addElement( + 'object', + 'Inline', + 'Optional: param | Flow | #PCDATA', + 'Common', + array( + // While technically not required by the spec, we're forcing + // it to this value. + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'data' => 'URI#embedded', + 'codebase' => new HTMLPurifier_AttrDef_Enum( + array( + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0' + ) + ), + ) + ); + $object->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeObject(); + + $param = $this->addElement( + 'param', + false, + 'Empty', + false, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'value' => 'Text' + ) + ); + $param->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeParam(); + $this->info_injector[] = 'SafeObject'; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php new file mode 100644 index 0000000..aea7584 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php @@ -0,0 +1,40 @@ +get('HTML.SafeScripting'); + $script = $this->addElement( + 'script', + 'Inline', + 'Optional:', // Not `Empty` to not allow to autoclose the #i', '', $html); + } + + return $html; + } + + /** + * Takes a string of HTML (fragment or document) and returns the content + * @todo Consider making protected + */ + public function extractBody($html) + { + $matches = array(); + $result = preg_match('|(.*?)]*>(.*)|is', $html, $matches); + if ($result) { + // Make sure it's not in a comment + $comment_start = strrpos($matches[1], ''); + if ($comment_start === false || + ($comment_end !== false && $comment_end > $comment_start)) { + return $matches[2]; + } + } + return $html; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php new file mode 100644 index 0000000..ca5f25b --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php @@ -0,0 +1,338 @@ +factory = new HTMLPurifier_TokenFactory(); + } + + /** + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_Token[] + */ + public function tokenizeHTML($html, $config, $context) + { + $html = $this->normalize($html, $config, $context); + + // attempt to armor stray angled brackets that cannot possibly + // form tags and thus are probably being used as emoticons + if ($config->get('Core.AggressivelyFixLt')) { + $char = '[^a-z!\/]'; + $comment = "/|\z)/is"; + $html = preg_replace_callback($comment, array($this, 'callbackArmorCommentEntities'), $html); + do { + $old = $html; + $html = preg_replace("/<($char)/i", '<\\1', $html); + } while ($html !== $old); + $html = preg_replace_callback($comment, array($this, 'callbackUndoCommentSubst'), $html); // fix comments + } + + // preprocess html, essential for UTF-8 + $html = $this->wrapHTML($html, $config, $context); + + $doc = new DOMDocument(); + $doc->encoding = 'UTF-8'; // theoretically, the above has this covered + + $options = 0; + if ($config->get('Core.AllowParseManyTags') && defined('LIBXML_PARSEHUGE')) { + $options |= LIBXML_PARSEHUGE; + } + + set_error_handler(array($this, 'muteErrorHandler')); + // loadHTML() fails on PHP 5.3 when second parameter is given + if ($options) { + $doc->loadHTML($html, $options); + } else { + $doc->loadHTML($html); + } + restore_error_handler(); + + $body = $doc->getElementsByTagName('html')->item(0)-> // + getElementsByTagName('body')->item(0); // + + $div = $body->getElementsByTagName('div')->item(0); //
+ $tokens = array(); + $this->tokenizeDOM($div, $tokens, $config); + // If the div has a sibling, that means we tripped across + // a premature
tag. So remove the div we parsed, + // and then tokenize the rest of body. We can't tokenize + // the sibling directly as we'll lose the tags in that case. + if ($div->nextSibling) { + $body->removeChild($div); + $this->tokenizeDOM($body, $tokens, $config); + } + return $tokens; + } + + /** + * Iterative function that tokenizes a node, putting it into an accumulator. + * To iterate is human, to recurse divine - L. Peter Deutsch + * @param DOMNode $node DOMNode to be tokenized. + * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens. + * @return HTMLPurifier_Token of node appended to previously passed tokens. + */ + protected function tokenizeDOM($node, &$tokens, $config) + { + $level = 0; + $nodes = array($level => new HTMLPurifier_Queue(array($node))); + $closingNodes = array(); + do { + while (!$nodes[$level]->isEmpty()) { + $node = $nodes[$level]->shift(); // FIFO + $collect = $level > 0 ? true : false; + $needEndingTag = $this->createStartNode($node, $tokens, $collect, $config); + if ($needEndingTag) { + $closingNodes[$level][] = $node; + } + if ($node->childNodes && $node->childNodes->length) { + $level++; + $nodes[$level] = new HTMLPurifier_Queue(); + foreach ($node->childNodes as $childNode) { + $nodes[$level]->push($childNode); + } + } + } + $level--; + if ($level && isset($closingNodes[$level])) { + while ($node = array_pop($closingNodes[$level])) { + $this->createEndNode($node, $tokens); + } + } + } while ($level > 0); + } + + /** + * Portably retrieve the tag name of a node; deals with older versions + * of libxml like 2.7.6 + * @param DOMNode $node + */ + protected function getTagName($node) + { + if (isset($node->tagName)) { + return $node->tagName; + } else if (isset($node->nodeName)) { + return $node->nodeName; + } else if (isset($node->localName)) { + return $node->localName; + } + return null; + } + + /** + * Portably retrieve the data of a node; deals with older versions + * of libxml like 2.7.6 + * @param DOMNode $node + */ + protected function getData($node) + { + if (isset($node->data)) { + return $node->data; + } else if (isset($node->nodeValue)) { + return $node->nodeValue; + } else if (isset($node->textContent)) { + return $node->textContent; + } + return null; + } + + + /** + * @param DOMNode $node DOMNode to be tokenized. + * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens. + * @param bool $collect Says whether or start and close are collected, set to + * false at first recursion because it's the implicit DIV + * tag you're dealing with. + * @return bool if the token needs an endtoken + * @todo data and tagName properties don't seem to exist in DOMNode? + */ + protected function createStartNode($node, &$tokens, $collect, $config) + { + // intercept non element nodes. WE MUST catch all of them, + // but we're not getting the character reference nodes because + // those should have been preprocessed + if ($node->nodeType === XML_TEXT_NODE) { + $data = $this->getData($node); // Handle variable data property + if ($data !== null) { + $tokens[] = $this->factory->createText($data); + } + return false; + } elseif ($node->nodeType === XML_CDATA_SECTION_NODE) { + // undo libxml's special treatment of )#si', + array($this, 'scriptCallback'), + $html + ); + } + + $html = $this->normalize($html, $config, $context); + + $cursor = 0; // our location in the text + $inside_tag = false; // whether or not we're parsing the inside of a tag + $array = array(); // result array + + // This is also treated to mean maintain *column* numbers too + $maintain_line_numbers = $config->get('Core.MaintainLineNumbers'); + + if ($maintain_line_numbers === null) { + // automatically determine line numbering by checking + // if error collection is on + $maintain_line_numbers = $config->get('Core.CollectErrors'); + } + + if ($maintain_line_numbers) { + $current_line = 1; + $current_col = 0; + $length = strlen($html); + } else { + $current_line = false; + $current_col = false; + $length = false; + } + $context->register('CurrentLine', $current_line); + $context->register('CurrentCol', $current_col); + $nl = "\n"; + // how often to manually recalculate. This will ALWAYS be right, + // but it's pretty wasteful. Set to 0 to turn off + $synchronize_interval = $config->get('Core.DirectLexLineNumberSyncInterval'); + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // for testing synchronization + $loops = 0; + + while (++$loops) { + // $cursor is either at the start of a token, or inside of + // a tag (i.e. there was a < immediately before it), as indicated + // by $inside_tag + + if ($maintain_line_numbers) { + // $rcursor, however, is always at the start of a token. + $rcursor = $cursor - (int)$inside_tag; + + // Column number is cheap, so we calculate it every round. + // We're interested at the *end* of the newline string, so + // we need to add strlen($nl) == 1 to $nl_pos before subtracting it + // from our "rcursor" position. + $nl_pos = strrpos($html, $nl, $rcursor - $length); + $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1); + + // recalculate lines + if ($synchronize_interval && // synchronization is on + $cursor > 0 && // cursor is further than zero + $loops % $synchronize_interval === 0) { // time to synchronize! + $current_line = 1 + $this->substrCount($html, $nl, 0, $cursor); + } + } + + $position_next_lt = strpos($html, '<', $cursor); + $position_next_gt = strpos($html, '>', $cursor); + + // triggers on "asdf" but not "asdf " + // special case to set up context + if ($position_next_lt === $cursor) { + $inside_tag = true; + $cursor++; + } + + if (!$inside_tag && $position_next_lt !== false) { + // We are not inside tag and there still is another tag to parse + $token = new + HTMLPurifier_Token_Text( + $this->parseText( + substr( + $html, + $cursor, + $position_next_lt - $cursor + ), $config + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_lt - $cursor); + } + $array[] = $token; + $cursor = $position_next_lt + 1; + $inside_tag = true; + continue; + } elseif (!$inside_tag) { + // We are not inside tag but there are no more tags + // If we're already at the end, break + if ($cursor === strlen($html)) { + break; + } + // Create Text of rest of string + $token = new + HTMLPurifier_Token_Text( + $this->parseText( + substr( + $html, + $cursor + ), $config + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } + $array[] = $token; + break; + } elseif ($inside_tag && $position_next_gt !== false) { + // We are in tag and it is well formed + // Grab the internals of the tag + $strlen_segment = $position_next_gt - $cursor; + + if ($strlen_segment < 1) { + // there's nothing to process! + $token = new HTMLPurifier_Token_Text('<'); + $cursor++; + continue; + } + + $segment = substr($html, $cursor, $strlen_segment); + + if ($segment === false) { + // somehow, we attempted to access beyond the end of + // the string, defense-in-depth, reported by Nate Abele + break; + } + + // Check if it's a comment + if (substr($segment, 0, 3) === '!--') { + // re-determine segment length, looking for --> + $position_comment_end = strpos($html, '-->', $cursor); + if ($position_comment_end === false) { + // uh oh, we have a comment that extends to + // infinity. Can't be helped: set comment + // end position to end of string + if ($e) { + $e->send(E_WARNING, 'Lexer: Unclosed comment'); + } + $position_comment_end = strlen($html); + $end = true; + } else { + $end = false; + } + $strlen_segment = $position_comment_end - $cursor; + $segment = substr($html, $cursor, $strlen_segment); + $token = new + HTMLPurifier_Token_Comment( + substr( + $segment, + 3, + $strlen_segment - 3 + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $strlen_segment); + } + $array[] = $token; + $cursor = $end ? $position_comment_end : $position_comment_end + 3; + $inside_tag = false; + continue; + } + + // Check if it's an end tag + $is_end_tag = (strpos($segment, '/') === 0); + if ($is_end_tag) { + $type = substr($segment, 1); + $token = new HTMLPurifier_Token_End($type); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Check leading character is alnum, if not, we may + // have accidently grabbed an emoticon. Translate into + // text and go our merry way + if (!ctype_alpha($segment[0])) { + // XML: $segment[0] !== '_' && $segment[0] !== ':' + if ($e) { + $e->send(E_NOTICE, 'Lexer: Unescaped lt'); + } + $token = new HTMLPurifier_Token_Text('<'); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + continue; + } + + // Check if it is explicitly self closing, if so, remove + // trailing slash. Remember, we could have a tag like
, so + // any later token processing scripts must convert improperly + // classified EmptyTags from StartTags. + $is_self_closing = (strrpos($segment, '/') === $strlen_segment - 1); + if ($is_self_closing) { + $strlen_segment--; + $segment = substr($segment, 0, $strlen_segment); + } + + // Check if there are any attributes + $position_first_space = strcspn($segment, $this->_whitespace); + + if ($position_first_space >= $strlen_segment) { + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($segment); + } else { + $token = new HTMLPurifier_Token_Start($segment); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Grab out all the data + $type = substr($segment, 0, $position_first_space); + $attribute_string = + trim( + substr( + $segment, + $position_first_space + ) + ); + if ($attribute_string) { + $attr = $this->parseAttributeString( + $attribute_string, + $config, + $context + ); + } else { + $attr = array(); + } + + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($type, $attr); + } else { + $token = new HTMLPurifier_Token_Start($type, $attr); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $cursor = $position_next_gt + 1; + $inside_tag = false; + continue; + } else { + // inside tag, but there's no ending > sign + if ($e) { + $e->send(E_WARNING, 'Lexer: Missing gt'); + } + $token = new + HTMLPurifier_Token_Text( + '<' . + $this->parseText( + substr($html, $cursor), $config + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } + // no cursor scroll? Hmm... + $array[] = $token; + break; + } + break; + } + + $context->destroy('CurrentLine'); + $context->destroy('CurrentCol'); + return $array; + } + + /** + * PHP 5.0.x compatible substr_count that implements offset and length + * @param string $haystack + * @param string $needle + * @param int $offset + * @param int $length + * @return int + */ + protected function substrCount($haystack, $needle, $offset, $length) + { + static $oldVersion; + if ($oldVersion === null) { + $oldVersion = version_compare(PHP_VERSION, '5.1', '<'); + } + if ($oldVersion) { + $haystack = substr($haystack, $offset, $length); + return substr_count($haystack, $needle); + } else { + return substr_count($haystack, $needle, $offset, $length); + } + } + + /** + * Takes the inside of an HTML tag and makes an assoc array of attributes. + * + * @param string $string Inside of tag excluding name. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array Assoc array of attributes. + */ + public function parseAttributeString($string, $config, $context) + { + $string = (string)$string; // quick typecast + + if ($string == '') { + return array(); + } // no attributes + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // let's see if we can abort as quickly as possible + // one equal sign, no spaces => one attribute + $num_equal = substr_count($string, '='); + $has_space = strpos($string, ' '); + if ($num_equal === 0 && !$has_space) { + // bool attribute + return array($string => $string); + } elseif ($num_equal === 1 && !$has_space) { + // only one attribute + list($key, $quoted_value) = explode('=', $string); + $quoted_value = trim($quoted_value); + if (!$key) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + return array(); + } + if (!$quoted_value) { + return array($key => ''); + } + $first_char = @$quoted_value[0]; + $last_char = @$quoted_value[strlen($quoted_value) - 1]; + + $same_quote = ($first_char == $last_char); + $open_quote = ($first_char == '"' || $first_char == "'"); + + if ($same_quote && $open_quote) { + // well behaved + $value = substr($quoted_value, 1, strlen($quoted_value) - 2); + } else { + // not well behaved + if ($open_quote) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing end quote'); + } + $value = substr($quoted_value, 1); + } else { + $value = $quoted_value; + } + } + if ($value === false) { + $value = ''; + } + return array($key => $this->parseAttr($value, $config)); + } + + // setup loop environment + $array = array(); // return assoc array of attributes + $cursor = 0; // current position in string (moves forward) + $size = strlen($string); // size of the string (stays the same) + + // if we have unquoted attributes, the parser expects a terminating + // space, so let's guarantee that there's always a terminating space. + $string .= ' '; + + $old_cursor = -1; + while ($cursor < $size) { + if ($old_cursor >= $cursor) { + throw new Exception("Infinite loop detected"); + } + $old_cursor = $cursor; + + $cursor += ($value = strspn($string, $this->_whitespace, $cursor)); + // grab the key + + $key_begin = $cursor; //we're currently at the start of the key + + // scroll past all characters that are the key (not whitespace or =) + $cursor += strcspn($string, $this->_whitespace . '=', $cursor); + + $key_end = $cursor; // now at the end of the key + + $key = substr($string, $key_begin, $key_end - $key_begin); + + if (!$key) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + $cursor += 1 + strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop + continue; // empty key + } + + // scroll past all whitespace + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor >= $size) { + $array[$key] = $key; + break; + } + + // if the next character is an equal sign, we've got a regular + // pair, otherwise, it's a bool attribute + $first_char = @$string[$cursor]; + + if ($first_char == '=') { + // key="value" + + $cursor++; + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor === false) { + $array[$key] = ''; + break; + } + + // we might be in front of a quote right now + + $char = @$string[$cursor]; + + if ($char == '"' || $char == "'") { + // it's quoted, end bound is $char + $cursor++; + $value_begin = $cursor; + $cursor = strpos($string, $char, $cursor); + $value_end = $cursor; + } else { + // it's not quoted, end bound is whitespace + $value_begin = $cursor; + $cursor += strcspn($string, $this->_whitespace, $cursor); + $value_end = $cursor; + } + + // we reached a premature end + if ($cursor === false) { + $cursor = $size; + $value_end = $cursor; + } + + $value = substr($string, $value_begin, $value_end - $value_begin); + if ($value === false) { + $value = ''; + } + $array[$key] = $this->parseAttr($value, $config); + $cursor++; + } else { + // boolattr + if ($key !== '') { + $array[$key] = $key; + } else { + // purely theoretical + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + } + } + } + return $array; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php new file mode 100644 index 0000000..72476dd --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php @@ -0,0 +1,4788 @@ +normalize($html, $config, $context); + $new_html = $this->wrapHTML($new_html, $config, $context, false /* no div */); + try { + $parser = new HTML5($new_html); + $doc = $parser->save(); + } catch (DOMException $e) { + // Uh oh, it failed. Punt to DirectLex. + $lexer = new HTMLPurifier_Lexer_DirectLex(); + $context->register('PH5PError', $e); // save the error, so we can detect it + return $lexer->tokenizeHTML($html, $config, $context); // use original HTML + } + $tokens = array(); + $this->tokenizeDOM( + $doc->getElementsByTagName('html')->item(0)-> // + getElementsByTagName('body')->item(0) // + , + $tokens, $config + ); + return $tokens; + } +} + +/* + +Copyright 2007 Jeroen van der Meer + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +class HTML5 +{ + private $data; + private $char; + private $EOF; + private $state; + private $tree; + private $token; + private $content_model; + private $escape = false; + private $entities = array( + 'AElig;', + 'AElig', + 'AMP;', + 'AMP', + 'Aacute;', + 'Aacute', + 'Acirc;', + 'Acirc', + 'Agrave;', + 'Agrave', + 'Alpha;', + 'Aring;', + 'Aring', + 'Atilde;', + 'Atilde', + 'Auml;', + 'Auml', + 'Beta;', + 'COPY;', + 'COPY', + 'Ccedil;', + 'Ccedil', + 'Chi;', + 'Dagger;', + 'Delta;', + 'ETH;', + 'ETH', + 'Eacute;', + 'Eacute', + 'Ecirc;', + 'Ecirc', + 'Egrave;', + 'Egrave', + 'Epsilon;', + 'Eta;', + 'Euml;', + 'Euml', + 'GT;', + 'GT', + 'Gamma;', + 'Iacute;', + 'Iacute', + 'Icirc;', + 'Icirc', + 'Igrave;', + 'Igrave', + 'Iota;', + 'Iuml;', + 'Iuml', + 'Kappa;', + 'LT;', + 'LT', + 'Lambda;', + 'Mu;', + 'Ntilde;', + 'Ntilde', + 'Nu;', + 'OElig;', + 'Oacute;', + 'Oacute', + 'Ocirc;', + 'Ocirc', + 'Ograve;', + 'Ograve', + 'Omega;', + 'Omicron;', + 'Oslash;', + 'Oslash', + 'Otilde;', + 'Otilde', + 'Ouml;', + 'Ouml', + 'Phi;', + 'Pi;', + 'Prime;', + 'Psi;', + 'QUOT;', + 'QUOT', + 'REG;', + 'REG', + 'Rho;', + 'Scaron;', + 'Sigma;', + 'THORN;', + 'THORN', + 'TRADE;', + 'Tau;', + 'Theta;', + 'Uacute;', + 'Uacute', + 'Ucirc;', + 'Ucirc', + 'Ugrave;', + 'Ugrave', + 'Upsilon;', + 'Uuml;', + 'Uuml', + 'Xi;', + 'Yacute;', + 'Yacute', + 'Yuml;', + 'Zeta;', + 'aacute;', + 'aacute', + 'acirc;', + 'acirc', + 'acute;', + 'acute', + 'aelig;', + 'aelig', + 'agrave;', + 'agrave', + 'alefsym;', + 'alpha;', + 'amp;', + 'amp', + 'and;', + 'ang;', + 'apos;', + 'aring;', + 'aring', + 'asymp;', + 'atilde;', + 'atilde', + 'auml;', + 'auml', + 'bdquo;', + 'beta;', + 'brvbar;', + 'brvbar', + 'bull;', + 'cap;', + 'ccedil;', + 'ccedil', + 'cedil;', + 'cedil', + 'cent;', + 'cent', + 'chi;', + 'circ;', + 'clubs;', + 'cong;', + 'copy;', + 'copy', + 'crarr;', + 'cup;', + 'curren;', + 'curren', + 'dArr;', + 'dagger;', + 'darr;', + 'deg;', + 'deg', + 'delta;', + 'diams;', + 'divide;', + 'divide', + 'eacute;', + 'eacute', + 'ecirc;', + 'ecirc', + 'egrave;', + 'egrave', + 'empty;', + 'emsp;', + 'ensp;', + 'epsilon;', + 'equiv;', + 'eta;', + 'eth;', + 'eth', + 'euml;', + 'euml', + 'euro;', + 'exist;', + 'fnof;', + 'forall;', + 'frac12;', + 'frac12', + 'frac14;', + 'frac14', + 'frac34;', + 'frac34', + 'frasl;', + 'gamma;', + 'ge;', + 'gt;', + 'gt', + 'hArr;', + 'harr;', + 'hearts;', + 'hellip;', + 'iacute;', + 'iacute', + 'icirc;', + 'icirc', + 'iexcl;', + 'iexcl', + 'igrave;', + 'igrave', + 'image;', + 'infin;', + 'int;', + 'iota;', + 'iquest;', + 'iquest', + 'isin;', + 'iuml;', + 'iuml', + 'kappa;', + 'lArr;', + 'lambda;', + 'lang;', + 'laquo;', + 'laquo', + 'larr;', + 'lceil;', + 'ldquo;', + 'le;', + 'lfloor;', + 'lowast;', + 'loz;', + 'lrm;', + 'lsaquo;', + 'lsquo;', + 'lt;', + 'lt', + 'macr;', + 'macr', + 'mdash;', + 'micro;', + 'micro', + 'middot;', + 'middot', + 'minus;', + 'mu;', + 'nabla;', + 'nbsp;', + 'nbsp', + 'ndash;', + 'ne;', + 'ni;', + 'not;', + 'not', + 'notin;', + 'nsub;', + 'ntilde;', + 'ntilde', + 'nu;', + 'oacute;', + 'oacute', + 'ocirc;', + 'ocirc', + 'oelig;', + 'ograve;', + 'ograve', + 'oline;', + 'omega;', + 'omicron;', + 'oplus;', + 'or;', + 'ordf;', + 'ordf', + 'ordm;', + 'ordm', + 'oslash;', + 'oslash', + 'otilde;', + 'otilde', + 'otimes;', + 'ouml;', + 'ouml', + 'para;', + 'para', + 'part;', + 'permil;', + 'perp;', + 'phi;', + 'pi;', + 'piv;', + 'plusmn;', + 'plusmn', + 'pound;', + 'pound', + 'prime;', + 'prod;', + 'prop;', + 'psi;', + 'quot;', + 'quot', + 'rArr;', + 'radic;', + 'rang;', + 'raquo;', + 'raquo', + 'rarr;', + 'rceil;', + 'rdquo;', + 'real;', + 'reg;', + 'reg', + 'rfloor;', + 'rho;', + 'rlm;', + 'rsaquo;', + 'rsquo;', + 'sbquo;', + 'scaron;', + 'sdot;', + 'sect;', + 'sect', + 'shy;', + 'shy', + 'sigma;', + 'sigmaf;', + 'sim;', + 'spades;', + 'sub;', + 'sube;', + 'sum;', + 'sup1;', + 'sup1', + 'sup2;', + 'sup2', + 'sup3;', + 'sup3', + 'sup;', + 'supe;', + 'szlig;', + 'szlig', + 'tau;', + 'there4;', + 'theta;', + 'thetasym;', + 'thinsp;', + 'thorn;', + 'thorn', + 'tilde;', + 'times;', + 'times', + 'trade;', + 'uArr;', + 'uacute;', + 'uacute', + 'uarr;', + 'ucirc;', + 'ucirc', + 'ugrave;', + 'ugrave', + 'uml;', + 'uml', + 'upsih;', + 'upsilon;', + 'uuml;', + 'uuml', + 'weierp;', + 'xi;', + 'yacute;', + 'yacute', + 'yen;', + 'yen', + 'yuml;', + 'yuml', + 'zeta;', + 'zwj;', + 'zwnj;' + ); + + const PCDATA = 0; + const RCDATA = 1; + const CDATA = 2; + const PLAINTEXT = 3; + + const DOCTYPE = 0; + const STARTTAG = 1; + const ENDTAG = 2; + const COMMENT = 3; + const CHARACTR = 4; + const EOF = 5; + + public function __construct($data) + { + $this->data = $data; + $this->char = -1; + $this->EOF = strlen($data); + $this->tree = new HTML5TreeConstructer; + $this->content_model = self::PCDATA; + + $this->state = 'data'; + + while ($this->state !== null) { + $this->{$this->state . 'State'}(); + } + } + + public function save() + { + return $this->tree->save(); + } + + private function char() + { + return ($this->char < $this->EOF) + ? $this->data[$this->char] + : false; + } + + private function character($s, $l = 0) + { + if ($s + $l < $this->EOF) { + if ($l === 0) { + return $this->data[$s]; + } else { + return substr($this->data, $s, $l); + } + } + } + + private function characters($char_class, $start) + { + return preg_replace('#^([' . $char_class . ']+).*#s', '\\1', substr($this->data, $start)); + } + + private function dataState() + { + // Consume the next input character + $this->char++; + $char = $this->char(); + + if ($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { + /* U+0026 AMPERSAND (&) + When the content model flag is set to one of the PCDATA or RCDATA + states: switch to the entity data state. Otherwise: treat it as per + the "anything else" entry below. */ + $this->state = 'entityData'; + + } elseif ($char === '-') { + /* If the content model flag is set to either the RCDATA state or + the CDATA state, and the escape flag is false, and there are at + least three characters before this one in the input stream, and the + last four characters in the input stream, including this one, are + U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, + and U+002D HYPHEN-MINUS (""), + set the escape flag to false. */ + if (($this->content_model === self::RCDATA || + $this->content_model === self::CDATA) && $this->escape === true && + $this->character($this->char, 3) === '-->' + ) { + $this->escape = false; + } + + /* In any case, emit the input character as a character token. + Stay in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + } elseif ($this->char === $this->EOF) { + /* EOF + Emit an end-of-file token. */ + $this->EOF(); + + } elseif ($this->content_model === self::PLAINTEXT) { + /* When the content model flag is set to the PLAINTEXT state + THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of + the text and emit it as a character token. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => substr($this->data, $this->char) + ) + ); + + $this->EOF(); + + } else { + /* Anything else + THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that + otherwise would also be treated as a character token and emit it + as a single character token. Stay in the data state. */ + $len = strcspn($this->data, '<&', $this->char); + $char = substr($this->data, $this->char, $len); + $this->char += $len - 1; + + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + $this->state = 'data'; + } + } + + private function entityDataState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, emit a U+0026 AMPERSAND character token. + // Otherwise, emit the character token that was returned. + $char = (!$entity) ? '&' : $entity; + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + // Finally, switch to the data state. + $this->state = 'data'; + } + + private function tagOpenState() + { + switch ($this->content_model) { + case self::RCDATA: + case self::CDATA: + /* If the next input character is a U+002F SOLIDUS (/) character, + consume it and switch to the close tag open state. If the next + input character is not a U+002F SOLIDUS (/) character, emit a + U+003C LESS-THAN SIGN character token and switch to the data + state to process the next input character. */ + if ($this->character($this->char + 1) === '/') { + $this->char++; + $this->state = 'closeTagOpen'; + + } else { + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->state = 'data'; + } + break; + + case self::PCDATA: + // If the content model flag is set to the PCDATA state + // Consume the next input character: + $this->char++; + $char = $this->char(); + + if ($char === '!') { + /* U+0021 EXCLAMATION MARK (!) + Switch to the markup declaration open state. */ + $this->state = 'markupDeclarationOpen'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Switch to the close tag open state. */ + $this->state = 'closeTagOpen'; + + } elseif (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new start tag token, set its tag name to the lowercase + version of the input character (add 0x0020 to the character's code + point), then switch to the tag name state. (Don't emit the token + yet; further details will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::STARTTAG, + 'attr' => array() + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Emit a U+003C LESS-THAN SIGN character token and a + U+003E GREATER-THAN SIGN character token. Switch to the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<>' + ) + ); + + $this->state = 'data'; + + } elseif ($char === '?') { + /* U+003F QUESTION MARK (?) + Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + + } else { + /* Anything else + Parse error. Emit a U+003C LESS-THAN SIGN character token and + reconsume the current input character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->char--; + $this->state = 'data'; + } + break; + } + } + + private function closeTagOpenState() + { + $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); + $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; + + if (($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && + (!$the_same || ($the_same && (!preg_match( + '/[\t\n\x0b\x0c >\/]/', + $this->character($this->char + 1 + strlen($next_node)) + ) || $this->EOF === $this->char))) + ) { + /* If the content model flag is set to the RCDATA or CDATA states then + examine the next few characters. If they do not match the tag name of + the last start tag token emitted (case insensitively), or if they do but + they are not immediately followed by one of the following characters: + * U+0009 CHARACTER TABULATION + * U+000A LINE FEED (LF) + * U+000B LINE TABULATION + * U+000C FORM FEED (FF) + * U+0020 SPACE + * U+003E GREATER-THAN SIGN (>) + * U+002F SOLIDUS (/) + * EOF + ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character + token, a U+002F SOLIDUS character token, and switch to the data state + to process the next input character. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'state = 'data'; + + } else { + /* Otherwise, if the content model flag is set to the PCDATA state, + or if the next few characters do match that tag name, consume the + next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new end tag token, set its tag name to the lowercase version + of the input character (add 0x0020 to the character's code point), then + switch to the tag name state. (Don't emit the token yet; further details + will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::ENDTAG + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Switch to the data state. */ + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F + SOLIDUS character token. Reconsume the EOF character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'char--; + $this->state = 'data'; + + } else { + /* Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + } + } + } + + private function tagNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } else { + /* Anything else + Append the current input character to the current tag token's tag name. + Stay in the tag name state. */ + $this->token['name'] .= strtolower($char); + $this->state = 'tagName'; + } + } + + private function beforeAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Stay in the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function attributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's name. + Stay in the attribute name state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['name'] .= strtolower($char); + + $this->state = 'attributeName'; + } + } + + private function afterAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the after attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the + before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function beforeAttributeValueState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the attribute value (double-quoted) state. */ + $this->state = 'attributeValueDoubleQuoted'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the attribute value (unquoted) state and reconsume + this input character. */ + $this->char--; + $this->state = 'attributeValueUnquoted'; + + } elseif ($char === '\'') { + /* U+0027 APOSTROPHE (') + Switch to the attribute value (single-quoted) state. */ + $this->state = 'attributeValueSingleQuoted'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Switch to the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function attributeValueDoubleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('double'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (double-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueDoubleQuoted'; + } + } + + private function attributeValueSingleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '\'') { + /* U+0022 QUOTATION MARK (') + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('single'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (single-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueSingleQuoted'; + } + } + + private function attributeValueUnquotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState(); + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function entityInAttributeValueState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, append a U+0026 AMPERSAND character to the + // current attribute's value. Otherwise, emit the character token that + // was returned. + $char = (!$entity) + ? '&' + : $entity; + + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + } + + private function bogusCommentState() + { + /* Consume every character up to the first U+003E GREATER-THAN SIGN + character (>) or the end of the file (EOF), whichever comes first. Emit + a comment token whose data is the concatenation of all the characters + starting from and including the character that caused the state machine + to switch into the bogus comment state, up to and including the last + consumed character before the U+003E character, if any, or up to the + end of the file otherwise. (If the comment was started by the end of + the file (EOF), the token is empty.) */ + $data = $this->characters('^>', $this->char); + $this->emitToken( + array( + 'data' => $data, + 'type' => self::COMMENT + ) + ); + + $this->char += strlen($data); + + /* Switch to the data state. */ + $this->state = 'data'; + + /* If the end of the file was reached, reconsume the EOF character. */ + if ($this->char === $this->EOF) { + $this->char = $this->EOF - 1; + } + } + + private function markupDeclarationOpenState() + { + /* If the next two characters are both U+002D HYPHEN-MINUS (-) + characters, consume those two characters, create a comment token whose + data is the empty string, and switch to the comment state. */ + if ($this->character($this->char + 1, 2) === '--') { + $this->char += 2; + $this->state = 'comment'; + $this->token = array( + 'data' => null, + 'type' => self::COMMENT + ); + + /* Otherwise if the next seven chacacters are a case-insensitive match + for the word "DOCTYPE", then consume those characters and switch to the + DOCTYPE state. */ + } elseif (strtolower($this->character($this->char + 1, 7)) === 'doctype') { + $this->char += 7; + $this->state = 'doctype'; + + /* Otherwise, is is a parse error. Switch to the bogus comment state. + The next character that is consumed, if any, is the first character + that will be in the comment. */ + } else { + $this->char++; + $this->state = 'bogusComment'; + } + } + + private function commentState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment dash state */ + $this->state = 'commentDash'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append the input character to the comment token's data. Stay in + the comment state. */ + $this->token['data'] .= $char; + } + } + + private function commentDashState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment end state */ + $this->state = 'commentEnd'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append a U+002D HYPHEN-MINUS (-) character and the input + character to the comment token's data. Switch to the comment state. */ + $this->token['data'] .= '-' . $char; + $this->state = 'comment'; + } + } + + private function commentEndState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '-') { + $this->token['data'] .= '-'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['data'] .= '--' . $char; + $this->state = 'comment'; + } + } + + private function doctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'beforeDoctypeName'; + + } else { + $this->char--; + $this->state = 'beforeDoctypeName'; + } + } + + private function beforeDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the before DOCTYPE name state. + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token = array( + 'name' => strtoupper($char), + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + + } elseif ($char === '>') { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->char--; + $this->state = 'data'; + + } else { + $this->token = array( + 'name' => $char, + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + } + } + + private function doctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'AfterDoctypeName'; + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token['name'] .= strtoupper($char); + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['name'] .= $char; + } + + $this->token['error'] = ($this->token['name'] === 'HTML') + ? false + : true; + } + + private function afterDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the DOCTYPE name state. + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['error'] = true; + $this->state = 'bogusDoctype'; + } + } + + private function bogusDoctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + // Stay in the bogus DOCTYPE state. + } + } + + private function entity() + { + $start = $this->char; + + // This section defines how to consume an entity. This definition is + // used when parsing entities in text and in attributes. + + // The behaviour depends on the identity of the next character (the + // one immediately after the U+0026 AMPERSAND character): + + switch ($this->character($this->char + 1)) { + // U+0023 NUMBER SIGN (#) + case '#': + + // The behaviour further depends on the character after the + // U+0023 NUMBER SIGN: + switch ($this->character($this->char + 1)) { + // U+0078 LATIN SMALL LETTER X + // U+0058 LATIN CAPITAL LETTER X + case 'x': + case 'X': + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 + // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER + // A, through to U+0046 LATIN CAPITAL LETTER F (in other + // words, 0-9, A-F, a-f). + $char = 1; + $char_class = '0-9A-Fa-f'; + break; + + // Anything else + default: + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE (i.e. just 0-9). + $char = 0; + $char_class = '0-9'; + break; + } + + // Consume as many characters as match the range of characters + // given above. + $this->char++; + $e_name = $this->characters($char_class, $this->char + $char + 1); + $entity = $this->character($start, $this->char); + $cond = strlen($e_name) > 0; + + // The rest of the parsing happens below. + break; + + // Anything else + default: + // Consume the maximum number of characters possible, with the + // consumed characters case-sensitively matching one of the + // identifiers in the first column of the entities table. + + $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); + $len = strlen($e_name); + + for ($c = 1; $c <= $len; $c++) { + $id = substr($e_name, 0, $c); + $this->char++; + + if (in_array($id, $this->entities)) { + if ($e_name[$c - 1] !== ';') { + if ($c < $len && $e_name[$c] == ';') { + $this->char++; // consume extra semicolon + } + } + $entity = $id; + break; + } + } + + $cond = isset($entity); + // The rest of the parsing happens below. + break; + } + + if (!$cond) { + // If no match can be made, then this is a parse error. No + // characters are consumed, and nothing is returned. + $this->char = $start; + return false; + } + + // Return a character token for the character corresponding to the + // entity name (as given by the second column of the entities table). + return html_entity_decode('&' . rtrim($entity, ';') . ';', ENT_QUOTES, 'UTF-8'); + } + + private function emitToken($token) + { + $emit = $this->tree->emitToken($token); + + if (is_int($emit)) { + $this->content_model = $emit; + + } elseif ($token['type'] === self::ENDTAG) { + $this->content_model = self::PCDATA; + } + } + + private function EOF() + { + $this->state = null; + $this->tree->emitToken( + array( + 'type' => self::EOF + ) + ); + } +} + +class HTML5TreeConstructer +{ + public $stack = array(); + + private $phase; + private $mode; + private $dom; + private $foster_parent = null; + private $a_formatting = array(); + + private $head_pointer = null; + private $form_pointer = null; + + private $scoping = array('button', 'caption', 'html', 'marquee', 'object', 'table', 'td', 'th'); + private $formatting = array( + 'a', + 'b', + 'big', + 'em', + 'font', + 'i', + 'nobr', + 's', + 'small', + 'strike', + 'strong', + 'tt', + 'u' + ); + private $special = array( + 'address', + 'area', + 'base', + 'basefont', + 'bgsound', + 'blockquote', + 'body', + 'br', + 'center', + 'col', + 'colgroup', + 'dd', + 'dir', + 'div', + 'dl', + 'dt', + 'embed', + 'fieldset', + 'form', + 'frame', + 'frameset', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'head', + 'hr', + 'iframe', + 'image', + 'img', + 'input', + 'isindex', + 'li', + 'link', + 'listing', + 'menu', + 'meta', + 'noembed', + 'noframes', + 'noscript', + 'ol', + 'optgroup', + 'option', + 'p', + 'param', + 'plaintext', + 'pre', + 'script', + 'select', + 'spacer', + 'style', + 'tbody', + 'textarea', + 'tfoot', + 'thead', + 'title', + 'tr', + 'ul', + 'wbr' + ); + + // The different phases. + const INIT_PHASE = 0; + const ROOT_PHASE = 1; + const MAIN_PHASE = 2; + const END_PHASE = 3; + + // The different insertion modes for the main phase. + const BEFOR_HEAD = 0; + const IN_HEAD = 1; + const AFTER_HEAD = 2; + const IN_BODY = 3; + const IN_TABLE = 4; + const IN_CAPTION = 5; + const IN_CGROUP = 6; + const IN_TBODY = 7; + const IN_ROW = 8; + const IN_CELL = 9; + const IN_SELECT = 10; + const AFTER_BODY = 11; + const IN_FRAME = 12; + const AFTR_FRAME = 13; + + // The different types of elements. + const SPECIAL = 0; + const SCOPING = 1; + const FORMATTING = 2; + const PHRASING = 3; + + const MARKER = 0; + + public function __construct() + { + $this->phase = self::INIT_PHASE; + $this->mode = self::BEFOR_HEAD; + $this->dom = new DOMDocument; + + $this->dom->encoding = 'UTF-8'; + $this->dom->preserveWhiteSpace = true; + $this->dom->substituteEntities = true; + $this->dom->strictErrorChecking = false; + } + + // Process tag tokens + public function emitToken($token) + { + switch ($this->phase) { + case self::INIT_PHASE: + return $this->initPhase($token); + break; + case self::ROOT_PHASE: + return $this->rootElementPhase($token); + break; + case self::MAIN_PHASE: + return $this->mainPhase($token); + break; + case self::END_PHASE : + return $this->trailingEndPhase($token); + break; + } + } + + private function initPhase($token) + { + /* Initially, the tree construction stage must handle each token + emitted from the tokenisation stage as follows: */ + + /* A DOCTYPE token that is marked as being in error + A comment token + A start tag token + An end tag token + A character token that is not one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE + An end-of-file token */ + if ((isset($token['error']) && $token['error']) || + $token['type'] === HTML5::COMMENT || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF || + ($token['type'] === HTML5::CHARACTR && isset($token['data']) && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) + ) { + /* This specification does not define how to handle this case. In + particular, user agents may ignore the entirety of this specification + altogether for such documents, and instead invoke special parse modes + with a greater emphasis on backwards compatibility. */ + + $this->phase = self::ROOT_PHASE; + return $this->rootElementPhase($token); + + /* A DOCTYPE token marked as being correct */ + } elseif (isset($token['error']) && !$token['error']) { + /* Append a DocumentType node to the Document node, with the name + attribute set to the name given in the DOCTYPE token (which will be + "HTML"), and the other attributes specific to DocumentType objects + set to null, empty lists, or the empty string as appropriate. */ + $doctype = new DOMDocumentType(null, null, 'HTML'); + + /* Then, switch to the root element phase of the tree construction + stage. */ + $this->phase = self::ROOT_PHASE; + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif (isset($token['data']) && preg_match( + '/^[\t\n\x0b\x0c ]+$/', + $token['data'] + ) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + } + } + + private function rootElementPhase($token) + { + /* After the initial phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED + (FF), or U+0020 SPACE + A start tag token + An end tag token + An end-of-file token */ + } elseif (($token['type'] === HTML5::CHARACTR && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF + ) { + /* Create an HTMLElement node with the tag name html, in the HTML + namespace. Append it to the Document object. Switch to the main + phase and reprocess the current token. */ + $html = $this->dom->createElement('html'); + $this->dom->appendChild($html); + $this->stack[] = $html; + + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + } + } + + private function mainPhase($token) + { + /* Tokens in the main phase must be handled as follows: */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A start tag token with the tag name "html" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { + /* If this start tag token was not the first start tag token, then + it is a parse error. */ + + /* For each attribute on the token, check to see if the attribute + is already present on the top element of the stack of open elements. + If it is not, add the attribute and its corresponding value to that + element. */ + foreach ($token['attr'] as $attr) { + if (!$this->stack[0]->hasAttribute($attr['name'])) { + $this->stack[0]->setAttribute($attr['name'], $attr['value']); + } + } + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Anything else. */ + } else { + /* Depends on the insertion mode: */ + switch ($this->mode) { + case self::BEFOR_HEAD: + return $this->beforeHead($token); + break; + case self::IN_HEAD: + return $this->inHead($token); + break; + case self::AFTER_HEAD: + return $this->afterHead($token); + break; + case self::IN_BODY: + return $this->inBody($token); + break; + case self::IN_TABLE: + return $this->inTable($token); + break; + case self::IN_CAPTION: + return $this->inCaption($token); + break; + case self::IN_CGROUP: + return $this->inColumnGroup($token); + break; + case self::IN_TBODY: + return $this->inTableBody($token); + break; + case self::IN_ROW: + return $this->inRow($token); + break; + case self::IN_CELL: + return $this->inCell($token); + break; + case self::IN_SELECT: + return $this->inSelect($token); + break; + case self::AFTER_BODY: + return $this->afterBody($token); + break; + case self::IN_FRAME: + return $this->inFrameset($token); + break; + case self::AFTR_FRAME: + return $this->afterFrameset($token); + break; + case self::END_PHASE: + return $this->trailingEndPhase($token); + break; + } + } + } + + private function beforeHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "head" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { + /* Create an element for the token, append the new element to the + current node and push it onto the stack of open elements. */ + $element = $this->insertElement($token); + + /* Set the head element pointer to this new element node. */ + $this->head_pointer = $element; + + /* Change the insertion mode to "in head". */ + $this->mode = self::IN_HEAD; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title". Or an end tag with the tag name "html". + Or a character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or any other start tag token */ + } elseif ($token['type'] === HTML5::STARTTAG || + ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || + ($token['type'] === HTML5::CHARACTR && !preg_match( + '/^[\t\n\x0b\x0c ]$/', + $token['data'] + )) + ) { + /* Act as if a start tag token with the tag name "head" and no + attributes had been seen, then reprocess the current token. */ + $this->beforeHead( + array( + 'name' => 'head', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inHead($token); + + /* Any other end tag */ + } elseif ($token['type'] === HTML5::ENDTAG) { + /* Parse error. Ignore the token. */ + } + } + + private function inHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. + + THIS DIFFERS FROM THE SPEC: If the current node is either a title, style + or script element, append the character to the current node regardless + of its content. */ + if (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( + $token['type'] === HTML5::CHARACTR && in_array( + end($this->stack)->nodeName, + array('title', 'style', 'script') + )) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('title', 'style', 'script')) + ) { + array_pop($this->stack); + return HTML5::PCDATA; + + /* A start tag with the tag name "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $element = $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the RCDATA state. */ + return HTML5::RCDATA; + + /* A start tag with the tag name "style" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "script" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { + /* Create an element for the token. */ + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "base", "link", or "meta" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta') + ) + ) { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + array_pop($this->stack); + + } else { + $this->insertElement($token); + } + + /* An end tag with the tag name "head" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { + /* If the current node is a head element, pop the current node off + the stack of open elements. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + array_pop($this->stack); + + /* Otherwise, this is a parse error. */ + } else { + // k + } + + /* Change the insertion mode to "after head". */ + $this->mode = self::AFTER_HEAD; + + /* A start tag with the tag name "head" or an end tag except "html". */ + } elseif (($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || + ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html') + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* If the current node is a head element, act as if an end tag + token with the tag name "head" had been seen. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + $this->inHead( + array( + 'name' => 'head', + 'type' => HTML5::ENDTAG + ) + ); + + /* Otherwise, change the insertion mode to "after head". */ + } else { + $this->mode = self::AFTER_HEAD; + } + + /* Then, reprocess the current token. */ + return $this->afterHead($token); + } + } + + private function afterHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "body" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { + /* Insert a body element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in body". */ + $this->mode = self::IN_BODY; + + /* A start tag token with the tag name "frameset" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { + /* Insert a frameset element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in frameset". */ + $this->mode = self::IN_FRAME; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta', 'script', 'style', 'title') + ) + ) { + /* Parse error. Switch the insertion mode back to "in head" and + reprocess the token. */ + $this->mode = self::IN_HEAD; + return $this->inHead($token); + + /* Anything else */ + } else { + /* Act as if a start tag token with the tag name "body" and no + attributes had been seen, and then reprocess the current token. */ + $this->afterHead( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inBody($token); + } + } + + private function inBody($token) + { + /* Handle the token as follows: */ + + switch ($token['type']) { + /* A character token */ + case HTML5::CHARACTR: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + break; + + /* A comment token */ + case HTML5::COMMENT: + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + break; + + case HTML5::STARTTAG: + switch ($token['name']) { + /* A start tag token whose tag name is one of: "script", + "style" */ + case 'script': + case 'style': + /* Process the token as if the insertion mode had been "in + head". */ + return $this->inHead($token); + break; + + /* A start tag token whose tag name is one of: "base", "link", + "meta", "title" */ + case 'base': + case 'link': + case 'meta': + case 'title': + /* Parse error. Process the token as if the insertion mode + had been "in head". */ + return $this->inHead($token); + break; + + /* A start tag token with the tag name "body" */ + case 'body': + /* Parse error. If the second element on the stack of open + elements is not a body element, or, if the stack of open + elements has only one node on it, then ignore the token. + (innerHTML case) */ + if (count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { + // Ignore + + /* Otherwise, for each attribute on the token, check to see + if the attribute is already present on the body element (the + second element) on the stack of open elements. If it is not, + add the attribute and its corresponding value to that + element. */ + } else { + foreach ($token['attr'] as $attr) { + if (!$this->stack[1]->hasAttribute($attr['name'])) { + $this->stack[1]->setAttribute($attr['name'], $attr['value']); + } + } + } + break; + + /* A start tag whose tag name is one of: "address", + "blockquote", "center", "dir", "div", "dl", "fieldset", + "listing", "menu", "ol", "p", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'p': + case 'ul': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "form" */ + case 'form': + /* If the form element pointer is not null, ignore the + token with a parse error. */ + if ($this->form_pointer !== null) { + // Ignore. + + /* Otherwise: */ + } else { + /* If the stack of open elements has a p element in + scope, then act as if an end tag with the tag name p + had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token, and set the + form element pointer to point to the element created. */ + $element = $this->insertElement($token); + $this->form_pointer = $element; + } + break; + + /* A start tag whose tag name is "li", "dd" or "dt" */ + case 'li': + case 'dd': + case 'dt': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + $stack_length = count($this->stack) - 1; + + for ($n = $stack_length; 0 <= $n; $n--) { + /* 1. Initialise node to be the current node (the + bottommost node of the stack). */ + $stop = false; + $node = $this->stack[$n]; + $cat = $this->getElementCategory($node->tagName); + + /* 2. If node is an li, dd or dt element, then pop all + the nodes from the current node up to node, including + node, then stop this algorithm. */ + if ($token['name'] === $node->tagName || ($token['name'] !== 'li' + && ($node->tagName === 'dd' || $node->tagName === 'dt')) + ) { + for ($x = $stack_length; $x >= $n; $x--) { + array_pop($this->stack); + } + + break; + } + + /* 3. If node is not in the formatting category, and is + not in the phrasing category, and is not an address or + div element, then stop this algorithm. */ + if ($cat !== self::FORMATTING && $cat !== self::PHRASING && + $node->tagName !== 'address' && $node->tagName !== 'div' + ) { + break; + } + } + + /* Finally, insert an HTML element with the same tag + name as the token's. */ + $this->insertElement($token); + break; + + /* A start tag token whose tag name is "plaintext" */ + case 'plaintext': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + return HTML5::PLAINTEXT; + break; + + /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + this is a parse error; pop elements from the stack until an + element with one of those tag names has been popped from the + stack. */ + while ($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { + array_pop($this->stack); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "a" */ + case 'a': + /* If the list of active formatting elements contains + an element whose tag name is "a" between the end of the + list and the last marker on the list (or the start of + the list if there is no marker on the list), then this + is a parse error; act as if an end tag with the tag name + "a" had been seen, then remove that element from the list + of active formatting elements and the stack of open + elements if the end tag didn't already remove it (it + might not have if the element is not in table scope). */ + $leng = count($this->a_formatting); + + for ($n = $leng - 1; $n >= 0; $n--) { + if ($this->a_formatting[$n] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$n]->nodeName === 'a') { + $this->emitToken( + array( + 'name' => 'a', + 'type' => HTML5::ENDTAG + ) + ); + break; + } + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag whose tag name is one of: "b", "big", "em", "font", + "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag token whose tag name is "button" */ + case 'button': + /* If the stack of open elements has a button element in scope, + then this is a parse error; act as if an end tag with the tag + name "button" had been seen, then reprocess the token. (We don't + do that. Unnecessary.) */ + if ($this->elementInScope('button')) { + $this->inBody( + array( + 'name' => 'button', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is one of: "marquee", "object" */ + case 'marquee': + case 'object': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is "xmp" */ + case 'xmp': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Switch the content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "table" */ + case 'table': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + break; + + /* A start tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'img': + case 'param': + case 'spacer': + case 'wbr': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "hr" */ + case 'hr': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "image" */ + case 'image': + /* Parse error. Change the token's tag name to "img" and + reprocess it. (Don't ask.) */ + $token['name'] = 'img'; + return $this->inBody($token); + break; + + /* A start tag whose tag name is "input" */ + case 'input': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an input element for the token. */ + $element = $this->insertElement($token, false); + + /* If the form element pointer is not null, then associate the + input element with the form element pointed to by the form + element pointer. */ + $this->form_pointer !== null + ? $this->form_pointer->appendChild($element) + : end($this->stack)->appendChild($element); + + /* Pop that input element off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "isindex" */ + case 'isindex': + /* Parse error. */ + // w/e + + /* If the form element pointer is not null, + then ignore the token. */ + if ($this->form_pointer === null) { + /* Act as if a start tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a stream of character tokens had been seen. */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if a start tag token with the tag name "input" + had been seen, with all the attributes from the "isindex" + token, except with the "name" attribute set to the value + "isindex" (ignoring any explicit "name" attribute). */ + $attr = $token['attr']; + $attr[] = array('name' => 'name', 'value' => 'isindex'); + + $this->inBody( + array( + 'name' => 'input', + 'type' => HTML5::STARTTAG, + 'attr' => $attr + ) + ); + + /* Act as if a stream of character tokens had been seen + (see below for what they should say). */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if an end tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'form', + 'type' => HTML5::ENDTAG + ) + ); + } + break; + + /* A start tag whose tag name is "textarea" */ + case 'textarea': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the + RCDATA state. */ + return HTML5::RCDATA; + break; + + /* A start tag whose tag name is one of: "iframe", "noembed", + "noframes" */ + case 'iframe': + case 'noembed': + case 'noframes': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "select" */ + case 'select': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in select". */ + $this->mode = self::IN_SELECT; + break; + + /* A start or end tag whose tag name is one of: "caption", "col", + "colgroup", "frame", "frameset", "head", "option", "optgroup", + "tbody", "td", "tfoot", "th", "thead", "tr". */ + case 'caption': + case 'col': + case 'colgroup': + case 'frame': + case 'frameset': + case 'head': + case 'option': + case 'optgroup': + case 'tbody': + case 'td': + case 'tfoot': + case 'th': + case 'thead': + case 'tr': + // Parse error. Ignore the token. + break; + + /* A start or end tag whose tag name is one of: "event-source", + "section", "nav", "article", "aside", "header", "footer", + "datagrid", "command" */ + case 'event-source': + case 'section': + case 'nav': + case 'article': + case 'aside': + case 'header': + case 'footer': + case 'datagrid': + case 'command': + // Work in progress! + break; + + /* A start tag token not covered by the previous entries */ + default: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + $this->insertElement($token, true, true); + break; + } + break; + + case HTML5::ENDTAG: + switch ($token['name']) { + /* An end tag with the tag name "body" */ + case 'body': + /* If the second element in the stack of open elements is + not a body element, this is a parse error. Ignore the token. + (innerHTML case) */ + if (count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { + // Ignore. + + /* If the current node is not the body element, then this + is a parse error. */ + } elseif (end($this->stack)->nodeName !== 'body') { + // Parse error. + } + + /* Change the insertion mode to "after body". */ + $this->mode = self::AFTER_BODY; + break; + + /* An end tag with the tag name "html" */ + case 'html': + /* Act as if an end tag with tag name "body" had been seen, + then, if that token wasn't ignored, reprocess the current + token. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->afterBody($token); + break; + + /* An end tag whose tag name is one of: "address", "blockquote", + "center", "dir", "div", "dl", "fieldset", "listing", "menu", + "ol", "pre", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'pre': + case 'ul': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with + the same tag name as that of the token, then this + is a parse error. */ + // w/e + + /* If the stack of open elements has an element in + scope with the same tag name as that of the token, + then pop elements from this stack until an element + with that tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is "form" */ + case 'form': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + } + + if (end($this->stack)->nodeName !== $token['name']) { + /* Now, if the current node is not an element with the + same tag name as that of the token, then this is a parse + error. */ + // w/e + + } else { + /* Otherwise, if the current node is an element with + the same tag name as that of the token pop that element + from the stack. */ + array_pop($this->stack); + } + + /* In any case, set the form element pointer to null. */ + $this->form_pointer = null; + break; + + /* An end tag whose tag name is "p" */ + case 'p': + /* If the stack of open elements has a p element in scope, + then generate implied end tags, except for p elements. */ + if ($this->elementInScope('p')) { + $this->generateImpliedEndTags(array('p')); + + /* If the current node is not a p element, then this is + a parse error. */ + // k + + /* If the stack of open elements has a p element in + scope, then pop elements from this stack until the stack + no longer has a p element in scope. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->elementInScope('p')) { + array_pop($this->stack); + + } else { + break; + } + } + } + break; + + /* An end tag whose tag name is "dd", "dt", or "li" */ + case 'dd': + case 'dt': + case 'li': + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + generate implied end tags, except for elements with the + same tag name as the token. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(array($token['name'])); + + /* If the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + pop elements from this stack until an element with that + tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + generate implied end tags. */ + if ($this->elementInScope($elements)) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as that of the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has in scope an element + whose tag name is one of "h1", "h2", "h3", "h4", "h5", or + "h6", then pop elements from the stack until an element + with one of those tag names has been popped from the stack. */ + while ($this->elementInScope($elements)) { + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "a", "b", "big", "em", + "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'a': + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* 1. Let the formatting element be the last element in + the list of active formatting elements that: + * is between the end of the list and the last scope + marker in the list, if any, or the start of the list + otherwise, and + * has the same tag name as the token. + */ + while (true) { + for ($a = count($this->a_formatting) - 1; $a >= 0; $a--) { + if ($this->a_formatting[$a] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$a]->tagName === $token['name']) { + $formatting_element = $this->a_formatting[$a]; + $in_stack = in_array($formatting_element, $this->stack, true); + $fe_af_pos = $a; + break; + } + } + + /* If there is no such node, or, if that node is + also in the stack of open elements but the element + is not in scope, then this is a parse error. Abort + these steps. The token is ignored. */ + if (!isset($formatting_element) || ($in_stack && + !$this->elementInScope($token['name'])) + ) { + break; + + /* Otherwise, if there is such a node, but that node + is not in the stack of open elements, then this is a + parse error; remove the element from the list, and + abort these steps. */ + } elseif (isset($formatting_element) && !$in_stack) { + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 2. Let the furthest block be the topmost node in the + stack of open elements that is lower in the stack + than the formatting element, and is not an element in + the phrasing or formatting categories. There might + not be one. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $length = count($this->stack); + + for ($s = $fe_s_pos + 1; $s < $length; $s++) { + $category = $this->getElementCategory($this->stack[$s]->nodeName); + + if ($category !== self::PHRASING && $category !== self::FORMATTING) { + $furthest_block = $this->stack[$s]; + } + } + + /* 3. If there is no furthest block, then the UA must + skip the subsequent steps and instead just pop all + the nodes from the bottom of the stack of open + elements, from the current node up to the formatting + element, and remove the formatting element from the + list of active formatting elements. */ + if (!isset($furthest_block)) { + for ($n = $length - 1; $n >= $fe_s_pos; $n--) { + array_pop($this->stack); + } + + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 4. Let the common ancestor be the element + immediately above the formatting element in the stack + of open elements. */ + $common_ancestor = $this->stack[$fe_s_pos - 1]; + + /* 5. If the furthest block has a parent node, then + remove the furthest block from its parent node. */ + if ($furthest_block->parentNode !== null) { + $furthest_block->parentNode->removeChild($furthest_block); + } + + /* 6. Let a bookmark note the position of the + formatting element in the list of active formatting + elements relative to the elements on either side + of it in the list. */ + $bookmark = $fe_af_pos; + + /* 7. Let node and last node be the furthest block. + Follow these steps: */ + $node = $furthest_block; + $last_node = $furthest_block; + + while (true) { + for ($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { + /* 7.1 Let node be the element immediately + prior to node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 7.2 If node is not in the list of active + formatting elements, then remove node from + the stack of open elements and then go back + to step 1. */ + if (!in_array($node, $this->a_formatting, true)) { + unset($this->stack[$n]); + $this->stack = array_merge($this->stack); + + } else { + break; + } + } + + /* 7.3 Otherwise, if node is the formatting + element, then go to the next step in the overall + algorithm. */ + if ($node === $formatting_element) { + break; + + /* 7.4 Otherwise, if last node is the furthest + block, then move the aforementioned bookmark to + be immediately after the node in the list of + active formatting elements. */ + } elseif ($last_node === $furthest_block) { + $bookmark = array_search($node, $this->a_formatting, true) + 1; + } + + /* 7.5 If node has any children, perform a + shallow clone of node, replace the entry for + node in the list of active formatting elements + with an entry for the clone, replace the entry + for node in the stack of open elements with an + entry for the clone, and let node be the clone. */ + if ($node->hasChildNodes()) { + $clone = $node->cloneNode(); + $s_pos = array_search($node, $this->stack, true); + $a_pos = array_search($node, $this->a_formatting, true); + + $this->stack[$s_pos] = $clone; + $this->a_formatting[$a_pos] = $clone; + $node = $clone; + } + + /* 7.6 Insert last node into node, first removing + it from its previous parent node if any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $node->appendChild($last_node); + + /* 7.7 Let last node be node. */ + $last_node = $node; + } + + /* 8. Insert whatever last node ended up being in + the previous step into the common ancestor node, + first removing it from its previous parent node if + any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $common_ancestor->appendChild($last_node); + + /* 9. Perform a shallow clone of the formatting + element. */ + $clone = $formatting_element->cloneNode(); + + /* 10. Take all of the child nodes of the furthest + block and append them to the clone created in the + last step. */ + while ($furthest_block->hasChildNodes()) { + $child = $furthest_block->firstChild; + $furthest_block->removeChild($child); + $clone->appendChild($child); + } + + /* 11. Append that clone to the furthest block. */ + $furthest_block->appendChild($clone); + + /* 12. Remove the formatting element from the list + of active formatting elements, and insert the clone + into the list of active formatting elements at the + position of the aforementioned bookmark. */ + $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + + $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); + $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); + $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); + + /* 13. Remove the formatting element from the stack + of open elements, and insert the clone into the stack + of open elements immediately after (i.e. in a more + deeply nested position than) the position of the + furthest block in that stack. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $fb_s_pos = array_search($furthest_block, $this->stack, true); + unset($this->stack[$fe_s_pos]); + + $s_part1 = array_slice($this->stack, 0, $fb_s_pos); + $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); + $this->stack = array_merge($s_part1, array($clone), $s_part2); + + /* 14. Jump back to step 1 in this series of steps. */ + unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); + } + break; + + /* An end tag token whose tag name is one of: "button", + "marquee", "object" */ + case 'button': + case 'marquee': + case 'object': + /* If the stack of open elements has an element in scope whose + tag name matches the tag name of the token, then generate implied + tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // k + + /* Now, if the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then pop + elements from the stack until that element has been popped from + the stack, and clear the list of active formatting elements up + to the last marker. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + + $marker = end(array_keys($this->a_formatting, self::MARKER, true)); + + for ($n = count($this->a_formatting) - 1; $n > $marker; $n--) { + array_pop($this->a_formatting); + } + } + break; + + /* Or an end tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "hr", "iframe", "image", "img", + "input", "isindex", "noembed", "noframes", "param", "select", + "spacer", "table", "textarea", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'hr': + case 'iframe': + case 'image': + case 'img': + case 'input': + case 'isindex': + case 'noembed': + case 'noframes': + case 'param': + case 'select': + case 'spacer': + case 'table': + case 'textarea': + case 'wbr': + // Parse error. Ignore the token. + break; + + /* An end tag token not covered by the previous entries */ + default: + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + /* Initialise node to be the current node (the bottommost + node of the stack). */ + $node = end($this->stack); + + /* If node has the same tag name as the end tag token, + then: */ + if ($token['name'] === $node->nodeName) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* If the tag name of the end tag token does not + match the tag name of the current node, this is a + parse error. */ + // k + + /* Pop all the nodes from the current node up to + node, including node, then stop this algorithm. */ + for ($x = count($this->stack) - $n; $x >= $n; $x--) { + array_pop($this->stack); + } + + } else { + $category = $this->getElementCategory($node); + + if ($category !== self::SPECIAL && $category !== self::SCOPING) { + /* Otherwise, if node is in neither the formatting + category nor the phrasing category, then this is a + parse error. Stop this algorithm. The end tag token + is ignored. */ + return false; + } + } + } + break; + } + break; + } + } + + private function inTable($token) + { + $clear = array('html', 'table'); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "caption" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'caption' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + + /* Insert an HTML element for the token, then switch the + insertion mode to "in caption". */ + $this->insertElement($token); + $this->mode = self::IN_CAPTION; + + /* A start tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'colgroup' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the + insertion mode to "in column group". */ + $this->insertElement($token); + $this->mode = self::IN_CGROUP; + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'col' + ) { + $this->inTable( + array( + 'name' => 'colgroup', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + $this->inColumnGroup($token); + + /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('tbody', 'tfoot', 'thead') + ) + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in table body". */ + $this->insertElement($token); + $this->mode = self::IN_TBODY; + + /* A start tag whose tag name is one of: "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && + in_array($token['name'], array('td', 'th', 'tr')) + ) { + /* Act as if a start tag token with the tag name "tbody" had been + seen, then reprocess the current token. */ + $this->inTable( + array( + 'name' => 'tbody', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inTableBody($token); + + /* A start tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'table' + ) { + /* Parse error. Act as if an end tag token with the tag name "table" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inTable( + array( + 'name' => 'table', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + + /* An end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + return false; + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a table element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a table element has been + popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'table') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'caption', + 'col', + 'colgroup', + 'html', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Parse error. Process the token as if the insertion mode was "in + body", with the following exception: */ + + /* If the current node is a table, tbody, tfoot, thead, or tr + element, then, whenever a node would be inserted into the current + node, it must instead be inserted into the foster parent element. */ + if (in_array( + end($this->stack)->nodeName, + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* The foster parent element is the parent element of the last + table element in the stack of open elements, if there is a + table element and it has such a parent element. If there is no + table element in the stack of open elements (innerHTML case), + then the foster parent element is the first element in the + stack of open elements (the html element). Otherwise, if there + is a table element in the stack of open elements, but the last + table element in the stack of open elements has no parent, or + its parent node is not an element, then the foster parent + element is the element before the last table element in the + stack of open elements. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table') { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $table->parentNode !== null) { + $this->foster_parent = $table->parentNode; + + } elseif (!isset($table)) { + $this->foster_parent = $this->stack[0]; + + } elseif (isset($table) && ($table->parentNode === null || + $table->parentNode->nodeType !== XML_ELEMENT_NODE) + ) { + $this->foster_parent = $this->stack[$n - 1]; + } + } + + $this->inBody($token); + } + } + + private function inCaption($token) + { + /* An end tag whose tag name is "caption" */ + if ($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a caption element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a caption element has + been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === 'caption') { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag + name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + )) || ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table') + ) { + /* Parse error. Act as if an end tag with the tag name "caption" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inCaption( + array( + 'name' => 'caption', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + + /* An end tag whose tag name is one of: "body", "col", "colgroup", + "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'col', + 'colgroup', + 'html', + 'tbody', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inColumnGroup($token) + { + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { + /* Insert a col element for the token. Immediately pop the current + node off the stack of open elements. */ + $this->insertElement($token); + array_pop($this->stack); + + /* An end tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'colgroup' + ) { + /* If the current node is the root html element, then this is a + parse error, ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + /* Otherwise, pop the current node (which will be a colgroup + element) from the stack of open elements. Switch the insertion + mode to "in table". */ + } else { + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* An end tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Act as if an end tag with the tag name "colgroup" had been seen, + and then, if that token wasn't ignored, reprocess the current token. */ + $this->inColumnGroup( + array( + 'name' => 'colgroup', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + } + } + + private function inTableBody($token) + { + $clear = array('tbody', 'tfoot', 'thead', 'html'); + + /* A start tag whose tag name is "tr" */ + if ($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Insert a tr element for the token, then switch the insertion + mode to "in row". */ + $this->insertElement($token); + $this->mode = self::IN_ROW; + + /* A start tag whose tag name is one of: "th", "td" */ + } elseif ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Parse error. Act as if a start tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inTableBody( + array( + 'name' => 'tr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inRow($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node from the stack of open elements. Switch + the insertion mode to "in table". */ + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead') + )) || + ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table') + ) { + /* If the stack of open elements does not have a tbody, thead, or + tfoot element in table scope, this is a parse error. Ignore the + token. (innerHTML case) */ + if (!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Act as if an end tag with the same tag name as the current + node ("tbody", "tfoot", or "thead") had been seen, then + reprocess the current token. */ + $this->inTableBody( + array( + 'name' => end($this->stack)->nodeName, + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inRow($token) + { + $clear = array('tr', 'html'); + + /* A start tag whose tag name is one of: "th", "td" */ + if ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in cell". */ + $this->insertElement($token); + $this->mode = self::IN_CELL; + + /* Insert a marker at the end of the list of active formatting + elements. */ + $this->a_formatting[] = self::MARKER; + + /* An end tag whose tag name is "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node (which will be a tr element) from the + stack of open elements. Switch the insertion mode to "in table + body". */ + array_pop($this->stack); + $this->mode = self::IN_TBODY; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* Act as if an end tag with the tag name "tr" had been seen, then, + if that token wasn't ignored, reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Otherwise, act as if an end tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inCell($token) + { + /* An end tag whose tag name is one of: "td", "th" */ + if ($token['type'] === HTML5::ENDTAG && + ($token['name'] === 'td' || $token['name'] === 'th') + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token, then this is a + parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Generate implied end tags, except for elements with the same + tag name as the token. */ + $this->generateImpliedEndTags(array($token['name'])); + + /* Now, if the current node is not an element with the same tag + name as the token, then this is a parse error. */ + // k + + /* Pop elements from this stack until an element with the same + tag name as the token has been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === $token['name']) { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in row". (The current node + will be a tr element at this point.) */ + $this->mode = self::IN_ROW; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html') + ) + ) { + /* Parse error. Ignore the token. */ + + /* An end tag whose tag name is one of: "table", "tbody", "tfoot", + "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token (which can only + happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), + then this is a parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inSelect($token) + { + /* Handle the token as follows: */ + + /* A character token */ + if ($token['type'] === HTML5::CHARACTR) { + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* A start tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'optgroup' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, act as if an end tag + with the tag name "optgroup" had been seen. */ + if (end($this->stack)->nodeName === 'optgroup') { + $this->inSelect( + array( + 'name' => 'optgroup', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* An end tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'optgroup' + ) { + /* First, if the current node is an option element, and the node + immediately before it in the stack of open elements is an optgroup + element, then act as if an end tag with the tag name "option" had + been seen. */ + $elements_in_stack = count($this->stack); + + if ($this->stack[$elements_in_stack - 1]->nodeName === 'option' && + $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup' + ) { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if ($this->stack[$elements_in_stack - 1] === 'optgroup') { + array_pop($this->stack); + } + + /* An end tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if (end($this->stack)->nodeName === 'option') { + array_pop($this->stack); + } + + /* An end tag whose tag name is "select" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'select' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // w/e + + /* Otherwise: */ + } else { + /* Pop elements from the stack of open elements until a select + element has been popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'select') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* A start tag whose tag name is "select" */ + } elseif ($token['name'] === 'select' && + $token['type'] === HTML5::STARTTAG + ) { + /* Parse error. Act as if the token had been an end tag with the + tag name "select" instead. */ + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + /* An end tag whose tag name is one of: "caption", "table", "tbody", + "tfoot", "thead", "tr", "td", "th" */ + } elseif (in_array( + $token['name'], + array( + 'caption', + 'table', + 'tbody', + 'tfoot', + 'thead', + 'tr', + 'td', + 'th' + ) + ) && $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. */ + // w/e + + /* If the stack of open elements has an element in table scope with + the same tag name as that of the token, then act as if an end tag + with the tag name "select" had been seen, and reprocess the token. + Otherwise, ignore the token. */ + if ($this->elementInScope($token['name'], true)) { + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + $this->mainPhase($token); + } + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterBody($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed if the insertion mode + was "in body". */ + $this->inBody($token); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the first element in the stack of open + elements (the html element), with the data attribute set to the + data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->stack[0]->appendChild($comment); + + /* An end tag with the tag name "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { + /* If the parser was originally created in order to handle the + setting of an element's innerHTML attribute, this is a parse error; + ignore the token. (The element will be an html element in this + case.) (innerHTML case) */ + + /* Otherwise, switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* Anything else */ + } else { + /* Parse error. Set the insertion mode to "in body" and reprocess + the token. */ + $this->mode = self::IN_BODY; + return $this->inBody($token); + } + } + + private function inFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::STARTTAG + ) { + $this->insertElement($token); + + /* An end tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::ENDTAG + ) { + /* If the current node is the root html element, then this is a + parse error; ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + } else { + /* Otherwise, pop the current node from the stack of open + elements. */ + array_pop($this->stack); + + /* If the parser was not originally created in order to handle + the setting of an element's innerHTML attribute (innerHTML case), + and the current node is no longer a frameset element, then change + the insertion mode to "after frameset". */ + $this->mode = self::AFTR_FRAME; + } + + /* A start tag with the tag name "frame" */ + } elseif ($token['name'] === 'frame' && + $token['type'] === HTML5::STARTTAG + ) { + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* An end tag with the tag name "html" */ + } elseif ($token['name'] === 'html' && + $token['type'] === HTML5::ENDTAG + ) { + /* Switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function trailingEndPhase($token) + { + /* After the main phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed in the main phase. */ + $this->mainPhase($token); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or a start tag token. Or an end tag token. */ + } elseif (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. Switch back to the main phase and reprocess the + token. */ + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* OMG DONE!! */ + } + } + + private function insertElement($token, $append = true, $check = false) + { + // Proprietary workaround for libxml2's limitations with tag names + if ($check) { + // Slightly modified HTML5 tag-name modification, + // removing anything that's not an ASCII letter, digit, or hyphen + $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); + // Remove leading hyphens and numbers + $token['name'] = ltrim($token['name'], '-0..9'); + // In theory, this should ever be needed, but just in case + if ($token['name'] === '') { + $token['name'] = 'span'; + } // arbitrary generic choice + } + + $el = $this->dom->createElement($token['name']); + + foreach ($token['attr'] as $attr) { + if (!$el->hasAttribute($attr['name'])) { + $el->setAttribute($attr['name'], $attr['value']); + } + } + + $this->appendToRealParent($el); + $this->stack[] = $el; + + return $el; + } + + private function insertText($data) + { + $text = $this->dom->createTextNode($data); + $this->appendToRealParent($text); + } + + private function insertComment($data) + { + $comment = $this->dom->createComment($data); + $this->appendToRealParent($comment); + } + + private function appendToRealParent($node) + { + if ($this->foster_parent === null) { + end($this->stack)->appendChild($node); + + } elseif ($this->foster_parent !== null) { + /* If the foster parent element is the parent element of the + last table element in the stack of open elements, then the new + node must be inserted immediately before the last table element + in the stack of open elements in the foster parent element; + otherwise, the new node must be appended to the foster parent + element. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table' && + $this->stack[$n]->parentNode !== null + ) { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $this->foster_parent->isSameNode($table->parentNode)) { + $this->foster_parent->insertBefore($node, $table); + } else { + $this->foster_parent->appendChild($node); + } + + $this->foster_parent = null; + } + } + + private function elementInScope($el, $table = false) + { + if (is_array($el)) { + foreach ($el as $element) { + if ($this->elementInScope($element, $table)) { + return true; + } + } + + return false; + } + + $leng = count($this->stack); + + for ($n = 0; $n < $leng; $n++) { + /* 1. Initialise node to be the current node (the bottommost node of + the stack). */ + $node = $this->stack[$leng - 1 - $n]; + + if ($node->tagName === $el) { + /* 2. If node is the target node, terminate in a match state. */ + return true; + + } elseif ($node->tagName === 'table') { + /* 3. Otherwise, if node is a table element, terminate in a failure + state. */ + return false; + + } elseif ($table === true && in_array( + $node->tagName, + array( + 'caption', + 'td', + 'th', + 'button', + 'marquee', + 'object' + ) + ) + ) { + /* 4. Otherwise, if the algorithm is the "has an element in scope" + variant (rather than the "has an element in table scope" variant), + and node is one of the following, terminate in a failure state. */ + return false; + + } elseif ($node === $node->ownerDocument->documentElement) { + /* 5. Otherwise, if node is an html element (root element), terminate + in a failure state. (This can only happen if the node is the topmost + node of the stack of open elements, and prevents the next step from + being invoked if there are no more elements in the stack.) */ + return false; + } + + /* Otherwise, set node to the previous entry in the stack of open + elements and return to step 2. (This will never fail, since the loop + will always terminate in the previous step if the top of the stack + is reached.) */ + } + } + + private function reconstructActiveFormattingElements() + { + /* 1. If there are no entries in the list of active formatting elements, + then there is nothing to reconstruct; stop this algorithm. */ + $formatting_elements = count($this->a_formatting); + + if ($formatting_elements === 0) { + return false; + } + + /* 3. Let entry be the last (most recently added) element in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. If the last (most recently added) entry in the list of active + formatting elements is a marker, or if it is an element that is in the + stack of open elements, then there is nothing to reconstruct; stop this + algorithm. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + return false; + } + + for ($a = $formatting_elements - 1; $a >= 0; true) { + /* 4. If there are no entries before entry in the list of active + formatting elements, then jump to step 8. */ + if ($a === 0) { + $step_seven = false; + break; + } + + /* 5. Let entry be the entry one earlier than entry in the list of + active formatting elements. */ + $a--; + $entry = $this->a_formatting[$a]; + + /* 6. If entry is neither a marker nor an element that is also in + thetack of open elements, go to step 4. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + break; + } + } + + while (true) { + /* 7. Let entry be the element one later than entry in the list of + active formatting elements. */ + if (isset($step_seven) && $step_seven === true) { + $a++; + $entry = $this->a_formatting[$a]; + } + + /* 8. Perform a shallow clone of the element entry to obtain clone. */ + $clone = $entry->cloneNode(); + + /* 9. Append clone to the current node and push it onto the stack + of open elements so that it is the new current node. */ + end($this->stack)->appendChild($clone); + $this->stack[] = $clone; + + /* 10. Replace the entry for entry in the list with an entry for + clone. */ + $this->a_formatting[$a] = $clone; + + /* 11. If the entry for clone in the list of active formatting + elements is not the last entry in the list, return to step 7. */ + if (end($this->a_formatting) !== $clone) { + $step_seven = true; + } else { + break; + } + } + } + + private function clearTheActiveFormattingElementsUpToTheLastMarker() + { + /* When the steps below require the UA to clear the list of active + formatting elements up to the last marker, the UA must perform the + following steps: */ + + while (true) { + /* 1. Let entry be the last (most recently added) entry in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. Remove entry from the list of active formatting elements. */ + array_pop($this->a_formatting); + + /* 3. If entry was a marker, then stop the algorithm at this point. + The list has been cleared up to the last marker. */ + if ($entry === self::MARKER) { + break; + } + } + } + + private function generateImpliedEndTags($exclude = array()) + { + /* When the steps below require the UA to generate implied end tags, + then, if the current node is a dd element, a dt element, an li element, + a p element, a td element, a th element, or a tr element, the UA must + act as if an end tag with the respective tag name had been seen and + then generate implied end tags again. */ + $node = end($this->stack); + $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); + + while (in_array(end($this->stack)->nodeName, $elements)) { + array_pop($this->stack); + } + } + + private function getElementCategory($node) + { + $name = $node->tagName; + if (in_array($name, $this->special)) { + return self::SPECIAL; + } elseif (in_array($name, $this->scoping)) { + return self::SCOPING; + } elseif (in_array($name, $this->formatting)) { + return self::FORMATTING; + } else { + return self::PHRASING; + } + } + + private function clearStackToTableContext($elements) + { + /* When the steps above require the UA to clear the stack back to a + table context, it means that the UA must, while the current node is not + a table element or an html element, pop elements from the stack of open + elements. If this causes any elements to be popped from the stack, then + this is a parse error. */ + while (true) { + $node = end($this->stack)->nodeName; + + if (in_array($node, $elements)) { + break; + } else { + array_pop($this->stack); + } + } + } + + private function resetInsertionMode() + { + /* 1. Let last be false. */ + $last = false; + $leng = count($this->stack); + + for ($n = $leng - 1; $n >= 0; $n--) { + /* 2. Let node be the last node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 3. If node is the first node in the stack of open elements, then + set last to true. If the element whose innerHTML attribute is being + set is neither a td element nor a th element, then set node to the + element whose innerHTML attribute is being set. (innerHTML case) */ + if ($this->stack[0]->isSameNode($node)) { + $last = true; + } + + /* 4. If node is a select element, then switch the insertion mode to + "in select" and abort these steps. (innerHTML case) */ + if ($node->nodeName === 'select') { + $this->mode = self::IN_SELECT; + break; + + /* 5. If node is a td or th element, then switch the insertion mode + to "in cell" and abort these steps. */ + } elseif ($node->nodeName === 'td' || $node->nodeName === 'th') { + $this->mode = self::IN_CELL; + break; + + /* 6. If node is a tr element, then switch the insertion mode to + "in row" and abort these steps. */ + } elseif ($node->nodeName === 'tr') { + $this->mode = self::IN_ROW; + break; + + /* 7. If node is a tbody, thead, or tfoot element, then switch the + insertion mode to "in table body" and abort these steps. */ + } elseif (in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { + $this->mode = self::IN_TBODY; + break; + + /* 8. If node is a caption element, then switch the insertion mode + to "in caption" and abort these steps. */ + } elseif ($node->nodeName === 'caption') { + $this->mode = self::IN_CAPTION; + break; + + /* 9. If node is a colgroup element, then switch the insertion mode + to "in column group" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'colgroup') { + $this->mode = self::IN_CGROUP; + break; + + /* 10. If node is a table element, then switch the insertion mode + to "in table" and abort these steps. */ + } elseif ($node->nodeName === 'table') { + $this->mode = self::IN_TABLE; + break; + + /* 11. If node is a head element, then switch the insertion mode + to "in body" ("in body"! not "in head"!) and abort these steps. + (innerHTML case) */ + } elseif ($node->nodeName === 'head') { + $this->mode = self::IN_BODY; + break; + + /* 12. If node is a body element, then switch the insertion mode to + "in body" and abort these steps. */ + } elseif ($node->nodeName === 'body') { + $this->mode = self::IN_BODY; + break; + + /* 13. If node is a frameset element, then switch the insertion + mode to "in frameset" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'frameset') { + $this->mode = self::IN_FRAME; + break; + + /* 14. If node is an html element, then: if the head element + pointer is null, switch the insertion mode to "before head", + otherwise, switch the insertion mode to "after head". In either + case, abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'html') { + $this->mode = ($this->head_pointer === null) + ? self::BEFOR_HEAD + : self::AFTER_HEAD; + + break; + + /* 15. If last is true, then set the insertion mode to "in body" + and abort these steps. (innerHTML case) */ + } elseif ($last) { + $this->mode = self::IN_BODY; + break; + } + } + } + + private function closeCell() + { + /* If the stack of open elements has a td or th element in table scope, + then act as if an end tag token with that tag name had been seen. */ + foreach (array('td', 'th') as $cell) { + if ($this->elementInScope($cell, true)) { + $this->inCell( + array( + 'name' => $cell, + 'type' => HTML5::ENDTAG + ) + ); + + break; + } + } + } + + public function save() + { + return $this->dom; + } +} diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php new file mode 100644 index 0000000..3995fec --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php @@ -0,0 +1,49 @@ +data = $data; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Comment($this->data, $this->line, $this->col), null); + } +} diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php new file mode 100644 index 0000000..6cbf56d --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php @@ -0,0 +1,59 @@ + form or the form, i.e. + * is it a pair of start/end tokens or an empty token. + * @bool + */ + public $empty = false; + + public $endCol = null, $endLine = null, $endArmor = array(); + + public function __construct($name, $attr = array(), $line = null, $col = null, $armor = array()) { + $this->name = $name; + $this->attr = $attr; + $this->line = $line; + $this->col = $col; + $this->armor = $armor; + } + + public function toTokenPair() { + // XXX inefficiency here, normalization is not necessary + if ($this->empty) { + return array(new HTMLPurifier_Token_Empty($this->name, $this->attr, $this->line, $this->col, $this->armor), null); + } else { + $start = new HTMLPurifier_Token_Start($this->name, $this->attr, $this->line, $this->col, $this->armor); + $end = new HTMLPurifier_Token_End($this->name, array(), $this->endLine, $this->endCol, $this->endArmor); + //$end->start = $start; + return array($start, $end); + } + } +} + diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php new file mode 100644 index 0000000..aec9166 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php @@ -0,0 +1,54 @@ +data = $data; + $this->is_whitespace = $is_whitespace; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Text($this->data, $this->line, $this->col), null); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php new file mode 100644 index 0000000..18c8bbb --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php @@ -0,0 +1,111 @@ +preserve[$i] = true; + } + for ($i = 65; $i <= 90; $i++) { // upper-case + $this->preserve[$i] = true; + } + for ($i = 97; $i <= 122; $i++) { // lower-case + $this->preserve[$i] = true; + } + $this->preserve[45] = true; // Dash - + $this->preserve[46] = true; // Period . + $this->preserve[95] = true; // Underscore _ + $this->preserve[126]= true; // Tilde ~ + + // extra letters not to escape + if ($preserve !== false) { + for ($i = 0, $c = strlen($preserve); $i < $c; $i++) { + $this->preserve[ord($preserve[$i])] = true; + } + } + } + + /** + * Our replacement for urlencode, it encodes all non-reserved characters, + * as well as any extra characters that were instructed to be preserved. + * @note + * Assumes that the string has already been normalized, making any + * and all percent escape sequences valid. Percents will not be + * re-escaped, regardless of their status in $preserve + * @param string $string String to be encoded + * @return string Encoded string. + */ + public function encode($string) + { + $ret = ''; + for ($i = 0, $c = strlen($string); $i < $c; $i++) { + if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])])) { + $ret .= '%' . sprintf('%02X', $int); + } else { + $ret .= $string[$i]; + } + } + return $ret; + } + + /** + * Fix up percent-encoding by decoding unreserved characters and normalizing. + * @warning This function is affected by $preserve, even though the + * usual desired behavior is for this not to preserve those + * characters. Be careful when reusing instances of PercentEncoder! + * @param string $string String to normalize + * @return string + */ + public function normalize($string) + { + if ($string == '') { + return ''; + } + $parts = explode('%', $string); + $ret = array_shift($parts); + foreach ($parts as $part) { + $length = strlen($part); + if ($length < 2) { + $ret .= '%25' . $part; + continue; + } + $encoding = substr($part, 0, 2); + $text = substr($part, 2); + if (!ctype_xdigit($encoding)) { + $ret .= '%25' . $part; + continue; + } + $int = hexdec($encoding); + if (isset($this->preserve[$int])) { + $ret .= chr($int) . $text; + continue; + } + $encoding = strtoupper($encoding); + $ret .= '%' . $encoding . $text; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php new file mode 100644 index 0000000..549e4ce --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php @@ -0,0 +1,218 @@ +getAll(); + $context = new HTMLPurifier_Context(); + $this->generator = new HTMLPurifier_Generator($config, $context); + } + + /** + * Main function that renders object or aspect of that object + * @note Parameters vary depending on printer + */ + // function render() {} + + /** + * Returns a start tag + * @param string $tag Tag name + * @param array $attr Attribute array + * @return string + */ + protected function start($tag, $attr = array()) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) + ); + } + + /** + * Returns an end tag + * @param string $tag Tag name + * @return string + */ + protected function end($tag) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_End($tag) + ); + } + + /** + * Prints a complete element with content inside + * @param string $tag Tag name + * @param string $contents Element contents + * @param array $attr Tag attributes + * @param bool $escape whether or not to escape contents + * @return string + */ + protected function element($tag, $contents, $attr = array(), $escape = true) + { + return $this->start($tag, $attr) . + ($escape ? $this->escape($contents) : $contents) . + $this->end($tag); + } + + /** + * @param string $tag + * @param array $attr + * @return string + */ + protected function elementEmpty($tag, $attr = array()) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Empty($tag, $attr) + ); + } + + /** + * @param string $text + * @return string + */ + protected function text($text) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Text($text) + ); + } + + /** + * Prints a simple key/value row in a table. + * @param string $name Key + * @param mixed $value Value + * @return string + */ + protected function row($name, $value) + { + if (is_bool($value)) { + $value = $value ? 'On' : 'Off'; + } + return + $this->start('tr') . "\n" . + $this->element('th', $name) . "\n" . + $this->element('td', $value) . "\n" . + $this->end('tr'); + } + + /** + * Escapes a string for HTML output. + * @param string $string String to escape + * @return string + */ + protected function escape($string) + { + $string = HTMLPurifier_Encoder::cleanUTF8($string); + $string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); + return $string; + } + + /** + * Takes a list of strings and turns them into a single list + * @param string[] $array List of strings + * @param bool $polite Bool whether or not to add an end before the last + * @return string + */ + protected function listify($array, $polite = false) + { + if (empty($array)) { + return 'None'; + } + $ret = ''; + $i = count($array); + foreach ($array as $value) { + $i--; + $ret .= $value; + if ($i > 0 && !($polite && $i == 1)) { + $ret .= ', '; + } + if ($polite && $i == 1) { + $ret .= 'and '; + } + } + return $ret; + } + + /** + * Retrieves the class of an object without prefixes, as well as metadata + * @param object $obj Object to determine class of + * @param string $sec_prefix Further prefix to remove + * @return string + */ + protected function getClass($obj, $sec_prefix = '') + { + static $five = null; + if ($five === null) { + $five = version_compare(PHP_VERSION, '5', '>='); + } + $prefix = 'HTMLPurifier_' . $sec_prefix; + if (!$five) { + $prefix = strtolower($prefix); + } + $class = str_replace($prefix, '', get_class($obj)); + $lclass = strtolower($class); + $class .= '('; + switch ($lclass) { + case 'enum': + $values = array(); + foreach ($obj->valid_values as $value => $bool) { + $values[] = $value; + } + $class .= implode(', ', $values); + break; + case 'css_composite': + $values = array(); + foreach ($obj->defs as $def) { + $values[] = $this->getClass($def, $sec_prefix); + } + $class .= implode(', ', $values); + break; + case 'css_multiple': + $class .= $this->getClass($obj->single, $sec_prefix) . ', '; + $class .= $obj->max; + break; + case 'css_denyelementdecorator': + $class .= $this->getClass($obj->def, $sec_prefix) . ', '; + $class .= $obj->element; + break; + case 'css_importantdecorator': + $class .= $this->getClass($obj->def, $sec_prefix); + if ($obj->allow) { + $class .= ', !important'; + } + break; + } + $class .= ')'; + return $class; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php new file mode 100644 index 0000000..29505fe --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php @@ -0,0 +1,44 @@ +def = $config->getCSSDefinition(); + $ret = ''; + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + $ret .= $this->start('table'); + + $ret .= $this->element('caption', 'Properties ($info)'); + + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Property', array('class' => 'heavy')); + $ret .= $this->element('th', 'Definition', array('class' => 'heavy', 'style' => 'width:auto;')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + + ksort($this->def->info); + foreach ($this->def->info as $property => $obj) { + $name = $this->getClass($obj, 'AttrDef_'); + $ret .= $this->row($property, $name); + } + + $ret .= $this->end('table'); + $ret .= $this->end('div'); + + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css new file mode 100644 index 0000000..3ff1a88 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css @@ -0,0 +1,10 @@ + +.hp-config {} + +.hp-config tbody th {text-align:right; padding-right:0.5em;} +.hp-config thead, .hp-config .namespace {background:#3C578C; color:#FFF;} +.hp-config .namespace th {text-align:center;} +.hp-config .verbose {display:none;} +.hp-config .controls {text-align:center;} + +/* vim: et sw=4 sts=4 */ diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js new file mode 100644 index 0000000..cba00c9 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js @@ -0,0 +1,5 @@ +function toggleWriteability(id_of_patient, checked) { + document.getElementById(id_of_patient).disabled = checked; +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php new file mode 100644 index 0000000..33ae113 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php @@ -0,0 +1,451 @@ +docURL = $doc_url; + $this->name = $name; + $this->compress = $compress; + // initialize sub-printers + $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); + $this->fields[HTMLPurifier_VarParser::C_BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); + } + + /** + * Sets default column and row size for textareas in sub-printers + * @param $cols Integer columns of textarea, null to use default + * @param $rows Integer rows of textarea, null to use default + */ + public function setTextareaDimensions($cols = null, $rows = null) + { + if ($cols) { + $this->fields['default']->cols = $cols; + } + if ($rows) { + $this->fields['default']->rows = $rows; + } + } + + /** + * Retrieves styling, in case it is not accessible by webserver + */ + public static function getCSS() + { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); + } + + /** + * Retrieves JavaScript, in case it is not accessible by webserver + */ + public static function getJavaScript() + { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); + } + + /** + * Returns HTML output for a configuration form + * @param HTMLPurifier_Config|array $config Configuration object of current form state, or an array + * where [0] has an HTML namespace and [1] is being rendered. + * @param array|bool $allowed Optional namespace(s) and directives to restrict form to. + * @param bool $render_controls + * @return string + */ + public function render($config, $allowed = true, $render_controls = true) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + + $this->config = $config; + $this->genConfig = $gen_config; + $this->prepareGenerator($gen_config); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $config->def); + $all = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $all[$ns][$directive] = $config->get($ns . '.' . $directive); + } + + $ret = ''; + $ret .= $this->start('table', array('class' => 'hp-config')); + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); + $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + foreach ($all as $ns => $directives) { + $ret .= $this->renderNamespace($ns, $directives); + } + if ($render_controls) { + $ret .= $this->start('tbody'); + $ret .= $this->start('tr'); + $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); + $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); + $ret .= '[Reset]'; + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a single namespace + * @param $ns String namespace name + * @param array $directives array of directives to values + * @return string + */ + protected function renderNamespace($ns, $directives) + { + $ret = ''; + $ret .= $this->start('tbody', array('class' => 'namespace')); + $ret .= $this->start('tr'); + $ret .= $this->element('th', $ns, array('colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + $ret .= $this->start('tbody'); + foreach ($directives as $directive => $value) { + $ret .= $this->start('tr'); + $ret .= $this->start('th'); + if ($this->docURL) { + $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); + $ret .= $this->start('a', array('href' => $url)); + } + $attr = array('for' => "{$this->name}:$ns.$directive"); + + // crop directive name if it's too long + if (!$this->compress || (strlen($directive) < $this->compress)) { + $directive_disp = $directive; + } else { + $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; + $attr['title'] = $directive; + } + + $ret .= $this->element( + 'label', + $directive_disp, + // component printers must create an element with this id + $attr + ); + if ($this->docURL) { + $ret .= $this->end('a'); + } + $ret .= $this->end('th'); + + $ret .= $this->start('td'); + $def = $this->config->def->info["$ns.$directive"]; + if (is_int($def)) { + $allow_null = $def < 0; + $type = abs($def); + } else { + $type = $def->type; + $allow_null = isset($def->allow_null); + } + if (!isset($this->fields[$type])) { + $type = 0; + } // default + $type_obj = $this->fields[$type]; + if ($allow_null) { + $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); + } + $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + } + $ret .= $this->end('tbody'); + return $ret; + } + +} + +/** + * Printer decorator for directives that accept null + */ +class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer +{ + /** + * Printer being decorated + * @type HTMLPurifier_Printer + */ + protected $obj; + + /** + * @param HTMLPurifier_Printer $obj Printer to decorate + */ + public function __construct($obj) + { + parent::__construct(); + $this->obj = $obj; + } + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + + $ret = ''; + $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Null/Disabled'); + $ret .= $this->end('label'); + $attr = array( + 'type' => 'checkbox', + 'value' => '1', + 'class' => 'null-toggle', + 'name' => "$name" . "[Null_$ns.$directive]", + 'id' => "$name:Null_$ns.$directive", + 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! + ); + if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { + // modify inline javascript slightly + $attr['onclick'] = + "toggleWriteability('$name:Yes_$ns.$directive',checked);" . + "toggleWriteability('$name:No_$ns.$directive',checked)"; + } + if ($value === null) { + $attr['checked'] = 'checked'; + } + $ret .= $this->elementEmpty('input', $attr); + $ret .= $this->text(' or '); + $ret .= $this->elementEmpty('br'); + $ret .= $this->obj->render($ns, $directive, $value, $name, array($gen_config, $config)); + return $ret; + } +} + +/** + * Swiss-army knife configuration form field printer + */ +class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer +{ + /** + * @type int + */ + public $cols = 18; + + /** + * @type int + */ + public $rows = 5; + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + // this should probably be split up a little + $ret = ''; + $def = $config->def->info["$ns.$directive"]; + if (is_int($def)) { + $type = abs($def); + } else { + $type = $def->type; + } + if (is_array($value)) { + switch ($type) { + case HTMLPurifier_VarParser::LOOKUP: + $array = $value; + $value = array(); + foreach ($array as $val => $b) { + $value[] = $val; + } + //TODO does this need a break? + case HTMLPurifier_VarParser::ALIST: + $value = implode(PHP_EOL, $value); + break; + case HTMLPurifier_VarParser::HASH: + $nvalue = ''; + foreach ($value as $i => $v) { + if (is_array($v)) { + // HACK + $v = implode(";", $v); + } + $nvalue .= "$i:$v" . PHP_EOL; + } + $value = $nvalue; + break; + default: + $value = ''; + } + } + if ($type === HTMLPurifier_VarParser::C_MIXED) { + return 'Not supported'; + $value = serialize($value); + } + $attr = array( + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:$ns.$directive" + ); + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + if (isset($def->allowed)) { + $ret .= $this->start('select', $attr); + foreach ($def->allowed as $val => $b) { + $attr = array(); + if ($value == $val) { + $attr['selected'] = 'selected'; + } + $ret .= $this->element('option', $val, $attr); + } + $ret .= $this->end('select'); + } elseif ($type === HTMLPurifier_VarParser::TEXT || + $type === HTMLPurifier_VarParser::ITEXT || + $type === HTMLPurifier_VarParser::ALIST || + $type === HTMLPurifier_VarParser::HASH || + $type === HTMLPurifier_VarParser::LOOKUP) { + $attr['cols'] = $this->cols; + $attr['rows'] = $this->rows; + $ret .= $this->start('textarea', $attr); + $ret .= $this->text($value); + $ret .= $this->end('textarea'); + } else { + $attr['value'] = $value; + $attr['type'] = 'text'; + $ret .= $this->elementEmpty('input', $attr); + } + return $ret; + } +} + +/** + * Bool form field printer + */ +class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer +{ + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + $ret = ''; + $ret .= $this->start('div', array('id' => "$name:$ns.$directive")); + + $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Yes'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:Yes_$ns.$directive", + 'value' => '1' + ); + if ($value === true) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' No'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:No_$ns.$directive", + 'value' => '0' + ); + if ($value === false) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->end('div'); + + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php new file mode 100644 index 0000000..ae86391 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php @@ -0,0 +1,324 @@ +config =& $config; + + $this->def = $config->getHTMLDefinition(); + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + + $ret .= $this->renderDoctype(); + $ret .= $this->renderEnvironment(); + $ret .= $this->renderContentSets(); + $ret .= $this->renderInfo(); + + $ret .= $this->end('div'); + + return $ret; + } + + /** + * Renders the Doctype table + * @return string + */ + protected function renderDoctype() + { + $doctype = $this->def->doctype; + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Doctype'); + $ret .= $this->row('Name', $doctype->name); + $ret .= $this->row('XML', $doctype->xml ? 'Yes' : 'No'); + $ret .= $this->row('Default Modules', implode(', ', $doctype->modules)); + $ret .= $this->row('Default Tidy Modules', implode(', ', $doctype->tidyModules)); + $ret .= $this->end('table'); + return $ret; + } + + + /** + * Renders environment table, which is miscellaneous info + * @return string + */ + protected function renderEnvironment() + { + $def = $this->def; + + $ret = ''; + + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Environment'); + + $ret .= $this->row('Parent of fragment', $def->info_parent); + $ret .= $this->renderChildren($def->info_parent_def->child); + $ret .= $this->row('Block wrap name', $def->info_block_wrapper); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Global attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr), null, 0); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Tag transforms'); + $list = array(); + foreach ($def->info_tag_transform as $old => $new) { + $new = $this->getClass($new, 'TagTransform_'); + $list[] = "<$old> with $new"; + } + $ret .= $this->element('td', $this->listify($list)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); + $ret .= $this->end('tr'); + + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Content Sets table + * @return string + */ + protected function renderContentSets() + { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Content Sets'); + foreach ($this->def->info_content_sets as $name => $lookup) { + $ret .= $this->heavyHeader($name); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($lookup)); + $ret .= $this->end('tr'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Elements ($info) table + * @return string + */ + protected function renderInfo() + { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Elements ($info)'); + ksort($this->def->info); + $ret .= $this->heavyHeader('Allowed tags', 2); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($this->def->info), array('colspan' => 2)); + $ret .= $this->end('tr'); + foreach ($this->def->info as $name => $def) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', "<$name>", array('class' => 'heavy', 'colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Inline content'); + $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); + $ret .= $this->end('tr'); + if (!empty($def->excludes)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Excludes'); + $ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_pre)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_post)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); + $ret .= $this->end('tr'); + } + if (!empty($def->auto_close)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Auto closed by'); + $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); + $ret .= $this->end('tr'); + } + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Allowed attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->attr), array(), 0); + $ret .= $this->end('tr'); + + if (!empty($def->required_attr)) { + $ret .= $this->row('Required attributes', $this->listify($def->required_attr)); + } + + $ret .= $this->renderChildren($def->child); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a row describing the allowed children of an element + * @param HTMLPurifier_ChildDef $def HTMLPurifier_ChildDef of pertinent element + * @return string + */ + protected function renderChildren($def) + { + $context = new HTMLPurifier_Context(); + $ret = ''; + $ret .= $this->start('tr'); + $elements = array(); + $attr = array(); + if (isset($def->elements)) { + if ($def->type == 'strictblockquote') { + $def->validateChildren(array(), $this->config, $context); + } + $elements = $def->elements; + } + if ($def->type == 'chameleon') { + $attr['rowspan'] = 2; + } elseif ($def->type == 'empty') { + $elements = array(); + } elseif ($def->type == 'table') { + $elements = array_flip( + array( + 'col', + 'caption', + 'colgroup', + 'thead', + 'tfoot', + 'tbody', + 'tr' + ) + ); + } + $ret .= $this->element('th', 'Allowed children', $attr); + + if ($def->type == 'chameleon') { + + $ret .= $this->element( + 'td', + 'Block: ' . + $this->escape($this->listifyTagLookup($def->block->elements)), + null, + 0 + ); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element( + 'td', + 'Inline: ' . + $this->escape($this->listifyTagLookup($def->inline->elements)), + null, + 0 + ); + + } elseif ($def->type == 'custom') { + + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $def->dtd_regex + ); + + } else { + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $this->escape($this->listifyTagLookup($elements)), + null, + 0 + ); + } + $ret .= $this->end('tr'); + return $ret; + } + + /** + * Listifies a tag lookup table. + * @param array $array Tag lookup array in form of array('tagname' => true) + * @return string + */ + protected function listifyTagLookup($array) + { + ksort($array); + $list = array(); + foreach ($array as $name => $discard) { + if ($name !== '#PCDATA' && !isset($this->def->info[$name])) { + continue; + } + $list[] = $name; + } + return $this->listify($list); + } + + /** + * Listifies a list of objects by retrieving class names and internal state + * @param array $array List of objects + * @return string + * @todo Also add information about internal state + */ + protected function listifyObjectList($array) + { + ksort($array); + $list = array(); + foreach ($array as $obj) { + $list[] = $this->getClass($obj, 'AttrTransform_'); + } + return $this->listify($list); + } + + /** + * Listifies a hash of attributes to AttrDef classes + * @param array $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) + * @return string + */ + protected function listifyAttr($array) + { + ksort($array); + $list = array(); + foreach ($array as $name => $obj) { + if ($obj === false) { + continue; + } + $list[] = "$name = " . $this->getClass($obj, 'AttrDef_') . ''; + } + return $this->listify($list); + } + + /** + * Creates a heavy header row + * @param string $text + * @param int $num + * @return string + */ + protected function heavyHeader($text, $num = 1) + { + $ret = ''; + $ret .= $this->start('tr'); + $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy')); + $ret .= $this->end('tr'); + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php new file mode 100644 index 0000000..189348f --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php @@ -0,0 +1,122 @@ +parent = $parent; + } + + /** + * Recursively retrieves the value for a key + * @param string $name + * @throws HTMLPurifier_Exception + */ + public function get($name) + { + if ($this->has($name)) { + return $this->data[$name]; + } + // possible performance bottleneck, convert to iterative if necessary + if ($this->parent) { + return $this->parent->get($name); + } + throw new HTMLPurifier_Exception("Key '$name' not found"); + } + + /** + * Sets the value of a key, for this plist + * @param string $name + * @param mixed $value + */ + public function set($name, $value) + { + $this->data[$name] = $value; + } + + /** + * Returns true if a given key exists + * @param string $name + * @return bool + */ + public function has($name) + { + return array_key_exists($name, $this->data); + } + + /** + * Resets a value to the value of it's parent, usually the default. If + * no value is specified, the entire plist is reset. + * @param string $name + */ + public function reset($name = null) + { + if ($name == null) { + $this->data = array(); + } else { + unset($this->data[$name]); + } + } + + /** + * Squashes this property list and all of its property lists into a single + * array, and returns the array. This value is cached by default. + * @param bool $force If true, ignores the cache and regenerates the array. + * @return array + */ + public function squash($force = false) + { + if ($this->cache !== null && !$force) { + return $this->cache; + } + if ($this->parent) { + return $this->cache = array_merge($this->parent->squash($force), $this->data); + } else { + return $this->cache = $this->data; + } + } + + /** + * Returns the parent plist. + * @return HTMLPurifier_PropertyList + */ + public function getParent() + { + return $this->parent; + } + + /** + * Sets the parent plist. + * @param HTMLPurifier_PropertyList $plist Parent plist + */ + public function setParent($plist) + { + $this->parent = $plist; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php new file mode 100644 index 0000000..15b330e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php @@ -0,0 +1,42 @@ +l = strlen($filter); + $this->filter = $filter; + } + + /** + * @return bool + */ + public function accept() + { + $key = $this->getInnerIterator()->key(); + if (strncmp($key, $this->filter, $this->l) !== 0) { + return false; + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php new file mode 100644 index 0000000..f58db90 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php @@ -0,0 +1,56 @@ +input = $input; + $this->output = array(); + } + + /** + * Shifts an element off the front of the queue. + */ + public function shift() { + if (empty($this->output)) { + $this->output = array_reverse($this->input); + $this->input = array(); + } + if (empty($this->output)) { + return NULL; + } + return array_pop($this->output); + } + + /** + * Pushes an element onto the front of the queue. + */ + public function push($x) { + array_push($this->input, $x); + } + + /** + * Checks if it's empty. + */ + public function isEmpty() { + return empty($this->input) && empty($this->output); + } +} diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php new file mode 100644 index 0000000..e1ff3b7 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php @@ -0,0 +1,26 @@ +strategies as $strategy) { + $tokens = $strategy->execute($tokens, $config, $context); + } + return $tokens; + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php new file mode 100644 index 0000000..4414c17 --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php @@ -0,0 +1,17 @@ +strategies[] = new HTMLPurifier_Strategy_RemoveForeignElements(); + $this->strategies[] = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->strategies[] = new HTMLPurifier_Strategy_FixNesting(); + $this->strategies[] = new HTMLPurifier_Strategy_ValidateAttributes(); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php new file mode 100644 index 0000000..6fa673d --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php @@ -0,0 +1,181 @@ +getHTMLDefinition(); + + $excludes_enabled = !$config->get('Core.DisableExcludes'); + + // setup the context variable 'IsInline', for chameleon processing + // is 'false' when we are not inline, 'true' when it must always + // be inline, and an integer when it is inline for a certain + // branch of the document tree + $is_inline = $definition->info_parent_def->descendants_are_inline; + $context->register('IsInline', $is_inline); + + // setup error collector + $e =& $context->get('ErrorCollector', true); + + //####################################################################// + // Loop initialization + + // stack that contains all elements that are excluded + // it is organized by parent elements, similar to $stack, + // but it is only populated when an element with exclusions is + // processed, i.e. there won't be empty exclusions. + $exclude_stack = array($definition->info_parent_def->excludes); + + // variable that contains the start token while we are processing + // nodes. This enables error reporting to do its job + $node = $top_node; + // dummy token + list($token, $d) = $node->toTokenPair(); + $context->register('CurrentNode', $node); + $context->register('CurrentToken', $token); + + //####################################################################// + // Loop + + // We need to implement a post-order traversal iteratively, to + // avoid running into stack space limits. This is pretty tricky + // to reason about, so we just manually stack-ify the recursive + // variant: + // + // function f($node) { + // foreach ($node->children as $child) { + // f($child); + // } + // validate($node); + // } + // + // Thus, we will represent a stack frame as array($node, + // $is_inline, stack of children) + // e.g. array_reverse($node->children) - already processed + // children. + + $parent_def = $definition->info_parent_def; + $stack = array( + array($top_node, + $parent_def->descendants_are_inline, + $parent_def->excludes, // exclusions + 0) + ); + + while (!empty($stack)) { + list($node, $is_inline, $excludes, $ix) = array_pop($stack); + // recursive call + $go = false; + $def = empty($stack) ? $definition->info_parent_def : $definition->info[$node->name]; + while (isset($node->children[$ix])) { + $child = $node->children[$ix++]; + if ($child instanceof HTMLPurifier_Node_Element) { + $go = true; + $stack[] = array($node, $is_inline, $excludes, $ix); + $stack[] = array($child, + // ToDo: I don't think it matters if it's def or + // child_def, but double check this... + $is_inline || $def->descendants_are_inline, + empty($def->excludes) ? $excludes + : array_merge($excludes, $def->excludes), + 0); + break; + } + }; + if ($go) continue; + list($token, $d) = $node->toTokenPair(); + // base case + if ($excludes_enabled && isset($excludes[$node->name])) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded'); + } else { + // XXX I suppose it would be slightly more efficient to + // avoid the allocation here and have children + // strategies handle it + $children = array(); + foreach ($node->children as $child) { + if (!$child->dead) $children[] = $child; + } + $result = $def->child->validateChildren($children, $config, $context); + if ($result === true) { + // nop + $node->children = $children; + } elseif ($result === false) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node removed'); + } else { + $node->children = $result; + if ($e) { + // XXX This will miss mutations of internal nodes. Perhaps defer to the child validators + if (empty($result) && !empty($children)) { + $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed'); + } else if ($result != $children) { + $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized'); + } + } + } + } + } + + //####################################################################// + // Post-processing + + // remove context variables + $context->destroy('IsInline'); + $context->destroy('CurrentNode'); + $context->destroy('CurrentToken'); + + //####################################################################// + // Return + + return HTMLPurifier_Arborize::flatten($node, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php new file mode 100644 index 0000000..a6eb09e --- /dev/null +++ b/serve/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php @@ -0,0 +1,659 @@ +getHTMLDefinition(); + + // local variables + $generator = new HTMLPurifier_Generator($config, $context); + $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); + // used for autoclose early abortion + $global_parent_allowed_elements = $definition->info_parent_def->child->getAllowedElements($config); + $e = $context->get('ErrorCollector', true); + $i = false; // injector index + list($zipper, $token) = HTMLPurifier_Zipper::fromArray($tokens); + if ($token === NULL) { + return array(); + } + $reprocess = false; // whether or not to reprocess the same token + $stack = array(); + + // member variables + $this->stack =& $stack; + $this->tokens =& $tokens; + $this->token =& $token; + $this->zipper =& $zipper; + $this->config = $config; + $this->context = $context; + + // context variables + $context->register('CurrentNesting', $stack); + $context->register('InputZipper', $zipper); + $context->register('CurrentToken', $token); + + // -- begin INJECTOR -- + + $this->injectors = array(); + + $injectors = $config->getBatch('AutoFormat'); + $def_injectors = $definition->info_injector; + $custom_injectors = $injectors['Custom']; + unset($injectors['Custom']); // special case + foreach ($injectors as $injector => $b) { + // XXX: Fix with a legitimate lookup table of enabled filters + if (strpos($injector, '.') !== false) { + continue; + } + $injector = "HTMLPurifier_Injector_$injector"; + if (!$b) { + continue; + } + $this->injectors[] = new $injector; + } + foreach ($def_injectors as $injector) { + // assumed to be objects + $this->injectors[] = $injector; + } + foreach ($custom_injectors as $injector) { + if (!$injector) { + continue; + } + if (is_string($injector)) { + $injector = "HTMLPurifier_Injector_$injector"; + $injector = new $injector; + } + $this->injectors[] = $injector; + } + + // give the injectors references to the definition and context + // variables for performance reasons + foreach ($this->injectors as $ix => $injector) { + $error = $injector->prepare($config, $context); + if (!$error) { + continue; + } + array_splice($this->injectors, $ix, 1); // rm the injector + trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING); + } + + // -- end INJECTOR -- + + // a note on reprocessing: + // In order to reduce code duplication, whenever some code needs + // to make HTML changes in order to make things "correct", the + // new HTML gets sent through the purifier, regardless of its + // status. This means that if we add a start token, because it + // was totally necessary, we don't have to update nesting; we just + // punt ($reprocess = true; continue;) and it does that for us. + + // isset is in loop because $tokens size changes during loop exec + for (;; + // only increment if we don't need to reprocess + $reprocess ? $reprocess = false : $token = $zipper->next($token)) { + + // check for a rewind + if (is_int($i)) { + // possibility: disable rewinding if the current token has a + // rewind set on it already. This would offer protection from + // infinite loop, but might hinder some advanced rewinding. + $rewind_offset = $this->injectors[$i]->getRewindOffset(); + if (is_int($rewind_offset)) { + for ($j = 0; $j < $rewind_offset; $j++) { + if (empty($zipper->front)) break; + $token = $zipper->prev($token); + // indicate that other injectors should not process this token, + // but we need to reprocess it. See Note [Injector skips] + unset($token->skip[$i]); + $token->rewind = $i; + if ($token instanceof HTMLPurifier_Token_Start) { + array_pop($this->stack); + } elseif ($token instanceof HTMLPurifier_Token_End) { + $this->stack[] = $token->start; + } + } + } + $i = false; + } + + // handle case of document end + if ($token === NULL) { + // kill processing if stack is empty + if (empty($this->stack)) { + break; + } + + // peek + $top_nesting = array_pop($this->stack); + $this->stack[] = $top_nesting; + + // send error [TagClosedSuppress] + if ($e && !isset($top_nesting->armor['MakeWellFormed_TagClosedError'])) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting); + } + + // append, don't splice, since this is the end + $token = new HTMLPurifier_Token_End($top_nesting->name); + + // punt! + $reprocess = true; + continue; + } + + //echo '
'; printZipper($zipper, $token);//printTokens($this->stack); + //flush(); + + // quick-check: if it's not a tag, no need to process + if (empty($token->is_tag)) { + if ($token instanceof HTMLPurifier_Token_Text) { + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) { + // See Note [Injector skips] + continue; + } + if ($token->rewind !== null && $token->rewind !== $i) { + continue; + } + // XXX fuckup + $r = $token; + $injector->handleText($r); + $token = $this->processToken($r, $i); + $reprocess = true; + break; + } + } + // another possibility is a comment + continue; + } + + if (isset($definition->info[$token->name])) { + $type = $definition->info[$token->name]->child->type; + } else { + $type = false; // Type is unknown, treat accordingly + } + + // quick tag checks: anything that's *not* an end tag + $ok = false; + if ($type === 'empty' && $token instanceof HTMLPurifier_Token_Start) { + // claims to be a start tag but is empty + $token = new HTMLPurifier_Token_Empty( + $token->name, + $token->attr, + $token->line, + $token->col, + $token->armor + ); + $ok = true; + } elseif ($type && $type !== 'empty' && $token instanceof HTMLPurifier_Token_Empty) { + // claims to be empty but really is a start tag + // NB: this assignment is required + $old_token = $token; + $token = new HTMLPurifier_Token_End($token->name); + $token = $this->insertBefore( + new HTMLPurifier_Token_Start($old_token->name, $old_token->attr, $old_token->line, $old_token->col, $old_token->armor) + ); + // punt (since we had to modify the input stream in a non-trivial way) + $reprocess = true; + continue; + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + // real empty token + $ok = true; + } elseif ($token instanceof HTMLPurifier_Token_Start) { + // start tag + + // ...unless they also have to close their parent + if (!empty($this->stack)) { + + // Performance note: you might think that it's rather + // inefficient, recalculating the autoclose information + // for every tag that a token closes (since when we + // do an autoclose, we push a new token into the + // stream and then /process/ that, before + // re-processing this token.) But this is + // necessary, because an injector can make an + // arbitrary transformations to the autoclosing + // tokens we introduce, so things may have changed + // in the meantime. Also, doing the inefficient thing is + // "easy" to reason about (for certain perverse definitions + // of "easy") + + $parent = array_pop($this->stack); + $this->stack[] = $parent; + + $parent_def = null; + $parent_elements = null; + $autoclose = false; + if (isset($definition->info[$parent->name])) { + $parent_def = $definition->info[$parent->name]; + $parent_elements = $parent_def->child->getAllowedElements($config); + $autoclose = !isset($parent_elements[$token->name]); + } + + if ($autoclose && $definition->info[$token->name]->wrap) { + // Check if an element can be wrapped by another + // element to make it valid in a context (for + // example,