• 微信开发之上传素材


    本文目录

    1. 上传图文素材的图片
    2. 上传其他素材
    3. 关键的http表单请求代码
    4. 小结
    5. 参考文档

    **前言**: 我在实现微信公众平台上传素材的时候遇到了许多问题,但最终还是成功实现这一功能,特此在这里做一下总结和记录。


    文中遇到诸如 getAccessToken() 等关键函数却没有找到实现时,可参考前面的这两篇文章:

    1、微信开发之获取用户详细列表
    2、微信开发之向用户群发文本消息


    1、 **上传图文素材的图片**

    首先选一个简单的接口来做说明例子,这个上传素材的接口在所有上传素材的接口中是参数最简单的,而且还单独享用一个URL, 作为入门例子再合适不过了。

    注意,本文主要侧重点是代码层面的实现,而不是微信官方一大堆规则的讲解,如果你有需要此方面的介绍,下面已给出官方链接不谢。

    官方文档:

    新增永久素材

    官方给的这个接口,除了需要惯例的 access_token ,还需要一个文件的参数,一般而言,只需要一个文件路径,其他文件参数通过这个路径获取解析则可,做成一个黑匣子,简单易用。
    我知道,有人就是专门找下边的 Requests::request() 的实现的,可在这就没看到实现,别急,下面就有。

    public function uploadNewsImage($path)
    {
        $access_token = $this->getAccessToken();
        if (!$access_token) {
            return false;
        }
    
        $path = realpath($path);
        $post = ['media '=> '@'.$path];
        $url ="https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={$access_token}";
        $return = $this->requestAndCheck($url, 'POST', $post);
        if ($return === false) {
            return false;
        }
    
        return $return;
    }
    
    /**
     * 专门用来检查微信接口返回值的。
     * 是的,这个接口比上一两篇文章的接口更加好用。东西一般做多,就知道要抽象了,如果还没有那水平的话。
     */
    public function requestAndCheck($url, $method = 'GET', $fields = [])
    {
        $return = Requests::request($url, $method, $fields);
        if ($return === false) {
            $this->setError("request出错! " . Requests::$error);
            return false;
        }
    
        $wxdata = json_decode($return, true);
        if (isset($wxdata['errcode']) && $wxdata['errcode'] != 0) {
            $this->setError("微信错误代码:{$wxdata['errcode']};<br>错误信息:{$wxdata['errmsg']}<br>请求链接:$url");
            return false;
        }
    
        if (strtoupper($method) === 'GET' && empty($wxdata)) {
            $this->setError("微信http请求返回为空!<br>请求链接:$url");
            return false;
        }
    
        return $wxdata;
    }
    

    2、 **上传其他素材**

    懂得上面的流程,其他的上传素材的接口,无非就是加多个 GETPOST 参数,主流程没变。
    其他相关接口列举如下:

    1、新增永久图文素材:https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN
    2、新增其他类型永久素材:https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE
    3、新增临时素材:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE


    功能的约束和细节还望参考官方文档:

    1、新增永久素材
    2、新增临时素材


    3、 **关键的http表单请求代码**

    先上代码:(这里边已经简化很多附加功能,比如可以改变header之类的功能,该代码主要参考一些开源的项目)

    public static function request($url, $method = 'GET', $fields = [])
    {
        self::$ch = curl_init();
        curl_setopt(self::$ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt(self::$ch, CURLOPT_CONNECTTIMEOUT, 10);
    
        $method = strtoupper($method);
        if ($method == 'GET' && !empty($fields)) {
            $url = $url . (strpos($url,"?")===false ? "?" : "&") . http_build_query($fields);
        }
        curl_setopt(self::$ch, CURLOPT_URL, $url);
    
        if ($method != 'GET') {
            curl_setopt(self::$ch, CURLOPT_POST, true);
    
            if (!empty($fields)) {
                if (is_array($fields)) {
                    /* 支持文件上传 */
                    if (class_exists('CURLFile')) {
                        curl_setopt(self::$ch, CURLOPT_SAFE_UPLOAD, true);
                        foreach ($fields as $key => $value) {
                            if (is_string($value) && strpos($value, '@') === 0) {
                                $fields[$key] = new CURLFile(realpath(ltrim($value, '@')),
                                				'image/jpg', basename(ltrim($value, '@')));
                            }
                        }
                    } elseif (defined('CURLOPT_SAFE_UPLOAD')) {
                        curl_setopt(self::$ch, CURLOPT_SAFE_UPLOAD, false);
                    }
                }
                curl_setopt(self::$ch, CURLOPT_POSTFIELDS, $fields);
            }
        }
    
        /* 关闭https验证 */
        if ("https" == substr($url, 0, 5)) {
            curl_setopt(self::$ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt(self::$ch, CURLOPT_SSL_VERIFYHOST, false);
        }
    
        self::$content = curl_exec(self::$ch);
        curl_close(self::$ch);
    
        return self::$content;
    }
    


    重点分析:

    /* 支持文件上传 */
    if (class_exists('CURLFile')) {
        curl_setopt(self::$ch, CURLOPT_SAFE_UPLOAD, true);
        foreach ($fields as $key => $value) {
            if (is_string($value) && strpos($value, '@') === 0) {
                $fields[$key] = new CURLFile(realpath(ltrim($value, '@')));
            }
        }
    } elseif (defined('CURLOPT_SAFE_UPLOAD')) {
        curl_setopt(self::$ch, CURLOPT_SAFE_UPLOAD, false);
    }
    

    这里面有个php版本的坑,5.4版本只支持用 @ 来进行上传文件,5.5是个过渡版本,支持 @CURLFile 两种方式上传文件,而到了5.6,就只支持 CURLFile 了。所以需要用兼容模式来适应不同版本。

    关于为什么不用php版本号来判断呢?你用版本号谁知道你是要来判断啥呢?难道加个注释?
    而常量 CURLOPT_SAFE_UPLOAD 是用来开启是否支持 @ 的,当然,5.6版本设置了也没有。

    还有,要上传file的时候,一定要用数组给 curl_setopt(self::$ch, CURLOPT_POSTFIELDS, $fields); 传值,而不能用 http_build_query() ,一个的http请求头中的 content-typemultipart/form-date ,另一个是 application/x-www-form-urlencoded 。file用二进制编码进行传输,而普通的post数据是文本传输。

    上面的相关知识还请详看 参考文档


    **小结**: 如果你已有上传文件的接口,其实这个功能不算啥,按照官方文档进行 post url 即可。如果没有,或者没有实现文件上传功能,就要对 curl 研究一下了,还要踩一下php版本的坑。。。不过对 curl 掌握就更加全面而牢固了,这难道不是我们的目的?
    *主要参考文档*: > 1、[微信公众号开发文档](https://mp.weixin.qq.com/wiki) > 2、[Multipart/form-data POST文件上传详解](http://blog.csdn.net/xiaojianpitt/article/details/6856536) > 3、[PHP的CURLOPT_POSTFIELDS参数使用数组和字符串的区别](http://blog.csdn.net/fableboy/article/details/18973483) > 4、[The CURLFile class](http://php.net/manual/zh/class.curlfile.php) > 5、[考虑 PHP 5.0~5.6 各版本兼容性的 cURL 文件上传](https://segmentfault.com/a/1190000000725185)


    -end-

  • 相关阅读:
    前端ajax传数据成功发送,但后端接收不到
    POST 400 (BAD REQUEST)
    chrome浏览器本地文件支持ajax请求的解决方法
    系统可能不会保存你所做的修改 onbeforeunload
    bootstrap 常用class(不定时更新)
    webstrom 一直反复indexing
    setInterval传递参数
    在CentOS 7上安装GitLab
    「Githug」Git 游戏通关流程
    分布式版本控制系统Git——图形化Git客户端工具TortoiseGit
  • 原文地址:https://www.cnblogs.com/hackbee/p/6859257.html
Copyright © 2020-2023  润新知