月度归档 2015年10月31日

通过清心醉

C2C的开发难点解剖

首先我们要知道C2C平台的标准。

所以的C2C,就是用户对用户在统一的网络里进行交易的模式。

很多PHP开发人员都肯定会接触过B2C平台的开发。

而且电子商城无非就这么几个要求。

1、可以上传产品,给用户选择;

2、用户可以查看自己的交易信息;

3、存在交易流程。

C2C难在哪?没错,每个来购买产品的人,他也可以自己开一个小网店。

由于多个用户收款及产品数据的不同,需要区分不同的用户上传的产品表和收款帐号。然后交易的时候,根据当前用户填写的支付帐号信息,进行交易。

最大的问题点来了,资金的对转要如何实现?

以前有大概听说过,如果要申请银行方向的支付接口,资金起码也是得上百万级别。

为什么这么难?

假设运营商的平台和银行有接口对接,用户在网站平台购买东西,实际钱第一步是到了网站的运营商帐户里,然后模拟淘宝之类的,用户确认收货之后,利用API请求银行进行资金转入到店家帐户上。所以一般的企业公司根本没办法实现该要求。

更难的还有一个就是请求资金转出的数据加密类型了,有做过PHP各大支付API接口开发都能知道数据泄密对网站造成的影响,居然谈到了数据安全,作者就再详解下做电子商城网站开发支付接口的一个最大问题。

不管支付宝、京东支付还是腾讯支付等各大国内收款第三方。都有企业级及个人级的收款(所谓企业级就是资金可以马上到帐,个人级就是由第三方暂扣资金XX天)

不管哪个级别,直接请求的时候,都是对数据进行MD5加密之后附加加密前的参数进行申请收款,当然,这就需要用户在第三收款方申请的KEY(简称密钥),而且是加密过后的参数,如果一旦泄露这些参数,攻击者可以利用这些数据,模拟交易请求

因为每次只要交易完成或者未支付,第三方平台都会有数据返回给网站,就是通过KEY等组合起来的参数。

如果攻击者得到了第三方的KEY,因为接口模式是公开的SDK/API,可以轻松利用组合模拟订单的交易状态,从而实现不花钱,订单全部是已付款状态。

通过清心醉

opencart前台获取支付方式的方法

在checkout.tpl视图文件里,进行了ajax的请求#collapse-payment-method

然后我们来看看请求的payment-method控制器

在index方法里

有这么几句:

$this->load->model(‘extension/extension’);
$results = $this->model_extension_extension->getExtensions(‘payment’);
$recurring = $this->cart->hasRecurringProducts();
foreach ($results as $result) {
if ($this->config->get($result[‘code’] . ‘_status’)) {
$this->load->model(‘payment/’ . $result[‘code’]);
$method = $this->{‘model_payment_’ . $result[‘code’]}->getMethod($this->session->data[‘payment_address’], $total);
if ($method) {
if ($recurring) {
if (method_exists($this->{‘model_payment_’ . $result[‘code’]}, ‘recurringPayments’) && $this->{‘model_payment_’ . $result[‘code’]}->recurringPayments()) {
$method_data[$result[‘code’]] = $method;
}
} else {
$method_data[$result[‘code’]] = $method;
}
}
}
}

作者前文写的安装配置,是因为要遵循opencart的模块规则标准,而如果定义为插件了的话

除了自定义的数据表,还会追加写入extension扩展表及setting环境配置表(可以当成为开关表)

在需要的时候,首先extension里提取当前需要使用的扩展类型

在$results = $this->model_extension_extension->getExtensions(‘payment’);这一句就可以看到

而且getExtensions的原型是:

function getExtensions($type) {
$query = $this->db->query(“SELECT * FROM ” . DB_PREFIX . “extension WHERE `type` = ‘” . $this->db->escape($type) . “‘”);

return $query->rows;
}

我们在来看数据库参数:

extension表

‘extension_id’=>’234’
‘type’=>’payment’
‘code’=>’ckzalipay’

当获取了扩展插件名之后,在获取插件的当前状态.$this->config->get($result[‘code’] . ‘_status’);

接着引用模型文件$this->load->model(‘payment/’ . $result[‘code’]);

其实等价于$this->load->mode(‘payment/ckzalipay’);

然后强制调用getMethod方法

$method = $this->{‘model_payment_’ . $result[‘code’]}->getMethod($this->session->data[‘payment_address’], $total);

等价于$method = $this->model_payment_ckzalipay->getMethod($this->session->data[‘payment_address’], $total);

getMethod($address, $total)里就是显示支付列表的参数

因为是在foreach循环里,所以会提取出所有打开的支付方式.

 

 

 

 

 

 

 

通过清心醉

opencart创建支付宝支付后台

由于处于开发阶段,可能需要更多的参数需要进行填写.暂时写的先贴上

默认需要有个install()安装控制器方法和uninstall()卸载方法

附上控制器和模型的类方法:

class ControllerPaymentCkzalipay extends Controller {
function index()
{
$this->load->language(‘payment/ckzalipay’);   //默认配置语言包
$this->document->setTitle($this->language->get(‘heading_title’)); //页面标题头
$this->load->model(‘setting/setting’);        //模块/插件的启用和关闭状态表
$this->load->model(‘payment/ckzalipay’); //模型配置模型包
/**
* 开始导入语言包
*/
$data[‘heading_title’] = $this->language->get(‘heading_title’);
$data[‘ckz_id’]=$this->language->get(‘ckz_id’);
$data[‘ckz_key’]=$this->language->get(‘ckz_key’);
$data[‘ckz_account’]=$this->language->get(‘ckz_account’);
$data[‘ckz_save’]=$this->language->get(‘ckz_save’);
$data[‘ckz_false’]=$this->language->get(‘ckz_false’);
$data[‘text_enabled’]=$this->language->get(‘text_enabled’);
$data[‘text_disabled’]=$this->language->get(‘text_disabled’);
$data[‘zhuangtai’]=$this->language->get(‘zhuangtai’);
$data[‘ckz_jishi_text’]=$this->language->get(‘ckz_jishi_text’);
$data[‘ckz_danbao_text’]=$this->language->get(‘ckz_danbao_text’);
$data[‘ckz_alipay_moshi’]=$this->language->get(‘ckz_alipay_moshi’);

/**
* 导入其他栏
*/
$data[‘header’] = $this->load->controller(‘common/header’);
$data[‘column_left’] = $this->load->controller(‘common/column_left’);
$data[‘footer’] = $this->load->controller(‘common/footer’);

/**
* 导入支付宝配置的参数
*/
$data[‘config’]=array();
if(isset($this->request->post[‘ckz_id’])
&& isset($this->request->post[‘ckz_key’])
&& isset($this->request->post[‘ckz_account’])
&& isset($this->request->post[‘ckz_zhuangtai’])
&& isset($this->request->post[‘ckz_moshi’])
)
{
//var_dump($_POST);die();
$data[‘config’][‘ckzalipay_id’]=$this->request->post[‘ckz_id’];
$data[‘config’][‘ckzalipay_key’]=$this->request->post[‘ckz_key’];
$data[‘config’][‘ckzalipay_account’]=$this->request->post[‘ckz_account’];
$data[‘config’][‘ckzalipay_type’]=$this->request->post[‘ckz_moshi’];
//以上三个参数为获取POST数据
$this->model_payment_ckzalipay->setckzalipayconfig($this->request->post[‘ckz_id’],
$this->request->post[‘ckz_key’],
$this->request->post[‘ckz_account’],
$this->request->post[‘ckz_moshi’]);
//执行更新用户的模型数据
$this->model_payment_ckzalipay->update_setting_value($this->request->post[‘ckz_zhuangtai’]);
//更新setting模块状态
$data[‘status_value’]=$this->request->post[‘ckz_zhuangtai’];
//获取当前模块的启用/关闭值得
}
else
{
$data[‘config’]=$this->model_payment_ckzalipay->getckzalipayconfig();
if (empty($data[‘config’]))
{
$data[‘config’][‘ckzalipay_id’]=’this is id’;
$data[‘config’][‘ckzalipay_key’]=’this is key’;
$data[‘config’][‘ckzalipay_account’]=’this is account’;
$data[‘config’][‘ckzalipay_type’]=’0′;
}
if($this->model_payment_ckzalipay->getckzalipayconfig_setting())
{
$data[‘status_value’]=1;
}
else
{
$data[‘status_value’]=0;
}
}
$data[‘action’] = $this->url->link(‘payment/ckzalipay’, ‘token=’ . $this->session->data[‘token’], ‘SSL’); //保存的时候请求的方法
$data[‘cancel’] = $this->url->link(‘extension/payment’, ‘token=’ . $this->session->data[‘token’], ‘SSL’);  //取消的时候返回的页面
$this->response->setOutput($this->load->view(‘payment/ckzalipay.tpl’, $data));
}

function install()
{
/**
* 加载语言模型文件
*/
$this->load->model(‘payment/ckzalipay’);
$this->load->model(‘setting/setting’);
$this->model_payment_ckzalipay->install();
}

function uninstall()
{
$this->load->model(‘payment/ckzalipay’);
$this->model_payment_ckzalipay->uninstall();
}
}

 

/**
* model file
*
*  由于是支付模块,属于extension
*  所以默认调用了安装,会给extension表内添加对应的字段
*
* */
class ModelPaymentCkzalipay extends Model
{
function install()
{
/**
$this->db->query(”
CREATE TABLE `” . DB_PREFIX . “order_ckzalipay` (
`order_id` int(11) NOT NULL,
`ckzalipay_order_id` varchar(255) NOT NULL,
`free_shipping`  tinyint NOT NULL DEFAULT 0,
KEY `ckzalipay_order_id` (`ckzalipay_order_id`),
PRIMARY KEY `order_id` (`order_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
“);

$this->db->query(”
CREATE TABLE `” . DB_PREFIX . “order_ckzalipay_product` (
`order_product_id`  int NOT NULL ,
`ckzalipay_order_item_code`  varchar(255) NOT NULL,
PRIMARY KEY (`order_product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
“);
*/
/**
* 创建支付宝支付配置
* 参数为:
* 验证ID,验证KEY,用户帐户及支付类型(即使到帐和担保交易)
* 其中type=1时为即时到帐
* type=0时为担保交易
*/
$this->db->query(”
CREATE TABLE `” . DB_PREFIX . “order_ckzalipay_config` (
`ckzalipay_id`  varchar(255) NOT NULL ,
`ckzalipay_key`  varchar(255) NOT NULL ,
`ckzalipay_account` varchar(255) NOT NULL ,
`ckzalipay_type` varchar(32) NOT NULL,
PRIMARY KEY (`ckzalipay_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
“);

//添加系统模块/插件配置开关
$this->db->query(”
INSERT INTO `” . DB_PREFIX . “setting`
(`store_id`, `code`, `key`, `value`, `serialized`)
VALUES (‘0’, ‘config’, ‘ckzalipay_status’, ‘0’, ‘0’);
“);

}
function uninstall()
{
//以下两个参数暂时不执行
// $this->db->query(“DROP TABLE IF EXISTS `” . DB_PREFIX . “order_ckzalipay`;”);
// $this->db->query(“DROP TABLE IF EXISTS `” . DB_PREFIX . “order_ckzalipay_product`;”);
$this->db->query(“DROP TABLE IF EXISTS `” . DB_PREFIX . “order_ckzalipay_config`;”);
$this->db->query(“DELETE FROM `” . DB_PREFIX . “setting` WHERE `key`=’ckzalipay_status’;”);
}

/**
* 获取清心醉-支付宝的参数配置
* 返回一行数据(只有一行)
* @return unknown
*/
function getckzalipayconfig()
{
$config=$this->db->query(“SELECT * FROM `” . DB_PREFIX . “order_ckzalipay_config`;”);
$config=$config->row; //提取一行数据 全部为rows;
return $config;
}

/**
* 用户写入的清心醉-支付宝数据进行写入保存
* @param unknown $id
* @param unknown $key
* @param unknown $account
*/
function setckzalipayconfig($id,$key,$account,$type)
{
$config=$this->getckzalipayconfig();//首先获取看看有没有数据
if (empty($config))
{
$this->db->query(”
INSERT INTO `” . DB_PREFIX . “order_ckzalipay_config`
(`ckzalipay_id`,`ckzalipay_key`,`ckzalipay_account`,`ckzalipay_type`)
VALUES(‘$id’,’$key’,’$account’,’$type’);
“);
}
else
{
$this->db->query(“UPDATE`” . DB_PREFIX . “order_ckzalipay_config` SET `ckzalipay_id`= ‘$id’, `ckzalipay_key`=’$key’, `ckzalipay_account`=’$account’, `ckzalipay_type`=’$type’;”);
}
}

/**
* 判断开起的模块/插件中key值中是否存在对应的
* $kye的值明确为 ckzalipay_status
* ckzalipay为插件的名称
* status为插件的启用状态
* @param unknown $key
* @return boolean
*/
function getckzalipayconfig_setting()
{
$keys=$this->db->query(“SELECT * FROM `” . DB_PREFIX . “setting` WHERE `key`=’ckzalipay_status'”);
$keys=$keys->row;
if (!empty($keys))
{
if ($keys[‘value’]==1)
{
return true;
}
else {
return false;
}
}
else {
return false;
}
}

function update_setting_value($value)
{
$this->db->query(“UPDATE`” . DB_PREFIX . “setting` SET `value`= ‘$value’ WHERE `key`=’ckzalipay_status’;”);
}
}

通过清心醉

ajax请求带特殊符号的参数

假设有两个input

一个参数为:100,id=’input1′

另一个参数为:a=100&b=200,id=’input2′

知道JS写AJAX的(非JQ框架AJAX)都知道,进行POST请求的时候,

我们先要把参数进行组合

比如先获取两个input的参数

var input1=document.getElementById(“input1”).value;

var input2=document.getElementById(“input2”).value;

var str=”data1=”+input1+”&data2=”+input2;

如果执行alert()

会输出:data1=100&data2=a=100&b=200;

在AJAX请求的时候每一个POST的数据都是以&做下一个的接口点

如此以来,POST过来的数据,就变为:

$_POST=array(

data1=>’100′,

data2=>’a=100′,

b=’200′

);

字符被当成数据的分割了,这时候我们需要用encodeURIComponent()的方法来完善: 即:

var str=”data1=”+input1+”&data2=”+encodeURIComponent(input2);

至于在JQ框架里是否一样暂未尝试,作者精力都放在后端的数据和LINUX服务器上面,所以只用JavaScript编写.

通过清心醉

1024-程序员们节日快乐

1024程序员节

1024是2的十次方,二进制计数的基本计量单位之一。程序员(英文Programmer)是从事程序开发、维护的专业人员。程序员就像是一个个1024,以最低调、踏实、核心的功能模块搭建起这个科技世界。1GB=1024M,而1GB与1级谐音,也有一级棒的意思。

从2014年起,每年10月24日定义为程序员节。以一个节日的形式,向通过coding改变世界,也以实际行动在浮躁的世界里,固执地坚持自己对于知识、技术和创新追求的程序员们表示致敬。
节日背景
1024程序员节,是全世界程序员的共同节日。在1842年,人称“数字女王”的阿达·洛芙莱斯(Ada Lovelace)编写了历史上首款电脑程序。
在1834年,阿达的朋友——英国数学家、发明家兼机械工程师查尔斯·巴贝其(Charles Babbage)——发明了一台分析机;阿达则致力于为该分析机编写算法,并于1843 年公布了世界上第一套算法。巴贝其分析机后来被认为是最早期的计算机雏形,而阿达的算法则被认为是最早的计算机程序和软件。
现今,一般将程序员分为程序设计人员和程序编码人员,但两者的界限并不非常清楚,特别是在中国。软件从业人员分为初级程序员、高级程序员、系统分析员,系统架构师,测试工程师五大类。
         更多参考: 百度百科-1024程序员节
通过清心醉

WDCP(WDLINUX)安装VPN

最近老想翻墙看GOOGLE之类的了,可无奈翻墙软件要么收费要么免费的不稳定,居然自己有个香港的VPS,所以就试试.

由于作者的还有独立的VPS做FTP空间群(使用WDCP架设),直接开工吧.

把以下代码写成一个脚本.

yum remove -y pptpd ppp
iptables –flush POSTROUTING –table nat
iptables –flush FORWARD
rm -rf /etc/pptpd.conf
rm -rf /etc/ppp
arch=`uname -m`
wget http://poptop.sourceforge.net/yum/stable/packages/pptpd-1.3.4-2.el6.$arch.rpm

yum -y install make libpcap iptables gcc-c++ logrotate tar cpio perl pam tcp_wrappers dkms kernel_ppp_mppe ppp
rpm -Uvh pptpd-1.3.4-2.el6.$arch.rpm

mknod /dev/ppp c 108 0
echo 1 > /proc/sys/net/ipv4/ip_forward
echo “mknod /dev/ppp c 108 0” >> /etc/rc.local
echo “echo 1 > /proc/sys/net/ipv4/ip_forward” >> /etc/rc.local
echo “localip 172.16.22.254” >> /etc/pptpd.conf
echo “remoteip 172.16.22.1-253” >> /etc/pptpd.conf
echo “ms-dns 8.8.8.8” >> /etc/ppp/options.pptpd
echo “ms-dns 8.8.4.4” >> /etc/ppp/options.pptpd

pass=`openssl rand 6 -base64`
if [ “$1” != “” ]
then pass=$1
fi

echo “vpn pptpd ${pass} *” >> /etc/ppp/chap-secrets

iptables -t nat -A POSTROUTING -s 172.16.22.0/24 -j SNAT –to-source `ifconfig  | grep ‘inet addr:’| grep -v ‘127.0.0.1’ | cut -d: -f2 | awk ‘NR==1 { print $1}’`
iptables -A FORWARD -p tcp –syn -s 172.16.22.0/24 -j TCPMSS –set-mss 1356
iptables -A OUTPUT -p tcp -m tcp –sport 1723 -j ACCEPT
iptables -A OUTPUT -p 47 -j ACCEPT
iptables -A INPUT -p tcp -m tcp –dport 1723 -j ACCEPT
iptables -A INPUT -p 47 -j ACCEPT

service iptables save

chkconfig iptables on
chkconfig pptpd on

service iptables start
service pptpd start

echo “VPN service is installed, your VPN username is vpn, VPN password is ${pass}”

在后台—安全管理—防火墙中,查看添加规则。
在目标端口中填写:1723  操作–选择通过。

提示:如果防火墙中已经有了这条规则请先删除再重新添加。

VPN用户管理:
直接编辑文件:,按照相同格式添加用户名和密码即可。
vi /etc/ppp/chap-secrets

修改密码之后别忘记了service pptpd restart哦

通过清心醉

mysql创建对应数据库/用户的权限代码

一个数据库多个用户登陆,然后不同用户访问的数据库又不同,很多人都不知道如何操作,网上也有一堆的过时的教程,根本没办法满足需求,作者写了个方法,可以实现创建用户名=数据库名(长度16)的权限的划分方法:

使用该方法前请确保启用了PDO_MYSQL

方法中的5个参数分别为:

$host=主机地址;

$user=用户,一般都是root(必须要最高权限的用户才能创建);

$password=用户密码,即root的密码;

$table=需要创建的数据库名称同时也是对应的用户名,长度16

$userpassword=创建新的MYSQL的用户的密码参数

 

function mysql_user_shell($host,$user,$password,$table,$userpassword)
{
$pdo=new PDO (“mysql:host=$host;charset=utf8”,$user,$password); //生成配置连接
$table=substr($table, 0, 16);//table重新赋值,提取前16位置
if($pdo->query(“create database $table”))  //如果创建数据库成功
{
echo “数据库:”.$table.”创建成功”;
}
else
{
echo “数据库已经存在或未启动参数错误.”;
}
$pdo=new PDO(“mysql:host=$host;dbname=$table;charset=utf8″,$user,$password); //重新创建PDO的连接并且连接对应的数据库
$sql=”grant select,insert,update,delete,create,drop on $table.* to $table@localhost identified by ‘$userpassword'”;
$pdo->exec($sql); //执行用户的创建
$sql=”REVOKE ALL PRIVILEGES ON `$table`.* FROM ‘$table’@’localhost'”;
$pdo->exec($sql);
$sql=”GRANT ALL PRIVILEGES ON `$table`.* TO ‘$table’@’localhost’ WITH GRANT OPTION”;
$pdo->exec($sql);
}

通过清心醉

PHP提取EXCEL数据

在这需要借助一个扩展,PHPExcel_1.8.0_doc,需要的可以自寻搜索下载.

正文开始:

class ExcelPhp
{
function excel_data($dir,$filepath)
{
require_once $dir.’Classes/PHPExcel/IOFactory.php’;
$reader = PHPExcel_IOFactory::createReader(‘Excel5’); //设置以Excel5格式(Excel97-2003工作簿)
$PHPExcel = $reader->load(“$filepath”); // 载入excel文件
$sheet = $PHPExcel->getSheet(0); // 读取第一個工作表
$highestRow = $sheet->getHighestRow(); // 取得总行数
$highestColumm = $sheet->getHighestColumn(); // 取得总列数
$import=array();
for ($row = 2; $row <= $highestRow; $row++) //从第2行开始读取参数
{
for ($column = ‘A’; $column <= $highestColumm; $column++)//
{
$number=$this->text_number($column); //列进行数字转换
$numrow=$row-2;
$import[$numrow][$number] = $sheet->getCell($column.$row)->getValue();
}
}
return $import;
}
function text_number($text)
{
switch ($text)
{
case’A’:$i=1;return $i;break;
case’B’:$i=2;return $i;break;
case’C’:$i=3;return $i;break;
case’D’:$i=4;return $i;break;
case’E’:$i=5;return $i;break;
case’F’:$i=6;return $i;break;
case’G’:$i=7;return $i;break;
case’H’:$i=8;return $i;break;
case’I’:$i=9;return $i;break;
}
}
}

数据格式为二维数组,即$import[$o][1]; 二维参数为1开始,如果要0开始修改text_number方法里的数值即可.