• 微信开发之JS-SDK + PHP实现录音、上传、语音识别


    先看效果图:先录音,录音成功之后,把录音追加到列表,点击列表可以播放;录音完成之后上传录音,上传成功再语音识别。

    微信官方文档 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

    实现流程:

    一、 公众号配置

    1.JS安全域名配置:登陆微信公众平台:公众号设置 -> 功能设置 -> JS安全域名,域名写到根域名就行,把下载的txt文件放到域名对应的根目录下

     2.配置ip白名单

    二、代码展示

    1.前端代码

    用到了'startRecord', 'stopRecord', 'playVoice', 'uploadVoice', 'translateVoice'五个接口,先调用 startRecord 开始录音,再调用 stopRecord 停止录音,会返回一个音频的本地Id,把录音追加的Html录音列表中,方便播放录音,使用 playVoice 播放录音列表中的录音,再使用 uploadVoice 把录音上传到微信服务器上,会返回微信服务器上的serverId(感觉上传录音没有使用到),通过使用本地音频id去识别语音

    <!DOCTYPE html>
    <html>
    <head>
        <title>语音识别</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <script type="text/javascript" src="/static/index/js/jquery.js"></script>
    <script src="http://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
    <link rel="stylesheet" type="text/css" href="/static/index/layui/css/layui.css">
    
          <style>
              button{
                  height: 40px;
                  width: 120px;
                  margin: 25px;
              }
              #ul{
                  margin-top: 15px;
                  height: 40px;
                  line-height: 40px;
                  text-align: center;
                  padding: 5px;
              }
              #ul li{
                  width: 80%;
              }
              #ullist button{
                width:98%;
                height:40px;
                border-radius:5;
                text-align: center;
                margin: 5px;
            }
    
          </style>
    </head>
    <body>
        <div class="container" style="100%">
            <div class="row">
                <ul class="list-unstyled" id="ullist">
                    
                </ul>
            </div>
            <div id="btn" class="navbar-fixed-bottom" style="user-select:none:align-content:center">
                <center>
                    <button id="talk_btn" type="button" class="layui-btn">录 音</button>
                    <button id="uploadVoice" type="button" class="layui-btn layui-btn-normal">上传 录音</button><br>
                    <button id="translateVoice" type="button" class="layui-btn layui-btn-danger" style="90%;">语音 识别</button><br>
                </center>
            </div>
        </div>
        
    <script type="text/javascript">
    
        // 全局变量
        var recordTimer = 300;
        var voice={
                      localId:'',
                      serverId:''
                  }
        
        wx.config({
            debug: false,
            appId: '{$signPackage.appId}',
            timestamp: {$signPackage.timestamp},
            nonceStr: '{$signPackage.nonceStr}',
            signature: '{$signPackage.signature}',
            jsApiList: [
              // 所有要调用的 API 都要加到这个列表中
              'startRecord', 'stopRecord', 'playVoice', 'uploadVoice', 'translateVoice'
            ]
          });
          
          // 在这里调用 API
        wx.ready(function () {
            var START;
            var END;
            
            // 开始录音
            $("#talk_btn").on('touchstart',function (event) {
                // console.log(event)
                event.preventDefault();
                START = new Date().getTime();
    
                // 延迟后录音,避免误操作
                recordTimer = setTimeout(function () {
    
                    wx.startRecord({
                        success:function () {
                            // 授权录音
                            localStorage.rainAllowRecord = 'true';
                        },
                        cancel:function () {
                            console.log('用户拒绝了录音');
                        }
                    });
                },300)
            });
            
            //松手结束录音
            $('#talk_btn').on('touchend', function(event){
                event.preventDefault();
                END = new Date().getTime();
                
                if((END - START) < 3000){
                    END = 0;
                    START = 0;
                    alert('录音时间不能少于3秒');
                    //小于300ms,不录音
                    clearTimeout(recordTimer);
                }else{
                    
                    var mytime = new Date().toLocaleTimeString();  //获取当前时间
                    
                    wx.stopRecord({
                      success: function (res) {
                          
                        voice.localId = res.localId;
                        console.log(voice.localId)
                        var str="<li audioid='"+voice.localId+"'><button class='layui-btn layui-btn-primary'>音频任务"+mytime+"</button></li>";
                        $("#ullist").append(str);//显示到列表
                      },
                      fail: function (res) {
                        alert(JSON.stringify(res));
                      }
                    });
                }
            });
        });
        wx.error(function (res) {
            console.log(res)
        });
        
        //list播放语音
        $("ul").on("click", "li", function() {
            var audioid = $(this).attr("audioid");
            
            wx.playVoice({
                localId: audioid
            });
        })
    
        // 上传语音
        $("#uploadVoice").click(function(){
            
            //调用微信的上传录音接口把本地录音先上传到微信的服务器
            wx.uploadVoice({
                localId:voice.localId,    // 需要上传的音频的本地ID,由stopRecord接口获得
                isShowProgressTips: 1,    // 默认为1,显示进度提示
                success:function(res){
                    
                    if(res.errMsg == 'uploadVoice:ok'){
                        voice.serverId = res.serverId
                        alert('录音上传成功');
                    }else{
                        alert(res.errMsg)
                    }
                }
            })
        })
        
        // 语音识别
        $("#translateVoice").click(function(){
            wx.translateVoice({
                localId:voice.localId,    // 需要识别的音频的本地Id,由录音相关接口获得
                isShowProgressTips:1,    // 默认为1,显示进度提示
                success:function(res){
                    console.log(res)
                    if(res.errMsg == "translateVoice:ok"){
                        alert(res.translateResult);    // 语音识别的结果
                    }else{
                        alert(res.errMsg)
                    }
                    
                }
            })
        })
    
    </script>
    
    </body>
    
    </html>

    后端代码(php)

    Wechat.php 此类主要是获取accessToken和jsapiTicket

    <?php
    namespace appindexcontroller;
    use thinkController;
    
    /**
     * 微信类
     */
    class Wechat extends Controller
    {
    
        protected  $APPID = 'XXXXXXXXXXXXX';
        protected  $APPSECRET = 'xxxxxxxxxxxxxxxxxx';
    
        /**
        * 微信服务器配置时 验证token的url
        */
        public function checkToken()
        {
            header("Content-type: text/html; charset=utf-8");
    
            //1.将timestamp,nonce,toke按字典顺序排序
            $timestamp = $_GET['timestamp'];
            $nonce = $_GET['nonce'];
            $token = 'asd123456zxc';
            $signature = $_GET['signature'];
            $array = array($timestamp,$nonce,$token);
            //2.将排序后的三个参数拼接之后用sha1加密
            $tmpstr = implode('',$array);
            $tmpstr = sha1($tmpstr);
            //3.将加密后的字符串与signature进行对比,判断该请求是否来自微信
            if($tmpstr == $signature){
                echo $_GET['echostr'];
                exit;
            }
        }
    
        /**
        * curl请求 
        */
        public function http_curl($url, $type = 'get', $res = 'json', $arr = ''){
          $cl = curl_init();
          curl_setopt($cl, CURLOPT_URL, $url);
          curl_setopt($cl, CURLOPT_RETURNTRANSFER, 1);
          curl_setopt($cl, CURLOPT_SSL_VERIFYPEER, false);
          curl_setopt($cl, CURLOPT_SSL_VERIFYHOST, false);
          if($type == 'post'){
            curl_setopt($cl, CURLOPT_POST, 1);
            curl_setopt($cl, CURLOPT_POSTFIELDS, $arr);
          }
          $output = curl_exec($cl);
          curl_close($cl);
          return json_decode($output, true);
          if($res == 'json'){
            if( curl_error($cl)){
              return curl_error($cl);
            }else{
              return json_decode($output, true);
            }
          }
        }
    
        /**
         * 获取 AccessToken
         */
        public function getAccessToken()
        {
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->APPID."&secret=".$this->APPSECRET;
    
            // 先判断 access_token 文件里的token是否过期,没过期继续使用,过期就更新
            $data = json_decode($this->get_php_file(ROOT_PATH."public".DS."wxtxt".DS."access_token.txt"));
            // 过期 更新
            if ($data->expire_time < time()) {
                
                $res = $this->http_curl($url);
                $access_token = $res['access_token'];
                if ($access_token) {
                    // 在当前时间戳的基础上加7000s (两小时)
                    $data->expire_time = time() + 7000;
                    $data->access_token = $res['access_token'];
                    $this->set_php_file(ROOT_PATH."public".DS."wxtxt".DS."access_token.txt",json_encode($data));
                }
            }else{
                // 未过期 直接使用
                $access_token = $data->access_token;
            }
            return $access_token;
        }
        
          /**
         * 获取 JsApiTicket
         */
          public function getJsApiTicket()
          {
              // 先判断 jsapi_ticket是否过期 没过期继续使用,过期就更新
              $data = json_decode($this->get_php_file(ROOT_PATH."public".DS."wxtxt".DS."jsapi_ticket.txt"));
    
              if ($data->expire_time < time()) {
                  // 过期 更新
                  $accessToken = $this->getAccessToken();
                  $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
                  $res = $this->http_curl($url);
                  $ticket = $res['ticket'];
                  if ($ticket) {
                      $data->expire_time = time() + 7000;
                      $data->jsapi_ticket = $ticket;
                      $this->set_php_file(ROOT_PATH."public".DS."wxtxt".DS."jsapi_ticket.txt",json_encode($data));
                  }
              }else{
                  $ticket = $data->jsapi_ticket;
              }
              return $ticket;
          }
    
    
        // 获取存储文件中的token ticket
        private function get_php_file($filename) {
            return trim(file_get_contents($filename));
          }
          // 把token ticket 存储到文件中
          private function set_php_file($filename, $content) {
            $fp = fopen($filename, "w");
            fwrite($fp,  $content);
            fclose($fp);
          }
    
    }

    Wxmedia.php  此类是返回语音识别的配置信息

    <?php
    namespace appindexcontroller;
    use thinkController;
    use appindexcontrollerWechat;
    
    /**
     * 微信语音识别
     */
    class Wxmedia extends Wechat
    {
    
        /**
         * 语音识别
         */
        public function index()
        {
            $signPackage = json_decode($this->getSignPackage(),true);
        
            $this->assign('signPackage',$signPackage);
            return $this->fetch();
        }
    
        /**
         * 生成签名
         */
        public function getSignPackage() 
        {
    
            // 实例化微信操作类
            $wx = new Wechat();
    
            // 获取 ticket
            $jsapiTicket = $wx->getJsApiTicket();
    
            // 注意 URL 一定要动态获取,不能 hardcode.
            $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
            // 当前页面的url
            $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
    
            $timestamp = time();    //生成签名的时间戳
            $nonceStr = $this->createNonceStr();    //生成前面的随机串
    
            // 这里参数的顺序要按照 key 值 ASCII 码升序排序
            $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
            // 对string进行sha1加密
            $signature = sha1($string);
    
            $signPackage = array(
              "appId"     => $wx->APPID,
              "nonceStr"  => $nonceStr,
              "timestamp" => $timestamp,
              "url"       => $url,
              "signature" => $signature,
              "rawString" => $string
            );
            return json_encode($signPackage); 
        }
    
        /**
         * 生成签名的随机串
         */
        private function createNonceStr($length = 16) {
            $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            $str = "";
            for ($i = 0; $i < $length; $i++) {
              $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
            }
            return $str;
        }
        
    }

     项目源码: https://github.com/zhxiangfei/wechat_voice.git

  • 相关阅读:
    判断奇偶
    数据库中去重时:建议使用group by
    将博客搬至CSDN
    FileZilla
    Windows通过VNC连接并显示Linux桌面(Ubuntu16.04)
    springMVC 中参数绑定
    get和post的区别主要有以下几方面
    Get、Post、Put与Delete的区别
    HTTP请求地址映射
    Spring MVC 框架
  • 原文地址:https://www.cnblogs.com/zxf100/p/12718661.html
Copyright © 2020-2023  润新知