分类归档 HTML/PHP

通过清心醉

PHP CRC16物联网硬件通讯升级

<?php
class crc{

private $SerialNumber = 1; //自增加
private $SerialNumberXOR = 254; //自减少

function issleep($time = 1){
    sleep($time);
}

private $binFile = '';
private $getSocketData = ''; //获取的16进制数据
function setBinFile($str){
    $this->binFile .=$str;
}
function getBinFile($str){
    $this->binFile .=$str;
    //$this->getSocketData .=$str;
}

function CreateSetLogFile($file){
    $file = SET_FILE;
    if($this->binFile){
        $hexstr = str_replace(" ","",$this->binFile);
        $data = pack('H*', $hexstr);
        file_put_contents($file, $data, true);
    }

    //因为获取的是16进制 所以直接写入16进制文件
    $getfile = GET_FILE;
    if($this->getSocketData){
        //$hexstr = str_replace(" ","",$this->getSocketData);
        //$data = pack('H*', $hexstr);
        file_put_contents($getfile, $this->getSocketData, true);
    }
}

public $str = array();
function setlog($str){
    $this->str[] = $str;
    $str = $str."\r\n";
    echo iconv('utf-8','gbk//IGNORE',$str);
}

function chaString($string){
    $str = '';
    for($i=0;$i<strlen($string);$i++){
        $str .= $this->getByteData($i, $string);
    }
    return $str;
}

function getByteData($k,$str){
    if($k%2==0){
        return " ".$str[$k];
    } else {
        return $str[$k];
    }
}
//字符串转16进制
function strToHex($str){
    $hex="";
    for($i=0;$i<strlen($str);$i++)
        $hex.=dechex(ord($str[$i]));
        $hex=strtoupper($hex);
        return $hex;
}
//16进制转字符串
function hexToStr($hex){
    $str="";
    for($i=0;$i<strlen($hex)-1;$i+=2)
        $str.=chr(hexdec($hex[$i].$hex[$i+1]));
        return $str;
}

function crc16($string) {
    $crc = 0xA28C;
    for ($x = 0; $x < strlen ($string); $x+=2) {
        $sys = '';
        if(isset($string[$x]) && isset($string[$x+1])){
            $sys = $string[$x].$string[$x+1];
        } else {
            continue;
        }
        //echo "sys = ". $sys."\r\n";
        $sys = hexdec($sys);

        $crc  ^= $sys;
        for ($y = 0; $y < 8; $y++) {
            $lbs = $crc & 0x0001;
            $crc >>=1;
            if($lbs == 1){
                $crc ^= 0x8408;
            }
        }
    }
    $crc ^=0xFFFF;
    return $crc;
}


private function dechexSerialNumber(){
    $str = dechex($this->SerialNumber);
    $str = $this->setHeadZero($str);
    $this->SerialNumber++;
    return $str;
}
private function dechexSerialNumberXOR(){
    $str = dechex($this->SerialNumberXOR);
    $str = $this->setHeadZero($str);
    $this->SerialNumberXOR--;
    return $str;
}

//前补0
private function setHeadZero($str,$max = 2){
    $leng = strlen($str);
    for($i=$leng;$i<$max;$i++){
        $str = "0".$str;
    }
    return $str;
}
//后补0
private function setEndZero($str,$max = 4){
    $leng = strlen($str);
    for($i=$leng;$i<$max;$i++){
        $str = $str."0";
    }
    return $str;
}


public function getdata($packet){
    $data = array();
    $data[0] = '6D';
    $data[1] = 'AC';
    $data[2] = $this->dechexSerialNumber();
    $data[3] = $this->dechexSerialNumberXOR();
    $packetNum = count($packet); //Packet Length
    $packetNum = dechex($packetNum);
    $packetNum = $this->setHeadZero($packetNum,4); //因为高字节要在前,比如包长度=10 那么实际就是0010,高低位转换就是10 00
    //数据包长度高低位
    $data[4] = substr($packetNum, 2,2);
    $data[5] = substr($packetNum, 0,2);

    //指令开始 协议头
    $command = '';

    for($i=0;$i<count($data);$i++){
        $command = $command.$this->setHeadZero($data[$i])." ";
        //$crcString .= $this->setHeadZero($data[$i]);
    }
    $crcString = '';
    //指令内容体
    for($i=0;$i<count($packet);$i++){
        $command = $command.$this->setHeadZero($packet[$i])." ";
        $crcString .= $this->setHeadZero($packet[$i]);
    }
    $crc = '';
    $temp_crc = dechex($this->crc16($crcString));
    $sum = strlen($temp_crc);
    for($i=$sum;$i<4;$i++){
        $temp_crc = "0".$temp_crc;
    }
    $crc = $temp_crc;
    $crc1 = $this->setHeadZero(substr($crc,2,2));
    $crc2 = $this->setHeadZero(substr($crc, 0,2));
    $command = $command.$crc1. " ".$crc2;
    $commandArray = array();
    return $command;
}

private function heightlow($readInt){
    $byte1 = (($readInt & 0xff));
    $byte2 = (($readInt & 0xff00) >> 8);
    // 拼装成 "高字节在后,低字节在前"的格式
    $realint = ($byte1 & 0xff) << 0 | ($byte2 & 0xff) << 8;
    //echo $byte1." = ".$byte2."\r\n";
    return $realint;
}
//更新
public function getUpdatePacket(){
    $data[0] = 26; //command
    $data[1] = 11; //type
    //p2-p9
    for($i=2;$i<=9;$i++){
        $data[$i] = 00;
    }
    return $data;
}
//握手
public function getHandshake(){
    $data[0] = 20; //command
    $data[1] = 11; //type
    //p2-p9
    for($i=2;$i<=9;$i++){
        $data[$i] = 00;
    }
    return $data;
}

private $falshAddress = 64;
private $defaultFalshAddress = 64; //falsh默认的10进制地址

private function getFalshAddress($zizeng = true){
    $falshAddress = $this->falshAddress;
    if($zizeng == true){
        $this->falshAddress = $this->falshAddress+2;
    }
    return dechex($falshAddress);
}
//跳转到Application
public function runApp(){
    $data[0] = 21;
    $data[1] = 11;
    for($i=2;$i<=9;$i++){
        $data[$i] = 00;
    }
    return $data;
}

//校验falsh
public function checkFalsh($res){
    $data[0] = 25;
    $data[1] = 12; 
    //p2-p9
    for($i=2;$i<=9;$i++){
        $data[$i] = 00;
    }
    $data[3] = dechex($this->defaultFalshAddress);

    //大小 = 224*0x200;
    $data[10] = dechex($this->defaultFalshAddress);
    $data[11] = 56;
    $data[12] = 00;
    $data[13] = 00;
    //dechex(224*0x200);
    return $data;
}
//擦除
public function getRemove(){
    $data[0] = 24; //command
    $data[1] = 12; //type
    //p2-p9
    for($i=2;$i<=9;$i++){
        $data[$i] = 00;
    }
    $data[3] = $this->getFalshAddress(false);
    //大小 = 224*0x200;
    $data[10] = dechex($this->defaultFalshAddress);
    $data[11] = 56;
    $data[12] = 00;
    $data[13] = 00;
    //dechex(224*0x200);
    return $data;
}
//下载
public function getUpload($arr){
    $data[0] = 22; //command
    $data[1] = 12; //type
    //p2-p9
    for($i=2;$i<=9;$i++){
        $data[$i] = 00;
    }
    $data[3] = $this->getFalshAddress(); //dechex();
    $array = explode(" ",$arr);
    for($i=0;$i<count($array);$i++){
        if(!empty($array[$i])){
            $data[] = $array[$i];
        }
    }
    return $data;
}

}

使用方式:

$filename = “C:\crc\APP-2020-02-05.bin”;
$host = ‘192.168.1.122’;
$port = 502;
define(“SET_FILE”,’C:\crc\log.log’);
define(“GET_FILE”,’C:\crc\getlog.log’);

require_once ‘crc.php’;
$req = new crc();
$res = bin2hex(file_get_contents($filename));
if (!$res){
$req->setlog(“打开更新文件失败”);
return;
}
$req->setlog(“连接设备中…”);
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($sock, SOL_SOCKET, SO_SNDTIMEO,array(‘sec’ => 1, ‘usec’ => 1));
$result = @socket_connect($sock, $host, $port);
if($result == false){
$req->setlog(“设备连接失败”);
return false;
}

//发送数据
function send($sock,$packets,$crc){
$status = socket_last_error($sock);
if($status!=0){
return false;
}
//记录的数据为字符串,实际发送的时候 重新转换成16进制的数据格式
$t = $packets;
$packets = str_split(str_replace(‘ ‘, ”, $packets), 2); //chr(hexdec($packets));
$packet = null;
for($i=0;$isetBinFile($t);
$res = getrec($sock,$crc);
$crc->getBinFile(bin2hex($res));
$crc->setlog(“接收的16进制数据:”.bin2hex($res));
return true;
}

function getrec($socket,$crc){
$rec = null;
$time = time();
$crc->setlog(“接收数据”);
while (@socket_recv($socket, $rec, 4096, 0)) { //设置接收长度最大值缓冲区
if($time+10setlog(“接收数据超时”);
break;
}
return $rec;
}
return false;
}
//

$req->setlog(“设备连接成功”);
$req->setlog(“更新帧”);
$getUpdatePacket = $req->getUpdatePacket(); //更新的包
$packets = $req->getdata($getUpdatePacket);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();
$req->setlog(“握手”);
$getHandshake = $req->getHandshake(); //更新的包
$packets = $req->getdata($getHandshake);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();

$req->setlog(“擦除falsh”);
$getRemove = $req->getRemove();
$packets = $req->getdata($getRemove);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();

$arr = array();
$head = 0;
$end = 1024;
$length = strlen($res);
while(true){
if($length<=0){ break; } $arr[] = substr($res, $head,$end); $head = ($head+1024); $length = ($length-1024); } for($i=0;$isetlog(“第”.($i+1).”次下载数据”);
$str = $req->chaString($arr[$i]);;
$getUpload = $req->getUpload($str);
$packets = $req->getdata($getUpload);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();
}

$req->setlog(“校验falsh”);
$checkfalsh = $req->checkFalsh($res);
$packets = $req->getdata($checkfalsh);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();

$req->setlog(“跳转到Application”);
$runApp = $req->runApp();
$packets = $req->getdata($runApp);
$req->setlog($packets);
if(send($sock, $packets,$req) == false){
$req->setlog(“发送数据”.$packets.”失败”);
}
$req->issleep();

$req->setlog(“执行完成”);
$req->setlog(“创建写入文件”);
$req->CreateSetLogFile(SET_FILE);

通过清心醉

WordPress目录安全权限

不管实在Linux还是Windows系统,我们都需要对PHP的系统应用进行权限的控制

Windows上我不懂,不给与评价

但是Liunx,默认很多权限是755,其实也足够了,但是不排除很多漏洞引起的垃圾文件被POST上传,其中最常见的就是POST木马脚本,什么一键改代码,改数据库的

针对WordPress,首先,我们给与整个web站点设置555权限

然后,因为我们的后台发布的文章,可能会需要上传图片/音频/视频等文件类型,这里就需要进行写入的权限

因此我们给与对应的上传目录设置755权限即可.

即:/web/wp-content/uploads

(切忌不要设置777,755就足够,777如果目录及文件权限过高,当心整个服务器给黑!)

通过清心醉

PHP多线程开发的坑

说起多线程,一般的人都想到的是用C类语言,或者JAVA来开发

因为我是做PHP为主的,对JAVA了解的少,而用C实际开发项目的经验少,所以入坑了。

在这也简单的来和大家说下:

首先,我们会以CLI的方式来运行SERVER进程,在进程里,读取数据库的设备信息,实现线程的创建。

在这里,PHP基本使用的是Pthread的扩展Thread。

由于项目需要,我们在创建了线程之后,在线程里实现while(true)与设备通讯,获取设备的最新信息。

来说说重点吧:

1:服务器的环境配置,在这里大家一定要特别的注意,一定要用5.6+的ZTS-X64版本,建议使用W_PHP 7.0X或Linux 7.2.X版本,因为这两个版本网上都有最近的线程扩展模块。如果使用的是非ZTS-X64版本,那么很遗憾,线程永远开启不了超过200个。因为进行了多次的模拟测试,包括线程内执行死循环和跑完之后挂起,查看系统的资源使用,如果是X86系统下,因为内存的其他限制(详细的内存有得说了,不一一解释,自行翻资料查看86-64的内存使用哈);

2:系统版本,一般开发调试,系统的最低要求是Windows7 SP1,LINUX则无限制(但必须都是X64),因为在WINDOWS下跑Thread需要VC2015的扩展支持;如果开发则还使用Windows7的,cmd->winver里查看版本内核是否低于7001,是的话,升级为SP1解决问题;

3:线程安全:现在网上什么ZTS、NTS的说话一大堆,都是老过时的东西,现在的线程安全,都是被人抄来抄去的过期文章!

PHP的Pthread扩展,V2和V3版本有了很大的实际变更,更像多线程的操作优化了;

A:V2版本,虽然实现了多线程,但一样可以通过稀哈操作数据数组,导致频繁的线程操作,导致线程挂起

B:线程内的成员在执行的时候,已经分配了适当的内存空间,也就是说一个空变量,分配了值=int(1),这时候,是不可能进行=String的操作,更不可以变成数组等,所以在线程内获取的数据资源,需要使用其他TCP端口来接收或者其他更好的操作方法;(这才是更好的理解什么是线程安全ZTS,对内存中的所有分配好的资源,是不可以随意修改的,当然$i=0;$i=1之类的占用相同地址同类型的,还是可以的)

C:线程锁,如果多线程内需要对同一地址的数据进行操作,切忌使用锁,否则同一时间的操作导致线程的异常,也会导致线程中止退出。

D:就是线程的内存占用了,说真的,PHP的线程占用内存还真好,也许是因为我在线程内也有发起TCP请求其他的关系,导致1个线程使用内存都接近了1MB,所以我们能以行参的方式传递参数,就别用成员!数据的销毁也一定要记得!

来一段2000个的线程创建实例吧:

class ThreadMax extends thread{

private $id;

function __construct($id){

$this->id = $id;

}

function run(){

while(true){

//echo “ID=”.$this->id.”\n”; //不执行其他任务工作

sleep(1);

}

}

}

$thread = array();

for($i=1;$i<=2000;$i++){

$thread[$i] = new ThreadMax($i);

}

$default  =0;

while(true){

if($default==0){

for($i=1;$i<=2000;$i++){

$thread[$i]->start();

}

$default = 1;

}

echo “thread All is OK!”;

sleep(10);

}

return;

微信图片_20180427222654

通过清心醉

模块化第三方接口开发一,模块化的登陆

很多做WEB开发的人都知道,现在做WEB,都需要使用第三方比如支付宝、微信等 。拿国内的ecshop来说吧,我们在添加一个支付宝授权登陆、微信授权登陆,支付宝支付、微信支付的时候,都会需要对不同的模块进行频繁的修改,虽然说也有封装部分的接口,但也不能得尽人意。而且如果后续要对接比如PAYPAY支付、GOOGLE支付等其他第三方支付的时候,会显示出我们写的代码的质量是多么的脆弱,好吧,上正题,本文将从登陆开始,来实现系统化的调用。

该文章作者会大概的阐述自定义

首先我们来定个目标变量,假设支付宝=0,微信=1

//定义第三方接口参数注册
$api = array(
0=>array(
‘extend’=>’AlipayApi’, //接口类名
‘useragent’=>’AlipayClient’,//接口识别用户访问类型
),
1=>array(
‘extend’=>’Weixin’,
‘useragent’=>’MicroMessenger’,
),
);

在这里我们定义好了第三方的接口所需要的信息。

一维代表类型,当然也可以自身在数据库中用户表来进行捆绑识别

二维代表实际参数extend表示需要调用的第三方文件类库,useragent是针对HTML5里识别APP的访问类型。

好吧,我们先从访问开始。

用户在进行HTML登陆的时候,当然也可以对接帐号密码登陆,因为我们都是通过$_SESSION来进行;

class LoginAPI{
function getlogin($user_agent,$store_id){
for ($i=0;$i<count($api);$i++){
if (strpos($user_agent,$api[$i][‘useragent’])){
$login = new $api[$i][‘extend’]();
$url = $login->getLoginApi($store_id);
header(“Location:”.$url);
exit();
}
}
die(“<h1>ERROR</h1>”);
}
}

我们在需要使用的地方,直接实例化LoginAPI,调用方法,附加用户的标识,交由脚本执行。

由于作者实际写的系统是针对HTML5为主,授权登陆我们都知道,需要跳转到支付宝、微信的开放平台的接口,执行实现回调URL;

$url = $login->getLoginApi($store_id);

我们来看看目录结果:

/loginapi.php //授权类

/api/alipay.php  //支付宝类,包括登陆、支付、模板消息

/api/weixin.php //微信类,包括登陆、支付、模板消息

上文的代码中我们没有看到任何实际性的requirce,因为作者使用的是自己写的框架,里面对常用的接口进行过requcie,虽然浪费资源,但能更快效率的进行实例化调用,而且现在大内存时候,也不用去考虑这一块;

 

好了,回正题,我们来看看调用的实际登陆

/***
* 支付获取请求的URL
* @return string
*/
function getLoginApi($store_id){
$url=’https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?’;
$url.=’app_id=’.$this->appid;
$url.=’&scope=auth_userinfo’;
$url.=’&redirect_uri=’.HTTP_SERVER.’api/alipay.php’;
$url.=’&state=’.$store_id;
return $url;
}

 

/***
* 微信获取登陆授权
* @param unknown $store_id
* @return string
*/
public function getLoginApi($store_id){
$url =’https://open.weixin.qq.com/connect/oauth2/authorize?’;
$url.=’appid=’.$this->appid;
$url.=’&redirect_uri=’.HTTP_SERVER.’api/weixin.php’;
$url.=’&response_type=code&scope=snsapi_userinfo’;
$url.=’&state=’.$store_id;
$url.=’#wechat_redirect’;
return $url;
}

这样一来,我们如果要添加京东授权登陆,添加对应的class添加对应的功能,然后统一回调写入数据库即可。

至于添加的时候,需要注册到全局的API里面,以方便在for()里实现调用

如此我们打开支付宝、微信,调用的都是同一个方法名,实现同样的效果,不再需要频繁的写switch(),if()来判断用户的登陆类型了。

 

下文作者将讲解模块化的支付、回调,代码前瞻:

return $this->pay_class[$this->login_type]->Pay($this->store_id,$this->order_id,$this->store_system,$title,$this->money,$this->customer,$this->return_url);

 

 

 

通过清心醉

开源一个微信公众号向关注用户下发消息的简单类库

$msg = new wxmsg();#实例化消息模板
$msg->setAccessToken($msg->getAccessToken()); #获取令牌并写入到类成员
$templatelist = $msg->getTemplateList();
if(count($templatelist)<=0){ #如果模板数量小于0,直接中止
return false;
}
for($i=0;$i<count($templatelist);$i++){
if($templatelist[$i][‘title’]==’订单支付成功’){ #如果消息模板中包含订单支付成功,下发通知信息
$openid=’ocbV9wGjFMbfGTUvh89Ro9J-ng7s’;
$productName=’测试的产品’;
$productDescription=’发送时间:’.date(‘Y-m-d H:i:s’);
$return_url = ‘http://www.qingxinzui.com/’;
$money = ‘123.45’;
$data = $msg->SendMsg($openid, $templatelist[$i][‘template_id’], $productName, $productDescription,$return_url,$money);
break;
}
}

 

然后是类的扩展::

<?php

/*******
*
* 本类库只提供小心模板下发,不进行模板配置
* 需要设置的模板库为:TM00015
*
* @author IPanYing
*
*/
class wxmsg{

private $appid;
private $appsecret;
private $access_token;

public function __construct(){
$this->appid = ”;
$this->appsecret = ”;
}

public function setAccessToken($access_token){
$this->access_token = $access_token;
}
public function getAccessToken(){
$url = “https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appid&secret=$this->appsecret”;
$AccessToken = $this->IPanYingGETCURL($url);
if (isset($AccessToken[‘access_token’]) && !empty($AccessToken[‘access_token’])){
return $AccessToken[‘access_token’];
} else {
return false;
}
}

public function getMsgModelName(){
$url = “https://api.weixin.qq.com/cgi-bin/template/get_industry?access_token=$this->access_token”;
return $this->IPanYingGETCURL($url);
}

public function getTemplateList(){
$url=”https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=$this->access_token”;
$list = $this->IPanYingGETCURL($url);
return $list[‘template_list’];
}

public function SendMsg($openid,$template_id,$producttext,$remarktext,$return_url,$money){
$return_url=’http://www.ipanying.com/’;
$data = array(
‘touser’=>”$openid”,
‘template_id’=>”$template_id”,
‘url’ =>”$return_url”,
‘topcolor’=>’#FF0000’,
‘data’=>array(
‘first’=>array(‘value’=>’尊敬的用户,你的支付订单信息如下:’,’color’=>’#173177′),
‘orderMoneySum’=>array(‘value’=>$money,’color’=>’#173177’),
‘orderProductName’=>array(‘value’=>$producttext,’color’=>’#173177’),
‘Remark’=>array(‘value’=>$remarktext,’color’=>’#173177’)
)
);
$url = “https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=$this->access_token”;
return $this->IPanYingPOSTCURL($url, $data);
}

private function IPanYingGETCURL($url){
$data = file_get_contents($url);
$data = (array)json_decode($data,true);
return $data;
}

private function IPanYingPOSTCURL($url, $data){
//$data = urldecode(json_encode($data));
$data = json_encode($data);
$post = array(
‘http’ =>array(
‘method’ => ‘POST’,
‘header’ => ‘Content-type: application/x-www-form-urlencoded’,
‘content’ => $data
)
);
$context = stream_context_create($post);
$data = file_get_contents($url, false, $context);
$data = (array)json_decode($data,true);
return $data;
}

}

?>

wxmsg-class

通过清心醉

开源一个高德地图地理位置获取API

<?php
/***
*
#–地图位置计算类库
$ipanying = new ipanying(); //实例化地图类库

#–构造商家数据坐标集
$data =array(
0 =>array(
‘mid’=>’111’,
‘lng’=>’111.111’,
‘lat’=>’22.22’
),
1 =>array(
‘mid’=>’112’,
‘lng’=>’112.112’,
‘lat’=>’23.23’
)
);

#–数据回调URL,把计算出的用户与商家的实际距离进行AJAX请求该URL
$return_url = ‘http://’.$_SERVER[‘HTTP_HOST’].’/ipanying.php’;
echo $ipanyingmap->getUserDir($data, $return_url, ‘color:red’);
*/
class ipanying{

/***
*
* @param unknown $ipanying #–商家地理位置二维数组
* @param unknown $return_url #–计算出的距离的数据AJAX请求URL
* @param unknown $style #–INPUT样式
* @param string $text #–显示的文字,比如没获取之前可以说获取位置,获取成功之后可以是更新位置等
* @param string $key #–KEY密钥
* @return string #–返回一个JS代码的页面字符串
* 注:在return接收页,lng,lat实际为用户的坐标数据,type=’dir’,
* 获取数据之后,销毁POST的lng,lat,type
*/
function getUserDir($ipanying,$return_url,$style,$text=’获取位置’,$key=’您的KEY值’){
$html='<script type=”text/javascript” src=”ipanying.js”></script>’;
$html.=”
<script type=’text/javascript’ src=’http://webapi.amap.com/maps?v=1.3&key=”.$key.”‘></script>
<script>
var usermap, geolocation;
var ipanyingmap_url='”.$return_url.”‘;
function getAddress(){
usermap = new AMap.Map(‘container-ipanying’, {
resizeEnable: true
});

usermap.plugin(‘AMap.Geolocation’, function() {
var geolocation = new AMap.Geolocation({
enableHighAccuracy: true,
timeout: 10000,
buttonOffset: new AMap.Pixel(10, 20),
zoomToAccuracy: true,
buttonPosition:’RB’
});
usermap.addControl(geolocation);
geolocation.getCurrentPosition();
AMap.event.addListener(geolocation, ‘complete’, onComplete);
});
}
//解析定位结果
function onComplete(data) {
var lng = data.position.getLng();
var lat = data.position.getLat();
if(lng==null || lng==undefined || lat==null || lat==undefined){
alert(‘用户坐标为空,无法计算’);
return false;
}
var ipanying = new Array();
“;

#—循环输出商家数据到JS
for($k=0;$k<count($ipanying);$k++){
$html.=”ipanying[$k]=new Array();
ipanying[$k][‘mid’]=”.$ipanying[$k][‘mid’].”;
ipanying[$k][‘dir’] = [“.$ipanying[$k][‘lng’].”,”.$ipanying[$k][‘lat’].”];”;
}

$html.=”
shangjiamaps(ipanying,lng,lat);
} //onComplete结束

function shangjiamaps(lnglats,xdir,ydir){ //位置计算方法
var str =’lng=’+xdir+’&lat=’+ydir;
for (var i = 0; i < lnglats.length; i++) {
var marker = new AMap.Marker({
position: lnglats[i],
//map: map
});
if(xdir == ” || xdir == undefined || xdir==null || ydir == ” || ydir == undefined || ydir==null){
var isadd =’nulls’;
} else {
var islnglat = new AMap.LngLat(xdir,ydir);
var cl = islnglat.distance(lnglats[i][‘dir’]);
var isadd = cl.toFixed(0);
}
str +=’&’+lnglats[i][‘mid’]+’=’+isadd;
//alert(‘距离商家ID’+lnglats[i][‘mid’]+’有’+isadd+’米’);
}
qingxinzui_alert(ipanyingmap_url,str,’dir’);
//alert(str);
}
</script>”;
$html.='<input type=”submit” onclick=”getAddress();” value=”‘.$text.'” style=”‘.$style.'” />’;
return $html;
}
}

if(isset($_POST[‘type’]) && $_POST[‘type’]==’dir’){
//处理回调
unset($_POST[‘type’]; //销毁类型参数

$userlng=$_POST[‘lng’]; //提取用户经度
$userlat=$_POST[‘lat’]; //提取用户纬度
//在这里获取的用户经纬度信息自行保留至SESSION或者COOKIE或者SQL

unset($_POST[‘lng’]); //销毁POST经度
unset($_POST[‘lat’]); //销毁POST纬度
$ipanying = $_POST; //数据给予数组
$text = ”;
foreach($ipanying as $key => $value){
$text.=’用户距离商家ID’.$key.’的直线距离=’.$value.’米 <br \>’;
}
}

 

扩展类库下载:高德地图距离计算类库PHP版

请尊重开源,转发请注明出处!

通过清心醉

php进行POST请求INPUT过多导致被截取的解决方法

今天修改微影院的开发,其中涉及座位最为麻烦,布局规划还需要有一个走道,如此一来,数据量是相当的庞大。

比如说,有20排,每排50个座位,那么就会出现1000个INPUT,而且还要有ID进行座位的详细捆绑

这么一来,就会有多个INPUT的数组。

一开始以为是请求的数据过大,修改了post_max_size = 32M,可是请求数据的时候,一样被截取。

作者请求的数组有3个,每个数组内有1000个数值,总累计INPUT的数量超过了3000个

GOOGLE搜索了一下,发现PHP5.3开始有个新的控制方法:max_input_vars

没错了,max_input_vars默认控制的数值是在1000内,如果超过的1000个就会被截取。

所以,修改max_input_vars就可以满足POST的数据请求!

通过清心醉

php-mysql主从表关联查询获取数据重复的解决方法

首先我们这有两张表,一个主表,一个从表

主表:TheFilm_Name包含以下关键字段

id =>int(11)唯一自增加;

name => varchar(32)节目名称;

access_token => varchar(32)多个管理员的唯一内部令牌

从表:TheFilm_Data包含以下关键字段

id=>int(11) 唯一自增ID,主要用于记录行数和做主键;

status=>int(4) 节目状态,0=未启用,1=启用中,2=播放完毕

access_token => varchar(32)多个管理员的唯一内部令牌

name_id => int(11) 对应的节目名称ID;

好了言归正传,如果我们要提取TheFilm_Name对应的节目详细数据status=1的,那么我们可以执行语句:

SELECT * FROM `TheFilm_Name` t1 LEFT JOIN `TheFilm_Data` t2
ON(t1.id=t2.name_id AND t1.access_token=t2.access_token) WHERE t2.status=’1′ AND t2.access_token=’admin_token’;

如此一执行,就会把TheFilm_Data内的所有status=1并且对应access_token的数据提取出来了;

但又有那么一个问题:

因为节目就那么几个,详细的可能涉及多个,比如一个节目(西游记),可能有多个数据(比如根据不同的时候写入到了TheFilm_Data),那么就会出现重复的数据;

一个简单的关联查询解决重复的问题:在于一句:GROUP BY t1.id;

SELECT t1.* FROM `TheFilm_Name` t1 LEFT JOIN `TheFilm_Data` t2
ON(t1.id=t2.name_id AND t1.access_token=t2.access_token) WHERE t2.status=’1′ AND t1.access_token=’admin_token’ GROUP BY t1.id; ORDER BY t1.id DESC;

在这特别注意,因为是关联查询,而且两个表内都有ID值,所以加上t1.*表示提取TheFilm_Name的全部

通过清心醉

PHP-MYSQL什么情况下应该用INT?

当然,该说明不只是针对PHP,NET和JSP如果对MYSQL进行操作一样也是可以的,而且对于ACCESS等其他数据库原理相同。(也就是说,只要你懂任意一门程序开发语言+数据库语言,都是可以在最短的时间内进行其他语言+数据库的学习的,别不自信,作者自学C++基础一个月不足,就拿下了PHP面向对象的精通,学不好的人,只能怪程序不是你的爱好,放弃吧!)

数据库中,我们常使用到INT,VARCHAR

其中INT基本都主要用于主键、KEY、自增ID记录行等,当然,VARCHAR就是对字符的了。

直接给段代码吧,看不懂的好好学学你的MYSQL功底!

SELECT * FROM `ipanying_cn_user` WHERE `user_id` = '19185' AND `status` = '1' AND `re_time`+`lg_time` >'1462969356';
字段对应值为:
user_id=>int(11);
re_time=>int(11);
lg_time=>int(11);
简单来说,就是表内对应用户并且状态=1并且注册时间+现在时间>指定日期。作者是用来进行升级用户等级!
附提供出来!
通过清心醉

php获取不同时间段的数据集

最近在做微影院的PHP开发,影院嘛,自然一个节目要在多个时间周期内使用。

假设有一部电影,安排的播放时间为:

2016-05-08 10:00:00 – 2016-05-08 11:45:00

2016-05-09 10:00:00 – 2016-05-09 11:45:00

2016-05-10 10:00:00 – 2016-05-10 11:45:00

2016-05-11 10:00:00 – 2016-05-11 11:45:00

2016-05-12 10:00:00 – 2016-05-12 11:45:00

然后我要显示3个大项目,一个为今天,二为明天,三为之后

如果今天/明天不存在,直接显示之后的全部

附带上个方法:

/**
* 根据节目信息进行时间序列化整理
* @param unknown $changci
* @return string|Ambigous <multitype:, multitype:unknown , multitype:unknown number >
*/
private function ChangCiData($changci){
if (empty($changci)){
return false;
}
$data=array(); #-对时间进行一个关联
date_default_timezone_set(‘Asia/Shanghai’); #-定义时区
for($i=0;$i<3;$i++){
$t = $i+1; #-日期默认+1
$time = mktime(0,0,0,date(“m”),date(“d”)+$t,date(“Y”)); #-获取时间,默认=第二天
for($o=0;$o<count($changci);$o++){ #-循环节目信息
if($i==2){ #-如果为第三次的关联
if($changci[$o][‘kaishi_time’]>($time-86000)){
#-开始时间全部就要求大于当前的
#-不过还有可能是有些小于第三天但又大于第二天的 所以条件修改为>第三天的时间-86000即大于2天后的
$data[$i][]=array(
‘time’ => $time, #-获取时间显示
‘yingpian’ => $changci[$o] #-获取详细信息
);
echo date(“Y-m-d”,$changci[$o][‘kaishi_time’]).”=jiemuid=”.$changci[$o][‘id’].”<br>”;
}
} else if($i==1){
if($changci[$o][‘kaishi_time’]<$time && $changci[$o][‘kaishi_time’]>($time-86000)){
#-如果开场的时间小于第二天的0点又大于前一天的
$data[$i][]=array(
‘time’ => $time, #-获取时间显示
‘yingpian’ => $changci[$o] #-获取详细信息
);
echo date(“Y-m-d”,$changci[$o][‘kaishi_time’]).”=jiemuid=”.$changci[$o][‘id’].”<br>”;
}
} else {
if($changci[$o][‘kaishi_time’]<$time){
#-如果开场的时间小于第二天的0点
$data[$i][]=array(
‘time’ => $time, #-获取时间显示
‘yingpian’ => $changci[$o] #-获取详细信息
);
echo date(“Y-m-d”,$changci[$o][‘kaishi_time’]).”=jiemuid=”.$changci[$o][‘id’].”<br>”;
}
}
}
}
return $data;
}

通过清心醉

javascript-select调用onchange方法错误

在这特别说下,能不用框架就别用框架,否则出现的问题会让你头痛的要命

首先来个JS代码,通用吧,然后在来罗列多种onchange不执行的问题

<script>
function ipanying(){
alert(“清心醉,网站开发建设运维SEO专业全栈开发工程师;”);
}
</script>

/**********************************************/

场景一:

<form>
<select name=”ipanying” id=”ipanying” onchange=”ipanying();”>
<option value=”0″>显示</option>
<option value=”1″>继续显示</option>
</select>
</form>

最终结果:无法执行,因为name和onchange调用的方法重名

/**********************************************/

场景二:

<select name=”ipanying” id=”ipanying” onchange=”ipanying();”>
<option value=”0″>显示</option>
<option value=”1″>继续显示</option>
</select>
最终结果:因为去除了form标签,所以是可以正常的执行!

/**********************************************/

场景三:

<form>
<select name=”ipanying1″ id=”ipanying” onchange=”ipanying();”>
<option value=”0″>显示</option>
<option value=”1″>继续显示</option>
</select>
</form>

最终结果:因为NAME值和onchange值不同,所以可以执行

/**********************************************/

经过多次的测试,select在form里对name和onchange有很高的要求判断

如果不是form表单则无任何影响

 

 

通过清心醉

微擎分销规则

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

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

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’];
}

}

 

通过清心醉

微擎无法调用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’];
}
}
}
}
}

通过清心醉

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′);

通过清心醉

微擎多用户多公众号出现公众号重复时商品订单查看BUG

首先来看看w7提取的订单数据的SQL代码:

$total = pdo_fetchcolumn(‘SELECT COUNT(*) FROM ‘ . tablename(‘ewei_shop_order’) . ” o ” .
” left join ” . tablename(‘ewei_shop_order_refund’) . ” r on r.orderid=o.id” .
” left join ” . tablename(‘ewei_shop_member’) . ” m on m.openid=o.openid ” .
” left join ” . tablename(‘ewei_shop_member_address’) . ” a on o.addressid = a.id ” .
” WHERE {$condition}”, $paras);

然后再看看提取产品的$list

$sql = “select o.* , a.realname,a.mobile,a.province,a.city,a.area,a.address, d.dispatchname,r.status as refundstatus from ” . tablename(‘ewei_shop_order’) . ” o” . ” left join ” . tablename(‘ewei_shop_order_refund’) . ” r on r.orderid=o.id and ifnull(r.status,-1)<>-1″ . ” left join ” . tablename(‘ewei_shop_member’) . ” m on m.openid=o.openid” . ” left join ” . tablename(‘ewei_shop_member_address’) . ” a on o.addressid = a.id ” . ” left join ” . tablename(‘ewei_shop_dispatch’) . ” d on d.id = o.dispatchid ” . ” where {$condition} ORDER BY o.createtime DESC,o.status DESC  “;
if (empty($_GPC[‘export’])) {
$sql .= “LIMIT ” . ($pindex – 1) * $psize . ‘,’ . $psize;
}

$list = pdo_fetchall($sql, $paras);

好吧有点跑题,

SQL语句中有两个变量,他们的原型是:

$condition = ” o.uniacid = :uniacid and o.deleted=0″;
$paras = array(‘:uniacid’ => $_W[‘uniacid’]);

很明显的对象o为ewei_shop_order,$condition变量里进行SQL组和

而$paras = array(‘:uniacid’ => $_W[‘uniacid’]);是用来区分公众号的,在SQL执行时起到筛选的作用

在这要特别注意,关联的表内有一个表’ewei_shop_member’。

这就是出现BUG的详细地方了

W7的原始思路就是有错误的.

ewei_shop_member表内

uniacid = > 公众号唯一ID

openid = > 用户在公众号内的唯一ID

W7在ewei_shop_order订单表内有根据uniacid来划分不同的公众号的订单,可是在表内关联了对应的用户ID

在逻辑上上来,openid = XXXX可以在任意uniacid(区分公众号的唯一ID值 )内下单 ,那么表关联查询是完全没问题的

先说问题吧:
每个用户在不同的公众号内,唯一的OPENID是不同的;
如果一个商户开了两个小站,分别为A(uniacid = 1)和B (uniacid = 2)
用户在A里访问下单了,那么ewei_shop_member表内就会有这么一行数据
uniacid => 1
openid => thisisuseropenid用户在当前公众号的唯一ID

可是如果用户突然把A的公众号放到B
那么就会出现
uniacid =>1
openid => thisisuseropenid
uniacid =>2
openid => thisisuseropenid
问题出来了,openid相同了,所以我们需要对ewei_shop_member的语句进行多一重uniacid的判断(因为W7在这里是没有做这个判断的,他没有考虑这个BUG的出现可能性)

//$condition = ” o.uniacid = :uniacid and o.deleted=0″;

$condition = ” o.uniacid = :uniacid and o.deleted=0 and m.uniacid = :uniacid”;

$paras = array(‘:uniacid’ => $_W[‘uniacid’]);

 

 

通过清心醉

php7添加memcached扩展

即使网站的访问量不大,memcached也能就SESSION的存储问题上做很好的处理

因为SESSION是以文件的方式存储在服务器上的,这样一样磁盘I/O负荷就是个很大的问题,哪怕文件在小,数量多了就麻烦

本文先不说SESSION的配置环境,只先说PHP7整合memcached的方法

memcached-1.4.25.tar

pecl-memcache-php7.tar

首先把pecl-memcache-php7.tar.gz和 memcached-1.4.25.tar.gz文件上传到自定义的目录内
然后解压

进入目录

[root@IPanYing home]# cd pecl-memcache-php7

执行下phpize,如果无法执行请执行完整的PHP目录,因为你的PHP没有添加到环境目录
如: /usr/local/php7/bin/phpize

[root@IPanYing pecl-memcache-php7]# phpize
Configuring for:
PHP Api Version:         20151012
Zend Module Api No:      20151012
Zend Extension Api No:   320151012

[root@IPanYing pecl-memcache-php7]# ./configure –with-php-config=/usr/local/php7/bin/php-config

[root@IPanYing pecl-memcache-php7]# make && make install

如果安装顺利会提示:
Installing shared extensions:     /usr/local/php/lib/php7/extensions/no-debug-non-zts-20151012/

修改php.ini,让PHP添加memcache扩展
[root@IPanYing pecl-memcache-php7]# echo “[memcache]” >> /etc/php.ini
[root@IPanYing pecl-memcache-php7]# echo “extension=/usr/local/php7/lib/php/extensions/no-debug-non-zts-20151012/memcache.so” >> /etc/php.ini

接下来安装个事件触发管理:
[root@IPanYing pecl-memcache-php7]# yum install -y libevent-devel

然后重启httpd和nginx

接下来安装memcached
cd memcached-1.4.25

[root@IPanYing memcached-1.4.25]# ./configure

[root@IPanYing memcached-1.4.25]# make && make install

启用memcached
[root@IPanYing memcached-1.4.25]# /usr/local/bin/memcached -d -m 256 -l 127.0.0.1 -p 7788 -u root
#256为memcached占用的内存大小,127.0.0.1为服务器的地址 7788为启用的端口,root为用户组,当然这可以使用其他的主机,负载均衡的时候再讲解

查看下是否生效:
[root@IPanYing memcached-1.4.25]# ps aux|grep memcached
root      7654  0.0  0.0 331112  1032 ?        Ssl  14:32   0:00 /usr/local/bin/memcached -d -m 256 -l 127.0.0.1 -p 7788 -u root
root      7671  0.0  0.0 103260   852 pts/0    S+   14:34   0:00 grep memcached

然后站点根目录打印phpinfo()看看

memcache

memcache support enabled
Active persistent connections 0
Version 2.2.7
Revision $Revision$

如果显示以上信息表示PHP7已经完整支持memcache了哦!
到此完成php7+memcached

 

 

通过清心醉

php7.0.1-magento出现500错误

最近测试PHP7对magento的性能影响,结果出现500错误。一开始以为是伪静态出错搞的鬼,后来安装了个wordpress重写伪静态发现又没问题,后来GOOGLE了一翻:

在app/code/core/Mage/Core/Model/Layout.php文件里第555行:

$out .= $this->getBlock($callback[0])->$callback[1]();

修改为:$out .= $this->getBlock($callback[0])->{$callback[1]}();

就可以解决问题了。

通过清心醉

php添加pdo_mysql扩展

由于作者是完全编译安装的,所以需要进入编译的源文件里:

cd /temp/php-5.6.17/ext/pdo_mysql;

执行下:

/usr/local/php-5.6/bin/phpize

再预编译:

./configure –with-php-config=/usr/local/php-5.6/bin/php-config –with-pdo-mysql=/uar/local/mysql-5.6.24/

再编译安装:

make && make install

接着写入php.ini

echo “extension=/usr/local/php-5.6/lib/php/extensions/no-debug-non-zts-20121212/pdo_mysql.so” >> /mydata/php.ini

通过清心醉

PHP开启INTL扩展之WINDOWS版

为了测试新的magento开源系统,所以在当前的WIN系统内安装了个WAMP快速部署环境.
安装完成之后,发现新的magento电子商城程序需要INTI的扩展支持
好吧,WINDOWS下的扩展开启比较简单,果断php.ini里打开extension=php_intl.dll
重启APACHE,发现还是存在对应的问题,提示扩展未开启
经过GOOGLE一翻,发现问题不在该扩展上,而是扩展以来的其他扩展文件的关系.
PHP的根目录有很多icu***50.dll文件 (50表示的是当前的PHP的版本,**为所有的文件名)
把文件复制到apache/bin/目录内,重启搞定!

更多直接打印phpinfo查看!

注: 新版MAGENTO为MAGNETO VER 2.0,如果需要进行二次开发建议使用UNIX,否则几万个文件,你的ZEND刷新项目就卡你一个多小时!

通过清心醉

PHP多参数多表查询实例

虽然前段时间作者写了多表查询,但作者自己也老是忘记,昨晚就为这个多表查询搞得头晕晕的。而且如果针对SQL有多个WHERE条件的话,就需要不同的语句:

以下是作者写的针对省市地区进行的AJAX进行请求地区筛选的模型:

public function getSettdataStoredata($data){
#– 这里$data为AJAX请求的GET数组
$sql=”SELECT * FROM “.PREFIX.”storedata s1 LEFT JOIN “.PREFIX.”settdata s2
ON(s1.store_id = s2.store_id) WHERE s2.key=’zone_id’ AND s2.value='”.$data[‘zone_id’].”‘”;

#– 因为请求中必须会包含zone,也就是最少会有个省份的筛选,生成初始SQL语句关联storedata和settdata两个表
if (isset($data[‘city_id’]) && !empty($data[‘city_id’])){
$sql .=” AND s1.city_id= ‘”.(int)$data[‘city_id’].”‘”;
}

#– 如果AJAX请求中包含有城市参数,SQL语句进行组合
if(isset($data[‘diqu_id’]) && !empty($data[‘adder_id’])){
$sql .=” AND s1.adder_id = ‘”.(int)$data[‘adder_id’].”‘”;
}

#- 如果AJAX请求中包含有城市的详细地区筛选,SQL再次进行组合
$query=$pdo->query($sql);
return $query->fetchAll();
}