1.大大减少服务器需要扫描的数据量
2.帮助服务器避免排序和临时表
3.将随机的I/O变为顺序的I/O
4.提高查询速度,降低写的速度、占用磁盘
1.对于非常小的表,大部分情况下全表扫描效率更高
2.中到大型表,索引非常有效
3.特大型表,建立和使用索引的代价将随之增长,可以使用分区技术解决
索引有很多种类型,都是实现在存储引擎层的:
1.普通索引:最基本的索引,没有任何约束限制
2.唯一索引:与普通索引类似,但具有唯一约束性
3.主键索引:特殊的唯一索引,不允许有空值
4.组合索引:将多个列组合在一起创建索引,可以覆盖多个列
5.外键索引:只有InnoDB使用,保证数据的一致性完整性和实现级联操作
6.全文索引:只有MyISAM使用,只能对英文进行全文检索
注意:一个表只有一个主键索引,可以有多个唯一索引
主键索引一定是唯一索引,唯一索引不是主键索引
主键可以与外键构成参照完整性约束,防止数据不一致
1.最适合索引的列是出现在WHERE子句中的列,或连接子句中的列而不是SELECT
关键字后的列
2.索引列的基数越大,索引的效果越好
3.对字符串进行索引,应该指定一个前缀长度,可以节省大量的索引空间
4.根据情况创建复合索引,复合索引可以提高查询效率
5.避免创建过多的索引,索引会占用额外的磁盘空间,降低写操作效率
6.主键尽可能选择较短的数据类型,可以有效减少索引的磁盘占用提高查询效率
]]>1.复合索引遵循前缀原则
2.like查询,%不能在前,可以使用全文索引
3.column is null 可以使用索引
4.如果mysql估计使用索引比全表扫描慢会放弃使用索引
5.如果or前的条件中的列有索引,后面的没有,索引都不会被用到
6.列类型是字符串,查询时一定要给值加引号,否则索引失效
一、JS API通过在页面上部署js代码的方式,收集网站的各类业务数据。
在部署百度统计开放平台JS API之前,先注册一个百度统计账号,并安装了百度统计的访问分析代码。
二、Tongji API支持将百度统计中的数据以通用格式导出,帮助您将报表中的数据导出至自身系统中,以便更加灵活地展现、分析、挖掘百度统计中的数据价值。
登录百度统计,在后台的管理—其它设置——数据导出服务,开通服务。
为了我们自己的网站后台看到数据,我们在自己的网站集成Tongji API
下载Tongji API Demo
Config.inc.php 配置用户名密码TOKEN等信息
<?php...//USERNAMEdefine('USERNAME', 'YOUR USERNAME');//PASSWORDdefine('PASSWORD', 'YOUR PASSWORD');//TOKENdefine('TOKEN', 'YOUR TOKEN');...
demo.php
//头部添加:header(‘Content-type:text/json’);'''//尾部添加:$res = json_decode($ret['raw'], true);print_r($res);
打印结果如下:
Array([header] => Array ( [desc] => success [failures] => Array ( ) [oprs] => 1 [succ] => 1 [oprtime] => 0 [quota] => 1 [rquota] => 49974 [status] => 0 )[body] => Array ( [data] => Array ( [0] => Array ( [result] => Array ( [total] => 1 [items] => Array ( [0] => Array ( [0] => Array ( [0] => 2018/06/22 ) ) [1] => Array ( [0] => Array ( [0] => 11201 [1] => 745 [2] => 46.15 [3] => 426 [4] => 12.34 ) ) . . ) [timeSpan] => Array ( [0] => 2018/06/22 ) [sum] => Array ( [0] => Array ( [0] => 11201 [1] => 745 [2] => 46.15 [3] => 426 [4] => 12.34 ) . ) [offset] => 0 [pageSum] => Array ( [0] => Array ( [0] => 11201 [1] => 745 [2] => 46.15 [3] => 426 [4] => 12.34 ) . . ) [fields] => Array ( [0] => simple_date_title [1] => pv_count [2] => visitor_count [3] => bounce_ratio [4] => avg_visit_time [5] => avg_visit_pages ) ) ) ) ))
下面新建GetData.php写一个方法获取数据并处理,数据比较乱,处理成以fields为键名对应相应的值的键值对形式便于处理
<?phpfunction getBdData($start_date, $end_date, $gran = '', $metrics = 'pv_count,visitor_count',$clientDevice = '', $method = 'trend/time/a', $max_results = '0'){ require_once('Config.inc.php'); require_once('LoginService.inc.php'); require_once('ReportService.inc.php'); header('Content-type:text/json'); $loginService = new LoginService(LOGIN_URL, UUID);// preLogin if (!$loginService->preLogin(USERNAME, TOKEN)) { exit(); }// doLogin $ret = $loginService->doLogin(USERNAME, PASSWORD, TOKEN); if ($ret) { $ucid = $ret['ucid']; $st = $ret['st']; } else { exit(); } $reportService = new ReportService(API_URL, USERNAME, TOKEN, $ucid, $st); $siteId = 'your siteId'; $ret = $reportService->getData(array( 'site_id' => $siteId, //站点ID 'method' => $method, //通常对应要查询的报告 'start_date' => $start_date, //所查询数据的起始日期 'end_date' => $end_date, //所查询数据的结束日期 'metrics' => $metrics, //自定义指标选择,多个指标用逗号分隔 'max_results' => $max_results, //返回所有条数 'gran' => $gran, //时间粒度(只支持有该参数的报告): day/hour/week/month )); //将获取的数据进行处理 $res = json_decode($ret['raw'], true); $res = $res["body"]["data"]['0']["result"]; array_shift($res["fields"]); $fields = $res["fields"]; foreach ($res["items"][1] as $key => &$val) { $val = array_combine($fields, $val); $time = $res["items"][0][$key][0]; $val['time'] = $time; } unset($val);// doLogout $loginService->doLogout(USERNAME, TOKEN, $ucid, $st); return $res["items"][1];}
结果如下:[items][1][0]就是处理后想得到的形式
Array([total] => 1[items] => Array ( . . . [1] => Array ( [0] => Array ( [pv_count] => 11201 [visitor_count] => 745 [bounce_ratio] => 46.15 [avg_visit_time] => 426 [avg_visit_pages] => 12.34 [time] => 2018/06/22 ) ) . . .)
最后在控制器中调用getBdData方法获取数据并存入数据库
public function getBdTongJi(){ require_once(APP_PATH.'Admin/Lib/bdtongji/GetData.php'); $start_date = I('get.start','','strval'); $end_date = I('get.end','','strval'); if(!$start_date||!$end_date){ $time = date('Ymd',time())-1; $start_date = $time; $end_date = $time; } $bdCount = M('bd_count'); $res = getBdData($start_date,$end_date,'day','pv_count,bounce_ratio,visitor_count,avg_visit_time,avg_visit_pages'); foreach ($res as &$data){ $data['count_time']=strtotime($data['time']); if(!$bdCount->where(array('count_time'=>$data['count_time']))->count()){ $bdCount->add($data); } } unset($data); }
]]>OAuth 允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth 允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要分享他们的访问许可或他们数据的所有内容。
OAuth授权流程
1.请求OAuth登陆页
Request Token URL - 未授权的令牌请求服务地址
2.用户使用第三方账号登陆并授权
3.返回登陆结果
User Authorization URL - 用户授权的令牌请求服务地址
AccessToken - 用户通过第三方应用访问OAuth接口令牌
新浪微博登陆 (http://open.weibo.com)
1.申请AppID和AppKey
2.下载PHP版本SDK
3.接入开发
QQ登陆 (http://connect.qq.com)
1.申请AppID和AppKey
2.下载PHP版本SDK
3.SDK配置
4.接入开发
以微博登陆为例:
config.php
define('WB_KEY','获取的AppKey');define('WB_SRC','获取的AppSecret');define('CALLBACK','回调地址(callback.php)');
wblogin.php
<?phprequire_once 'config.php';require_once 'saetv2.ex.class.php';$o = new SaeTOAuthV2('WB_KEY','WB_SRC');$url = CALLBACK;$oauth = $o->getAuthorizeUrl($url);header('Location: '.$oauth);
callback.php
<?phprequire_once 'config.php';require_once 'saetv2.ex.class.php';$code = $_GET('code');$keys['code'] = $code;$keys['redirect_uri'] = CALLBACK;$o = new SaeTOAuthV2('WB_KEY','WB_SRC');$auth = $o->getAccessToken($keys);setcookie('accesstoken',$auth['access_token'],time()+86400);header('location: index.php');
index.php
<?php equire_once 'config.php'; require_once 'saetv2.ex.class.php'; $isLogin=isset($_COOKIE['accesstoken']);?><!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>微博测试</title> </head> <body> <?php if(!$isLogin){ ?> <a href='wblogin.php'><img src='./weibo_login.png'></a> <?php }else{ ?> 您已成功登陆微博账号; <?php $o = new SaeTClientV2('WB_KEY','WB_SRC',$_COOKIE['accesstoken']); //调用接口发布微博 $o->update('发布微博'); } ?> </body></html>
debug调试方法
function debug($val,$dump = false,$exit = true) { //自动获取函数名称$func if($dump){ $func = 'var_dump'; } else { $func = (is_array($val) || is_object($val) )? 'print_r' : 'printf'; } header("Content-type: text/html; charset = utf-8"); echo '<pre>debug output:<hr />'; $func($val); echo '</pre>'; if($exit); exit;}
]]>表单页面
表单发送方式为 post
添加 enctype=”multipart/form-data”
通过使用 PHP 的全局数组 $_FILES,你可以从客户计算机向远程服务器上传文件。
第一个参数是表单的 input name,第二个下标可以是 “name”, “type”, “size”, “tmp_name” 或 “error”。就像这样:
$_FILES[“file”][“name”] - 被上传文件的名称
$_FILES[“file”][“type”] - 被上传文件的类型
$_FILES[“file”][“size”] - 被上传文件的大小,以字节计
$_FILES[“file”][“tmp_name”] - 存储在服务器的文件的临时副本的名称
$_FILES[“file”][“error”] - 由文件上传导致的错误代码
move_uploaded_file() 函数将上传的文件移动到新位置。
若成功,则返回 true,否则返回 false。
move_uploaded_file(file,newloc)
将文件从 source 拷贝到 destination。如果成功则返回 TRUE,否则返回 FALSE。
copy(source,destination)
file_uploads=on,支持HTTP上传
upload_tmp_dir=,临时文件保存的目录
upload_max_filesize=2M,允许上传文件的最大值
max_file_uploads=20,允许文件上传的最大文件数
post_max_size=8M,POST方式发送数据的最大值
max_execution_time=-1,设置了脚本被解析器终止之前允许的最大执行时间,单位为秒,防止程序写的不好而占尽服务器资源
max_input_time=60,脚本解析输入数据允许的最大时间,单位为秒
max_input_nesting_level=64,设置输入变量的嵌套深度
max_input_vars=1000,接受多少输入的变量(限制分别应用于$_GET、$_POST和$_COOKIE超全局变量)指令的使用减轻了以哈希碰撞来进行拒绝服务器攻击的可能性。如果有超过指令指定数量的变量,将会导致$_WARNING的产生,更多的输入变量将会从请求中截断。
memory_limit=128M,最大单线程的独立内存使用量。也就是一个web请求,给予线程最大使用量的定义。
1、UPLOAD_ERR_OK
其值为 0,没有错误发生,文件上传成功。
2、UPLOAD_ERR_INI_SIZE
其值为 1,上传的文件超过了 php.ini 中 upload_max_filesize选项限制的值。
3、UPLOAD_ERR_FORM_SIZE
其值为 2,上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
4、UPLOAD_ERR_PARTIAL
其值为 3,文件只有部分被上传。
5、UPLOAD_ERR_NO_FILE
其值为 4,没有文件被上传。
6、UPLOAD_ERR_NO_TMP_DIR
其值为 6,找不到临时文件夹。PHP 4.3.10 和 PHP 5.0.3 引进。
7、UPLOAD_ERR_CANT_WRITE
其值为 7,文件写入失败。PHP 5.1.0 引进。
8、UPLOAD_ERR_EXTENSION
其值为 8,上传的文件被PHP扩展程序中断
通过表单隐藏域限制文件上传的最大值
<input type="hidden" name='MAX_FILE_SIZE' value='字节数' />
通过accept属性限制上传文件类型
<input type="file" name="file" accept="文件的MIME类型" />
(ps:表单限制不可靠)
服务器限制
限制文件上传的大小、类型、检测类型、检测是否为HTTP POST方式上传
$filename=$_GET['filename'];header('Content-Disposition:attachment;filename='.$filename);header("Content-length:".filesize($filename));readfile($filename);
]]>//引入组件js和css<script src="__STATIC__/layui/layui.js"></script><link rel="stylesheet" href="__STATIC__/layui/css/layui.css">$(function () { var url = '请求地址' var data = {}; data.page = 1; ajax(data); function ajax(data) { $.ajax({ type: "post", url: url, data: data, success: function (result) { var res = result.data; var count = result.count; var page = result.page; var limit = result.limit; console.log(res); //查看服务器返回的数据 if(count>limit){ lay_page(count,limit,page); } } }) } function lay_page(count,limit,page) { layui.use(['laypage', 'layer'], function() { var laypage = layui.laypage , layer = layui.layer; laypage.render({ elem: '指向存放分页的容器,值可以是容器ID、DOM对象' , count: count //数据总数,从服务端得到 , limit: limit //每页显示的条数 , curr: page , jump: function (obj, first) { //obj包含了当前分页的所有参数,比如: //console.log(obj.curr); //得到当前页,以便向服务端请求对应页的数据。 //console.log(obj.limit); //得到每页显示的条数 //首次不执行 if (!first) { data.page=obj.curr; ajax(data); } } }); }); } })
]]>public function alipay(){ require_once("alipay/wappay/service/AlipayTradeService.php"); require_once("alipay/wappay/buildermodel/AlipayTradeWapPayContentBuilder.php"); require_once("alipay/config.php"); //商户订单号,商户网站订单系统中唯一订单号,必填 $out_trade_no = '商户订单号'; //订单名称,必填 $subject = '订单名称'; //付款金额,必填 $total_amount = '付款金额'; //商品描述,可空 $body = '商品描述'; //超时时间 $timeout_express="1m"; $payRequestBuilder = new \AlipayTradeWapPayContentBuilder(); $payRequestBuilder->setBody($body); $payRequestBuilder->setSubject($subject); $payRequestBuilder->setOutTradeNo($out_trade_no); $payRequestBuilder->setTotalAmount($total_amount); $payRequestBuilder->setTimeExpress($timeout_express); $payResponse = new \AlipayTradeService($config); $payResponse->wapPay($payRequestBuilder,$config['return_url'],$config['notify_url']); }
调起支付宝app支付示例
//由于微信浏览器屏蔽支付宝链接 官方给出跳出微信环境支付的解决方案 引入ap.js(将ap.js和pay.htm放在网站根目录)<script type="text/javascript" src="ap.js"></script> <script> $(document).on('click','[data-role="alipay"]',function (e) { var order_id = $(this).attr('data-id'); var ua = window.navigator.userAgent.toLowerCase(); $.post("{:U('xxx/xxx/alipay')}",{order_id:order_id},function (res) { if(res.status==false){ $.toast(res.info); }else { if(ua.match(/MicroMessenger/i) == 'micromessenger'){//判断微信浏览器 e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); _AP.pay(res); return false; }else{ window.location.href = res; } } }); }) </script>
回调示例
public function alipay_notify() { require_once("alipay/wappay/service/AlipayTradeService.php"); require_once("alipay/config.php"); $arr = $_POST; $alipaySevice = new \AlipayTradeService($config); $alipaySevice->writeLog(var_export($_POST, true)); $result = $alipaySevice->check($arr); if ($result) {//验证成功 //商户订单号 $out_trade_no = $_POST['out_trade_no']; //支付宝交易号 $trade_no = $_POST['trade_no']; //交易状态 $trade_status = $_POST['trade_status']; if ($_POST['trade_status'] == 'TRADE_FINISHED') { //判断该笔订单是否在商户网站中已经做过处理 //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序 //请务必判断请求时的total_amount与通知时获取的total_fee为一致的 //如果有做过处理,不执行商户的业务程序 //注意: //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知 } else if ($_POST['trade_status'] == 'TRADE_SUCCESS') { //支付成功 /** * 业务逻辑 */ echo "success"; //请不要修改或删除 } else { //验证失败 echo "fail"; //请不要修改或删除 } } }
]]> $tools = new JsApiPay(); $openId = $tools->GetOpenid();//获取openid $input = new WxPayUnifiedOrder(); $input->SetBody($name);//商品描述 $input->SetOut_trade_no($out_trade_no);//订单号 $input->SetTotal_fee($amount);//订单总金额,单位分 $input->SetTime_start(date("YmdHis")); $input->SetTime_expire(date("YmdHis", time() + 600)); $input->SetNotify_url("回调域名"); $input->SetTrade_type("JSAPI");//交易类型 $input->SetOpenid($openId); $order = WxPayApi::unifiedOrder($input);//统一下单接口 $jsApiParameters = $tools->GetJsApiParameters($order);
调起微信支付示例
<script type="text/javascript"> //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest',{ "appId":"wx2421b1c4370ec43b", //公众号名称,由商户传入 "timeStamp":"1395712654", //时间戳,自1970年以来的秒数 "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串 "package":"prepay_id=u802345jgfjsdfgsdg888", "signType":"MD5", //微信签名方式: "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok"){ if(res.err_msg == "get_brand_wcpay_request:ok" ) {} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 } } ); } function callpay() { if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } } $(function(){ callpay(); })</script>
回调处理示列
$WxPay = new \WxPayResults();header('Content-type: text/xml');$returnResult = $GLOBALS['HTTP_RAW_POST_DATA']; //接收微信发送的信息$res = $WxPay::Init($returnResult);if(res['result_code'] == 'SUCCESS'){/** 业务处理*/$success = array('return_code' => 'SUCCESS', 'return_msg' => 'OK');exit(ToXml($success));//转成xml通知给微信}
]]> public function mchPay($params) { $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; //检测必填参数 if($params["partner_trade_no"] == null) { throw new WxPayException("企业付款申请接口中,缺少必填参数partner_trade_no!"); }else if($params["openid"] == null){ throw new WxPayException("企业付款申请接口中,缺少必填参数openid!"); }else if($params["check_name"] == null){ throw new WxPayException("企业付款申请接口中,缺少必填参数check_name!"); }else if($params["amount"] == null){ throw new WxPayException("企业付款申请接口中,缺少必填参数amount!"); }else if($params["desc"] == null){ throw new WxPayException("企业付款申请接口中,缺少必填参数desc!"); } $params["mch_appid"] = WxPayConfig::APPID();//公众账号ID $params["mchid"] = WxPayConfig::MCHID();//商户号 $params["nonce_str"] = self::getNonceStr();//随机字符串 $params['spbill_create_ip'] = $_SERVER['REMOTE_ADDR'] == '::1' ? '192.127.1.1' : $_SERVER['REMOTE_ADDR'];//获取IP $obj = new \WxPayDataBase(); $params["sign"] = $this->MakeSign($params);//签名 $xml = $this->arrayToXml($params); $response = self::postXmlCurl($xml, $url, true); $obj->FromXml($response); return $obj->GetValues(); }
//array转xml public function arrayToXml($arr) { $xml = "<xml>"; foreach ($arr as $key=>$val) { if (is_numeric($val)) { $xml.="<".$key.">".$val."</".$key.">"; } else $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } $xml.="</xml>"; return $xml; }
//生成签名 public function MakeSign($params) { //签名步骤一:按字典序排序参数 ksort($params); $string = $this->ToUrlParams($params); //签名步骤二:在string后加入KEY $string = $string . "&key=".WxPayConfig::KEY(); //签名步骤三:MD5加密 $string = md5($string); //签名步骤四:所有字符转为大写 $result = strtoupper($string); return $result; } public function ToUrlParams($params) { $buff = ""; foreach ($params as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; }
调用示例:
$mchPay = new \WxPayApi(); $amount = '付款金额';//企业付款金额,单位“分” $desc = '企业付款';//描述 $partner_trade_no = '订单号'; $openid = '用户oppenid'; $params = array( 'partner_trade_no' => $partner_trade_no, 'openid' => $openid, 'check_name' => 'NO_CHECK',//不校验姓名 'amount' => $amount, 'desc' => $desc, ); $toPay = $mchPay->mchPay($params); if($toPay["return_code"]=="SUCCESS"&&$toPay["result_code"]=="SUCCESS"){ /** * 业务逻辑 数据库操作 */ echo "付款成功"; }else{ //输出错误信息 echo $toPay['err_code'].$toPay['err_code_des']; }
]]>$aop = new AopClient;$aop->gatewayUrl = "https://openapi.alipay.com/gateway.do";$aop->appId = "app_id";$aop->rsaPrivateKey = '请填写开发者私钥去头去尾去回车,一行字符串';$aop->format = "json";$aop->charset = "UTF-8";$aop->signType = "RSA2";$aop->alipayrsaPublicKey = '请填写支付宝公钥,一行字符串';//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay$request = new AlipayTradeAppPayRequest();//SDK已经封装掉了公共参数,这里只需要传入业务参数$bizcontent = "{\"body\":\"我是测试数据\"," . "\"subject\": \"App支付测试\"," . "\"out_trade_no\": \"20170125test01\"," . "\"timeout_express\": \"30m\"," . "\"total_amount\": \"0.01\"," . "\"product_code\":\"QUICK_MSECURITY_PAY\"" . "}";$request->setNotifyUrl("商户外网可以访问的异步地址");$request->setBizContent($bizcontent);//这里和普通的接口调用不同,使用的是sdkExecute$response = $aop->sdkExecute($request);//htmlspecialchars是为了输出到页面时防止被浏览器将关键参数html转义,实际打印到日志以及http传输不会有这个问题echo htmlspecialchars($response);//就是orderString 可以直接给客户端请求,无需再做处理。
PHP服务端验证异步通知信息参数示例
$aop = new AopClient;$aop->alipayrsaPublicKey = '请填写支付宝公钥,一行字符串';$flag = $aop->rsaCheckV1($_POST, NULL, "RSA2");
]]>$input = new WxPayUnifiedOrder();$input->SetBody("test"); //商品描述$input->SetOut_trade_no("商户订单号");$input->SetTotal_fee("1"); //订单总金额,注意单位为分$input->SetTime_start(date("YmdHis"));$input->SetTime_expire(date("YmdHis", time() + 600));$input->SetNotify_url("商户外网可以访问的异步地址");$input->SetTrade_type("APP");$order = WxPayApi::unifiedOrder($input); //调用统一下单接口
调起支付
商户服务器生成支付订单,先调用【统一下单API】生成预付单,获取到prepay_id后将参数再次签名传输给APP发起支付。以下是调起微信支付的关键代码:
$order_data = $WxPayApi->GetAppParameters($order); //调起支付所需的请求参数
GetAppParameters()是外加的代码,微信SDK中没有这个方法,下面是在微信SDK中代码APP支付补充部分。
在WxPay.Api.php中补充代码:
/** * * 获取App支付的参数 * @param array $UnifiedOrderResult 统一支付接口返回的数据 * @throws WxPayException * * @return $parameters */public function GetAppParameters($UnifiedOrderResult){ if(!array_key_exists("appid", $UnifiedOrderResult) || !array_key_exists("prepay_id", $UnifiedOrderResult) || $UnifiedOrderResult['prepay_id'] == "" || !array_key_exists("mch_id", $UnifiedOrderResult) || $UnifiedOrderResult['mch_id'] == "") { throw new WxPayException("参数错误"); } $app = new WxPayAppPay(); $app->SetAppid($UnifiedOrderResult["appid"]); $app->SetPrepayId($UnifiedOrderResult["prepay_id"]); $app->SetPartnerId($UnifiedOrderResult['mch_id']); $timeStamp = time(); $app->SetTimeStamp("$timeStamp"); $app->SetNonceStr(WxPayApi::getNonceStr()); $app->SetPackage("Sign=WXPay"); $app->SetPaySign($app->MakeSign()); $parameters = $app->GetValues(); return $parameters;}
在WxPay.Data.php中补充代码:
/** * * 提交App输入对象 * @author lin * */class WxPayAppPay extends WxPayDataBase{ /** * 设置微信分配的公众账号ID * @param string $value **/ public function SetAppid($value) { $this->values['appid'] = $value; } /** * 设置预支付交易会话ID * @param string $value **/ public function SetPrepayId($value) { $this->values['prepayid'] = $value; } /** * 设置商户号ID * @param string $value **/ public function SetPartnerId($value) { $this->values['partnerid'] = $value; } /** * 设置支付时间戳 * @param string $value **/ public function SetTimeStamp($value) { $this->values['timestamp'] = $value; } /** * 随机字符串 * @param string $value **/ public function SetNonceStr($value) { $this->values['noncestr'] = $value; } /** * 设置订单详情扩展字符串 * @param string $value **/ public function SetPackage($value) { $this->values['package'] = $value; } /** * 设置签名方式 * @param string $value **/ public function SetPaySign($value) { $this->values['sign'] = $value; }}
回调处理的示列
$WxPay = new \WxPayResults();header('Content-type: text/xml');$returnResult = $GLOBALS['HTTP_RAW_POST_DATA']; //接收微信发送的信息$res = $WxPay::Init($returnResult);if(res['result_code'] == 'SUCCESS'){/** 业务处理*/$success = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";exit($success);//回调结果通知}
]]>import axios from 'axios'import Qs from 'qs'Vue.prototype.$axios = axios;Vue.config.productionTip = falsevar axios_instance = axios.create({transformRequest: [function (data) {data = Qs.stringify(data);return data;}],//Post请求传递参数时,需要在请求头加上item.ContentType = "application/x-www-form-urlencoded";headers:{'Content-Type':'application/x-www-form-urlencoded'}})Vue.prototype.$axios = axios_instance;
PHP部分后端响应头进行设置
// 指定允许其他域名访问header("Access-Control-Allow-Origin:*");// 响应类型header("Access-Control-Allow-Methods:GET, POST, PATCH, PUT, DELETE");// 响应头设置header("Access-Control-Allow-Headers:x-requested-with,content-type");
解决了跨域问题后,接下来就能通过接口请求和数据处理了。
在Vue的/config/dev.env.js 设置 API_HOST
'use strict'const merge = require('webpack-merge')const prodEnv = require('./prod.env')module.exports = merge(prodEnv, {NODE_ENV: '"development"',API_HOST:'"http://127.0.0.1/tp5/"'})
下面是一个简单的列表,包含简单的增删改查,查看单条数据等功能
列表部分代码
<template> <div class="list-table"> <h1>TODO-LIST</h1> <form> 姓名:<input type="text" v-model="nickname"/> {{nickname}} <br/> 年龄:<input type="text" v-model="age"/> {{age}} <br/> <span style="color:red" v-if="!isAge">年龄必须是数字</span> <br/> <br/> <button type="button" @click="addList">添加</button> <button type="button" @click="init()">重置</button> </form> <br/> <table border="1" cellspacing="0"> <thead> <th>序号</th> <th>姓名</th> <th>年龄</th> <th>操作</th> </thead> <tr v-for="(data,index) in list"> <td>{{index+1}}</td> <td>{{data.nickname}}</td> <td>{{data.age}}</td> <td> <button @click="detail(index)">查看详情</button> <button @click="delList(index)">删除</button> </td> </tr> <tr> <td colspan="2" style="text-align: center">总年龄:</td> <td>{{sumAge}}</td> <td><button @click="controlList">清空/还原</button></td> </tr> </table> </div></template><script>export default { name:"TODOList" data () { return { //姓名 nickname:"", //年龄 age:"", //age是数字 isAge:true, list: [], } }, created(){ this.getList() }, methods:{ /** * 获取列表数据 */ getList: function () { let $this = this; this.$axios.get(process.env.API_HOST) .then(function(response){ $this.list = response.data; console.log(response.data); }) .catch(function (error) { console.log(error); }); }, /** * 新增列表数据 */ addList:function(){ let $this = this; if(!this.isAge){ return false; } if($this.nickname && $this.age){ $this.$axios.get(process.env.API_HOST + 'index/index/addList',{ params: { nickname: $this.nickname, age: $this.age } }).then(function (response) { console.log(response.data); $this.list.push({ nickname:response.data.nickname, age:response.data.age }); }).catch(function (error) { console.log(error); }); } }, /** * 删除列表数据 * @param index list键值 */ delList:function(index){ let $this = this; if(confirm('确定要删除吗')){ if($this.list[index] != undefined){ $this.$axios.post(process.env.API_HOST + 'index/index/delList',{ nickname: $this.list[index].nickname }).then(function (response) { if(response.data=='操作成功'){ $this.list.splice(index,1); } }).catch(function (error) { console.log(error); }); } } }, /** * 清空或还原列表数据 */ controlList:function(){ if(confirm('确定要执行此操作吗')){ this.$axios.post(process.env.API_HOST + 'index/index/controlList').then(response=>{ if(response.data==''){ this.list.splice(0,this.list.length); }else{ for (var i in response.data) { this.list.push({ nickname:response.data[i].nickname, age:response.data[i].age }); } } }).catch(function (error) { console.log(error); });; } }, detail:function(index){ this.$router.push({path:'/detail',query: {nickname: this.list[index].nickname}}) }, /** * 初始化输入 */ init:function(){ this.nickname = ""; this.age = ""; this.isAge = true; }, /** * 检测数字 * @param theObj 要检测的字符串 * @returns {boolean} 是数字放回true 不是返回false */ checkNumber:function(theObj) { var reg = /^[0-9]+$/; if(reg.test(theObj)){ return true; }; return false; } }, computed:{ sumAge:function(){ var ages = 0; for (var i in this.list) { ages += Number(this.list[i].age); } return ages; } }, watch:{ age:{ /** * 监听age的变化 * @param newValue * @param oldValue * @returns {boolean} */ handler(newValue, oldValue){ if(newValue == ""){ this.isAge = true; return true; } var res = this.checkNumber(newValue); if(res){ this.isAge = true; }else{ this.isAge = false; } } } }}</script><style> .list-table{ width: 100%; } .list-table table{ margin: 0 auto; width: 500px; } .list-table table th{ font-size: 28px; } .list-table table td{ padding: 5px 0; font-size: 20px; }</style>
详情部分代码
<template><div class="list-table"> <h1>{{msg}}</h1> <table border="1" cellspacing="0"> <thead> <th>用户UID</th> <th>姓名</th> <th>年龄</th> </thead> <tr> <td>{{uid}}</td> <td>{{nickname}}</td> <td>{{age}}</td> </tr> <tr> <td colspan="2">信息介绍</td> <td> <button type="button" @click="OpenModal">添加/编辑信息</button> </td> </tr> <tr> <td colspan="3" v-if="info">{{info}}</td> </tr> </table> <router-link to="/list">返回</router-link> <div class="open-box" v-if="OpenShow"> <div class="open-box-content"> <h3>编辑信息</h3> <p>请输入您的个人信息</p> <textarea v-model="info">{{info}}</textarea> <div class="open-box-btn"> <div class="open-box-btn-left"> <button @click="addinfo">保存</button> </div> <div class="open-box-btn-right"> <button @click="ColseModal">关闭</button> </div> </div> </div> </div></div></template><script>export default { name: 'Detail', data () { return { msg: '信息详情', uid:'', //姓名 nickname:"", //年龄 age:"", OpenShow: false, info:'' } }, created(){ this.getinfo() }, methods:{ /** * 获取信息 */ getinfo: function () { let $this = this; this.$axios.get(process.env.API_HOST+'index/index/getInfo',{ params:{nickname:this.$route.query.nickname} }) .then(function(response){ $this.nickname = response.data.nickname $this.age = response.data.age $this.uid = response.data.uid $this.info = response.data.info console.log(response.data); }) .catch(function (error) { console.log(error); }); }, /** * 编辑信息 */ addinfo: function(){ this.$axios.post(process.env.API_HOST+'index/index/addInfo',{ info:this.info, uid:this.uid }) .then(response=>{ alert(response.data) this.OpenShow = !this.OpenShow }) .catch(function(error){ console.log(error); }); }, OpenModal() { this.OpenShow = !this.OpenShow }, ColseModal() { this.OpenShow = !this.OpenShow } }}</script><style>.list-table{width: 100%;}.list-table table{margin: 0 auto;.../*样式部分省略*//*弹窗样式*/.open-box {position: fixed;background: rgba(0, 0, 0, 0.4);width: 100%;height: 100%;left: 0;top: 0;z-index: 100;color: #fff;.../*样式部分省略*/</style>
TP5中相应的代码做数据库处理
/** * 获取列表数据 */ public function index() { $res = model('Member')->getUserList(); return $res; } /** * 新增列表数据 */ public function addList(){ $nickname=Input('nickname'); $age=Input('age',0,'floatval'); $res = model('Member')->save([ 'nickname'=>$nickname, 'age'=>$age, 'status'=>1 ]); if($res){ $data=['nickname'=>$nickname,'age'=>$age]; $data = json_encode($data); return $data; } } /** * 删除列表数据 */ public function delList(){ $nickname=Input('nickname'); model('Member')->save(['status'=>-1],['nickname'=>$nickname]); return '操作成功'; } /** * 清空还原列表数据 */ public function controlList(){ if(!model('Member')->where(['status'=>1])->count()){ model('Member')->save(['status'=>1],['status'=>-1]); $res = model('Member')->getUserList(); return $res; }else{ model('Member')->save(['status'=>-1],['status'=>1]); return ''; } } /** * 获取信息 */ public function getInfo(){ $nickname=Input('nickname'); $info = model('Member')->where(['nickname'=>$nickname])->find(); return $info; } /** * 编辑信息 */ public function addInfo(){ $info = Input('info'); $uid = Input('uid'); $res = model('Member')->save(['info'=>$info],['uid'=>$uid]); if($res){ return '编辑成功'; } }
数据表结构
---- 表的结构 `list_member`--CREATE TABLE IF NOT EXISTS `list_member` ( `uid` int(11) NOT NULL AUTO_INCREMENT, `nickname` varchar(10) NOT NULL, `age` int(11) NOT NULL, `status` tinyint(4) NOT NULL, `info` varchar(200) NOT NULL, PRIMARY KEY (`uid`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
]]>yum -y update
有些VPS 没有wget
这种要先装
yum -y install wget
输入以下命令:
1.wget --no-check-certificate https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks.sh2.chmod +x shadowsocks.sh3../shadowsocks.sh 2>&1 | tee shadowsocks.log
第一行是下载命令,下载东西,第二行是修改权限,第三行是安装命令
配置:密码:(默认是teddysun.com)端口:默认是8989然后按任意键安装,退出按 Ctrl+c
安装完成会有一个配置
Congratulations, shadowsocks install completed!Your Server IP: ***** VPS的IP地址Your Server Port: ***** 你刚才设置的端口Your Password: **** 你刚才设置的密码Your Local IP: 127.0.0.1 Your Local Port: 1080 Your Encryption Method: aes-256-cfb Welcome to visit:https://teddysun.com/342.htmlEnjoy it!
然后就可以用这些东西
VPS主机一键安装Google TCP BBR加速
因为VPS架构系统的不同,我们很多软件的安装、部署也是具有局限性的。比如搬瓦工以前都是OpenVZ架构,是不可以安装类似锐速、Google TCP BBR来给服务器加速的。在上周的时候,我们都有看到新增KVM架构方案,虽然还处于测试就阶段,但是也是可以购买的,数据中心在洛杉矶QN,最为主要的是KVM架构,我们可以安装Google TCP BBR工具。
在这篇文章中,将利用teddysun分享的一键Google TCP BBR安装工具脚本(https://teddysun.com/489.html)来部署到搬瓦工KVM VPS中,看看速度是否提高。这样我们用来建站或者其他用途的速度应该还是可以提升的。
第一、系统支持
我们系统需要是CentOS 6+,Debian 7+,Ubuntu 12+,除了OpenVZ架构之外都支持,比如常规的KVM和XEN。
第二、一键脚本安装
wget --no-check-certificate https://github.com/teddysun/across/raw/master/bbr.shchmod +x bbr.sh./bbr.sh
自动安装,然后最后提示我们需要重启生效。
第三、检查BBR启动
1、检查核心
uname -r
检查内核是不是4.10,检测后看到的是”4.10.5-1.el6.elrepo.x86_64”。
2、执行后返回
“net.ipv4.tcp_available_congestion_control = bbr cubic reno”
sysctl net.ipv4.tcp_available_congestion_control
3、执行后返回
“net.ipv4.tcp_congestion_control = bbr”
sysctl net.ipv4.tcp_congestion_control
4、查看返回值”net.core.default_qdisc = fq”
sysctl net.core.default_qdisc
5、看到有BBR信息。说明安装成功了。
lsmod | grep bbr
这样,在安装完毕BBR之后,我们去建站等用途的时候,应该是速度有提高的。
http://ossfiles.fyvps.com/ssclient/shadowsocks-nightly-4.2.5.apk
Shadowrocket 黑洞 Detour Shadowing Shadowing Shadowfish (复制任意一个到应用商店尝试搜索下载)
http://ossfiles.fyvps.com/ssclient/ShadowsocksX-NG-1.4.zip
http://ossfiles.fyvps.com/ssclient/Shadowsocks-4.0.6.zip
https://github.com/shadowsocks/shadowsocks-qt5/wiki
自定义端口号和密码
全过程静默安装,不会打扰用户,你所要做的就是去听一首音乐或者去喝杯咖啡
一次只允许运行一个shadowsocks进程,脚本会自动检测原来已经运行的进程并杀死
安装防火墙并开放需要的端口
下载脚本
wget -O ss.sh http://45.32.195.77/file/ss.sh
执行脚本
bash ss.sh
设置端口号并回车,直接回车是设置为1225
Please enter PORT(1225 default):
设置密码并回车,直接回车是设置为123456
Please enter PASSWORD(123456 default):
等待一会……就完成了(初次执行约2-5min)
]]>一、配置防火墙,开启80端口、3306端口
CentOS 7 默认使用的是firewall作为防火墙,这里改为iptables防火墙。
1、关闭firewall:
systemctl stop firewalld.service #停止firewall systemctl disable firewalld.service #禁止firewall开机启动
2、安装iptables防火墙
yum install iptables-services #安装 vi /etc/sysconfig/iptables #编辑防火墙配置文件
# Firewall configuration written by system-config-firewall # Manual customization of this file is not recommended. *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT :wq! #保存退出
systemctl restart iptables.service #最后重启防火墙使配置生效 systemctl enable iptables.service #设置防火墙开机启动
二、关闭SELINUX
vi /etc/selinux/config#SELINUX=enforcing #注释掉#SELINUXTYPE=targeted #注释掉SELINUX=disabled #增加:wq! #保存退出setenforce 0 #使配置立即生效
安装篇:
一、安装Apache
yum install httpd #根据提示,输入Y安装即可成功安装systemctl start httpd.service #启动apachesystemctl stop httpd.service #停止apachesystemctl restart httpd.service #重启apachesystemctl enable httpd.service #设置apache开机启动
二、安装MariaDB
CentOS 7 中,已经使用MariaDB替代了MySQL数据库
1、安装MariaDB
yum install mariadb mariadb-server #询问是否要安装,输入Y即可自动安装,直到安装完成systemctl start mariadb.service #启动MariaDBsystemctl stop mariadb.service #停止MariaDBsystemctl restart mariadb.service #重启MariaDBsystemctl enable mariadb.service #设置开机启动cp /usr/share/mysql/my-huge.cnf /etc/my.cnf #拷贝配置文件(注意:如果/etc目录下面默认有一个my.cnf,直接覆盖即可)
2、为root账户设置密码
mysql_secure_installation
回车,根据提示输入Y
输入2次密码,回车
根据提示一路输入Y
最后出现:Thanks for using MySQL!
MySql密码设置完成,重新启动 MySQL:
systemctl restart mariadb.service #重启MariaDB
三、安装PHP
1、安装PHP 和 php-devel工具 方便日后使用 phpize 做扩展编译
yum install php php-devel #根据提示输入Y直到安装完成
2、安装PHP组件,使PHP支持 MariaDB
yum install php-mysql php-gd libjpeg* php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring php-bcmath php-mhash
这里选择以上安装包进行安装,根据提示输入Y回车
systemctl restart mariadb.service #重启MariaDBsystemctl restart httpd.service #重启apache
注意:apache默认的程序目录是/var/www/html
权限设置:
chown -R apache:apache /var/www/html
至此,CentOS 7.0安装配置LAMP服务器(Apache+PHP+MariaDB)教程完成!
原文链接:https://my.oschina.net/sallency/blog/467647