场景

在微信服务号中开发上传图片功能

环境

后端 php yii2 前端javscript

遇到的问题

1.https 域 下前端处理base64为图片,苹果不支持。
2.七牛的fech接口很坑,有些数据不能存储,随机性的成功。

思路

1.通过微信的接口,调取手机的拍照和选取相册很方便可以设置选择几张和原图和缩略图,然后上传到微信的服务>器,返回一个media_id发送到后端,通过微信的文件媒体接口获取数据(数据token只存在两个小时),然后通过php
处理成base64位数据,上传到七牛,七牛返回链接存储在本地。
2.前端处理图片到七牛返回发到后端

前端处理

<div class="page-group">
<div class="page">
    <div class="content" style="background-color: white;">
        <img src="/image/distant/distant-view.png" width="100%">
        <div class="distant-click">
            <?php
                if ($model->distant_view) {
                    echo '<img id="distant-click-img" src="'.$model->distant_view.'"  width="100%" alt="" />';
                }else {
                    echo '<img id="distant-click-img" src="/image/distant/distant-click.png"  width="100%" alt="" />';
                }
            ?>
        </div>
        <input type="hidden" id='token' value ="<?php echo $token;?>" name="">
            <div class="wish-hider-next-button">
                <span id="submit">下一步</span>
            </div>
    </div>
</div>
</div>



<script>

<?php
    $wechat = Yii::$app->wechat;
?>
wx.config(<?php
        echo json_encode(
                $wechat->jsApiConfig(
                        [
                        "jsApiList" => [
                        "onMenuShareTimeline",
                        "onMenuShareAppMessage",
                        "onMenuShareQQ",
                        "onMenuShareWeibo",
                        "chooseImage",
                        'uploadImage'
                        ]
                        ]
                )
        );
?>)
Zepto(function($){

    var obj = $('#distant-click-img');
    var id = "<?=$id?>";
    var _csrf = "<?= Yii::$app->request->getCsrfToken()?>";
    var distant_src  = $("#distant-click-img").attr('src');
    var flag = 0;
    if(distant_src != '/image/distant/distant-click.png'){
        flag = 1;
    }
    
    wx.ready(function() {
微信上传代码
    // 点击更换按钮
    $('#distant-click-img').click(function(){
        wx.chooseImage({
            count: 1, // 默认9 选择几张照片
            sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
            sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
            success: function (res) {
                var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
                obj.attr('src',localIds)
                flag = 0;
                UpToWexinService();
            }
        });

        // 上传图片到微信服务器
        function UpToWexinService() {
            var src = obj.attr('src');
            wx.uploadImage({
                localId: src, // 需要上传的图片的本地ID,由chooseImage接口获得
                isShowProgressTips: 1, // 默认为1,显示进度提示
                success: function (res) {
                    // 把图片保存在自己的服务器
                    saveImageInfo(res.serverId);
                }
            });
        }

    })
    
    
    /**
     * 上传远景图片到自己的服务器
     * @param  [type] imgData [description]
     * @return [type]         [description]
     */
    function saveImageInfo(imgData) {
        $.ajax({
            url:'save-distant-img-data',
            type:'post',
            data:{'id':id,'img':imgData,'_csrf':_csrf},
            success:function(res){
                if (res.data.status == 1) {
                    flag = 1
                    $.toast(res.data.data);
                } else {
                    $.toast(res.data.data);
                }
            },
            error:function(res){
                $.toast("图片上传错误");
            }

        })
    }
})
})
</script>

上传到七牛前端处理

注意 网站使用了https,苹果手机不能处理。

    /**
     * 上传64位编码到七牛
     * @param  [type] data [description]
     * @return [type]      [description]
     */
    function putb64(data){
      var pic = data;
      var token = $('#token').val();
      var url = "https://upload.qiniu.com/putb64/-1";
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange=function(){
        if (xhr.readyState==4){
            var str =JSON.parse(xhr.responseText)
            var srcImg = 'https://obf949end.qnssl.com/'+str.key;
            $('#distant-click-img').attr('src',srcImg);
            saveImageInfo(srcImg);
        }
      }
      xhr.open("POST", url, true);
      xhr.setRequestHeader("Content-Type", "application/octet-stream");
      xhr.setRequestHeader("Authorization", "UpToken "+token);
      xhr.send(pic);
    }

后端处理图片上传到七牛

七牛有点坑,说明很不明确,处理个图片到七牛,找到两个接口,fetch 和 pubtb64

fetch 不稳定总是失败,不知道是不是跨域或者拦截,感觉不可靠。最终又改成了pubtb64位处理的

后端处理代码

自己在开发的过程中,各种百度,谷歌,很少有给全的代码,都靠自己去猜。在这里贴上全部代码,节省大家时间。

注释尽量加全,把所有的都集中在这里

    /**
     * 把图片存在服务器上面
     * @return [type] [description]
     */
    public function actionSaveDistantImgData()
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        $request = Yii::$app->request;
        $data = $request->post();
        $img = $data['img'];
        $id = $data['id'];

        // 获取七牛的token
        $token = self::GetUploadToken();
        $upToken = $token['token'];

        // 获取微信的 access_token
        $weixin_token = \DockerEnv::get('WEIXIN_TOKEN');
        $appid = \DockerEnv::get('WEIXIN_APP_ID');
        $secret = \DockerEnv::get('WEIXIN_APP_SECRET');
        $url_get = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$secret;
        $json=$this->curlGet($url_get);
        $weixin_token =  json_decode($json);
        $weixin_token=$weixin_token->access_token;

        // 从微信服务器下载
        $str = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=".$weixin_token."&media_id=".$img;
        
        // 把从微信获得的数据用七牛上传到服务器上面
        $access_key = \DockerEnv::get('QINIU_ACCESS_KEY');
        $secret_key = \DockerEnv::get('QINIU_SECRET_KEY');
        $this->request_by_curl($remote_server,$post_string,$upToken);
        $strr = file_get_contents($str);
        $fetch =base64_encode($strr);
        $imggg = $this->request_by_curl('http://upload.qiniu.com/putb64/-1',$fetch,$upToken);
        $imgs = json_decode(trim($imggg),true);
        $imgss = $imgs['hash'];
        $imgUrl = 'https://obf949end.qnssl.com/'.$imgss.'?imageslim';
        
        // 把远景数据存在试管表里面
        $test_tube = TestTube::findOne($id);
        $test_tube->distant_view = $imgUrl;
        $test_tube->save();

        // 把远景图片存在藏匿者表里
        $solid_sneak = SolidSneak::find()->where(['test_tube_id' => $id])->one();
        $solid_sneak->distant_view = $imgUrl;
        $solid_sneak->updated_at = time();

        if ($solid_sneak->save()) {
            return ['status' => 1,'data' => '图片上传成功'];
        }
        return ['status' => 0,'data' => '图片上传失败'];
    }

其他调用方法


    public function curlGet($url){
        $ch = curl_init();
        $header = "Accept-Charset: utf-8";
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        // curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $temp = curl_exec($ch);
        return $temp;
    }

    public function send($url, $header = '') {
        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER,0);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl, CURLOPT_POST, 1);
        $con = curl_exec($curl);
        if ($con === false) {
            echo 'CURL ERROR: ' . curl_error($curl);
        } else {
            return $con;
        }
    }

    public function urlsafe_base64_encode($str){
        $find = array("+","/");
        $replace = array("-", "_");
        return str_replace($find, $replace, base64_encode($str));
    }



    public function request_by_curl($remote_server,$post_string,$upToken) {

      $headers = array();
      $headers[] = 'Content-Type:image/png';
      $headers[] = 'Authorization:UpToken '.$upToken;
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL,$remote_server);
      //curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_setopt($ch, CURLOPT_HTTPHEADER ,$headers);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      //curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
      curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
      curl_setopt($ch, CURLOPT_TIMEOUT, 30);
      $data = curl_exec($ch);
      curl_close($ch);

      return $data;
    }



    /**
     * generate_access_token
     *
     * @desc 签名运算
     * @param string $access_key
     * @param string $secret_key
     * @param string $url
     * @param array  $params
     * @return string
     */
    public  function generate_access_token($access_key, $secret_key, $url, $params = ''){
        $parsed_url = parse_url($url);
        $path = $parsed_url['path'];
        $access = $path;
        if (isset($parsed_url['query'])) {
            $access .= "?" . $parsed_url['query'];
        }
        $access .= "\n";
        if($params){
            if (is_array($params)){
                $params = http_build_query($params);
            }
            $access .= $params;
        }
        $digest = hash_hmac('sha1', $access, $secret_key, true);
        return $access_key.':'.$this->urlsafe_base64_encode($digest);
    }


    public function base64EncodeImage ($image_file) {
      $base64_image = '';
      $image_info = getimagesize($image_file);
      $image_data = fread(fopen($image_file, 'r'), filesize($image_file));
      $base64_image = 'data:' . $image_info['mime'] . ';base64,' . chunk_split(base64_encode($image_data));
      return $base64_image;
    }

西树先森
7.1k 声望926 粉丝

从事开发多年,前端、后端(go、Python、php)、服务架构都有涉猎,经历过大公司、创业公司,擅长前端及公司技术选型。


引用和评论

0 条评论