微信卡包是去年微信开放平台推出的新接口,由于前段时间一直在忙公司的微信行业定制项目,所以直到现在才有时间将这个接口的功能开发出来。下面就为大家总结一下开发过程中遇到的10个问题:
1.数据发送不再使用XML格式的数据,而是使用JSON。
这点算是卡包和其他微信接口最大的不同了,既然如此,我们就需要对 CURL 的请求方法进行一些改造:
function httpPost($url, $data, $is_json=false) { if(!$is_json){ if(is_array($data)){ $query_data = http_build_query($data); } else { $query_data = $data; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_TIMEOUT, 500); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $query_data); $res = curl_exec($ch); } else { if(is_array($data)){ $json = json_encode($data); } else { $json = $data; } $ch = curl_init($url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS, $json); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', 'Content-Length: ' . strlen($json)) ); $res = curl_exec($ch); } curl_close($ch); return $res; }
2*.使用json_encode提交门店信息,发现在后台数据变成了unicode 码。
这是因为在使用PHP的json_encode函数,底层已经做了 unicode 处理。所以中文会自动转成unicode。所以我们需要使用urlencode函数对中文进行编码,转成json字符之后再用json_decode进行回转。
例如:
$arr = array ('a'=>'云秀网'); echo json_encode($arr); // 输出: {"a":"\u811a\u672c\u4e4b\u5bb6"}
$arr = array ('a'=>urlencode('云秀网')); echo urldecode(json_encode($arr)); // 输出:{"a":"云秀网"}
在PHP5.4, 这个问题终于得以解决, Json新增了一个选项: JSON_UNESCAPED_UNICODE, 故名思议, 就是说, Json不要编码Unicode.
让Json更懂中文(JSON_UNESCAPED_UNICODE)
<?php echo json_encode("中文",JSON_UNESCAPED_UNICODE);
3.微信官方提供的CardSDK有BUG
官方提供的CardSDK是用来生成卡券的json数据,我发现里面有些字段的设置已经和新版的文档有不少出入,而且中文字符会出现unicode编码的问题,下面是我修改过的微信卡包CardSDK:
<?php /* 微信卡包api SDK V1.0 !!README!!: base_info的构造函数的参数是必填字段,有set接口的可选字段。 针对某一种卡的必填字段(参照文档)仍然需要手动set(比如团购券Groupon的deal_detail),通过card->get_card()拿到card的实体对象来set。 ToJson就能直接转换为符合规则的json。 Signature是方便生成签名的类,具体用法见示例。 注意填写的参数是int还是string或者bool或者自定义class。 更具体用法见最后示例test,各种细节以最新文档为准。 */ class Sku{ function __construct($quantity){ $this->quantity = $quantity; } }; class DateInfo{ function __construct($type, $arg0, $arg1 = null) { if (!is_int($type) ) exit("DateInfo.type must be integer"); $this->type = $type; if ( $type == 1 ) //固定日期区间 { if (!is_int($arg0) || !is_int($arg1)) exit("begin_timestamp and end_timestamp must be integer"); $this->begin_timestamp = $arg0; $this->end_timestamp = $arg1; } else if ( $type == 2 ) //固定时长(自领取后多少天内有效) { if (!is_int($arg0) || !is_int($arg1)) exit("fixed_term and fixed_begin_term must be integer"); $this->fixed_term = $arg0; $this->fixed_begin_term = $arg1; }else exit("DateInfo.tpye Error"); } }; class BaseInfo{ function __construct($logo_url, $brand_name, $code_type, $title, $color, $notice, $description, $date_info, $sku) { if (! $date_info instanceof DateInfo ) exit("date_info Error"); if (! $sku instanceof Sku ) exit("sku Error"); // if (! is_int($code_type) ) // exit("code_type must be integer"); $this->logo_url = urlencode($logo_url); $this->brand_name = urlencode($brand_name); $this->code_type = $code_type; $this->title = urlencode($title); $this->color = $color; $this->notice = urlencode($notice); $this->description = urlencode($description); $this->date_info = $date_info; $this->sku = $sku; } function set_sub_title($sub_title){ $this->sub_title = urlencode($sub_title); } // function set_use_limit($use_limit){ // if (! is_int($use_limit) ) // exit("use_limit must be integer"); // $this->use_limit = $use_limit; // } function set_location_id_list($location_id_list) { if (! is_array($location_id_list)) exit("location_id_list must be array"); $this->location_id_list = $location_id_list; } function set_use_custom_code($use_custom_code){ $this->use_custom_code = $use_custom_code; } function set_bind_openid($bind_openid){ $this->bind_openid = $bind_openid; } function set_can_share($can_share){ $this->can_share = $can_share; } function set_can_give_friend($can_give_friend) { $this->can_give_friend = $can_give_friend; } function set_get_limit($get_limit){ if (! is_int($get_limit) ) exit("get_limit must be integer"); $this->get_limit = $get_limit; } function set_service_phone($service_phone) { $this->service_phone = urlencode($service_phone); } function set_source($source) { $this->source = urlencode($source); } // function set_location_id_list($location_id_list){ // $this->location_id_list = $location_id_list; // } function set_custom_url_name($custom_url_name){ $this->custom_url_name = urlencode($custom_url_name); } function set_custom_url($custom_url){ $this->custom_url = urlencode($custom_url); } function set_custom_url_sub_title($custom_url_sub_title){ $this->custom_url_sub_title = urlencode($custom_url_sub_title); } function set_promotion_url_name($promotion_url_name){ $this->promotion_url_name = urlencode($promotion_url_name); } function set_promotion_url($promotion_url){ $this->promotion_url = urlencode($promotion_url); } function set_promotion_url_sub_title($promotion_url_sub_title){ $this->promotion_url_sub_title = urlencode($promotion_url_sub_title); } }; class CardBase{ public function __construct($base_info){ $this->base_info = $base_info; } }; class GeneralCoupon extends CardBase{ function set_default_detail($default_detail){ $this->default_detail = urlencode($default_detail); } }; class Groupon extends CardBase{ function set_deal_detail($deal_detail){ $this->deal_detail = urlencode($deal_detail); } }; class Discount extends CardBase{ function set_discount($discount){ if (!is_int($discount)) exit("discount must be integer"); $this->discount = $discount; } }; class Gift extends CardBase{ function set_gift($gift){ $this->gift = urlencode($gift); } }; class Cash extends CardBase{ function set_least_cost($least_cost){ if (!is_int($least_cost)) exit("least_cost must be integer"); $this->least_cost = $least_cost; } function set_reduce_cost($reduce_cost){ if (!is_int($reduce_cost)) exit("reduce_cost must be integer"); $this->reduce_cost = $reduce_cost; } }; class MemberCard extends CardBase{ function set_supply_bonus($supply_bonus){ $this->supply_bonus = $supply_bonus?true:false; } function set_supply_balance($supply_balance){ $this->supply_balance = $supply_balance?true:false; } function set_bonus_cleared($bonus_cleared){ $this->bonus_cleared = urlencode($bonus_cleared); } function set_bonus_rules($bonus_rules){ $this->bonus_rules = urlencode($bonus_rules); } function set_balance_rules($balance_rules){ $this->balance_rules = urlencode($balance_rules); } function set_prerogative($prerogative){ $this->prerogative = urlencode($prerogative); } function set_bind_old_card_url($bind_old_card_url){ $this->bind_old_card_url = urlencode($bind_old_card_url); } function set_activate_url($activate_url){ $this->activate_url = urlencode($activate_url); } }; class ScenicTicket extends CardBase{ function set_ticket_class($ticket_class){ $this->ticket_class = urlencode($ticket_class); } function set_guide_url($guide_url){ $this->guide_url = urlencode($guide_url); } }; class MovieTicket extends CardBase{ function set_detail($detail){ $this->detail = urlencode($detail); } }; class Card{ //工厂 private $CARD_TYPE = Array("GENERAL_COUPON", "GROUPON", "DISCOUNT", "GIFT", "CASH", "MEMBER_CARD", "SCENIC_TICKET", "MOVIE_TICKET" ); function __construct($card_type, $base_info) { if (!in_array($card_type, $this->CARD_TYPE)) exit("CardType Error"); if (! $base_info instanceof BaseInfo ) exit("base_info Error"); $this->card_type = $card_type; switch ($card_type) { case $this->CARD_TYPE[0]: $this->general_coupon = new GeneralCoupon($base_info); break; case $this->CARD_TYPE[1]: $this->groupon = new Groupon($base_info); break; case $this->CARD_TYPE[2]: $this->discount = new Discount($base_info); break; case $this->CARD_TYPE[3]: $this->gift = new Gift($base_info); break; case $this->CARD_TYPE[4]: $this->cash = new Cash($base_info); break; case $this->CARD_TYPE[5]: $this->member_card = new MemberCard($base_info); break; case $this->CARD_TYPE[6]: $this->scenic_ticket = new ScenicTicket($base_info); break; case $this->CARD_TYPE[8]: $this->movie_ticket = new MovieTicket($base_info); break; default: exit("CardType Error"); } return true; } function get_card() { switch ($this->card_type) { case $this->CARD_TYPE[0]: return $this->general_coupon; case $this->CARD_TYPE[1]: return $this->groupon; case $this->CARD_TYPE[2]: return $this->discount; case $this->CARD_TYPE[3]: return $this->gift; case $this->CARD_TYPE[4]: return $this->cash; case $this->CARD_TYPE[5]: return $this->member_card; case $this->CARD_TYPE[6]: return $this->scenic_ticket; case $this->CARD_TYPE[8]: return $this->movie_ticket; default: exit("GetCard Error"); } } function toJson() { return "{ \"card\":" . urldecode(json_encode($this)) . "}"; } }; class Signature{ function __construct(){ $this->data = array(); } function add_data($str){ array_push($this->data, (string)$str); } function get_signature(){ sort( $this->data, SORT_STRING ); return sha1( implode( $this->data ) ); } }; // 调用官方创建卡包的SDK //------------------------set base_info----------------------------- $base_info = new BaseInfo($baseInfo['logo_url'], $baseInfo['brand_name'], $baseInfo['code_type'], $baseInfo['title'], $baseInfo['color'], $baseInfo['notice'], $baseInfo['description'], $dateInfo, new Sku((int)$baseInfo['quantity']) ); if($baseInfo['sub_title']) { $base_info->set_sub_title( $baseInfo['sub_title'] ); } if($baseInfo['location_id_list']) { $base_info->set_location_id_list( $baseInfo['location_id_list'] ); } $base_info->set_use_custom_code( $baseInfo['use_custom_code'] ); $base_info->set_bind_openid( $baseInfo['bind_openid'] ); $base_info->set_can_share( $baseInfo['can_share'] ); $base_info->set_can_give_friend( $baseInfo['can_give_friend'] ); if($baseInfo['get_limit']) { $base_info->set_get_limit( (int)$baseInfo['get_limit'] ); } if($baseInfo['service_phone']) { $base_info->set_service_phone( $baseInfo['service_phone'] ); } if($baseInfo['source']) { $base_info->set_source( $baseInfo['source'] ); } if($baseInfo['custom_url_name']) { $base_info->set_custom_url_name( $baseInfo['custom_url_name'] ); } if($baseInfo['custom_url']) { $base_info->set_custom_url( $baseInfo['custom_url'] ); } if($baseInfo['custom_url_sub_title']) { $base_info->set_custom_url_sub_title( $baseInfo['custom_url_sub_title'] ); } if($baseInfo['promotion_url_name']) { $base_info->set_promotion_url_name( $baseInfo['promotion_url_name'] ); } if($baseInfo['promotion_url']) { $base_info->set_promotion_url( $baseInfo['promotion_url'] ); } if($baseInfo['promotion_url_sub_title']) { $base_info->set_promotion_url_sub_title( $baseInfo['promotion_url_sub_title'] ); } //---------------------------set_card-------------------------------- $wxcard = new Card($cardType, $base_info); foreach($card as $func => $args) { $func='set_'.$func; $wxcard->get_card()->$func( $args ); } //--------------------------to json-------------------------------- $data = $wxcard->toJson(); //----------------------check signature------------------------ $signature = new Signature(); $signature->add_data( "875e5cc094b78f230b0588c2a5f3c49f" ); $signature->add_data( "wx57bf46878716c27e" ); $signature->add_data( "213168808" ); $signature->add_data( "12345" ); $signature->add_data( "55555" ); echo $signature->get_signature(); ?>
4.*微信上传Logo图片接口
最后的话:微信卡包其实在微信公众平台已经有一个管理面板,但是为了扩展第三方平台的微信接入功能,已经方便以后定制开发使用这个接口进行二次营销,所以这个功能还是非常重要的。