月度归档 2016年4月26日

通过清心醉

微擎分销规则

今天把微擎的分销系统整合到独立开发的影院模块,进行了多项的测试,并且把测试的结果写起来:

过程是这样的,用户在独立开发的影院系统里进行下单,支付成功在回调的时候,调用分销数据的写入:

1:分销中心必须为开启状态;

2:分销的等级必须开启

在这顺便讨论下问题,如有三级分销A->B->C->D

如果开启的为三级,那么ABC都会获取对应的返佣规则(对于D来说,1级=C;2级=B;3级=A);

假设佣金的规则为:1级10%;2级8%;3级5%;

D用户购买了100元的产品

A获取5元;B获取8元;C获取10元

由于订单是独立在影院系统的,所以需要同步写入一份订单数据到微擎的三级分销order即可!

附上一个扩展类库

直接调用get_shop_sysset()方法,并且带上需要的参数

class IPanYing{

/**
* 判断公众号数据是否对应,因为一个用户可以有多个公众号!权限判断!
* @param unknown $uniacid
* @param unknown $uid
* @return boolean
*/
private function get_uni_account_user($uniacid,$uid){
$sql=”SELECT * FROM `”.$this->pre.”uni_account_users` WHERE `uniacid`='”.(int)$uniacid.”‘ AND `uid`='”.(int)$uid.”‘”;
$data = $this->pdo->query($sql);
$data = $data->fetch(PDO::FETCH_ASSOC);
if (!empty($data)){
return true;
} else {
return false;
}
}

/**
* 获取当前公众号的plugins
* @param unknown $appid
* @return unknown
*/
private function get_ewei_shop_sysset($appid){
$sql = “SELECT plugins FROM `”.$this->pre.”ewei_shop_sysset` WHERE `uniacid` = ‘”.(int)$appid.”‘”;
$data = $this->pdo->query($sql);
$data = $data->fetch(PDO::FETCH_ASSOC);
return $data[‘plugins’];
}

/**
* 查看商家是否开启了公众号模块状
* @param unknown $appid
* @param unknown $uid
*/
private function get_rule($appid){
$sql = “SELECT * FROM `”.$this->pre.”rule` WHERE `uniacid` = ‘”.(int)$appid.”‘ AND `module`=’cover'”;
$data = $this->pdo->query($sql);
return $data->fetch(PDO::FETCH_ASSOC);
}

private $openid; #-记录当前的用户ID

/**
*
* @param unknown $appid #-公众号唯一ID
* @param unknown $uid #-商家的唯一ID
* @param unknown $openid #-发起订单的用户ID,私有成员不同
* @param unknown $money #-金额
* @param unknown $orders #-订单数据
*/
function get_shop_sysset($appid,$uid,$openid,$money,$orders){
if ($this->get_uni_account_user($appid, $uid)){ #-判断是否合法,即根据用户ID再判断公众号
$status = $this->get_rule($appid); #-判断三级分销是否已经为启用的状态
$this->openid= $openid; //获取当前的用户OPENID;
if ($status[‘status’]==1 || $status[‘status’]==’1′){ #-如果有打开分销系统
$plugins = unserialize($this->get_ewei_shop_sysset($appid)); #-提取分销的数据
$level = $plugins[‘commission’][‘level’];
$temp_agentid = $this->getagentid($appid); #-获取临时的上级ID,因为要写入订单数据的
$this->setOrder($orders, $money, $appid, $temp_agentid); #-写入一份订单数据
$order_id = $this->pdo->lastInsertId(); #-获取当前的订单ID
$commission = array();
if ($level>0){ #-如果大于0表示开启了佣金
$default_money = 100; #-测试的时候使用的默认金额,否则使用$money
for ($i=1;$i<=$level;$i++){ #-最大的次数字
$text = ‘commission’.$i; #-获取需要循环提取的字段
$temp_data = $plugins[‘commission’][$text]*0.01; #-提取对应字段值的VALUE并且转化成百分比
$commission[$i] = intval($default_money*$temp_data); #-获取完整的佣金数据,只保留整数
#-如果需要小数后两位使用round()方法
}
for ($o=1;$o<=3;$o++){
if (isset($commission[$o]) && !empty($commission[$o])){

} else {
$commission[$o]=’0.00′;
}
}
$this->setOrderGoods($appid, $order_id, $money, ‘电影票level=’.$level,$commission);
} else {
for ($o=1;$o<=3;$o++){
$commission[$o]=’0.00′;
}
$this->setOrderGoods($appid, $order_id, $money, ‘电影票level=’.$level,$commission);
}
} else {

}
}
}

private function setOrderGoods($appid,$order_id,$price,$optionname,$commission){
$sql = “INSERT INTO `”.$this->pre.”ewei_shop_order_goods`
SET `uniacid` = ‘”.(int)$appid.”‘,
`orderid` = ‘”.(int)$order_id.”‘,
`goodsid` = ‘0’,
`price` = ‘”.$price.”‘,
`total` = ‘1’,
`optionid` = ‘0’,
`createtime` = ‘”.time().”‘,
`optionname` = ‘”.$optionname.”‘,
`commission1` = ‘”.$this->orderCommission($commission[1]).”‘,
`applytime1` = ‘0’,
`checktime1` = ‘0’,
`paytime1` = ‘”.time().”‘,
`invalidtime1` = ‘0’,
`deletetime1` = ‘0’,
`status1` =’0′,
`content1` =’NULL’,
`commission2` = ‘”.$this->orderCommission($commission[2]).”‘,
`applytime2` = ‘0’,
`checktime2` = ‘0’,
`paytime2` = ‘”.time().”‘,
`invalidtime2` = ‘0’,
`deletetime2` = ‘0’,
`status2` =’0′,
`content2` =’NULL’,
`commission3` = ‘”.$this->orderCommission($commission[3]).”‘,
`applytime3` = ‘0’,
`checktime3` = ‘0’,
`paytime3` = ‘”.time().”‘,
`invalidtime3` = ‘0’,
`deletetime3` = ‘0’,
`status3` =’0′,
`content3` =’NULL’,
`realprice` = ‘”.$price.”‘”;
$this->pdo->exec($sql);
}

/**
* 根据金额进行序列化
* @param unknown $money
* @return unknown
*/
private function orderCommission($money){
$arr[‘default’]=”$money”;
$text = serialize($arr);
return $text;
}

/**
* 写入订单数据
* @param unknown $order
* @param unknown $money
* @param unknown $appid
* @param unknown $agentid
*/
private function setOrder($order,$money,$appid,$agentid){
$sql=”INSERT INTO `”.$this->pre.”ewei_shop_order`
SET `uniacid`='”.(int)$appid.”‘,
`openid` = ‘”.$this->openid.”‘,
`agentid` = ‘”.(int)$agentid.”‘,
`ordersn` = ‘”.$order[‘out_trade_no’].”‘,
`price` = ‘”.$money.”‘,
`goodsprice` = ‘”.$money.”‘,
`discountprice` = ‘0.00’,
`status` =’3′,
`paytype` = ’21’,
`addressid` = ‘”.(int)$this->getAdders($appid).”‘,
`dispatchprice` = ‘0.00’,
`dispatchid` = ‘0’,
`createtime` = ‘”.time().”‘,
`dispatchtype` =’0′,
`carrier` =’a:0:{}’,
`refundid` =’0′,
`iscomment` =’0′,
`creditadd` =’0′,
`deleted` =’0′,
`userdeleted` = ‘0’,
`finishtime` = ‘0’,
`paytime` ='”.time().”‘,
`sendtime` =’0′,
`fetchtime` =’0’,
`cash` = ‘0’,
`canceltime` =’NULL’,
`cancelpaytime` =’0′,
`refundtime` =’0′,
`isverify` = ‘0’,
`verified` =’0′,
`verifytime` =’0′,
`verifystoreid` =’0′,
`deductprice` =’0.00′,
`deductcredit` =’0′,
`deductcredit2` = ‘0.00’,
`deductenough` =’0.00′”;
$this->pdo->exec($sql);
}

/**
* 根据公众号ID和用户OPENID获取订单地址ID
* @param unknown $appid
* @return unknown
*/
private function getAdders($appid){
$sql = “SELECT id FROM `”.$this->pre.”ewei_shop_member_address` WHERE `uniacid`='”.(int)$appid.”‘ AND `openid` = ‘”.$this->openid.”‘”;
$data = $this->pdo->query($sql);
$data = $data->fetch(PDO::FETCH_ASSOC);
return $data[‘id’];
}

/**
* 根据公众号唯一ID和用户的唯一OPENID,提取出上一级
* @param unknown $appid
* @return unknown
*/
private function getagentid($appid){
$sql = “SELECT agentid FROM `”.$this->pre.”ewei_shop_member`
WHERE `uniacid` = ‘”.(int)$appid.”‘ AND `openid` = ‘”.$this->openid.”‘”;
$data = $this->pdo->query($sql);
$data = $data->fetch(PDO::FETCH_ASSOC);
return $data[‘agentid’];
}

}

 

通过清心醉

kingroot到底有多垃圾?

用图说话

Screenshot_2016-04-24-14-11-28_com.miui.securitycenterScreenshot_2016-04-24-14-11-19_com.miui.securitycenterScreenshot_2016-04-24-14-09-55_com.miui.home

 

上次刷了机,删除了,今天重启结果出现了

结果把系统重置了,结果他把数据写入到了安装包

中国的软件就只能这么的废物!

通过清心醉

微擎无法调用oAuth

由于无聊玩玩改代码,结果发现,公众号无法调用oAuth;

file:///web/source/mc/passport.ctrl.php

OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAUTH的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAUTH是安全的。oAuth是Open Authorization的简写。

来说说问题吧:

每一个公众号都有个唯一的uniacid唯一参数值,在创建完成之后,写入扩展表:uni_settings

有这么一个字段:oauth

字段值:a:2:{s:4:”host”;s:0:””;s:7:”account”;i:26;}

host=其他域名的,account=对应的oauth参数组合URL;

再来看看URL需要的参数

后台访问的时候,会GET个do=oauth,执行该方法

 

if($do == ‘oauth’) {
uni_user_permission_check(‘mc_passport_oauth’);
$_W[‘page’][‘title’] = ‘公众平台oAuth选项 – 会员中心’;

$where = ”;
$params = array();
if(empty($_W[‘isfounder’])) {
$where = ” WHERE `uniacid` IN (SELECT `uniacid` FROM ” . tablename(‘uni_account_users’) . ” WHERE `uid`=:uid)”;
$params[‘:uid’] = $_W[‘uid’];
}
$sql = “SELECT * FROM ” . tablename(‘uni_account’) . $where;

$uniaccounts = pdo_fetchall($sql, $params);
$accounts = array();
if(!empty($uniaccounts)) {
foreach($uniaccounts as $uniaccount) {
$accountlist = uni_accounts($uniaccount[‘uniacid’]);
if(!empty($accountlist)) {
foreach($accountlist as $account) {
if(!empty($account[‘key’]) && !empty($account[‘secret’]) && in_array($account[‘level’], array(4))) {
$accounts[$account[‘acid’]] = $account[‘name’];
}
}
}
}
}
…..次处省略N个字符……
}

在这特别注意:uni_accounts($uniaccount[‘uniacid’])方法

原型是:

function uni_accounts($uniacid = 0) {
global $_W;
$uniacid = empty($uniacid) ? $_W[‘uniacid’] : intval($uniacid);
$accounts = pdo_fetchall(“SELECT w.*, a.type, a.isconnect FROM ” . tablename(‘account’) . ” a INNER JOIN ” . tablename(‘account_wechats’) . ” w USING(acid) WHERE a.uniacid = :uniacid ORDER BY a.acid ASC”, array(‘:uniacid’ => $uniacid), ‘acid’);
return $accounts;
}

该方法里获取的值,是account_wechats里的数据,里面有个level,必须=4,否则将无法调用!

顺便给个方法:

if(!empty($uniaccounts)) {
foreach($uniaccounts as $uniaccount) {
$accountlist = uni_accounts($uniaccount[‘uniacid’]);
if(!empty($accountlist)) {
foreach($accountlist as $account) {
$arr=array(
‘2’ => 2,
‘3’ => 3,
‘4’ => 4,
);
if(!empty($account[‘key’]) && !empty($account[‘secret’]) && in_array($account[‘level’], $arr)) {
$accounts[$account[‘acid’]] = $account[‘name’];
}
}
}
}
}

这样就只提取2-4等级的了

 

JSAUTH也一样,文件位置:file:///web/source/profile/jsauth.ctrl.php

if(!empty($uniaccounts)) {
foreach($uniaccounts as $uniaccount) {
$accountlist = uni_accounts($uniaccount[‘uniacid’]);
if(!empty($accountlist)) {
foreach($accountlist as $account) {
if(!empty($account[‘key’])
&& !empty($account[‘secret’])
&& in_array($account[‘level’], array(2, 3, 4))) {
$accounts[$account[‘acid’]] = $account[‘name’];
}
}
}
}
}

通过清心醉

可伸缩Web架构的4个问题:瓶颈,CPU,数据库,IO

负载均衡器扩展

可以通过将DNS指向多个IP以及使用DNS轮循查找IP地址的方式来实现负载均衡器的横向扩展。或者可以使用多级负载均衡,使上一级负载均衡器来分发至下一级负载均衡器,但使用多个负载均衡器的情况比较少,主要是由于Web容器一般可以处理几千并发请求,而使用nginx或者HAProxy的单个负载均衡器可以处理超过20000的并发请求,因此单个负载均衡器完全可以代理多个web应用。

数据库功能扩展

数据库功能扩展是非常常用的方式,但是扩展数据库功能(比如创建存储过程或自定义函数)都会给数据层带来额外开销以及增加数据层的复杂性。

关系型数据库

关系型数据库可以通过主从同步的模式实现扩展,主库以写入数据为主,从库只做读操作。但是,如果业务量比较大时主从同步模式所提供的扩展能力非常有限,此外,开发人员还需要通过数据库拆分技术来进一步满足业务需求。

NoSQL

CAP定理(译者注:不熟悉的读者可通过谷歌查阅)告诉我们一个应用不可能同时满足一致性、可用性、分区容错性三个要求。而NoSQL一般则是通过牺牲一定的一致性来获得更高可用性以及更好的分区容错性。

数据库拆分

数据库拆分可以垂直拆分和水平拆分:

 垂直拆分(Partitioning):根据领域模型概念的基础可以将数据库拆分为几个松耦合的子库。例如,拆分为消费者数据库、产品数据库。另一种垂直拆分数据库的方式是将一个实体的一部分字段拆分出来作为一个新数据库,另一部分字段作为另一个数据库。例如,将消费者数据拆分为消费者联系信息和订单数据两部分。

 水平拆分(Sharding):可以根据数据的离散属性将数据进行水平分割。例如,消费者可以根据地域不同拆分为美国消费者数据库和欧洲消费者数据库。

将数据库从单个数据库使用分区或者sharding拆分为多个数据库是一项非常有挑战性的任务。

架构瓶颈

可扩展系统出现性能瓶颈的原因主要在于以下两方面:

 中心化组件 应用中一个不可扩展的组件直接影响整个系统或者请求处理通道所能处理请求数的上限。

 高延迟组件 一个高延迟的组件会影响整个系统响应时间的下限,使整个系统响应时间更长。通常解决这个问题的办法是使高延迟的组件作为后台任务线程或者使用异步队列来解决。

CPU消耗型应用

如果一个应用的吞吐量受CPU的限制,那么该应用就是CPU消耗型应用。此类引用通过增加CPU计算速度即可减少响应时间。

以下这些应用场景可能属于CPU消耗性:

 需要计算或者处理数据而不需要做IO操作的应用(财务或者交易类系统)

 非常依赖缓存而且不做任何IO操作的应用

 异步(非阻塞)模型而且不需要等待外部资源的应用(被动应用或者使用NoJs的应用)

在以上使用场景中已经正常运行的应用,如果在一些应用场景中写了糟糕的或者效率低下的代码来对每次请求做大量额外的计算或者循环,那么这些应用的CPU占用率将非常高。但是通过分析应用可以很容易发现并修改效率低的问题。

IO消耗型应用

如果一个应用的吞吐量受IO或者网络操作影响而且提升CPU计算速度并不能减少响应时间,那么该应用即为IO消耗型应用。大多数应用是IO消耗型应用主要是由于要做增、删、改、查操作。而性能调优和对iO消耗型应用进行扩展也由于这些系统依赖于其他系统的下行流量变得非常困难。

以下这些应用场景可能是IO消耗性:

 依赖数据库并进行增、删、改、查操作的应用

 需要下行流量来完成本身操作的应用

让我们先来了解一些术语。稍后我将对Web应用扩展过程中所遇到的不同问题进行讲解,例如:

1:架构瓶颈

2:数据库扩展

3:CPU消耗型应用

4:IO消耗型应用

性能

Web系统的性能受多方面因素的影响,但大多数开发人员主要关心的是响应时间和可扩展性这两方面。

响应时间

响应时间是指Web应用从收到请求到返回响应结果所花费的时间。而应用系统应该在可接受的时间范围内返回响应结果,否则就不能算是一个性能良好的应用系统。

可扩展性

如果Web应用通过增加更多硬件可以使处理的请求数呈线性增长,那么该应用是可扩展的。

扩展的方式可以分为以下两种:

1) 纵向扩展(垂直扩展):为单台机器增加CPU或者提高单台机器CPU性能。

2) 横向扩展(水平扩展):增加服务器数量

垂直扩展 VS 水平扩展

一般情况下水平扩展比垂直扩展更重要,主要是因为普通硬件商品远比需要特殊配置的硬件便宜(比如大型机);但是增强单个应用在一个硬件商品上处理的请求数同样也是比较重要的。同时,一个应用系统在不降低响应时间的前提下,如果通过添加更多的资源能够处理更多的请求,那么这个系统表现良好。

响应时间 VS 可扩展性

在同一个应用中,响应时间和可扩展性并不总是能够同时达到最好的效果。要么应用程序有可接受的响应时间但是不能处理超过一定数量的请求;要么应用程序可以处理大量请求,但是响应时间却不尽如人意,甚至非常糟糕。因此,通常情况下我们需要在这两个要素中寻求平衡点使我们的应用系统性能达到最佳状态。

容量规划

容量规划需要我们根据产品期望的负载量来预估所需要的硬件数量。除了整体的预估外,这通常还包括使用更少硬件时系统的性能表现情况以及单台机器下的性能的测试及评估。

架构扩展

如果Web应用的每一层在多层架构体系中都是可扩展的,那么该应用也具有可扩展性(横向扩展)。例如,如下图所示,我们就可以通过增加额外的资源来实现应用层和数据库层的线性扩展。

 

 

通过清心醉

PHP截取中文字符串

开发PHP的时候,如果从数据库中提取的数据需要进行字符串的截取(比如文章的标题);

如果只是截取英文和数字,那简单的很,substr()方法就可以,附加3个参数:

1->需要截取的字符;

2->开始位置;

3->结束位置;

开始和结束位置如果为负数,即表示从尾端截取上来。

可是在截取UTF8的中文就好麻烦了,这时候,就需要使用到MB类库的mb_substr()方法了

首先请确保服务器的PHP是否开起了MB类库的扩展

使用方法:mb_substr(string,leng_head,leng_end,type);

前面3个和substr一样,关键最后面多了一个type,即截取的字符串的类型,通用一般为:utf-8

如:mb_substr(‘我是清心醉,一个网站全栈架构师’,3,15,’utf-8′);