小程序交易组件-自定义交易组件相关知识
自定义组件提交商品,标题乱码 是怎么回事?
<?php
$data = [
//添加商品的数据
];
$data = json_encode($data,JSON_UNESCAPED_UNICODE);//第二个参数应为 JSON_UNESCAPED_UNICODE
$response = curl_http($url, $data);
对接自定义版交易组件必须需要下面两个文件
一 接收事件回调方法
<?php
namespace app\controller;
use app\BaseController;
class Msg extends BaseController
{
public function actionIndex()
{
if (!$this->checkSignature()) {
//记录日志,应该用自己的方法记录日志,此次仅为示例
file_put_contents('/log.txt', date('ymd H:i:s') . '=>' . json_encode($_GET, true) . PHP_EOL, FILE_APPEND);
//可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试
return 'error signature ~~';
}
$params = $this->request->param();
if (array_key_exists('echostr', $params) && $params['echostr']) {//用于微信第一次认证的
return $params['echostr'];
}
//因为很多都设置了register_globals禁止,不能用$GLOBALS["HTTP_RAW_POST_DATA"];
$xml_data = file_get_contents("php://input");
//记录日志,应该用自己的方法记录日志,此次仅为示例
file_put_contents('/log.txt', date('ymd H:i:s') . '=>' . $xml_data . PHP_EOL, FILE_APPEND);
if (!$xml_data) {
return 'error xml ~~';
}
$xml_obj = simplexml_load_string($xml_data, 'SimpleXMLElement', LIBXML_NOCDATA);
$from_username = $xml_obj->FromUserName;
$to_username = $xml_obj->ToUserName;
$msg_type = $xml_obj->MsgType;//信息类型
$res = ['type' => 'text', 'data' => $this->defaultTip()];
switch ($msg_type) {
case "text":
if ($xml_obj->Content == "商城账号") {
$res = ['type' => 'text', 'data' => 'hello world'];
} else {
$kw = trim($xml_obj->Content);
$res = $this->search($kw);
}
break;
case "event":
$res = $this->parseEvent($xml_obj);
break;
default:
break;
}
switch ($res['type']) {
case "rich":
return $this->richTpl($from_username, $to_username, $res['data']);
break;
case "text":
return $this->textTpl($from_username, $to_username, $res['data']);
break;
default:
return "success";
}
return "success";
}
private function search($kw)
{
$query = Book::find()->where(['status' => 1]);
$where_name = ['LIKE', 'name', '%' . strtr($kw, ['%' => '\%', '_' => '\_', '\\' => '\\\\']) . '%', false];
$where_tag = ['LIKE', 'tags', '%' . strtr($kw, ['%' => '\%', '_' => '\_', '\\' => '\\\\']) . '%', false];
$query->andWhere(['OR', $where_name, $where_tag]);
$res = $query->orderBy(['id' => SORT_DESC])->limit(3)->all();
$data = $res ? $this->getRichXml($res) : $this->defaultTip();
$type = $res ? "rich" : "text";
return ['type' => $type, "data" => $data];
}
private function parseEvent($dataObj)
{
$resType = "text";
$resData = $this->defaultTip();
$event = $dataObj->Event;
$arr = json_decode(json_encode($dataObj, true), true);
switch ($event) {
case "subscribe":
$resData = $this->subscribeTips();
break;
case "CLICK"://自定义菜单点击类型是CLICK的,可以回复指定内容
$eventKey = trim($dataObj->EventKey);
switch ($eventKey) {
}
break;
case "open_product_spu_audit":
//接收商品审核回调
$resType = "shipinhao";
$goods = $arr['OpenProductSpuAudit'];
break;
case "open_product_category_audit":
//类目审核回调
// 调用数据库
$resType = "shipinhao";
break;
case "open_product_brand_audit":
//品牌审核回调
// 调用数据库
$resType = "shipinhao";
break;
case "open_product_spu_audit":
//品牌审核回调
// 调用数据库
$resType = "shipinhao";
break;
case "open_product_account_register":
//账户接入回调
// 调用数据库
$resType = "shipinhao";
break;
}
return ['type' => $resType, 'data' => $resData];
}
//文本内容模板
private function textTpl($from_username, $to_username, $content)
{
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
return sprintf($textTpl, $from_username, $to_username, time(), "text", $content);
}
//富文本
private function richTpl($from_username, $to_username, $data)
{
$tpl = <<<EOT
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
%s
</xml>
EOT;
return sprintf($tpl, $from_username, $to_username, time(), $data);
}
private function getRichXml($list)
{
$article_count = count($list);
$article_content = "";
foreach ($list as $_item) {
$tmp_description = mb_substr(strip_tags($_item['summary']), 0, 20, "utf-8");
$tmp_pic_url = UrlService::buildPicUrl("book", $_item['main_image']);
$tmp_url = UrlService::buildMUrl("/product/info", ['id' => $_item['id']]);
$article_content .= "
<item>
<Title><![CDATA[{$_item['name']}]]></Title>
<Description><![CDATA[{$tmp_description}]]></Description>
<PicUrl><![CDATA[{$tmp_pic_url}]]></PicUrl>
<Url><![CDATA[{$tmp_url}]]></Url>
</item>";
}
$article_body = "<ArticleCount>%s</ArticleCount>
<Articles>
%s
</Articles>";
return sprintf($article_body, $article_count, $article_content);
}
/**
* 默认回复语
*/
private function defaultTip()
{
$resData = <<<EOT
hello world(:\n
EOT;
return $resData;
}
/**
* 关注默认提示
*/
private function subscribeTips()
{
$resData = <<<EOT
hello world
EOT;
return $resData;
}
public function checkSignature()
{
$signature = $this->request->param('signature', '', 'trim');
$timestamp = $this->request->param('timestamp', '', 'trim');
$nonce = $this->request->param('nonce', '', 'trim');
$token = config('wexin.token');
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr, SORT_STRING);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
if ($tmpStr == $signature) {
return true;
} else {
return false;
}
}
}
二,curl方法
<?php /** * Http 请求类 */ class Http { /** * 发送一个POST请求 * @param string $url 请求URL * @param array $params 请求参数 * @param array $options 扩展参数 * @return mixed|string */ public static function post($url, $params = [], $options = []) { $req = self::sendRequest($url, $params, 'POST', $options); return $req['ret'] ? $req['msg'] : ''; } /** * 发送一个GET请求 * @param string $url 请求URL * @param array $params 请求参数 * @param array $options 扩展参数 * @return mixed|string */ public static function get($url, $params = [], $options = []) { $req = self::sendRequest($url, $params, 'GET', $options); return $req['ret'] ? $req['msg'] : ''; } public static function getDouyinShare($url,$params=array(),$header=array("Content-Type:application/html")){ if (empty($url)) { return false; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 0);//设置header curl_setopt($ch, CURLOPT_TIMEOUT, 50); curl_setopt($ch, CURLOPT_USERAGENT, 'curl'); //curl_setopt($ch, CURLOPT_REFERER,_REFERER_); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HTTPHEADER,$header); //curl_setopt($ch, CURLOPT_POST, 1);//post提交方式 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书下同 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // if(!empty($params)){ curl_setopt($ch, CURLOPT_POST, true); // $param=''; // foreach ($params as $key=>$value){ // $param.="&{$key}={$value}"; // } curl_setopt($ch, CURLOPT_POSTFIELDS, $params); } $r = curl_exec($ch); if (curl_errno($ch)) { $message = $params ? ( is_string( $params ) ? $params : http_build_query( $params ) ) : ''; \Think\Log::write( '外部请求错误:'.curl_error($ch).',url:'.$url.',params:'.$message ); } curl_close($ch); return $r; } /** * CURL发送Request请求,含POST和REQUEST * @param string $url 请求的链接 * @param mixed $params 传递的参数 * @param string $method 请求的方法 * @param mixed $options CURL的参数 * @return array */ public static function sendRequest($url, $params = [], $method = 'POST', $options = []) { $method = strtoupper($method); $protocol = substr($url, 0, 5); $query_string = is_array($params) ? http_build_query($params) : $params; $ch = curl_init(); $defaults = []; if ('GET' == $method) { $geturl = $query_string ? $url . (stripos($url, "?") !== false ? "&" : "?") . $query_string : $url; $defaults[CURLOPT_URL] = $geturl; } else { $defaults[CURLOPT_URL] = $url; if ($method == 'POST') { $defaults[CURLOPT_POST] = 1; } else { $defaults[CURLOPT_CUSTOMREQUEST] = $method; } $defaults[CURLOPT_POSTFIELDS] = $params; } $defaults[CURLOPT_HEADER] = false; $defaults[CURLOPT_USERAGENT] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.98 Safari/537.36"; $defaults[CURLOPT_FOLLOWLOCATION] = true; $defaults[CURLOPT_RETURNTRANSFER] = true; $defaults[CURLOPT_CONNECTTIMEOUT] = 3; $defaults[CURLOPT_TIMEOUT] = 3; // disable 100-continue curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); if ('https' == $protocol) { $defaults[CURLOPT_SSL_VERIFYPEER] = false; $defaults[CURLOPT_SSL_VERIFYHOST] = false; } curl_setopt_array($ch, (array)$options + $defaults); $ret = curl_exec($ch); $err = curl_error($ch); if (false === $ret || !empty($err)) { $errno = curl_errno($ch); $info = curl_getinfo($ch); curl_close($ch); return [ 'ret' => false, 'errno' => $errno, 'msg' => $err, 'info' => $info, ]; } curl_close($ch); return [ 'ret' => true, 'msg' => $ret, ]; } /** * 异步发送一个请求 * @param string $url 请求的链接 * @param mixed $params 请求的参数 * @param string $method 请求的方法 * @return boolean TRUE */ public static function sendAsyncRequest($url, $params = [], $method = 'POST') { $method = strtoupper($method); $method = $method == 'POST' ? 'POST' : 'GET'; //构造传递的参数 if (is_array($params)) { $post_params = []; foreach ($params as $k => &$v) { if (is_array($v)) { $v = implode(',', $v); } $post_params[] = $k . '=' . urlencode($v); } $post_string = implode('&', $post_params); } else { $post_string = $params; } $parts = parse_url($url); //构造查询的参数 if ($method == 'GET' && $post_string) { $parts['query'] = isset($parts['query']) ? $parts['query'] . '&' . $post_string : $post_string; $post_string = ''; } $parts['query'] = isset($parts['query']) && $parts['query'] ? '?' . $parts['query'] : ''; //发送socket请求,获得连接句柄 $fp = fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80, $errno, $errstr, 3); if (!$fp) { return false; } //设置超时时间 stream_set_timeout($fp, 3); $out = "{$method} {$parts['path']}{$parts['query']} HTTP/1.1\r\n"; $out .= "Host: {$parts['host']}\r\n"; $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; $out .= "Content-Length: " . strlen($post_string) . "\r\n"; $out .= "Connection: Close\r\n\r\n"; if ($post_string !== '') { $out .= $post_string; } fwrite($fp, $out); //不用关心服务器返回结果 //echo fread($fp, 1024); fclose($fp); return true; } /** * 发送文件到客户端 * @param string $file * @param bool $delaftersend * @param bool $exitaftersend */ public static function sendToBrowser($file, $delaftersend = true, $exitaftersend = true) { if (file_exists($file) && is_readable($file)) { header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment;filename = ' . basename($file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check = 0, pre-check = 0'); header('Pragma: public'); header('Content-Length: ' . filesize($file)); ob_clean(); flush(); readfile($file); if ($delaftersend) { unlink($file); } if ($exitaftersend) { exit; } } } }
添加商品