여기서는 WeChat JSSDK의 이미지 인터페이스를 사용하여 이미지 업로드 기능을 구현하도록 개발했습니다. 왜 이 인터페이스를 선택했나요? 첫째, 현재 프로젝트는 WeChat에서 열리는 웹페이지입니다. 결국에는 WeChat 자체의 성능이 향상됩니다. 둘째, 이 인터페이스를 사용하면 개발 효율성이 높아집니다. 중요한 점은 이미지를 압축할 수 있다는 점입니다. 예를 들어 2M 이미지를 사용하면 WeChat 이미지 업로드 인터페이스를 통해 이미지를 수백 K 크기로 압축할 수 있어 웹사이트 성능에 매우 도움이 됩니다.
1. 내 아이디어는 다음과 같습니다.
먼저 "사진 또는 휴대폰 앨범 인터페이스에서 사진 선택"을 호출합니다. -> 성공한 사진을 선택한 후 -> 인터페이스' -> 업로드가 성공한 후(즉, 이미지가 WeChat 서버에 업로드됨) -> "이미지 다운로드 인터페이스" 호출 -> 저장을 위해 이미지를 자체 서버에 다운로드합니다.
2. JSSDK 사용 단계
1. 개요
WeChat JS-SDK는 WeChat 웹 기반의 웹 개발자를 위해 WeChat 공개 플랫폼에서 제공됩니다. 개발 툴킷.
WeChat JS-SDK를 사용하면 웹 개발자는 WeChat을 사용하여 사진 촬영, 사진 선택, 음성 선택, 위치 등 휴대폰 시스템의 기능을 효율적으로 사용하는 동시에 WeChat을 직접 사용할 수 있습니다. 공유, 스캔, 쿠폰 등. 결제와 같은 WeChat의 고유한 기능은 WeChat 사용자에게 더 나은 웹 경험을 제공합니다.
2. 사용 단계
1단계: 도메인 이름 바인딩
먼저 WeChat 공개 플랫폼에 로그인하고 "공식 계정 설정"의 "기능 설정"으로 들어갑니다. "JS 인터페이스 보안" 도메인 이름을 입력합니다.
참고: 로그인 후 "개발자 센터"에서 해당 인터페이스 권한을 확인할 수 있습니다.
2단계: JS 파일 소개
JS 인터페이스를 호출해야 하는 페이지에 다음 JS 파일을 소개합니다(https 지원): http://res.wx.qq.com /open/js /jweixin-1.0.0.js
3단계: 구성 인터페이스를 통해 권한 확인 구성 주입
JS-SDK를 사용해야 하는 모든 페이지는 먼저 구성 정보를 주입해야 하며, 그렇지 않으면 호출되지 않습니다. (URL은 한 번만 호출하면 되고 URL이 변경될 때마다 URL을 변경하는 SPA 웹 앱을 호출할 수 있는 것과 같습니다.)
wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名,见附录1 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });
wx.ready(function(){ // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。 });
wx.error(function(res){ // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 });
모든 인터페이스는 wx 개체를 통해 호출됩니다(jWeixin 개체도 사용할 수 있음). , 매개변수는 객체입니다. 단, 각 인터페이스 자체는 전달되어야 합니다. 매개변수 외에도 다음과 같은 일반 매개변수가 있습니다.
success: 콜백 함수가 실행될 때 실행됩니다. 인터페이스 호출이 성공했습니다.
fail: 인터페이스 호출이 실패했을 때 실행되는 콜백 함수입니다.
완료: 성공, 실패에 관계없이 인터페이스 호출이 완료되면 실행되는 콜백 함수입니다.
cancel: 사용자가 취소를 클릭할 때의 콜백 함수는 사용자가 작업을 취소하는 경우에만 사용됩니다.
trigger: 메뉴의 버튼을 클릭했을 때 실행되는 메서드입니다. 이 메서드는 메뉴의 관련 인터페이스만 지원합니다.
참고: 이 공유의 콘텐츠를 수정하기 위해 트리거에서 ajax 비동기 요청을 사용하지 마십시오. 클라이언트 공유 작업은 동기 작업이고 ajax를 사용하는 반환 패킷은 지금은 돌아올 수 없습니다.
위 함수에는 모두 객체 유형의 매개변수가 있습니다. 각 인터페이스 자체에서 반환되는 데이터 외에도 값 형식이 다음과 같은 일반 속성 errMsg도 있습니다.
호출이 성공한 경우: "xxx:ok", 여기서 xxx는 호출된 인터페이스 이름입니다.
사용자가 취소한 경우: "xxx: cancel" , 여기서 xxx는 호출된 인터페이스의 이름입니다.
호출이 실패하는 경우: 해당 값은 특정 오류 메시지입니다
3. 개발 및 코드 분석에 대한 자세한 설명(CI 프레임워크 사용, MVC 모드인 경우)
1. 먼저 서버측에서 획득: 고유 식별자 appId 공식 계정과 생성된 서명의 타임스탬프를 사용하여 서명된 임의 문자열 nonceStr 및 서명 서명을 생성합니다.
<?php class wx_upload extends xx_Controller { public function __construct() { parent::__construct(); } public function wxUploadImg() { //在模板里引入jssdk的js文件 $this->addResLink('http://res.wx.qq.com/open/js/jweixin-1.0.0.js'); //取得:公众号的唯一标识appId、生成签名的时间戳timestamp、生成签名的随机串nonceStr、签名signature这些值,并以json形式传到模板页面 $this->smartyData['wxJsApi'] = json_encode(array('signPackage' => $this->model->weixin->signPackage())); }
이미지 업로드 컨트롤러
<?php class WxModel extends ModelBase{ public $appId; public $appSecret; public $token; public function __construct() { parent::__construct(); //审核通过的移动应用所给的AppID和AppSecret $this->appId = 'wx0000000000000000'; $this->appSecret = '00000000000000000000000000000'; $this->token = '00000000'; } /** * 获取jssdk所需参数的所有值 * @return array */ public function signPackage() { $protocol = (!empty($_SERVER['HTTPS'] && $_SERVER['HTTPS'] == 'off' || $_SERVER['port'] == 443)) ? 'https://' : 'http://'; //当前网页的URL $url = "$protocol$_SERVER['host']$_SERVER['REQUEST_URI']"; //生成签名的时间戳 $timestamp = time(); //生成签名的随机串 $nonceStr = $this->createNonceStr(); //获取公众号用于调用微信JS接口的临时票据 $jsApiTicket = $this->getJsApiTicket(); //对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后, //使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串$str。 //这里需要注意的是所有参数名均为小写字符 $str = "jsapi_ticket=$jsApiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url"; //对$str进行sha1签名,得到signature: $signature = sha1($str); $signPackage = array( "appId" => $this->AppId, "nonceStr" => $nonceStr, "timestamp" => $timestamp, "url" => $url, "signature" => $signature, "rawString" => $string ); return $signPackage; } /** * 创建签名的随机字符串 * @param int $length 字符串长度 * @return string 随机字符串 */ private function createNonceStr($length == 16) { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $str = ''; for ($i=0; $i < $length; $i++) { $str .= substr(mt_rand(0, strlen($chars)), 1); } return $str; } /** * 获取公众号用于调用微信JS接口的临时票据 * @return string */ private function getJsApiTicket() { //先查看redis里是否存了jsapi_ticket此值,假如有,就直接返回 $jsApiTicket = $this->library->redisCache->get('weixin:ticket'); if (!$jsApiTicket) { //先获取access_token(公众号的全局唯一票据) $accessToken = $this->getApiToken(); //通过access_token 采用http GET方式请求获得jsapi_ticket $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$accessToken&type=jsapi"); //得到了jsapi_ticket $jsApiTicket = $result['ticket']; //将jsapi_ticket缓存到redis里面,下次就不用再请求去取了 $expire = max(1, intval($result['expire']) - 60); $this->library->redisCache->set('weixin:ticket', $jsApiTicket, $expire); } return $jsApiTicket; } /** * 获取众号的全局唯一票据access_token * @param boolean $forceRefresh 是否强制刷新 * @return string 返回access_token */ private function getApiToken($forceRefresh = false) { //先查看redis是否存了accessToken,如果有了,就不用再去微信server去请求了(提高效率) $accessToken = $this->library->redisCache->get('weixin:accessToken'); //强制刷新accessToken或者accessToken为空时就去请求accessToken if ($forceRefresh || empty($accessToken)) { //请求得到accessToken $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}"); $accessToken = $result['access_token']; $expire = max(1, intval($result['expire']) - 60); //将其存进redis里面去 $this->library->redisCache->set('weixin:accessToken', $accessToken, $expire); } return $accessToken; }
appId, nonceStr, 타임스탬프, 서명 모델 가져오기
다음은 JS-SDK에서 권한 서명 알고리즘 사용에 대한 몇 가지 아이디어와 참고 사항입니다( 여기서는 모두가 볼 수 있도록 공식 웹사이트 문서를 직접 복사합니다.)
jsapi_ticket
서명을 생성하기 전에 먼저 jsapi_ticket이 WeChat을 호출하기 위해 공용 계정에서 사용하는 임시 티켓이라는 점을 이해해야 합니다. JS 인터페이스. 일반적인 상황에서 jsapi_ticket의 유효 기간은 7200초이며 access_token을 통해 얻습니다. jsapi_ticket을 얻기 위한 API 호출 수는 매우 제한되어 있으므로 jsapi_ticket을 자주 새로 고치면 API 호출이 제한되고 개발자는 자체 서비스에서 jsapi_ticket을 전역적으로 캐시해야 합니다.
1. access_token을 얻습니다(7200초 동안 유효하며 개발자는 자신의 서비스에서 전역적으로 access_token을 캐시해야 합니다)
2. 첫 번째 단계에서 얻은 access_token을 사용하여 http GET 메서드를 사용하여 jsapi_ticket을 요청합니다( 유효 기간은 7200초입니다. 개발자는 자체 서비스에서 jsapi_ticket을 전역적으로 캐시해야 합니다.
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
成功返回如下JSON:
{ "errcode":0, "errmsg":"ok", "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA", "expires_in":7200 }
获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。
签名算法
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
即signature=sha1(string1)。 示例:
noncestr=Wm3WZYTPz0wzccnW
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
timestamp=1414587457
url=http://mp.weixin.qq.com?params=value
步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://www.php.cn/
步骤2. 对string1进行sha1签名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事项
1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
2.签名用的url必须是调用JS接口页面的完整URL。
3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
2、取到我们所需要的值后,就在js文件里面开始使用了
uploadImg.tpl
<script> $(function(){ $.util.wxMenuImage('{$wxJsApi|default:""}') }); </script>
uploadImg.js
if(typeof($util)=='undefined')$util={}; $.util.wxMenuImage = function(json) { if (json.length == 0) return; //解析json变成js对象 wxJsApi = JSON.parse(json); //通过config接口注入权限验证配置 wx.config({ debug: false, //开启调试模式,调用的所有api的返回值会在客户端alert出来 appId: wxJsApi.signPackage.appId, //公众号的唯一标识 timestamp: wxJsApi.signPackage.timestamp, //生成签名的时间戳 nonceStr: wxJsApi.signPackage.nonceStr, //生成签名的随机串 signature: wxJsApi.signPackage.signature, //签名 jsApiList: ['chooseImage', 'uploadImage'] //需要使用的JS接口列表 这里我用了选择图片和上传图片接口 }); //通过ready接口处理成功验证,config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后 wx.ready(function(){ //得到上传图片按钮 document.querySelector('#uploadImage').onclick = function() { var images = {localId:[],serverId:[]}; //调用 拍照或从手机相册中选图接口 wx.chooseImage({ success: function(res) { if (res.localIds.length != 1) { alert('只能上传一张图片'); return; } //返回选定照片的本地ID列表 iamges.localId = res.localIds; images.serverId = []; //上传图片函数 function upload() { //调用上传图片接口 wx.uploadImage({ localId: images.localId[0], // 需要上传的图片的本地ID,由chooseImage接口获得 isShowProcess: 1, // 默认为1,显示进度提示 success: function(res) { //返回图片的服务器端ID res.serverId,然后调用wxImgCallback函数进行下载图片操作 wxImgCallback(res.serverId); }, fail: function(res) { alert('上传失败'); } }); } upload(); } }); } }); } function wxImgCallback(serverId) { //将serverId传给wx_upload.php的upload方法 var url = 'wx_upload/upload/'+serverId; $.getJSON(url, function(data){ if (data.code == 0) { alert(data.msg); } else if (data.code == 1) { //存储到服务器成功后的处理 // } }); } 图片选择和图片上传接口调用
图片选择和图片上传接口调用
3、图片上传完成后会返回一个serverId,然后通过这个来下载图片到本地服务器
这里先补充下如何调用下载图片接口(我直接复制官方文档的说明了)
公众号可调用本接口来获取多媒体文件。请注意,视频文件不支持下载,调用该接口需http协议。
接口调用请求说明
http请求方式: GET http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
参数说明
参数 | 是否必须 | 说明 |
---|---|---|
access_token | 是 | 调用接口凭证 |
media_id | 是 | 媒体文件ID |
返回说明
正确情况下的返回HTTP头如下:
HTTP/1.1 200 OK Connection: close Content-Type: image/jpeg Content-disposition: attachment; filename="MEDIA_ID.jpg" Date: Sun, 06 Jan 2013 10:20:18 GMT Cache-Control: no-cache, must-revalidate Content-Length: 339721 curl -G "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID"
错误情况下的返回JSON数据包示例如下(示例为无效媒体ID错误)::
{"errcode":40007,"errmsg":"invalid media_id"} 接下来看自己写的代码 wx_upload.php
/*********************图片下载到本地服务器****************************************/ //从微信服务器读取图片,然后下载到本地服务器 public function upload($media_id) { //图片文件名 $fileName = md5($this->wxId."/$media_id"); //调用下载图片接口,返回路径 $path = $this->weixin->wxDownImg($media_id, sys_get_temp_dir()."$fileName"); if ($path != false) { //将图片的路径插入数据库去存储 if ($this->model->weixin->updateByWxid($this->wxId, array('img_path'=>$path))) { $this->output->_display(json_encode( array( 'code'=>1, 'msg'=>'上传成功', 'fileUrl' =>$path; ) )); } else { $this->output->_display(json_encode2(array('code'=>0,'msg' => '上传失败','err'=>'1'))); } } else { $this->output->_display(json_encode2(array('code'=>0,'msg' => '上传失败','err'=>'2'))); } }
从微信服务器下载图片到本地存储
//从微信服务器端下载图片到本地服务器 public function wxDownImg($media_id, $path) { //调用 多媒体文件下载接口 $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token={$this->model->weixin->_getApiToken()}&media_id=$media_id"; //用curl请求,返回文件资源和curl句柄的信息 $info = $this->curl_request($url); //文件类型 $types = array('image/bmp'=>'.bmp', 'image/gif'=>'.gif', 'image/jpeg'=>'.jpg', 'image/png'=>'.png'); //判断响应首部里的的content-type的值是否是这四种图片类型 if (isset($types[$info['header']['content_type']])) { //文件的uri $path = $path.$types[$info['header']['content_type']]; } else { return false; } //将资源写入文件里 if ($this->saveFile($path, $info['body'])) { //将文件保存在本地目录 $imgPath = rtrim(base_url(), '/').'/img'.date('Ymd').'/'.md5($this->controller->wxId.$media_id).$types[$info['header'['content_type']]]; if (!is_dir($imgPath)) { if(mkdir($imgPath)) { if (false !== rename($path, $imgPath) { return $imgPath; } } } return $path; } return false; } /** * curl请求资源 * @param string $url 请求url * @return array */ private function curl_request($url = '') { if ($url == '') return; $ch = curl_init(); //这里返回响应报文时,只要body的内容,其他的都不要 curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_NOBODY, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $package = curl_exec($ch); //获取curl连接句柄的信息 $httpInfo = curl_getinfo($ch); curl_close($ch); $info = array_merge(array($package), array($httpInfo)); return $info; } /** * 将资源写入文件 * @param string 资源uri * @param source 资源 * @return boolean */ private function saveFile($path, $fileContent) { $fp = fopen($path, 'w'); if (false !== $localFile) { if (false !== fwrite($fp, $fileContent)) { fclose($fp); return true; } } return false; }
从微信服务器下载图片到本地存储接口
到这里,已经完成了:
先调用“拍照或从手机相册选择图片接口”—>选择成功图片后—>调用“上传图片接口”—>上传成功后(也就是图片上传到了微信服务器上)—>调用“下载图片接口”—>将图片下载到自己的服务器存储。
这一思路的实现。我们用到了微信的选择图片接口、上传图片接口和下载媒体资源接口。
下面我附上这一接口开发的全部代码:
<?php class wx_upload extends xx_Controller { public function __construct() { parent::__construct(); } public function wxUploadImg() { //在模板里引入jssdk的js文件 $this->addResLink('http://res.wx.qq.com/open/js/jweixin-1.0.0.js'); //取得:公众号的唯一标识appId、生成签名的时间戳timestamp、生成签名的随机串nonceStr、签名signature这些值,并以json形式传到模板页面 $this->smartyData['wxJsApi'] = json_encode(array('signPackage' => $this->model->weixin->signPackage())); } /*********************图片下载到本地服务器****************************************/ //从微信服务器读取图片,然后下载到本地服务器 public function upload($media_id) { //图片文件名 $fileName = md5($this->wxId."/$media_id"); //调用下载图片接口,返回路径 $path = $this->weixin->wxDownImg($media_id, sys_get_temp_dir()."$fileName"); if ($path != false) { //将图片的路径插入数据库去存储 if ($this->model->weixin->updateByWxid($this->wxId, array('img_path'=>$path))) { $this->output->_display(json_encode( array( 'code'=>1, 'msg'=>'上传成功', 'fileUrl' =>$path; ) )); } else { $this->output->_display(json_encode2(array('code'=>0,'msg' => '上传失败','err'=>'1'))); } } else { $this->output->_display(json_encode2(array('code'=>0,'msg' => '上传失败','err'=>'2'))); } } } ?>
<?php class WxModel extends ModelBase{ public $appId; public $appSecret; public $token; public function __construct() { parent::__construct(); //审核通过的移动应用所给的AppID和AppSecret $this->appId = 'wx0000000000000000'; $this->appSecret = '00000000000000000000000000000'; $this->token = '00000000'; } /** * 获取jssdk所需参数的所有值 * @return array */ public function signPackage() { $protocol = (!empty($_SERVER['HTTPS'] && $_SERVER['HTTPS'] == 'off' || $_SERVER['port'] == 443)) ? 'https://' : 'http://'; //当前网页的URL $url = "$protocol$_SERVER['host']$_SERVER['REQUEST_URI']"; //生成签名的时间戳 $timestamp = time(); //生成签名的随机串 $nonceStr = $this->createNonceStr(); //获取公众号用于调用微信JS接口的临时票据 $jsApiTicket = $this->getJsApiTicket(); //对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后, //使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串$str。 //这里需要注意的是所有参数名均为小写字符 $str = "jsapi_ticket=$jsApiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url"; //对$str进行sha1签名,得到signature: $signature = sha1($str); $signPackage = array( "appId" => $this->AppId, "nonceStr" => $nonceStr, "timestamp" => $timestamp, "url" => $url, "signature" => $signature, "rawString" => $string ); return $signPackage; } /** * 创建签名的随机字符串 * @param int $length 字符串长度 * @return string 随机字符串 */ private function createNonceStr($length == 16) { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $str = ''; for ($i=0; $i < $length; $i++) { $str .= substr(mt_rand(0, strlen($chars)), 1); } return $str; } /** * 获取公众号用于调用微信JS接口的临时票据 * @return string */ private function getJsApiTicket() { //先查看redis里是否存了jsapi_ticket此值,假如有,就直接返回 $jsApiTicket = $this->library->redisCache->get('weixin:ticket'); if (!$jsApiTicket) { //先获取access_token(公众号的全局唯一票据) $accessToken = $this->getApiToken(); //通过access_token 采用http GET方式请求获得jsapi_ticket $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$accessToken&type=jsapi"); //得到了jsapi_ticket $jsApiTicket = $result['ticket']; //将jsapi_ticket缓存到redis里面,下次就不用再请求去取了 $expire = max(1, intval($result['expire']) - 60); $this->library->redisCache->set('weixin:ticket', $jsApiTicket, $expire); } return $jsApiTicket; } /** * 获取众号的全局唯一票据access_token * @param boolean $forceRefresh 是否强制刷新 * @return string 返回access_token */ private function getApiToken($forceRefresh = false) { //先查看redis是否存了accessToken,如果有了,就不用再去微信server去请求了(提高效率) $accessToken = $this->library->redisCache->get('weixin:accessToken'); //强制刷新accessToken或者accessToken为空时就去请求accessToken if ($forceRefresh || empty($accessToken)) { //请求得到accessToken $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}"); $accessToken = $result['access_token']; $expire = max(1, intval($result['expire']) - 60); //将其存进redis里面去 $this->library->redisCache->set('weixin:accessToken', $accessToken, $expire); } return $accessToken; } //从微信服务器端下载图片到本地服务器 public function wxDownImg($media_id, $path) { //调用 多媒体文件下载接口 $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token={$this->model->weixin->_getApiToken()}&media_id=$media_id"; //用curl请求,返回文件资源和curl句柄的信息 $info = $this->curl_request($url); //文件类型 $types = array('image/bmp'=>'.bmp', 'image/gif'=>'.gif', 'image/jpeg'=>'.jpg', 'image/png'=>'.png'); //判断响应首部里的的content-type的值是否是这四种图片类型 if (isset($types[$info['header']['content_type']])) { //文件的uri $path = $path.$types[$info['header']['content_type']]; } else { return false; } //将资源写入文件里 if ($this->saveFile($path, $info['body'])) { //将文件保存在本地目录 $imgPath = rtrim(base_url(), '/').'/img'.date('Ymd').'/'.md5($this->controller->wxId.$media_id).$types[$info['header'['content_type']]]; if (!is_dir($imgPath)) { if(mkdir($imgPath)) { if (false !== rename($path, $imgPath) { return $imgPath; } } } return $path; } return false; } /** * curl请求资源 * @param string $url 请求url * @return array */ private function curl_request($url = '') { if ($url == '') return; $ch = curl_init(); //这里返回响应报文时,只要body的内容,其他的都不要 curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_NOBODY, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $package = curl_exec($ch); //获取curl连接句柄的信息 $httpInfo = curl_getinfo($ch); curl_close($ch); $info = array_merge(array($package), array($httpInfo)); return $info; } /** * 将资源写入文件 * @param string 资源uri * @param source 资源 * @return boolean */ private function saveFile($path, $fileContent) { $fp = fopen($path, 'w'); if (false !== $localFile) { if (false !== fwrite($fp, $fileContent)) { fclose($fp); return true; } } return false; } } ?>
<html> <head> </head> <body> <button id="uploadImage">点击上传图片</button> <script> $(function(){ $.util.wxMenuImage('{$wxJsApi|default:""}') }); </script> </body> </html>
if(typeof($util)=='undefined')$util={}; $.util.wxMenuImage = function(json) { if (json.length == 0) return; //解析json变成js对象 wxJsApi = JSON.parse(json); //通过config接口注入权限验证配置 wx.config({ debug: false, //开启调试模式,调用的所有api的返回值会在客户端alert出来 appId: wxJsApi.signPackage.appId, //公众号的唯一标识 timestamp: wxJsApi.signPackage.timestamp, //生成签名的时间戳 nonceStr: wxJsApi.signPackage.nonceStr, //生成签名的随机串 signature: wxJsApi.signPackage.signature, //签名 jsApiList: ['chooseImage', 'uploadImage'] //需要使用的JS接口列表 这里我用了选择图片和上传图片接口 }); //通过ready接口处理成功验证,config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后 wx.ready(function(){ //得到上传图片按钮 document.querySelector('#uploadImage').onclick = function() { var images = {localId:[],serverId:[]}; //调用 拍照或从手机相册中选图接口 wx.chooseImage({ success: function(res) { if (res.localIds.length != 1) { alert('只能上传一张图片'); return; } //返回选定照片的本地ID列表 iamges.localId = res.localIds; images.serverId = []; //上传图片函数 function upload() { //调用上传图片接口 wx.uploadImage({ localId: images.localId[0], // 需要上传的图片的本地ID,由chooseImage接口获得 isShowProcess: 1, // 默认为1,显示进度提示 success: function(res) { //返回图片的服务器端ID res.serverId,然后调用wxImgCallback函数进行下载图片操作 wxImgCallback(res.serverId); }, fail: function(res) { alert('上传失败'); } }); } upload(); } }); } }); } function wxImgCallback(serverId) { //将serverId传给wx_upload.php的upload方法 var url = 'wx_upload/upload/'+serverId; $.getJSON(url, function(data){ if (data.code == 0) { alert(data.msg); } else if (data.code == 1) { //存储到服务器成功后的处理 // } }); }
本次讲解就到此,这篇博文是给对微信接口开发有兴趣的朋友参考,如果你是高手,完全可以绕道。
更多微信JS-SDK之图像接口开发相关文章请关注PHP中文网!