天天看点

Laravel+EasyWechat使用微信语音录制,播放,上传七牛

总体逻辑就是,我们从微信的服务器端,把录制好的音频,放到本地,但放到本地的音频是amr格式的无法播放,所以我们要将录好的音频,上传到七牛转码成mp3格式,然后本地调用七牛的链接地址就可以了。

微信播放录制上传,仅支持https协议

首先,需要安装EasyWechat,七牛的php-sdk

安装EasyWechat,具体配置方法参照官方文档:https://www.easywechat.com/docs/5.x/installation

composer require overtrue/wechat:~5.0 -vvv
           

安装七牛php-sdk,配置方法参照官方文档:https://developer.qiniu.com/kodo/1241/php

php require qiniu/php-sdk
           

接下来

使用EasyWechat获取到微信的配置,遇到微信配置没过会显示什么signature invalid,可能是因为你没有在公众号配置域名白名单,也可能是因为你没有在公众号里把域名加入到JS安全名单里:

app/Http/Controllers/UserController.php

use EasyWechat;
...
public function voice_test(){

        $app = EasyWeChat::officialAccount();
        return view("voice.test")
            ->withApp($app);

}
           

resource/voice/test.blade.php

直接复制就可以了

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="viewport" content="width=640, user-scalable=no">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-title" content="">
<title>录音test</title>
<style type="text/css">
@charset "utf-8";
*{ margin:0px; padding:0px; box-sizing:border-box; -webkit-tap-highlight-color:rgba(0,0,0,0);}
html{ max-width:640px; margin:0 auto;}
body{ font-family:"PingFangSC-Regular","sans-serif","STHeitiSC-Light","微软雅黑","Microsoft YaHei"; font-size:24px; line-height:1.5em; color:#000;
    -webkit-user-select:none; user-select:none;
    -webkit-touch-callout:none; touch-callout:none;
}
 
.start_btn , .play_btn , .send_btn{ width:250px; height:60px; line-height:60px; margin:20px auto; text-align:center; border:#eee solid 2px; cursor:pointer;}
.start_btn_in , .stop_btn{ color:#f00; border:#f00 solid 2px;}
</style>
</head>
 
<body>
 
<div class="start_btn">按住不放即可录音</div>
 
<div class="play_btn">点我播放</div>
 
<div class="send_btn">点我保存</div>
 
 
 
 
<script type="text/javascript" src="/plugins/jQuery/jQuery-2.1.4.min.js"></script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
wx.config(<?php echo $app->jssdk->buildConfig(array('onMenuShareTimeline','onMenuShareAppMessage','startRecord','stopRecord','onVoiceRecordEnd','playVoice','stopVoice','onVoicePlayEnd','uploadVoice'), true) ?>);
// wx.config({
// 	debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
// 	appId: '', // 必填,公众号的唯一标识
// 	timestamp: '', // 必填,生成签名的时间戳
// 	nonceStr: '', // 必填,生成签名的随机串
// 	signature: '',// 必填,签名,见附录1
// 	jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage','startRecord','stopRecord','onVoiceRecordEnd','playVoice','stopVoice','onVoicePlayEnd','uploadVoice'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
// });
 
wx.ready(function(){
	//返回音频的本地ID
	var localId;
	//返回音频的服务器端ID
	var serverId;
	//录音计时,小于指定秒数(minTime = 10)则设置用户未录音
	var startTime , endTime , minTime = 2;
	
	
	//***********************************//
	
	
	//开始录音
	$('.start_btn').on('touchstart',function(e){
		e.preventDefault();
		var $this = $(this);
		$this.addClass('start_btn_in');
		startTime = new Date().getTime();
		
		//开始录音
		wx.startRecord();
	});
	//***********************************//
	//停止录音接口
	$('.start_btn').on('touchend', function(){
		var $this = $(this);
		$this.removeClass('start_btn_in');
		
		//停止录音接口
		wx.stopRecord({
			success: function (res) {
				localId = res.localId;
			}
		});
		
		endTime = new Date().getTime();
		alert((endTime - startTime) / 1000);
		if((endTime - startTime) / 1000 < minTime){
			localId = '';
			alert('录音少于' + minTime +  '秒,录音失败,请重新录音');
		}
		
	});
	//监听录音自动停止接口
	wx.onVoiceRecordEnd({
		//录音时间超过一分钟没有停止的时候会执行 complete 回调
		complete: function (res) {
			localId = res.localId;
			
			$('.start_btn').removeClass('start_btn_in');
		}
	});
	
	
	//***********************************//
	
	
	$('.play_btn').on('click',function(){
		if(!localId){
			alert('您还未录音,请录音后再点击播放');
			return;
		}
		var $this = $(this);
		if($this.hasClass('stop_btn')){
			$(this).removeClass('stop_btn').text('点我播放');
			
	//		//暂停播放接口
	//		wx.pauseVoice({
	//			//需要暂停的音频的本地ID,由 stopRecord 或 onVoiceRecordEnd 接口获得
	//			localId: localId
	//		});
	
			//停止播放接口
			wx.stopVoice({
				//需要停止的音频的本地ID,由 stopRecord 或 onVoiceRecordEnd 接口获得
				localId: localId
			});
		}else{
			$this.addClass('stop_btn').text('点我停止');
			
			//播放语音接口
			wx.playVoice({
				//需要播放的音频的本地ID,由 stopRecord 或 onVoiceRecordEnd 接口获得
				localId: localId
			});
		}
	});
	//监听语音播放完毕接口
	wx.onVoicePlayEnd({
		//需要下载的音频的服务器端ID,由uploadVoice接口获得
		serverId: localId,
		success: function (res) {
			$('.play_btn').removeClass('stop_btn').text('点我播放');
			
			//返回音频的本地ID
			//localId = res.localId;
		}
	});
	
	
	//***********************************//
	
	
	//上传语音接口
	$('.send_btn').on('click',function(){
		if(!localId){
			alert('您还未录音,请录音后再保存');
			return;
		}
		
		// alert('上传语音,测试,并未提交保存');
		// return;
		
		//上传语音接口
		wx.uploadVoice({
			//需要上传的音频的本地ID,由 stopRecord 或 onVoiceRecordEnd 接口获得
			localId: localId, 
			//默认为1,显示进度提示
			isShowProgressTips: 1,
			success: function (res) {
				//返回音频的服务器端ID
				serverId = res.serverId;
				window.location.href = "/voice_save?serverId="+serverId;
			}
		});
	});
	
});
 
</script>
</body>
</html>
           

注册路由:

routes/web.php

Route::get("/voice_test","[email protected]_test");
Route::get("/voice_save","[email protected]_save"); //这个方法我们最后会写
           

需要引入公共方法,Laravel公共方法怎么使用不再赘述,不想用公共方法的,可以把这些写到控制器里,方法前面加个public就行:

app/Functions/qiniu.php

<?php 
 require_once __DIR__.'/../../vendor/qiniu/php-sdk/autoload.php';
 //qiniu上传的sdk文件夹放在vendor文件夹下
 use Qiniu\Auth;
 use Qiniu\Storage\UploadManager;
 use Qiniu\Storage\BucketManager;

 // AK和SK,和上传空间要在该页面设置,AK和SK和bucket名字要上七牛才能看见
 global $accessKey;
 global $secretKey;
 global $bucket;

 $accessKey='去七牛找到你的AK';
 $secretKey='去七牛找到你的SK';
 $bucket='你的空间的名字';




function voiceUploads($media_id,$file_path){
        global $accessKey; 
        global $secretKey;
        global $bucket;
        $auth = new Auth($accessKey,$secretKey);
        $bucket = trim($bucket);
        $savekey = \Qiniu\base64_urlSafeEncode($bucket.':speaker/'.$media_id.'.mp3'); //冒号后为七牛保存文件名,这个文件可以播放
        //设置转码参数
        $fops = "avthumb/mp3/ab/320k/ar/44100/acodec/libmp3lame";
        $fops = $fops.'|saveas/'.$savekey;
        $policy = array(
            'persistentOps' => $fops
        );
        $up_token = $auth->uploadToken($bucket, null, 3600, $policy);
        $key = 'speaker_del/'.$media_id.'.mp3'; //七牛云中保存的amr文件名,该文件无法播放,但最后ret返回的是这个文件名
        $uploadMgr = new UploadManager();
        list($ret, $err) = $uploadMgr->putFile($up_token, $key, $file_path);
        if ($err !== null) {
            return false;
        }else {
            //此时七牛云中同一段音频文件有amr和MP3两个格式的两个文件同时存在
            $bucketMgr = new BucketManager($auth);
          
            //为节省空间,删除本地amr格式文件
            unlink($file_path);
            return $ret;
            // return $ret['key'];

        }
    }

 ?>
           

app/Functions/common.php

function httpGet($url){
	    $ch = curl_init($url);
	    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);
	    $http_info = curl_getinfo($ch);
	    curl_close($ch);
	    $res = array_merge(array_merge(array('header' => $http_info)),array('body' => $package));
	    return $res;
	}

	function saveWeixinFile($file_name,$file_content){
	    $local_file = fopen($file_name,'w');
	    if(false !== $local_file){
	        if(false !== fwrite($local_file,$file_content)){
	            fclose($local_file);
	        }else{
	            return false;
	        }
	    }else{
	        return false;
	    }
	}
           

接下来,就可以继续写控制器了

app/Http/Controllers/UserController.php

public function voice_save(Request $request){
    	$serverId = $request->get("serverId");//微信语音的服务器ID
    	$app = EasyWeChat::officialAccount();
		// 获取 access token 实例
		$accessToken = $app->access_token; // EasyWeChat\Core\AccessToken 实例
		$token = $accessToken->getToken(); // token 字符串
        $access_token = $token["access_token"];
		// dd($access_token);
    	$url = "https://file.api.weixin.qq.com/cgi-bin/media/get?access_token=$access_token&media_id=$serverId";
    	$res = httpGet($url); //common中的方法
		//文件保存路径
		$file_name  = public_path('/uploads/audio/'.$serverId.'.mp3');
		$save = saveWeixinFile($file_name,$res['body']); //common中的方法
		if(false === $save){
		    exit('音频文件本地化失败');
		}
        $ret = voiceUploads($serverId,$file_name); //qiniu中的方法
        dd($ret['key']);
    }
           

最后打印出来的$ret['key'],就是我们上传到七牛的文件名,但是,这个文件是不能播放的!需要把speaker_del前缀,改成speaker才能播放(文件名更改在qiniu.php里,可根据需求更改),最后把$ret['key']得到的字符串,连接上你的域名就可以啦!

https://你的七牛域名/更换前缀后的$ret['key'] //最后生成的外链地址样式,可以直接播放
           

大功告成,如果各位有不懂的,可以联系QQ582874942,有偿。