快乐每一天

自己选择的路,跪着也要走下去...

PHP7.0.7微信公众号开发-新增临时素材(解决 {"errcode":41005,"errmsg":"media data missing hint: )

微信官文文档: 注意事项
1、对于临时素材,每个素材(media_id)会在开发者上传或粉丝发送到微信服务器3天后自动删除(所以用户发送给开发者的素材,若开发者需要,应尽快下载到本地),以节省服务器资源。

2、media_id是可复用的。

3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/amr格式

4、需使用https调用本接口。调用示例(使用curl命令,用FORM表单方式上传一个多媒体文件):curl -F media=@test.jpg "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE"

根据微信的官方文档开看,我们只需要传三个参数 access_token、type、@fileurl(绝对路径)

所以笔者第一次就按照这个文档来了,传了三个参数,但是上传返回 48001 好吧接口未授权,然后笔者去微信官方申请了一个测试号,录入AppID和AppSecret 然后继续重来,这次没出现 48001 出现了一个 45001 重点来了,45001 看后面的英文意思就是媒体文件不存在,怎么可能不存在呢?返回代码打印了文件路径,发现路径没有任何问题,继续重来还是45001。郁闷了,然后用命令进行测试看是否是问下的接口问题,curl -F media=@test.jpg "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE" 这行命令代码换上正确的参数后 执行 发现能正确返回media_id.

2019-06-16T14:52:45.png

那么到底是什么问题呢?现在我们能确定两点1:不是微信接口的问题,2:不是路径问题,让我不禁怀疑到curl函数的问题,刚开始没怀疑它是因为这个函数能正确的获取的access_token但是现在不得不怀疑是否上传文件的时候要发生改变。好吧,咱们去百度curl模拟上传文件发现了一个很重要的问题

PHP5.5以下是支持@+文件这种方式上传文件

PHP5.5以上是支持 new CURLFile(文件) 这种方式上传文件

网上所有的案例百分之就是都是 路径加了 @ ,这就是一个坑。

然后笔者的却是php7.0.7那么事不宜迟赶紧换方式上传试试,改掉文件上传的方式后,测试成功

真是皇天不负有心人啊,说了这么多不如给大家分享点代码,那么下面上代码吧

2019-06-16T14:54:29.png
2019-06-16T14:54:42.png

总结:总之微信的文档不会写的很详细,这就需要我们一步步排查错误,大胆怀疑不能错的地方。然后谷歌、百度看看大牛们都怎么处理的。祝你们能写出一个完美的程序!

Basewx.php

<?php
namespace app\index\controller;
use think\Db;
class Basewx
{

    protected $appid;
    protected $appsecret;
    protected $templateId;
    protected $token = null;
    public $data = null;
    public function __construct($appid, $appsecret)
    {
        $this->appid = $appid;
        $this->appsecret = $appsecret;
        $this->token = $this->getToken();
    }

    // 获取TOKEN,一天就2000条,用一次少一次,跟获取用户信息的access_token 不一样。
    public static function getToken(){
        $tokeninfo=Db::name('access_token')->find(1);
        $time=time()-$tokeninfo['time'];
        if($time>1800){
            $appid = config('appid');
            $secret = config('secret');
            $urla = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" .$appid . "&secret=" . $secret;
            $outputa = self::curlGet($urla);
            $result = json_decode($outputa, true);

            Db::name('access_token')->where('id',1)->update(array('token'=>$result['access_token'],'time'=>time()));

            return $result['access_token'];
        }else{
            return $tokeninfo['token'];
        }
    }


    public function menuCreate($data)
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token='.$this->getToken();
        $menu = array();
        $i=0;
        foreach ($data as $item){
            if($i==0){
                $menu['button'][$i]['name'] = $item['name'][0];
                $menu['button'][$i]['type'] = 'click';
                $menu['button'][$i]['key'] = $item['name'][1];
            }else{
                $menu['button'][$i]['name'] = $item['name'][0];
                $menu['button'][$i]['type'] = 'view';
                $menu['button'][$i]['url'] = $item['name'][1];
            }

            $i++;
        }

        $data = self::xjson_encode($menu);
        $data = str_replace('\/','/',$data);
        $result = self::curlPost($url,$data);
        return json_decode($result,true);
    }


    public static function curlGet($url = '', $options = array())
    {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https请求 不验证证书和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }
    public static function curlPost($url = '', $postData = '', $options = array())
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https请求 不验证证书和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        if($data === false)
        {
            echo 'Curl error: ' . curl_error($ch);exit();
        }
        curl_close($ch);
        return $data;
    }

    //HTTP请求(支持HTTP/HTTPS,支持GET/POST)
    protected function http_request($url, $data = null)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (!empty($data)){
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

    /*
    * PART 素材管理
    */
    //新增临时素材(原多媒体文件)( (图片(image)、语音(voice)、视频(video)和缩略图(thumb))) ,临时素材 不包括图文消息
    // $weixin->upload_temporary_material("thumb", "logo.jpg"); //logo.jpg须放于类同目录,注意路径
    // { ["type"]=> string(5) "thumb" ["thumb_media_id"]=> string(64) "4rqefcVf-dcsnmuz1Q9ESn_KC3sBVuZhC7JM5-0fEvrttwQFs2KNErCw2YTYPx_l" ["created_at"]=> int(1463105848) }
    public function upload_temporary_material()
    {

        $file='./tmp.png';
//        $newpath='@'.$_SERVER['DOCUMENT_ROOT'].$path;
//        $data = array("media"  => $newpath);

        if (PHP_OS == "Linux"){        //Linux
            $data = array("media"  => new \CURLFile($file));
        }else{                        //WINNT
            $data = array("media"  => "@".dirname(__FILE__).'\\'.$file);
        }
//        $data = array("media"  => "/tmp.png");

        var_dump($data);

        $url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=".$this->getToken()."&type=image";
        $res = $this->http_request($url, $data);
        return json_decode($res, true);
    }

    public static function xjson_encode($data)
    {
        if(version_compare(PHP_VERSION,'5.4.0','<')){
            $str = json_encode($data);
            $str = preg_replace_callback("#\\\u([0-9a-f]{4})#i",function($matchs){
                return iconv('UCS-2BE', 'UTF-8', pack('H4', $matchs[1]));
            },$str);
            return $str;
        }
        return json_encode($data, JSON_UNESCAPED_UNICODE);
    }
}

Index.php

<?php
namespace app\index\controller;
use think\Db;

class Index
{


    public function index(){
        header('Content-type:text');
        $token="weixin";
        $post=request()->param();
        if (!isset($post['echostr'])) {
            $this->responseMsg();
        }else{
            $this->valid($token);
        }
    }

    public function test(){
        $class = new \app\index\controller\Basewx(config('appid'),config('secret'));
        $result = $class->upload_temporary_material();
        var_dump($result);
    }

    /*创建菜单*/
    /*http://m.cssnb.com/index/index/createmenu*/
    public function createmenu(){
        $class = new \app\index\controller\Basewx(config('appid'),config('secret'));

        $data[0]['name'] = array('客服','kefu98');
        $data[1]['name'] = array('官网','http://www.baidu.com');
        $result = $class->menuCreate($data);
        if($result['errcode']==0){
            echo '<h1>创建菜单成功!</h1>';
        }else{
            echo '<h1>创建菜单失败:'.$result['errmsg'].'</h1>';
        }
    }

    //验证签名
    public function valid($token)
    {
        $post=request()->param();
        $echoStr = $post["echostr"];
        $signature = $post["signature"];
        $timestamp = $post["timestamp"];
        $nonce = $post["nonce"];
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);
        if($tmpStr == $signature){
            echo $echoStr;
            exit;
        }
    }

    //响应消息
    public function responseMsg()
    {
//        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
        $postStr = file_get_contents('php://input');
        if (!empty($postStr)){
//            $this->logger("R \r\n".$postStr);
            trace("KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK1");
            trace($postStr);
            trace("KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK2");


            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            $RX_TYPE = trim($postObj->MsgType);

            //消息类型分离
            switch ($RX_TYPE)
            {
                case "event":
                    $result = $this->receiveEvent($postObj);
                    break;
                case "text":
                    $result = $this->receiveText($postObj);
                    break;
                case "image":
                    $result = $this->receiveImage($postObj);
                    break;
                case "location":
                    $result = $this->receiveLocation($postObj);
                    break;
                case "voice":
                    $result = $this->receiveVoice($postObj);
                    break;
                case "video":
                case "shortvideo":
                    $result = $this->receiveVideo($postObj);
                    break;
                case "link":
                    $result = $this->receiveLink($postObj);
                    break;
                default:
                    $result = "unknown msg type: ".$RX_TYPE;
                    break;
            }
//            $this->logger("T \r\n".$result);
            trace("KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK3");
            trace($result);
            trace("KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK4");
            echo $result;
        }else {
            echo "";
            exit;
        }
    }

    //接收事件消息
    private function receiveEvent($object)
    {
        $content = "";
        switch ($object->Event)
        {
            case "subscribe":
                $content = "欢迎关注土好网——直接连接买卖双方开发商董事长的二手地直卖网。";
                break;
            case "unsubscribe":
                $content = "取消关注";
                break;
            case "CLICK":
                switch ($object->EventKey)
                {
                    case "kefu98":
//                        $content = '我要返回图片';
//                        break;
//                        $content = array();
//                        $content[] = array("Title"=>"单图文标题",  "Description"=>"单图文内容", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
//                        break;
                        $content = array();
                        $content[] = array("MediaId"=>"huNJ_LxG8vmFunz2Hjeb73X1IS02pu0jslBK24HAhSqi3bw2ZTCCYwKU2PaIer5n");
                        break;
                    default:
                        $content = '';
                        break;
                }
                break;
            case "pic_weixin":
                $content = "相册发图:数量 ".$object->SendPicsInfo->Count;
                break;
            default:
                $content = "receive a new event: ".$object->Event;
                break;
        }

        if(is_array($content)){
//            $result = $this->transmitNews($object, $content);
            $result = $this->transmitImage($object, $content);
        }else{
            $result = $this->transmitText($object, $content);
        }
        return $result;
    }

    //接收文本消息
    private function receiveText($object)
    {
        $keyword = trim($object->Content);

        //自动回复模式
        if (strstr($keyword, "文本")){
            $content = "这是个文本消息";
        }else if (strstr($keyword, "表情")){
            $content = "微笑:/::)\n乒乓:/:oo\n中国:".$this->bytes_to_emoji(0x1F1E8).$this->bytes_to_emoji(0x1F1F3)."\n仙人掌:".$this->bytes_to_emoji(0x1F335);
        }else if (strstr($keyword, "单图文")){
            $content = array();
            $content[] = array("Title"=>"单图文标题",  "Description"=>"单图文内容", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
        }else if (strstr($keyword, "图文") || strstr($keyword, "多图文")){
            $content = array();
            $content[] = array("Title"=>"多图文1标题", "Description"=>"", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
            $content[] = array("Title"=>"多图文2标题", "Description"=>"", "PicUrl"=>"http://d.hiphotos.bdimg.com/wisegame/pic/item/f3529822720e0cf3ac9f1ada0846f21fbe09aaa3.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
            $content[] = array("Title"=>"多图文3标题", "Description"=>"", "PicUrl"=>"http://g.hiphotos.bdimg.com/wisegame/pic/item/18cb0a46f21fbe090d338acc6a600c338644adfd.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
        }else if (strstr($keyword, "音乐")){
            $content = array();
            $content = array("Title"=>"最炫民族风", "Description"=>"歌手:凤凰传奇", "MusicUrl"=>"http://mascot-music.stor.sinaapp.com/zxmzf.mp3", "HQMusicUrl"=>"http://mascot-music.stor.sinaapp.com/zxmzf.mp3");
        }else{
            $content = date("Y-m-d H:i:s",time())."\nOpenID:".$object->FromUserName."\n技术支持 方倍工作室";
            // $content = "";
        }

        if(is_array($content)){
            if (isset($content[0])){
                $result = $this->transmitNews($object, $content);
            }else if (isset($content['MusicUrl'])){
                $result = $this->transmitMusic($object, $content);
            }
        }else{
            $result = $this->transmitText($object, $content);
        }
        return $result;
    }

    //接收图片消息
    private function receiveImage($object)
    {
        $content = array("MediaId"=>$object->MediaId);
        $result = $this->transmitImage($object, $content);
        return $result;
    }

    //接收位置消息
    private function receiveLocation($object)
    {
        $content = "你发送的是位置,经度为:".$object->Location_Y.";纬度为:".$object->Location_X.";缩放级别为:".$object->Scale.";位置为:".$object->Label;
        $result = $this->transmitText($object, $content);
        return $result;
    }

    //接收语音消息
    private function receiveVoice($object)
    {
        if (isset($object->Recognition) && !empty($object->Recognition)){
            $content = "你刚才说的是:".$object->Recognition;
            $result = $this->transmitText($object, $content);
        }else{
            $content = array("MediaId"=>$object->MediaId);
            $result = $this->transmitVoice($object, $content);
        }
        return $result;
    }

    //接收视频消息
    private function receiveVideo($object)
    {
        $content = array("MediaId"=>$object->MediaId, "ThumbMediaId"=>$object->ThumbMediaId, "Title"=>"", "Description"=>"");
        $result = $this->transmitVideo($object, $content);
        return $result;
    }

    //接收链接消息
    private function receiveLink($object)
    {
        $content = "你发送的是链接,标题为:".$object->Title.";内容为:".$object->Description.";链接地址为:".$object->Url;
        $result = $this->transmitText($object, $content);
        return $result;
    }

    //回复文本消息
    private function transmitText($object, $content)
    {
        if (!isset($content) || empty($content)){
            return "";
        }

        $xmlTpl = "<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[%s]]></Content>
</xml>";
        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), $content);

        return $result;
    }


    //回复图文消息
    private function transmitNews($object, $newsArray)
    {
        if(!is_array($newsArray)){
            return "";
        }
        $itemTpl = "        <item>
            <Title><![CDATA[%s]]></Title>
            <Description><![CDATA[%s]]></Description>
            <PicUrl><![CDATA[%s]]></PicUrl>
            <Url><![CDATA[%s]]></Url>
        </item>
";
        $item_str = "";
        foreach ($newsArray as $item){
            $item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
        }
        $xmlTpl = "<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[news]]></MsgType>
    <ArticleCount>%s</ArticleCount>
    <Articles>
$item_str    </Articles>
</xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), count($newsArray));
        return $result;
    }

    //回复音乐消息
    private function transmitMusic($object, $musicArray)
    {
        if(!is_array($musicArray)){
            return "";
        }
        $itemTpl = "<Music>
        <Title><![CDATA[%s]]></Title>
        <Description><![CDATA[%s]]></Description>
        <MusicUrl><![CDATA[%s]]></MusicUrl>
        <HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
    </Music>";

        $item_str = sprintf($itemTpl, $musicArray['Title'], $musicArray['Description'], $musicArray['MusicUrl'], $musicArray['HQMusicUrl']);

        $xmlTpl = "<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[music]]></MsgType>
    $item_str
</xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    //回复图片消息
    private function transmitImage($object, $imageArray)
    {
        $itemTpl = "<Image>
        <MediaId><![CDATA[%s]]></MediaId>
    </Image>";

//        $item_str = sprintf($itemTpl, 'huNJ_LxG8vmFunz2Hjeb73X1IS02pu0jslBK24HAhSqi3bw2ZTCCYwKU2PaIer5n');
        $item_str = sprintf($itemTpl, $imageArray['MediaId']);

        $xmlTpl = "<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[image]]></MsgType>
    $item_str
</xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    //回复语音消息
    private function transmitVoice($object, $voiceArray)
    {
        $itemTpl = "<Voice>
        <MediaId><![CDATA[%s]]></MediaId>
    </Voice>";

        $item_str = sprintf($itemTpl, $voiceArray['MediaId']);
        $xmlTpl = "<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[voice]]></MsgType>
    $item_str
</xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    //回复视频消息
    private function transmitVideo($object, $videoArray)
    {
        $itemTpl = "<Video>
        <MediaId><![CDATA[%s]]></MediaId>
        <ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
        <Title><![CDATA[%s]]></Title>
        <Description><![CDATA[%s]]></Description>
    </Video>";

        $item_str = sprintf($itemTpl, $videoArray['MediaId'], $videoArray['ThumbMediaId'], $videoArray['Title'], $videoArray['Description']);

        $xmlTpl = "<xml>
    <ToUserName><![CDATA[%s]]></ToUserName>
    <FromUserName><![CDATA[%s]]></FromUserName>
    <CreateTime>%s</CreateTime>
    <MsgType><![CDATA[video]]></MsgType>
    $item_str
</xml>";

        $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
        return $result;
    }

    //日志记录
//    private function logger($log_content)
//    {
//        if(isset($_SERVER['HTTP_APPNAME'])){   //SAE
//            sae_set_display_errors(false);
//            sae_debug($log_content);
//            sae_set_display_errors(true);
//        }else if($_SERVER['REMOTE_ADDR'] != "127.0.0.1"){ //LOCAL
//            $max_size = 1000000;
//            $log_filename = "log.xml";
//            if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);}
//            file_put_contents($log_filename, date('Y-m-d H:i:s')." ".$log_content."\r\n", FILE_APPEND);
//        }
//    }
}
?>
此文章共有条评论, 人参与 |Powerd By Angboo