微擎 生成二维码&下载二维码

新建一个类文件code.php

load()->library('qrcode');
class code{
    //生成二维码
    //参数: $content:二维码的内容 string
    //      $size:二维码的尺寸  string
    public function createCode($content,$size){        
            $errorCorrectionLevel = "L";//错误校正级别        
            $code = QRcode::png($content, false, $errorCorrectionLevel,$size);
            return $code;
    }
    //下载二维码
    //参数:二维码的内容数据content 大小size 
    public function downloadCode($content,$size){
        $code = $this->createCode($content,$size);
        $name = random(8);
        header('cache-control:private');
        header('content-type:image/jpeg');
        header('content-disposition: attachment;filename="'.$name.'.jpg"');
        readfile($code);
    }
}

在需要用到此方法的地方实例化。(注意文件的路径问题,避免实例化出错)

$code = new code();
$res_code = $code ->createCode("这里放的是二维码的内容","5");//生成二维码
$download_code = $code ->downloadCode("这里是二维码的内容","5");//下载二维码

配置码云git自动更新的webhook

配置项目提交到git的时候自动同步服务器代码

一、在服务器项目跟目录新建文件hook.php 代码如下:

<?php
$json = file_get_contents("php://input");
$data = json_decode($json,true);
if (isset($data['ref']) && $data['total_commits_count']>0) {
    $res = PHP_EOL."pull start ——————————————————————".PHP_EOL;
    $res .= shell_exec("cd /home/www/leokim && git pull https://xxxxxx.com:passwod@gitee.com/xxxx/xxxx.git 2<&1 ");
    $res_log = '——————————————————————————————'.PHP_EOL;
    $res_log .= $data['user_name'] . ' 在' . date('Y-m-d H:i:s') . '向' . $data['repository']['name'] . '项目的' . $data['ref'] . '分支push了' . $data['total_commits_count'] . '个commit:'.$data['commits']['message'];
    $res_log .= $res.PHP_EOL;
    $res_log .= "pull end ——————————————————————————".PHP_EOL;
    file_put_contents("/home/wwwlogs/webhook/".date('Y-m-d',time()).".txt", $res_log, FILE_APPEND);//写入日志到log文件中
}
?>

二、配置码云webhook:

545324-20180927103508565-515404566.png

三、确认服务器安装了git,在web目录下clone 项目:git clone https://gitee.com/xxxx/xxxx.git;

四、把git的目录权限改为web用户权限: chown -r www:www

五、手动更新代码:cd /home/www/leokim && git pull;

六、git pull 冲突或错误时,用命令git stash && git pull解决冲突或错误

Laravel 中大型项目构架

初学者学习Laravel时分两种,一种是乖乖的将程序填入MVC构架内,导致controller与model异常的肥大,日后一样很难维护;一种是常常不知道程序该写在哪一个class内而犹豫不决,毕竟传统PHP都是一个页面一个档案。本文整理出最适合Laravel的中大型项目构架,兼具容易维护、容易扩充与容易重复使用的特点,并且容易测试。

Controller过于肥大

受RoR的影响,初学者常认为MVC构架就是model,view,controller:

Model就是数据库。

Controller负责与HTTP沟通,调用model与view。

View就是HTML。

假如依照这个定义,以下这些需求该写在哪里呢?

发送Email,使用外部API。

使用PHP写的逻辑。

依需求将显示格式作转换。

依需求是否显示某些数据。

依需求显示不同数据。

其中1,2属于商业逻辑,而3,4,5属于显示逻辑,若依照一般人对MVC的定义,model是数据库,而view又是HTML,以上这些需求都不能写在model与view,只能勉强写在controller。

因此初学者开始将大量程序写在controller,造成controller的肥大难以维护。

Model过于肥大

既然逻辑写在controller不方便维护,那我将逻辑都写在model就好了?

当你将逻辑从controller搬到model后,虽然controller变瘦了,但却肥了model,model从原本代表数据库,现在变成还要负担商业逻辑与显示逻辑,结果更惨。

Model代表数据库吗?把它想成是Eloquent class就好,数据库逻辑应该写在repository里,这也是为什么Laravel 5已经没有models目录,Eloquent class仅仅是放在app根目录下而已。

中大型项目构架

那我们该怎么写呢?别将我们的思维局限在MVC内:

Model:仅当成Eloquent class。

Repository:辅助model,处理数据库逻辑,然后注入到service。

Service:辅助controller,处理商业逻辑,然后注入到controller。

Controller:接收HTTP request,调用其他service。

Presenter:处理显示逻辑,然后注入到view。

View:使用blade将数据binding到HTML。

5a426dd9e6cc9.png

其中蓝色为原本的MVC,而紫色为本文要介绍的的重点:Repository模式,Service模式与Presenter模式。

箭头表示物件依赖注入的方向。

我们可以发现MVC构架还在,由于SOLID的单一职责原则与依赖反转原则:

我们将数据库逻辑从model分离出来,由repository辅助model,将model依赖注入进repository。

我们将商业逻辑从controller分离出来,由service辅助controller,将service依赖注入进controller。

我们将显示逻辑从view分离出来,由presenter辅助view,将presenter依赖注入进view。

建立目录

在 app 目录建立 Repositories,Services 与 Presenters 目录。

image.png

别害怕在Laravel预设目录以外建立的其他目录,根据SOLID的单一职责原则,class功能越多,责任也越多,因此越违反单一职责原则,所以你应该将你的程序分割成更小的部分,每个部分都有它专属的功能,而不是一个class功能包山包海,也就是所谓的万能类别,所以整个项目不应该只有MVC三个部分,放手根据你的需求建立适当的目录,并将适当的class放到该目录下,只要我们的class有namespace帮我们分类即可。

Repository

由于篇幅的关系,将repository独立成专文讨论,请参考如何使用Repository模式?、

由于篇幅的关系,将service独立成专文讨论,请参考如何使用Service模式?

由于篇幅的关系,将presenter独立成专文讨论,请参考如何使用Presenter模式?

由于现在model、view、controller的相依物件都已经拆开,也都使用依赖注入,因此每个部分都可以单独的做单元测试,如要测试service,就将repository加以mock,也可以将其他service加以mock。

Presenter也可以单独跑单元测试,将其他service加以mock,不一定要跑验收测试才能测显示逻辑。

Conclusion

本文谈到的构架只是开始,你可以依照实际需求增加更多的目录与class,当你发现你的MVC违反SOLID原则时,就大胆的将class从MVC拆开重构,然后依照以下手法:

建立新的class或interface。

将相依物件依赖注入到class。

在class内处理他的职责。

将class或interface注入到controller或view。

最后搭配单元测试,测试重构后的构架是否与原来的需求结果相同。

如何使用mamp的php版本作为控制台的php版本

把mac上的默认php修改为MAMP等扩展环境中的php 版本,也就是不使用 mac 自带的。步骤如下:

打开terminal。输入locate .bash_profile, 找到我们需要编辑的文件的路径。

cd 到该目录下执行sudo vim .bash_profile,这个文件也有可能没有,如果没有就新建一个。

在vim中打开或新建好该文件后在文件末尾添加

export PATH="/Applications/MAMP/bin/php/php5.6.10/bin:$PATH"

注:“=”号之后,“:”号之前的路径就是你要修改成的php的路径,我这里选取的是MAMP中自带的5.6版本。

保存后运行: source .bash_profile,可能会报错,不用管。

就大功告成了,接着我们验证一下,另开terminal,输入which PHP,有没有发现默认php的路径已经修改好了呢。接下来就可以正常使用了,如果还不行,重启电脑就可以了。

坑:在 /etc/profiles 中设置了环境变量后, 还是不能在 zsh 中使用. 是因为没有在 .zshrc 中配置.

在终端中输入: cat ~/.zshrc 以此来查看 .zshrc 文件, 找到里面的 # User configuration 部分. 可以看到当前 zsh 支持的所有本地已配置环境变量.

在 export PATH=”XXXX” 里面追加一条想要配置的环境变量路径.

laravel 递归循环子类

public function get_children_cate($parent_id){
        $childrens_arr = array();

        //check have children
        $children_cnt = DB::table('pms_product_category')->where('parentId', $parent_id)->count();
        if($children_cnt > 0){
            //get children by parent ids
            $childrens = DB::table('pms_product_category')->where('parentId', $parent_id)->get()->toArray();
            foreach($childrens as $row){
                $children = $this->get_children_cate($row->id);
                if(!empty($
                    $row->children = $children;
                }

                $childrens_arr[] = $row;
            }
        }

        return json_decode(json_encode($childrens_arr), true);
    }

小程序微信支付

wx.requestPayment(
{
'timeStamp': e.data.timeStamp.toString(),
'nonceStr': e.data.nonceStr.toString(),
'package': e.data.package,
'signType': e.data.signType,
'paySign': e.data.sign,
'success': function (res) {

//create order
wx.request({
url: o.d.ceshiUrl + "/leokim/create_order",
method: "post",
data: {
openid: openid,
id: goods_info.goods_id,
type: goods_info.type,
code: goods_info.code
},
header: {
"Content-Type": "application/x-www-form-urlencoded"
},
'success': function (e) {
var pages = getCurrentPages();
var currPage = pages[1];

currPage.setData({
is_buy: 1
});
},
'fail': function (res) { }
})

wx.showToast({
image: '/images/success.png',
title: "购买成功.",
duration: 2e3
});

},
'fail': function (res) {
var msg = '购买失败';
if (res.errMsg == 'requestPayment:fail cancel'){
msg = '取消支付';
};

wx.showToast({
image: '/images/failed.png',
title: msg,
});
},
'complete': function (res) {
console.log('支付完成');
}
})

后端:

function wechat_pay()
    {
        $openid = 'ocLsr5OXtYZZe6dUrMLJxsm0CTEk';
        $key = 'a81bfe3a84df3ceb5cc54bd3e1605ba2';

        $post = $this->input->post();
        $goods_name = $post['goods_name'];

        //get prepay_id
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $data = array();
        $data['appid'] = $this->appid;
        $data['mch_id'] = $this->mch_id;
        $data['nonce_str'] = mt_rand(10000000,99999999);
        $data['body'] = $goods_name;
        $data['out_trade_no'] = 'wkt' . time(). mt_rand(10000000,99999999);
//        $data['total_fee'] = $price * 100;
        $data['total_fee'] = 1;
        $data['spbill_create_ip'] = '114.96.242.184';
        $data['notify_url'] = 'http://www.weixin.qq.com/wxpay/pay.php';
        $data['trade_type'] = 'JSAPI';
        $data['openid'] = $openid;
        $data['sign'] = $this->createSign($data,$key);
        $data = $this->array_to_xml($data);
        $result = $this->curlPost($url, $data);
        $result = $this->xml_to_array($result);
        $prepay_id = $result['prepay_id'];


        $return_data = array(
            'appId' => $this->appid,
            'timeStamp'=>time(),
            'nonceStr'=>mt_rand(10000000,99999999),
            'package'=>"prepay_id=$prepay_id",
            'signType'=>'MD5'
        );
        $return_data['sign'] = $this->createSign($return_data,$key);

        echo json_encode($return_data);
    }

    public function create_order(){
        $result = array('flag'=>'N');
        $post = $this->input->post();
        $type = $post['type'];
        $id = $post['id'];
        $openid = $post['openid'];
        $code = $post['code'];
        $user_id = $this->get_user_id_by_open_id($openid);
        $goods_table_info = $this->get_table_info_by_type($type);
        $table = $goods_table_info['table'];
        $key = $goods_table_info['key'];

        $sql = "INSERT INTO `t_aci_bought` (`bought_id`, `type`, `related_id`, `price`, `status`, `user_id`, `add_time`)
                SELECT NULL, '$type', $id, price, 0, $user_id, NOW() FROM `$table` WHERE `$key`= $id";
        $this->db->query($sql);

        $insert_id = $this->db->insert_id();
        if($insert_id > 0){
            $result['flag'] = 'Y';

            //TODO 三级分销
        }

        echo json_encode($result);
    }

微信发送红包

//发送红包start
$url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack';

//获取openID
$uid = $list['uid'];
$result  = pdo_fetch("SELECT openid FROM ims_meepo_online_user WHERE id=:id",array(':id'=>$uid));
$open_id = $result['openid'];
$money   = (int)$list['money'];

$package = array();
$package['nonce_str'] = random(8);
$package['mch_billno'] = 'ydl'.rand(10000000000000,99999999999999);
$package['mch_id'] = '1515256111';
$package['wxappid'] = 'wx57a837f1e72026c3';
$package['send_name'] = 'xxxx';
$package['re_openid'] = $open_id;
$package['total_amount'] = $money*100;
$package['total_num'] = 1;
$package['wishing'] = 'xxxxxx'.date('Y-m-d');
$package['client_ip'] = CLIENT_IP;
$package['act_name'] = 'xxxxx';
$package['remark'] = 'xxxxxxxxxxxx.';

ksort($package, SORT_STRING);
$string1 = '';
foreach($package as $key => $v) {
if (empty($v)) {
continue;
}
$string1 .= "{$key}={$v}&";
}
$string1 .= "key=2nHuHsDijB4Ye7mNN22QxFAP3AW6l3hT";

$package['sign'] = strtoupper(md5($string1));
$dat = array2xml($package);

load()->func('communication');

$certPath = 'xxxxxx/cert/apiclient_cert.pem';
$keyPath = 'xxxxxx/cert/apiclient_key.pem';

$extra = array(
CURLOPT_SSL_VERIFYPEER=>false,
CURLOPT_SSL_VERIFYHOST=>false,
CURLOPT_SSLCERTTYPE=>'PEM',
CURLOPT_SSLKEYTYPE=>'PEM',
CURLOPT_SSLCERT=>$certPath,
CURLOPT_SSLKEY=>$keyPath,
CURLOPT_POST=>1
);
$response = ihttp_request($url, $dat, $extra);

// print_r($response);
// exit;

// echo $response;

获取小程序二维码

function getCode(){
    $post = $this->input->post();
    $openid = $post['openid'];
    $token = json_decode($this->get_token('wx725d23dc9ddc4223','8d5971b6282b271b23474849cb3ea562','client_credential'),true);
    $token_str = $token['access_token'];

    $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=$token_str";
    $data = array("scene"=>"1001");
    $file_code = $this->https_request($url, json_encode($data));

    $filename = 'uploadfile/qrcode/'.$openid.'.png';
    file_put_contents($filename,$file_code);

    echo 'https://yj.chuanyinhulian.com/'.$filename;
}

function get_token($appid, $secret, $grant_type){
    $url = "https://api.weixin.qq.com/cgi-bin/token?appid=$appid&secret=$secret&grant_type=$grant_type";
    return $this->https_request($url);
}

function https_request($url, $data = null)
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    if (!empty($data)){
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    $output = curl_exec($curl);
    curl_close($curl);
    return $output;
}