由于现在手头的项目中有一个上传证件照认证的功能(手机端),之前的思路是直接点击上传,然后直接将图片上传到服务器去,这篇文章有讲到(http://www.cnblogs.com/it-cen/p/4535219.html),但在微信里打开网页去上传,速度并不快,而且,假如我上传一张2M大的图片,也没有对其进行压缩处理,这样很影响上传和下载的速度。

  所以,我这里借助微信JSSDK的图像接口对其进行开发实现图片上传的功能,为何我选择此接口?第一,目前的项目是在微信中打开的网页,利用此接口,性能肯定是好一点的啦,毕竟是微信自己的东西;第二,用此接口,开发效率更高嘛;第三,最重要的一点,就是它能对图片进行压缩,假如一张2M的图片,通过微信图片上传接口可以将图片压缩成几百K的大小,这对网站的性能是很有帮助的。

  一、我的思路是:

先调用“拍照或从手机相册选择图片接口”—>选择成功图片后—>调用“上传图片接口”—>上传成功后(也就是图片上传到了微信服务器上)—>调用“下载图片接口”—>将图片下载到自己的服务器存储。

  二、JSSDK的使用步骤

  1、概述 

  微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。

  通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

  2、使用步骤

  步骤一:绑定域名

  先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

  备注:登录后可在“开发者中心”查看对应的接口权限。

  步骤二:引入JS文件

  在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js

  步骤三:通过config接口注入权限验证配置

  所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用)

 wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名,见附录1
jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

  步骤四:通过ready接口处理成功验证

  

 wx.ready(function(){

     // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});

  步骤五:通过error接口处理失败验证

 wx.error(function(res){

     // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。

 });

  接口调用说明

  所有接口通过wx对象(也可使用jWeixin对象)来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:

  1. success:接口调用成功时执行的回调函数。
  2. fail:接口调用失败时执行的回调函数。
  3. complete:接口调用完成时执行的回调函数,无论成功或失败都会执行。
  4. cancel:用户点击取消时的回调函数,仅部分有用户取消操作的api才会用到。
  5. trigger: 监听Menu中的按钮点击时触发的方法,该方法仅支持Menu中的相关接口。

  备注:不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回。

  以上几个函数都带有一个参数,类型为对象,其中除了每个接口本身返回的数据之外,还有一个通用属性errMsg,其值格式如下:

    1. 调用成功时:"xxx:ok" ,其中xxx为调用的接口名
    2. 用户取消时:"xxx:cancel",其中xxx为调用的接口名
    3. 调用失败时:其值为具体错误信息

  

  三、开发及代码分析详解(用的是CI框架,只要是MVC模式都可以)

  1、先在服务器端取到:公众号的唯一标识appId、生成签名的时间戳timestamp、生成签名的随机串nonceStr、签名signature。

  wx_upload.php

 <?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()));
}

图片上传控制器

  WeixinModel.php

 <?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&timestamp=$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、timestamp、signature模型

  这里要补充一些 JS-SDK使用权限签名算法 的思路和注意点(这里我直接复制官网文档给大家看看)

    jsapi_ticket

    生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信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&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value

    步骤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')));
} }

从微信服务器下载图片到本地存储

  WeixinModel.php

 //从微信服务器端下载图片到本地服务器
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')));
} }
} ?>

wx_upload.php

 <?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&timestamp=$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;
} } ?>

WeixinModel.php

 <html>
<head> </head>
<body>
<button id="uploadImage">点击上传图片</button>
<script>
$(function(){
$.util.wxMenuImage('{$wxJsApi|default:""}')
});
</script>
</body>
</html>

uploadImg.tpl

 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) {
//存储到服务器成功后的处理
//
}
});
}

uploadImg.js

  代码中有些方法没有贴出来,大家要是想看看,可以到http://www.cnblogs.com/it-cen/p/4535219.html这篇博文去看。

  本次讲解就到此,这篇博文是给对微信接口开发有兴趣的朋友参考,如果你是高手,完全可以绕道。

  如果此博文中有哪里讲得让人难以理解,欢迎留言交流,若有讲解错的地方欢迎指出。

  如果您觉得您能在此博文学到了新知识,请为我顶一个,如文章中有解释错的地方,欢迎指出。

  互相学习,共同进步!

微信JS-SDK之图像接口开发详解的更多相关文章

  1. 微信 JS SDK 的 chooseImage 接口在部分安卓机上容易造成页面刷新

    该问题的症状是,当调用 chooseImage 接口并选择拍照,选择照片确定之后,然后从相机返回后,当前web页面就刷新了一次,导致拍照的图片无法选择上传:但是如果直接从相册中选择图片,则不会出现这个 ...

  2. 基于H5的微信支付开发详解

    这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...

  3. ****基于H5的微信支付开发详解[转]

    这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...

  4. ***PHP基于H5的微信支付开发详解(CI框架)

    这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...

  5. 实战微信JS SDK开发:贺卡制作与播放(1)

    前段时间忙于CanTK 2.0的开发,所以博客一直没有更新.CanTK 2.0主要增强了游戏和富媒体的开发,现在编码和测试基本完成了,等文档完成了再正式发布,里面有不少激动人心的功能,等发布时再一一细 ...

  6. 微信JS SDK接入的几点注意事项

    微信JS SDK接入,主要可以先参考官网说明文档,总结起来有几个步骤: 1.绑定域名:先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”.备注:登录后可在“开发者中心”查看对 ...

  7. 微信js sdk上传多张图片

    微信js sdk上传多张图片,微信上传多张图片 该案例已tp3.2商城为例 直接上代码: php代码: public function ind(){ $appid="111111111111 ...

  8. javaCV开发详解之4:转流器实现(也可作为本地收流器、推流器,新增添加图片及文字水印,视频图像帧保存),实现rtsp/rtmp/本地文件转发到rtmp流媒体服务器(基于javaCV-FFMPEG)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

  9. EasyPR--开发详解(6)SVM开发详解

    在前面的几篇文章中,我们介绍了EasyPR中车牌定位模块的相关内容.本文开始分析车牌定位模块后续步骤的车牌判断模块.车牌判断模块是EasyPR中的基于机器学习模型的一个模块,这个模型就是作者前文中从机 ...

随机推荐

  1. android textview空格占位符以及一些其他占位符汇总

    == 普通的英文半角空格   ==   ==   == no-break space (普通的英文半角空格但不换行)   == 中文全角空格 (一个中文宽度)   ==   == en空格 (半个中文 ...

  2. How to Tell Science Stories with Maps

    Reported Features How to Tell Science Stories with Maps August 25, 2015   Greg Miller This map, part ...

  3. java.lang.System.arraycopy() 与java.util.Arrays.copyOf()的区别

    java.lang.System.arraycopy() 与java.util.Arrays.copyOf()的区别 一.java.lang.System.arraycopy() 该方法的声明: /* ...

  4. 知名网站内部资料:WEB页面内容优化管理与性能技巧

    回想一下,以前我们不得不花费大量时间去优化页面内容(图片.CSS等等),如今用户有更快速的互联网链接,我们似乎能够使用更大的图像或更大的闪 存文件,里面包含的有视频或者图片.然而,随着移动开发的兴起, ...

  5. 悲催的IE6 七宗罪大吐槽(带解决方法)第一部分

    一.奇数宽高 悲剧的IE6啊,为何有如此多bug,但用户市场又那么大,真让我们搞网站的纠结.今天就遇到了一个非常奇怪但又很细节的一个bug,一个外部的相对定位div,内部一个绝对定位的div(righ ...

  6. [大数据测试]ETL测试或数据仓库测试入门

    转载自: http://blog.csdn.net/zhusongziye/article/details/78633934 概述 在我们学习ETL测试之前,先了解下business intellig ...

  7. PHP面向对象__set(赋值方法)

    //类Ren里面的变量都是私有的,子类$r里面直接取是取不到的,正常给变量赋值的方法为$r->__set("age",20);,但是可以直接写成$r->age = 20 ...

  8. 微信小程序开发教程(七)逻辑层——.js详解

    逻辑层,是事务逻辑处理的地方.对于小程序而言,逻辑层就是.js脚本文件的集合.逻辑层将数据进行处理后发送给视图层,同时接收视图层的事件反馈. 微信小程序开发框架的逻辑层是由JavaScript编写.在 ...

  9. kafka入门(2)- 环境部署

    部署Zookeeper(单机/集群) 1.下载安装文件: http://mirror.bit.edu.cn/apache/zookeeper/ 2.解压文件(本文解压到 D:\zookeeper-3. ...

  10. mysql 时区设置

    ##查看当前时间 select curtime(); ##查看当前时区设置 show variables like "%time_zone%"; ##修改mysql全局时区为北京时 ...