Ubuntu 14.04 svn服务端配置

工作环境:

Server端:系统 Ubuntu 14.04 64bit

Client端:系统Windows 10 64bit,Tortoise 1.9.3.27038

服务器端安装流程:
安装svn:sudo apt-get install subversion
创建svn仓库: mkdir /home/.svn(使用隐藏目录)

cd /home/.svn
mkdir repos1
sudo svnadmin create /home/.svn/repos1(创建仓库repos1,执行成功后repos1目录下有svnadmin创建的目录和文件)
mkdir repos2
sudo svnadmin create /home/.svn/repos2(创建仓库repos2,执行成功后repos2目录下有svnadmin创建的目录和文件)
配置和管理svn(repos1和repos2是两个独立的仓库,配置过程相似,我们以repos1进行说明) 配置/home/.svn/repos1/conf/svnserve.conf 文件,vim svnserve.conf,配置[general]下的参数 掉以下几行的“#”,并根据需要进行权限设置

anon-access:匿名用户的权限,可以为read,write和none,默认值read。不允许匿名用户访问:anon-access = none
auth-access:认证用户的权限,可以为read,write和none,默认值write
password-db:密码数据库的路径,去掉前边的#
authz-db:认证规则库的路径,去掉前边的#。
注意:
这些配置项的行都要顶格,否则会报错。修改配置后需要重启svn才能生效。

启动SVN服务:sudo svnserve -d -r /home/.svn

查看是否运行:sudo netstat -antp |grep svnserve

如果想关闭服务,可使用pkill svnserve

之前犯了一个错误,误将groups-db = groups(设置权限的文件),但是conf路径下没有响应文件,一直报错,连不上svn
realm = repos,realm作用是定义登陆授权文件路径,单个repository尽量不要使用,容易跟authz中的路径产生歧义。
配置/home/.svn/repos1/conf/passwd 文件,vim passwd,根据配置文件提示,添加用户名及密码 格式:用户名 = 密码(明码)

举例:test = 123456
配置/home/.svn/repos1/conf/authz文件,vim authz [groups]:用户群组管理,可根据用户权限大小,设置不同的群组, 格式:群组名 = 用户名1,用户名2,用户名3,…

如manger = zhangsan,lisi
如coder = linuxmi,linuxidc
[groups]权限设置:
groups下面的sections表示对一个目录的认证规则,根目录认证规则为[/]. 单个用户分别进行认证设定        [/]zhangsan = rw  #zhangsan对根目录的权限为rwlisi = r #lisi对根目录的权限为r

如果用户角度较多,可以对群组直接进行配置,群组名前加“@”[/]@manager = rw #等价于上面两行的设定效果
如果启动时从/home/.svn/repos1启动, /就是repos1的目录
如果从/home/.svn/启动,每个仓库的根目录是自己文件路径下的起始目录,其权限设置如下:          [repos1:/]@manager =  rw@coder = r
[repos2:/]

@manager =  rw

@coder = r
注意:不能跨越仓库设置权限;
问题:初次配置时,会遇到认证失败或无效的问题,原因有二: svnserve.conf中,每行可能存在空格,去掉空格即可

authz文件中,配置使用repos1根目录启动,但是却采用svn://192.168.1.123/repos1进行访问
建议:authz文件中尽量采用一种权限设置模式,切勿多种权限设置。
总结:每个仓库的根目录/就是该仓库的起始目录;[repos1:/]适用于多仓库;[/]适用于但仓库和多仓库;
启动和停止svn 启动 从repos1目录启动 sudo svnserve -d -r /home/.svn/repos1

根目录/是repos1,authz中的规则配置使用session[/]
访问方式:svn://192.168.1.123/
从.svn目录启动 sudo svnserve -d -r /home/.svn

根目录/是.svn,authz对repos1的配置使用session[repos1:/],对repos2的配置使用session[repos2:/]
访问方式:svn://192.168.1.123/
检测svn服务器是否已经启动 方式一:ps axu | grep svnserve

方式二:netstat -an | grep 3690(svn默认端口3690)
停止svn服务器 方式一: ps aux | grep svnserve,获取其pid

sudo kill -9 pid
方式二: sudo killall svnserve

svn服务开机自启动 cd /etc/init.d(Ubuntu自启动脚本位置)

vim startsvn.sh
添加以下两行代码        #! /bin/bashsvnserve -d -r /home/.svn(多仓库启动模式)
使配置生效 update-rc.d startsvn.sh defaults 这个命令等效于update-rc.d startsvn.sh start 20 2 3 4 5 . stop 20 0 1 6

20是默认的启动顺序号,可以手动修改,当然也可以在defaults后面加一个启动顺序号。0\1\2\3\4\5\6是ubuntu的运行级别。
update-rc.d 可以生成或者移除System-V启动模式下的初始化脚本的链接,System-V是Ubuntu采用的一种启动方式(好像记得更先进的启动方式是System-d),update-rc.d会在/etc/rcrunlevel

.d/目录下生成/etc/init.d/目录下的启动脚本的链接。

Ubuntu 14.04 下搭建SVN服务器 SVN://  http://www.linuxidc.com/Linux/2015-01/111956.htm

CentOS 6.2 SVN搭建 (YUM安装) http://www.linuxidc.com/Linux/2013-10/91903.htm

CentOS 6.5部署Apache+SVN  http://www.linuxidc.com/Linux/2013-12/94315.htm

Apache+SVN搭建SVN服务器 http://www.linuxidc.com/Linux/2013-03/81379.htm

Windows下SVN服务器搭建和使用 + 客户端重新设置密码 http://www.linuxidc.com/Linux/2013-05/85189p5.htm

Ubuntu Server 12.04 安装 SVN 并迁移 Virtual SVN数据 http://www.linuxidc.com/Linux/2013-05/84695.htm

Ubuntu Server搭建SVN服务以及迁移方法 http://www.linuxidc.com/Linux/2013-05/84693.htm

Subversion (SVN) 的详细介绍请点这里
Subversion (SVN) 的下载地址请点这里

更多Ubuntu相关信息见Ubuntu 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=2

本文永久更新链接地址http://www.linuxidc.com/Linux/2016-07/133249.htm

微信小程序中实现微信支付

微信小程序中实现微信支付

原创 2017年06月24日 17:21:07
最近做小程序,涉及到微信支付,看了看微信小程序开发文档,尽管之前做过微信支付,还是有点懵逼,不过好在之前研究过,不然真的是无从下手。对比了一下发现,其实小程序中做支付比公众号支付要省事很多,因为不需要支付授权目录,也不需要授权域名,但是支付流程却比公众号多了一步,就是统一下单是预支付,然后需要对预支付的结果再次签名之后,才调起支付。

前期准备:
1.开通了微信支付,并且小程序绑定了微信支付;
2.准备好小程序的appid,微信支付的商户号,支付秘钥。

商户系统和微信支付系统主要交互:
1、小程序内调用登录接口,获取到用户的openid
此步骤在小程序内完成,也很简单,方法见:【小程序登录API
2、调用商户服务器支付统一下单接口,进行预支付

[php] view plain copy

  1. /**
  2.  * 预支付请求接口(POST)
  3.  * @param string $openid    openid
  4.  * @param string $body      商品简单描述
  5.  * @param string $order_sn  订单编号
  6.  * @param string $total_fee 金额
  7.  * @return  json的数据
  8.  */
  9. public function prepay(){
  10.     $config = $this->config;
  11.     $openid = I(‘post.openid’);
  12.     $body = I(‘post.body’);
  13.     $order_sn = I(‘post.order_sn’);
  14.     $total_fee = I(‘post.total_fee’);
  15.     //统一下单参数构造
  16.     $unifiedorder = array(
  17.         ‘appid’         => $config[‘appid’],
  18.         ‘mch_id’        => $config[‘pay_mchid’],
  19.         ‘nonce_str’     => self::getNonceStr(),
  20.         ‘body’          => $body,
  21.         ‘out_trade_no’  => $order_sn,
  22.         ‘total_fee’     => $total_fee * 100,
  23.         ‘spbill_create_ip’  => get_client_ip(),
  24.         ‘notify_url’    => ‘https://’.$_SERVER[‘HTTP_HOST’].‘/Api/Wxpay/notify’,
  25.         ‘trade_type’    => ‘JSAPI’,
  26.         ‘openid’        => $openid
  27.     );
  28.     $unifiedorder[‘sign’] = self::makeSign($unifiedorder);
  29.     //请求数据
  30.     $xmldata = self::array2xml($unifiedorder);
  31.     $url = ‘https://api.mch.weixin.qq.com/pay/unifiedorder’;
  32.     $res = self::curl_post_ssl($url$xmldata);
  33.     if(!$res){
  34.         self::return_err(“Can’t connect the server”);
  35.     }
  36.     // 这句file_put_contents是用来查看服务器返回的结果 测试完可以删除了
  37.     //file_put_contents(APP_ROOT.’/Statics/log1.txt’,$res,FILE_APPEND);
  38.     $content = self::xml2array($res);
  39.     if(strval($content[‘result_code’]) == ‘FAIL’){
  40.         self::return_err(strval($content[‘err_code_des’]));
  41.     }
  42.     if(strval($content[‘return_code’]) == ‘FAIL’){
  43.         self::return_err(strval($content[‘return_msg’]));
  44.     }
  45.     self::return_data(array(‘data’=>$content));
  46.     //$this->ajaxReturn($content);
  47. }

3、调用商户服务器再次签名接口,返回支付数据

[php] view plain copy

  1. /**
  2.  * 进行支付接口(POST)
  3.  * @param string $prepay_id 预支付ID(调用prepay()方法之后的返回数据中获取)
  4.  * @return  json的数据
  5.  */
  6. public function pay(){
  7.     $config = $this->config;
  8.     $prepay_id = I(‘post.prepay_id’);
  9.     $data = array(
  10.         ‘appId’     => $config[‘appid’],
  11.         ‘timeStamp’ => time(),
  12.         ‘nonceStr’  => self::getNonceStr(),
  13.         ‘package’   => ‘prepay_id=’.$prepay_id,
  14.         ‘signType’  => ‘MD5’
  15.     );
  16.     $data[‘paySign’] = self::makeSign($data);
  17.     $this->ajaxReturn($data);
  18. }

4、小程序内完成支付,商户服务器接收支付回调通知小程序端代码:

[javascript] view plain copy

  1. wx.requestPayment({
  2.    ‘timeStamp’,
  3.    ‘nonceStr’,
  4.    ‘package’,
  5.    ‘signType’‘MD5’,
  6.    ‘paySign’,
  7.    ‘success’:function(res){
  8.    },
  9.    ‘fail’:function(res){
  10.    }
  11. })

服务器回调通知:

[php] view plain copy

  1. //微信支付回调验证
  2. public function notify(){
  3.     $xml = $GLOBALS[‘HTTP_RAW_POST_DATA’];
  4.     // 这句file_put_contents是用来查看服务器返回的XML数据 测试完可以删除了
  5.     //file_put_contents(APP_ROOT.’/Statics/log2.txt’,$res,FILE_APPEND);
  6.     //将服务器返回的XML数据转化为数组
  7.     $data = self::xml2array($xml);
  8.     // 保存微信服务器返回的签名sign
  9.     $data_sign = $data[‘sign’];
  10.     // sign不参与签名算法
  11.     unset($data[‘sign’]);
  12.     $sign = self::makeSign($data);
  13.     // 判断签名是否正确  判断支付状态
  14.     if ( ($sign===$data_sign) && ($data[‘return_code’]==‘SUCCESS’) && ($data[‘result_code’]==‘SUCCESS’) ) {
  15.         $result = $data;
  16.         //获取服务器返回的数据
  17.         $order_sn = $data[‘out_trade_no’];          //订单单号
  18.         $openid = $data[‘openid’];                  //付款人openID
  19.         $total_fee = $data[‘total_fee’];            //付款金额
  20.         $transaction_id = $data[‘transaction_id’];  //微信支付流水号
  21.         //更新数据库
  22.         $this->updateDB($order_sn,$openid,$total_fee,$transaction_id);
  23.     }else{
  24.         $result = false;
  25.     }
  26.     // 返回状态给微信服务器
  27.     if ($result) {
  28.         $str=‘<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>’;
  29.     }else{
  30.         $str=‘<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>’;
  31.     }
  32.     echo $str;
  33.     return $result;
  34. }

我将完整的接口代码封装成了一个类文件,可以直接引入项目更改一下配置参数就可以使用的,源码下载:http://download.csdn.net/detail/sinat_35861727/9879682
小程序端完整代码如下:

[javascript] view plain copy

  1. /**
  2.  * 支付函数
  3.  * @param  {[type]} _payInfo [description]
  4.  * @return {[type]}          [description]
  5.  */
  6. pay:function(_payInfo,success,fail){
  7.     var payInfo = {
  8.         body:,
  9.         total_fee:0,
  10.         order_sn:
  11.     }
  12.     Object.assign(payInfo, _payInfo);
  13.     if(payInfo.body.length==0){
  14.         wx.showToast({
  15.             title:‘支付信息描述错误’
  16.         })
  17.         return false;
  18.     }
  19.     if(payInfo.total_fee==0){
  20.         wx.showToast({
  21.             title:‘支付金额不能0’
  22.         })
  23.         return false;
  24.     }
  25.     if(payInfo.order_sn.length==0){
  26.         wx.showToast({
  27.             title:‘订单号不能为空’
  28.         })
  29.         return false;
  30.     }
  31.     var This = this;
  32.     This.getOpenid(function(openid){
  33.         payInfo.openid=openid;
  34.         This.request({
  35.             url:‘api/pay/prepay’,
  36.             data:payInfo,
  37.             success:function(res){
  38.                 var data = res.data;
  39.                 console.log(data);
  40.                 if(!data.status){
  41.                     wx.showToast({
  42.                         title:data[‘errmsg’]
  43.                     })
  44.                     return false;
  45.                 }
  46.                 This.request({
  47.                     url:‘api/pay/pay’,
  48.                     data:{prepay_id:data.data.data.prepay_id},
  49.                     success:function(_payResult){
  50.                         var payResult = _payResult.data;
  51.                         console.log(payResult);
  52.                         wx.requestPayment({
  53.                             ‘timeStamp’: payResult.timeStamp.toString(),
  54.                             ‘nonceStr’: payResult.nonceStr,
  55.                             ‘package’: payResult.package,
  56.                             ‘signType’: payResult.signType,
  57.                             ‘paySign’: payResult.paySign,
  58.                             ‘success’function (succ) {
  59.                                 success&&success(succ);
  60.                             },
  61.                             ‘fail’function (err) {
  62.                                 fail&&fail(err);
  63.                             },
  64.                             ‘complete’function (comp) {
  65.                             }
  66.                         })
  67.                     }
  68.                 })
  69.             }
  70.         })
  71.     })
  72. }

Modern PHP(中文版)

内容简介  · · · · · ·

检测html 标签闭合

function dealWithBrief($brief) {
$strlen = strlen($brief);

//不包含html标签
if (strpos($brief, ‘<‘) === false) {
return $brief;
}

$html_tag = 0;

/**
* 数组用作记录摘要范围内出现的 html 标签
* 开始和结束分别保存在 left 和 right 键名下
* 如字符串为:<h3><p><b>a</b></h3>,假设 p 未闭合
* 数组则为:array(‘left’ => array(‘h3’, ‘p’, ‘b’), ‘right’ => ‘b’, ‘h3’);
* 仅补全 html 标签,<? <% 等其它语言标记,会产生不可预知结果
*/
$html_array = array(‘left’ => array(), ‘right’ => array());
for ($i = 0; $i < $strlen; $i++) {
$current_letter = substr($brief, $i, 1);

if ($current_letter == ‘<‘) {
$html_tag = 1;
$html_array_str = ”;
} else if ($html_tag == 1) {
if ($current_letter == ‘>’) {
$html_array_str = trim($html_array_str);
if (substr($html_array_str, -1) != ‘/’) {
$f = substr($html_array_str, 0, 1);
if ($f == ‘/’) {
$html_array[‘right’][] = str_replace(‘/’, ”, $html_array_str);
} else if ($f != ‘?’) {
/**
* 判断是否有半角空格,若有,以空格分割,第一个单元为 html 标签
* 如 <h2 class=”a”> <p class=”a”>
*/
if(strpos($html_array_str, ‘ ‘) !== false){
// 分割成2个单元,可能有多个空格,如:<h2 class=”” id=””>
$html_array[‘left’][] = strtolower(current(explode(‘ ‘, $html_array_str, 2)));
}else{
/**
* 若没有空格,整个字符串为 html 标签,如:<b> <p> 等
* 统一转换为小写
*/
$html_array[‘left’][] = strtolower($html_array_str);
}
}
}

$html_array_str = ”;
$html_tag = 0;
} else {
//将< >之间的字符组成一个字符串,用于提取 html 标签
$html_array_str .= $current_letter;
}
}
}

if ($html_array[‘left’]) {
$html_array[‘left’] = array_reverse($html_array[‘left’]);
foreach ($html_array[‘left’] as $index => $tag) {
$key = array_search($tag, $html_array[‘right’]);
if ($key !== false) {
unset($html_array[‘right’][$key]);
} else {
$brief .= ‘</’.$tag.’>’;
}
}
}

return $brief;
}

thinkphp join 别名 SHOW COLUMNS FROM ocenter_auth_group_access a报错

ThinkPHP\Library\Think\Db\Driver\
Mysqli.class.php
 * 取得数据表的字段信息
 * @access public
 * @return array
 */
public function getFields($tableName) {
 /*
 * 如果表有别名 则剔除
 * modify by zhangheng@hongren.com 2017-09-11 start
 */

 $tableName = explode(" ",$tableName);
 $tableName = $tableName[0];
 /*
 * modify by zhangheng@hongren.com 2017-09-11 end
 */
 $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName));
 
 $info = array();
 if($result) {
 foreach ($result as $key => $val) {
 $info[$val['Field']] = array(
 'name' => $val['Field'],
 'type' => $val['Type'],
 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes
 'default' => $val['Default'],
 'primary' => (strtolower($val['Key']) == 'pri'),
 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'),
 );
 }
 }
 return $info;
}

PHP匿名函数和use子句用法

输出 hello everyone

function test()
{
    $param2 = 'every';
    // 返回一个匿名函数
    return function ($param1) use ($param2) {
        // use子句 让匿名函数使用其作用域的变量
        $param2 .= 'one';
        print $param1 . ' ' . $param2;
    };
}
$anonymous_func = test();
$anonymous_func('hello');



下面的方式 输出hello everybody

$param2中多了一个引用

1
2
3
4
5
6
7
8
9
10
11
12
function test()
{
  $param2 = 'everyone';
  $func = function ($param1) use (&$param2) {
    // use子句 让匿名函数使用其父作用域的变量
    print $param1 . ' ' . $param2;
  };
  $param2 = 'everybody';
  return $func;
}
$anonymous_func = test();
$anonymous_func('hello');