有位朋友让我给他新开的网站帮忙做几个小功能,如下:

  1. 输入快递公司、快递单号,查询出这个快件的所有动态(从哪里出发,到了哪里)
  2. 在注册、登录等场景下的手机验证码(要求有一定的防刷策略)
  3. 通过输入公司名的关键词,查看这个公司是否已经注册、法人信息、有类似名称的公司等等

并且可以用的接口、文档都提供给我了。
其中需求 1、2,都通过 聚合数据 这家网站提供的接口实现;需求 3 通过 云聚数据 来实现。

本项目的文件

因为朋友的网站是用 ThinkPHP 写的,为了保持将来代码的兼容,这三个功能也用 ThinkPHP 写成。

项目的所有文件都放在了 GitHub 上,部分敏感数据已经隐藏,你需要自行替换,地址如下:

GitHub 地址:使用聚合数据API查询快递数据-短信验证码-企业核名

因为这三个功能并不是正式产品,将来会需要嵌入到网站的各个功能模块中去,所以为了查看起来方便,三个功能的代码都写在一个文件里,你只要重点关注以下几个文件就好:

  • /Home/Conf/config.php 参数配置文件
  • /Home/Controller/IndexController.class.php 后端代码、API的请求与处理
  • /Home/View/Index_index.html 前端 html

申请 KEY 和阅读开发文档

分别到上面两家网站上找到“快递”、“短信”、“核名”的文档地址,根据里面的说明,把 KEY、URL 等信息放入配置文件Home/Conf/config.php,方便后面重复使用。

常用快递API文档

短信API文档

核名-文档

注意 短信的 API 服务,要先到网站的后台添加“短信模板”,让管理员审核后才可以正常调用

最后,Home/Conf/config.php 配置文件里的内容如下

return array(
// 快递查询
'EXPRESS_APP_KEY' => '你的快递 APPKEY',
'EXPRESS_QUERY_URL' => 'http://v.juhe.cn/exp/index', //快递单号查询
'EXPRESS_COM_URL' => 'http://v.juhe.cn/exp/com', //快递公司查询
// 发短信
'SEND_SMS_KEY' => '你的短信接口 APPKEY',
'SEND_SMS_URL' => 'http://v.juhe.cn/sms/send',
// 核名
'COMPANY_KEY' => '核名 APPKEY',
'COMPANY_URL' => 'http://eci.yjapi.com/ECIFast/Search',
//数据库配置信息
'DB_TYPE' => 'mysql', // 数据库类型
'DB_HOST' => 'localhost', // 服务器地址
'DB_NAME' => '你的数据库名', // 数据库名
'DB_USER' => '你的数据库用户名', // 用户名
'DB_PWD' => '密码', // 密码
'DB_PORT' => 3306, // 端口
'DB_PREFIX' => 'pre_', // 数据库表前缀
'DB_CHARSET'=> 'utf8', // 字符集
);

设置数据库

为了防止恶意用户利用暴露在外的短信接口捣乱,需要对每个手机号码的行为进行记录。例如:

  • 向某个手机号码发送短信验证码后, 60 秒内不能再次发送
  • 必须在 1 小时内填写短信验证码,否则会过期
  • 避免 ajax 请求地址被机器人程序利用,在表单里要使用图片验证码才能提交数据

关于“表单验证码”我们后面代码会说明,这里先创建表结构如下,用于记录短信发送记录:

CREATE TABLE `pre_smsrecord` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`mobile` varchar(11) NOT NULL DEFAULT '',
`tpl_id` int(11) NOT NULL,
`code` int(6) NOT NULL,
`time` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=M
  • mobile 是手机号码
  • tpl_id是在网站后台添加并通过审核的短信模板
  • code是发送的验证码(一般是4位或6位)
  • time是发送时间戳

直接下载sql进行还原:在本项目的 GitHub 地址上也可以直接从 /Pubic 目录找到 sql 文件,你可以直接把它还原你的 MySQL 上。

表单验证码的实现

最终效果如下:

因为三个功能都需要表单验证码,所以首先实现它。

打开 /Home/View/Index_index.html,注意里面图片验证码 img 标签,以及对应的 javascript

<p>
(通用)输入验证码 <input type="text" name="verify" id="verify">
<img id="verify-img" src="/?m=Home&c=Index&a=verify" alt="">
<a id="btn-refresh-verify" href="javascript:;" title="">刷新</a>
</p>
<script type="text/javascript" charset="utf-8">
jQuery(document).ready(function($) {
// 刷新验证码按钮
$("#btn-refresh-verify").click(function(event) { $("#verify-img").attr('src', '/?m=Home&c=Index&a=verify' + "&time=" + new Date().getTime());
});
});
</script>

对应的后端代码在 /Home/Controller/IndexController.class.php 中

/**
* +--------------------------------------------------------------------------
* 生成验证码
*
* +--------------------------------------------------------------------------
*/
public function verify(){
$Verify = new \Think\Verify();
$Verify->entry();
}
/**
* +--------------------------------------------------------------------------
* 检查验证码
*
* @param string $code 输入的验证码
* @return boolean
* +--------------------------------------------------------------------------
*/
protected function check_verify($code){
$verify = new \Think\Verify();
return $verify->check($code);
}

通用的 Curl 方法,用来向第三方网站的 API 发起请求并获取返回值

因为 3 个功能实际上都是通过网络来请求一个第三方网站的 API 接口地址,因此可以统一成一个通用的方法。代码如下,可以传入三个变量,分别为 :url、参数数组、请求方式(是否是post,默认为0),返回一个 json 格式的数据。

/**
* +--------------------------------------------------------------------------
* 通用的“聚合数据”请求接口,返回JSON数据
*
* @param string $url 接口地址
* @param array $params 传递的参数
* @param int $ispost 是否以POST提交,默认GET
* @return json
* +--------------------------------------------------------------------------
*/
public function juhecurl($url,$params=false,$ispost=0){
$httpInfo = array();
$ch = curl_init();
curl_setopt( $ch, CURLOPT_HTTP_VERSION , CURL_HTTP_VERSION_1_1 );
curl_setopt( $ch, CURLOPT_USERAGENT , 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22' );
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT , 30 );
curl_setopt( $ch, CURLOPT_TIMEOUT , 30);
curl_setopt( $ch, CURLOPT_RETURNTRANSFER , true );
if( $ispost )
{
curl_setopt( $ch , CURLOPT_POST , true );
curl_setopt( $ch , CURLOPT_POSTFIELDS , $params );
curl_setopt( $ch , CURLOPT_URL , $url );
}
else
{
if($params){
curl_setopt( $ch , CURLOPT_URL , $url.'?'.$params );
}else{
curl_setopt( $ch , CURLOPT_URL , $url);
}
}
$response = curl_exec( $ch );
if ($response === FALSE) {
//echo "cURL Error: " . curl_error($ch);
return false;
}
$httpCode = curl_getinfo( $ch , CURLINFO_HTTP_CODE );
$httpInfo = array_merge( $httpInfo , curl_getinfo( $ch ) );
curl_close( $ch );
return $response;
}

后面我们获取快递数据、发送短信、查询企业名称,都可以调用这个通用的方法。

获取快递数据列表的实现

最终效果如下:

打开 /Home/View/Index_index.html

<h1>获取快递数据</h1>
<div id="express-module">
<p>
选择公司
<select name="express-company" id="express-company">
<option value="sf">顺丰</option>
<option value="sto">申通</option>
<option value="yt">圆通</option>
<option value="yd">韵达</option>
<option value="tt">天天</option>
<option value="ems">EMS</option>
<option value="zto">中通</option>
<option value="ht">汇通</option>
</select>
</p>
<p>
输入单号 <input type="text" name="express-number" id="express-number">
</p>
<p>
<button id="btn-query-express" type="button" class="btn btn-default">查询快递</button>
</p> <p>返回结果:</p>
<p id="reason" style="color:#FF0000"></p> <p>快件动态:</p>
<ul id="express-result"> </ul>
</div>
<!-- 引入jquery库 -->
<script src="__PUBLIC__/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
jQuery(document).ready(function($) {
//点击快递查询按钮
$("#btn-query-express").click(function(event) {
$("#reason").html("");
// 更新验证码
$("#verify-img").attr('src', '/?m=Home&c=Index&a=verify' + "&time=" + new Date().getTime());
$.getJSON(
'/?m=Home&c=Index&a=getExpressData',
{
company: $("#express-company").val(),
number: $("#express-number").val(),
verify: $("#verify").val(),
},
function(json, textStatus) {
if(json['resultcode'] == 200){
var result_list = json['result']['list'];
$("#express-result").html("");
for(var i = 0, l = result_list.length; i < l; i++) {
$("#express-result").append("<li>" + result_list[i]['datetime'] + "," + result_list[i]['remark'] + "," +result_list[i]['zone'] + "</li>");
}
}
$("#reason").html(json['reason']);
});
});
});
</script>

对应的后端代码为如下,特别注意,你要把 $content = $this->juhecurl(C("EXPRESS_QUERY_URL"), $params, 1); 这段的注释去掉(因为我开发的时候查询余额不足,所以使用了一个写死的数组来让程序能正常运行)

/**
* +--------------------------------------------------------------------------
* 获取快递数据
*
* @param string $get.company 快递公司代码
* @param string $get.number 快递单号
* @return json
* +--------------------------------------------------------------------------
*/
public function getExpressData(){
// 传入 get 参数,包括公司代号、快递单号、验证码
$com = I("get.company");
$no = I("get.number");
$verify = I("get.verify");
// 处理验证码
if ( !$this->check_verify($verify) ) {
$content = array('resultcode'=>1000, 'reason'=>'验证码填写错误');
echo json_encode($content);
exit();
}
// 处理机器人程序刷接口(目前通过IP判断)
$ip = get_client_ip(0, true);
$Record = M("expressrecord");
$express_record = $Record->where("ip='" . $ip . "'")->find();
if( $express_record && ( (time() - $express_record['time']) < 60 ) ){
echo json_encode(array('reason'=>'60秒内只能查询一次'));
exit();
}
if ( $com && $no ) {
$params = array(
'key' => C("EXPRESS_APP_KEY"),
'com' => $com,
'no' => $no
);
// 开发测试阶段直接返回值,不请求 API
// $content = $this->juhecurl(C("EXPRESS_QUERY_URL"), $params, 1);
$content = array('resultcode'=>200, 'reason'=>'查询成功', 'result'=>array('list'=>array()));
// 删除旧记录(如果有),然后添加新的记录
$Record->where("ip='" . $ip . "'")->delete();
$data = array(
'ip' => $ip,
'time'=>time()
);
$Record->add($data);
//$returnArray = json_decode($content,true);
echo json_encode($content, true);
}
}

短信验证码的发送和检验

废话不多说,前端html直接上代码。这里实际上有两个动作,一个是“给我手机号码 xxxxx 发个验证码”,另一个是“我已经收到了,并填写了,请看我填写的验证码对不对”。

<h1>发送短信验证码与检查</h1>
<div id="sms-module">
<p>
短信模板:
<select name="send-sms-tplid" id="send-sms-tplid">
<option value="5596">申请注册</option>
<option value="5602">申请找回密码</option>
<option value="5603">在线核名</option>
</select>
</p> <p>
手机号码:<input type="text" name="send-sms-mobile" id="send-sms-mobile">
</p> <p>
输入手机验证码:<input type="text" name="send-sms-code" id="send-sms-code">
<span id="sms-count-down"></span>
<button id="btn-send-sms" type="button" class="btn btn-default">发送验证码</button>
</p> <p>
<button id="btn-check-sms" type="button" class="btn btn-default">提交手机验证码</button>
</p>
</div>
<script type="text/javascript" charset="utf-8">
/**
* 发送短信验证码后,60秒倒计时
*/
var seconds_left = 60;
function sms_count_down(){
if(seconds_left > 0){
seconds_left = seconds_left-1;
//var b=new Date(); document.getElementById("sms-count-down").innerHTML = seconds_left + "秒";
setTimeout("sms_count_down()",1000);
} else {
//根据 http://stackoverflow.com/questions/7526601/setattributedisabled-false-changes-editable-attribute-to-false
// 不能为 setAttribute 设置任何值,都会变成 ”disabled“,要使用 removeAttribute
document.getElementById("btn-send-sms").removeAttribute("disabled");
document.getElementById("btn-send-sms").innerHTML = "重新发送";
document.getElementById("sms-count-down").innerHTML = "";
}
}
jQuery(document).ready(function($) {
//发送短信
$("#btn-send-sms").click(function(event) {
$("#reason").html("");
$.getJSON(
'/?m=Home&c=Index&a=sendSMS',
{
tplid: $("#send-sms-tplid").val(),
mobile: $("#send-sms-mobile").val(),
},
function(json, textStatus) {
$("#reason").html(json['reason']);
var error_code = json['error_code'];
if(error_code == 0){
// 测试阶段,不禁用,可检查 60 秒重复发送
//$("#btn-send-sms").attr("disabled", true);
//开始倒计时
sms_count_down();
}else{
$("#btn-send-sms").html("重新发送");
} });
});
//检查短信验证码
$("#btn-check-sms").click(function(event) {
$("#reason").html("");
// 更新验证码
$("#verify-img").attr('src', '/?m=Home&c=Index&a=verify' + "&time=" + new Date().getTime());
$.getJSON(
'/?m=Home&c=Index&a=checkSmsCode',
{
tplid: $("#send-sms-tplid").val(),
mobile: $("#send-sms-mobile").val(),
code: $("#send-sms-code").val(),
verify: $("#verify").val(),
},
function(json, textStatus) {
$("#reason").html(json['reason']); });
}); });

同样因为有两个动作,后端会稍微复杂一点点

/**
* +--------------------------------------------------------------------------
* 请求发送短信接口,60秒后才能重新发送
*
* @param int $get.tplid 短信模板id
* @param string $get.mobile 手机号码
* @return json
* +--------------------------------------------------------------------------
*/
public function sendSMS(){
$tpl_id = I("get.tplid"); // 短信模板id:注册 5596 找回密码 5602 在线核名 5603
$mobile = I("get.mobile"); // 手机号码
// 检查数据库记录 ,是否在 60 秒内已经发送过一次
$Record = M("smsrecord");
$where = array(
'mobile' => $mobile,
'tpl_id' => $tpl_id,
);
$sms_record = $Record->where($where)->find();
if( $sms_record && ( (time() - $sms_record['time']) < 60 ) ){
echo json_encode(array('reason'=>'60秒内不能多次发送'));
exit();
}
// 如果60秒内没有发过,则发送验证码短信(6位随机数字)
$code = mt_rand(100000, 999999);
$smsConf = array(
'key' => C("SEND_SMS_KEY"), //您申请的APPKEY
'mobile' => $mobile, //接受短信的用户手机号码
'tpl_id' => $tpl_id, //您申请的短信模板ID,根据实际情况修改
'tpl_value' =>'#code#=' . $code //您设置的模板变量,根据实际情况修改 '#code#=1234&#company#=聚合数据'
); //测试阶段,不发短信,直接设置一个“发送成功” json 字符串
$content = $this->juhecurl(C("SEND_SMS_URL") ,$smsConf, 1); //请求发送短信
//$content = json_encode(array('error_code'=>0, 'reason'=>'发送成功'));
if($content){
$result = json_decode($content,true);
$error_code = $result['error_code'];
if($error_code == 0){
// 状态为0,说明短信发送成功
// 数据库存储发送记录,用于处理倒计时和输入验证,首先要删除旧记录
$Record->where("mobile=" . $mobile)->delete();
$data = array(
'mobile' => $mobile,
'tpl_id'=> $tpl_id,
'code'=>$code,
'time'=>time()
);
$Record->data($data)->add();
//echo "短信发送成功,短信ID:".$result['result']['sid'];
}else{
//状态非0,说明失败
//echo "短信发送失败(".$error_code."):".$msg;
}
}else{
//返回内容异常,以下可根据业务逻辑自行修改
//$result['reason'] = '短信发送失败';
}
echo $content;
}
/**
* +--------------------------------------------------------------------------
* 检查填写的手机验证码是否填写正确
* 可以添加更多字段改造成注册、登录等表单
*
* @param string $get.verify 验证码
* @param string $get.mobile 手机号码
* @param int $get.tplid 短信模板ID
* @param int $get.code 手机接收到的验证码
* +--------------------------------------------------------------------------
*/
public function checkSmsCode(){
$verify = I("get.verify");
$tpl_id = I("get.tplid"); // 短信模板id:注册 5596 找回密码 5602 在线核名 5603
$mobile = I("get.mobile"); // 手机号码
$code = I("get.code"); // 手机收到的验证码
if(!$this->check_verify($verify)){
$content = array('resultcode'=>1000, 'reason'=>'验证码填写错误');
echo json_encode($content);
exit();
}
// 检查数据库记录,输入的手机验证码是否和之前通过短信 API 发送到手机的一致
$Record = M("smsrecord");
$where = array(
'mobile' => $mobile,
'tpl_id' => $tpl_id,
'code' => $code,
);
$sms_record = $Record->where($where)->find();
if($sms_record){
echo json_encode(array('reason'=>'短信验证码核对成功'));
// 处理后面的程序(如继续登录、注册等)
}else{
echo json_encode(array('reason'=>'短信验证码错误'));
}
}

最后是企业核名

因为这个接口本来只提供了每次查询一个关键词,而朋友的网站要求能每次查询用“,”分隔的多个关键词,因此需要对提交的数据和返回到前端的进行一番处理(循环处理多个列表)。

前端代码比较简单

<h1>企业核名</h1>
<div id="company-module">
<p>
省份:上海
<input type="hidden" name="company-province" id="company-province" value="SH">
</p>
<p>
<input type="text" name="company-name" id="company-name">
</p>
</div>
<button id="btn-company" type="button" class="btn btn-default">企业核名</button>
<p>公司查询列表:</p>
<ul id="company-result"> </ul>
<javascript 略……
//企业核名(可输入多个以逗号分隔的名称来多次查询)
$("#btn-company").click(function(event) {
$("#reason").html("");
$("#company-result").html("");
// 更新验证码
$("#verify-img").attr('src', '/?m=Home&c=Index&a=verify' + "&time=" + new Date().getTime());
$.getJSON(
'/?m=Home&c=Index&a=getCompanyName',
{
province: $("#company-province").val(),
companyName: $("#company-name").val(),
verify: $("#verify").val(),
},
function(json, textStatus) {
if(json['reason']){
$("#reason").html(json['reason']);
} else {
//console.log(json);
var json_list = JSON.parse(json);
if (json_list.length > 0){
for(i in json_list){
var result_list = json_list[i].Result;
if (result_list.length > 0){
for(j in result_list){
//console.log(result_list[j]);
$("#company-result").append("<li> 名称:" + result_list[j].Name + ", 法人:" + result_list[j].OperName + ", 状态:" + result_list[j].Status + "</li>");
}
}
}
}
}
});
});
</javascript>

后端代码

/**
* +--------------------------------------------------------------------------
* 企业核名
* 该接口 http://eci.yjapi.com/ECIFast/Search 仅支持 GET 方式,因此 $param 为字符串形式
*
* @param string $get.province 省份
* @param string $get.companyName 公司名
* @return json
* +--------------------------------------------------------------------------
*/
public function getCompanyName(){
// 传入 get 参数
$province = I("get.province");
$companyName = I("get.companyName");
$verify = I("get.verify");
// 处理验证码
if ( !$this->check_verify($verify) ) {
$content = array('resultcode'=>1000, 'reason'=>'验证码填写错误');
echo json_encode($content);
exit();
}
// 处理机器人程序刷接口(目前通过IP判断)
$ip = get_client_ip(0, true);
$Record = M("companyrecord");
$company_record = $Record->where("ip='" . $ip . "'")->find();
// if( $company_record && ( (time() - $company_record['time']) < 60 ) ){
// echo json_encode(array('reason'=>'60秒内只能查询一次企业名称'));
// exit();
// }
$resultArray = array();
if ( $province && $companyName ) {
// 删除旧记录(如果有),然后添加新的记录
$Record->where("ip='" . $ip . "'")->delete();
// 循环处理多个公司名
$companies = explode(",", $companyName);
foreach ($companies as $key => $value) {
$params = "key=" . C("COMPANY_KEY") . "&province={$province}&companyName={$value}";
// 开发测试阶段直接返回值,不请求 API
$content = $this->juhecurl(C("COMPANY_URL"), $params, 0);
$returnArray = json_decode($content,true);
// 循环插入新的结果
$resultArray[] = $returnArray;
//$content = array('resultcode'=>200, 'reason'=>'查询成功', 'result'=>array('list'=>array()));
}
$data = array(
'ip' => $ip,
'time'=>time()
);
$Record->add($data);
$content = json_encode($resultArray, true);
echo json_encode($content, true);
}
}

结束

至此三个功能都已经完成了,但是在防止恶意用户利用接口干坏事的策略上,还可以更进一步。例如

  • 必须要注册用户才能发送请求
  • 手机号码每天只能限制发送有限的验证码(因为目前即使每分钟发送一次,一天下来也比较可观了)
  • 手机号码注册后,再次请求发送验证码时,只能发给“已有”的手机号码数据表里的手机号码,而不能把“找回密码”发给一个还没注册的人。

使用聚合数据API查询快递数据-短信验证码-企业核名的更多相关文章

  1. Django商城项目笔记No.5用户部分-注册接口-短信验证码

    Django商城项目笔记No.4用户部分-注册接口-短信验证码 短信验证码也保存在redis里(sms_code_15101234567) 在views中新增SMSCodeView类视图,并且写出步骤 ...

  2. 功能:使用QQ号登陆,并加上微信和短信提醒,是否增量备份可选,阿里大鱼短信发送开发与测试,聚合数据(用JSON发短信,比较清楚)

    微博就可以,所以其它软件也可以http://desktop.weibo.com/ http://blog.csdn.net/jueblog/article/details/14497181http:/ ...

  3. Android 项目开发实战:聚合数据短信验证码

    聚合数据集成短信验证码官网: https://www.juhe.cn/docs/api/id/54 我根据文档集成了一个例子 效果: 源码下载:http://download.csdn.net/det ...

  4. day102:MoFang:后端完成对短信验证码的校验&基于celery完成异步短信发送&flask_jwt_extended&用户登录的API接口

    目录 1.用户注册 1.后端完成对短信验证码的校验 2.基于celery实现短信异步发送 2.用户登录 1.jwt登录验证:flask_jwt_extended 2.服务端提供用户登录的API接口 1 ...

  5. flask开发restful api系列(5)-短信验证码

    我们现在开发app,注册用户的时候,不再像web一样,发送到个人邮箱了,毕竟个人邮箱在移动端填写验证都很麻烦,一般都采用短信验证码的方式.今天我们就讲讲这方面的内容. 首先,先找一个平台吧.我们公司找 ...

  6. 短信API——短信验证码

    简介 短信服务(Short Message Service.SMS)是指通过调用短信发送API,将指定短信内容发送给指定手机用户. 阿里云短信服务 阿里云短信服务产品介绍:https://www.al ...

  7. 短信验证码api

    最近遇到的项目需要个随机短信验证码实现注册用户 选用的是“云信使”,因为有15条免费的测试短信可以验证代码是否正确调用该短信api 地址 进入短信平台 一.实名认证 + 短信模板 用户认证完成后,创建 ...

  8. Android开发之短信验证码示例

    在说Android中的短信验证码这个知识点前,我们首先来了解下聚合数据 聚合数据介绍 聚合数据是一家国内最大的基础数据API提供商,专业从事互联网数据服务.免费提供从天气查询.空气质量.地图坐标到金融 ...

  9. vue_drf之实现短信验证码

    一.需求 1,需求 我们在做网站开发时,登录页面很多情况下是可以用手机号接收短信验证码,然后实现登录的,那我们今天就来做一做这一功能. 伪代码: 进入登录页面,点击短信登录 输入手机号码,点击获取验证 ...

随机推荐

  1. python 使用入的坑

    如测试代码,并没有将li.li_ 的交集查询出来 li=[1,2,3,4,5] li_=[2,5,6,7,9] for i in li_: if i in li: li_.remove(i) prin ...

  2. java 例子

    1. 本章学习总结 今天主要学习了三个知识点 封装 继承 多态 2. 书面作业 Q1. java HelloWorld命令中,HelloWorld这个参数是什么含义? 今天学了一个重要的命令javac ...

  3. mapserver+openlayers实现左键点击查询

    效果图 第一步,配置自己的mapfile,在要查询的图层LAYER对象内加上HEADER,TEMPLATE,FOOTER三个参数,同时,TEMPLATE fooOnlyForWMSGetFeature ...

  4. GDOI2018前夕 错误总结

    算法易错点 $FFT$ 1.注意精度,以及是否取整 2.注意$complex$类不要写错,复数乘法是这样的: complex operator *(const complex &b){retu ...

  5. ci支持pathinfo

    location ~ \.php { #去掉$ root H:/PHPServer/WWW; fastcgi_pass ; fastcgi_index index.php; fastcgi_split ...

  6. vmware虚拟机无法ping通主机,也无法联网

  7. Nature Reserve

    Nature Reserve time limit per test:2 seconds memory limit per test:256 megabytes input:standard inpu ...

  8. 洛谷 P1038 神经网络

    题目背景 人工神经网络(Artificial Neural Network)是一种新兴的具有自我学习能力的计算系统,在模式识别.函数逼近及贷款风险评估等诸多领域有广泛的应用.对神经网络的研究一直是当今 ...

  9. 【LA5059】Playing With Stones (SG函数)

    题意:有n堆石子,分别有a[i]个.两个游戏者轮流操作,每次可以选一堆,拿走至少一个石子,但不能拿走超过一半的石子. 谁不能拿石子就算输,问先手胜负情况 n<=100,1<=a[i]< ...

  10. Educational Codeforces Round 37 A B C D E F

    A. water the garden Code #include <bits/stdc++.h> #define maxn 210 using namespace std; typede ...