本节口主要难题是body体的构造,下面是公共配置文件代码,命名为wxBase.php,代码如下:
<?php
//#微信基础信息
$wxMerchantId = "商户号"; //商户号
$wxMerchantApiCertificate = __DIR__ . "/cert/apiclient_cert.pem"; //商户证书
$wxMerchantApiPrivateKey = __DIR__ . "/cert/apiclient_key.pem"; //商户私钥
$wxApiV3Key = "微信API v3密钥"; //微信API v3密钥
$wxApiSerialNo = "商户API证书序列号"; //商户API证书序列号
######微信 API V3构造签名流程#######
/**
* 生成签名
* @param string $method 请求方法 POST 或者GET
* @param string $url 请求URL
* @param string $request 请求中的请求报文主体
* @param $wxMerchantId商户号
* @param $certKey商户私钥
* @param $wxApiSerialNo商户API证书序列号
* @return string
*/
function RequestSign($method = "POST", $url = "", $request = "", $wxMerchantId, $certKey, $wxApiSerialNo)
{
#截取获取当前请求地址【去除域名】
$url_parts = parse_url($url);
$path = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
#获取当前时间戳
$timeStamp = time();
#生成一个随机字符串
$nonceStr = getNonceStr();
#构造签名串
$requestSign = sprintf("%s\n%s\n%s\n%s\n%s\n", $method, $path, $timeStamp, $nonceStr, $request);
#计算计算签名值
$sign = calculateSignatureValue($requestSign, $certKey);
#设置HTTP头获取Authorization
$token = createToken($wxMerchantId, $nonceStr, $timeStamp, $wxApiSerialNo, $sign);
#返回
return $token;
}
/**
* 计算签名值
* @param $requestSign
* @param $certKey
* @return string
* 使用商户私钥对待签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码得到签名值
*/
function calculateSignatureValue($requestSign, $certKey)
{
$certKey = file_get_contents($certKey);
openssl_sign($requestSign, $raw_sign, $certKey, 'sha256WithRSAEncryption');
$sign = base64_encode($raw_sign);
return $sign;
}
/**
* 获取token
* @param $merchant_id
* @param $nonce
* @param $timestamp
* @param $serial_no
* @param $sign
* @return string
*/
function createToken($merchant_id, $nonce, $timestamp, $serial_no, $sign)
{
$schema = 'WECHATPAY2-SHA256-RSA2048';
$token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
$merchant_id, $nonce, $timestamp, $serial_no, $sign);
return $token;
}
/**
* 产生随机字符串,不长于32位
* @param int $length
* @return string
*/
function getNonceStr($length = 32)
{
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
/**
* POST发送图片数据源
* @param $url
* @param $data
* @param array $header
* @param string $referer
* @param int $timeout
* @return mixed
*/
function curlPostToImage($url, $data, $header = array(), $referer = '', $timeout = 30)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
//避免https 的ssl验证
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSLVERSION, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
// 模拟来源
curl_setopt($ch, CURLOPT_REFERER, $referer);
$response = curl_exec($ch);
if ($error = curl_error($ch)) {
die($error);
}
curl_close($ch);
//json转数组
$result = json_decode($response,true);
//返回
return $result;
}
/ 然后是调用文件代码,我们先提前创建好一个images的文件夹,并给777权限,用来存放图片,代码如下:
<?php
#引入微信公共配置文件
require __DIR__ . "/wxBase.php";
#头部响应设置
header('Access-Control-Allow-Origin:*');
// 响应类型
header('Access-Control-Allow-Methods:GET');
// 响应头设置
header('Access-Control-Allow-Headers:x-requested-with,content-type');
header('Content-Type:application/json; charset=utf-8');
#获取上传图片
$file = $_FILES["file"];
#判断上传的是否为图片格式
if ((($_FILES["file"]["type"] != "image/gif")
&& ($_FILES["file"]["type"] != "image/jpeg")
&& ($_FILES["file"]["type"] != "image/jpg")
&& ($_FILES["file"]["type"] != "image/pjpeg")
&& ($_FILES["file"]["type"] != "image/x-png")
&& ($_FILES["file"]["type"] != "image/png"))
) {
$json = json_encode(array(
'status' => '-1',
'msg' => "请上传图片"
));
echo($json);
exit();
}
#重新设置文件名
$fileType = str_replace("image/", "", $_FILES["file"]["type"]);
$saveName = time() . rand(1, 1000);
$fileName = $saveName . "." . $fileType;
#保存图片
move_uploaded_file($_FILES["file"]["tmp_name"], "images/" . $fileName);
#拼接当前地址
$src = "images/" . $fileName;
$imageUrl = __DIR__ . "/images/" . $fileName;
#请求地址
$url = "https://api.mch.weixin.qq.com/v3/marketing/favor/media/image-upload";
#请求参数
$params = array(
"filename" => $fileName, //文件名
'sha256' => hash_file('sha256', $imageUrl) //图片文件的二进制内容进行sha256
);
#获取authorization
$authorization = RequestSign("POST", $url, json_encode($params), $wxMerchantId, $wxMerchantApiPrivateKey, $wxApiSerialNo);
#组合body请求体
$boundary = uniqid(); //分割符号
$boundaryStr = "--{$boundary}\r\n";
$out = $boundaryStr;
$out .= 'Content-Disposition: form-data; name="meta"' . "\r\n";
$out .= 'Content-Type: application/json' . "\r\n";
$out .= "\r\n";
$out .= json_encode($params) . "\r\n";
$out .= $boundaryStr;
$out .= 'Content-Disposition: form-data; name="file"; filename="' . $params['filename'] . '"' . "\r\n";
$out .= 'Content-Type: ' . $fileType . ';' . "\r\n";
$out .= "\r\n";
$out .= file_get_contents($imageUrl) . "\r\n";
$out .= "--{$boundary}--\r\n";
#组合请求头
$header[] = 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36';
$header[] = 'Accept:application/json';
$header[] = 'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $authorization;
$header[] = 'Content-Type:multipart/form-data;boundary=' . $boundary;
#请求发送文件
$result = curlPostToImage($url, $out, $header);
#删除本地图片
unlink($imageUrl);
#判断是否成功
if (!isset($result["media_url"])) {
$json = json_encode(array(
'status' => '-1',
'msg' => "上传失败"
));
echo($json);
exit();
}
#返回请求结果
$json = json_encode(array(
'status' => '1',
'msg' => $result["media_url"]
));
echo($json);
exit();