我正在尝试在我的网站中实现录音机。我想要的是让用户将录制的文件直接保存到数据库和/或我网站上的子文件夹(称为/ speaking_audios)。主要文件如下:recorder.php,sync.html,upload.php,js / main.js,js / swfobject.js,js / recorder.js,recorder.swf(我不知道它的用途)
recorder.php
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>FlashWavRecorder demo</title>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js'></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/recorder.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<h1><a href="https://github.com/cykod/FlashWavRecorder">FlashWavRecorder</a></h1>
<p><strong>Upload requires php, i.e. example will not work on github.com</strong></p>
<div id="recorder-audio" class="control_panel idle">
<button class="record_button" onclick="FWRecorder.record('audio', 'audio.wav');" title="Record">
<img src="images/record.png" alt="Record"/>
</button>
<button class="stop_recording_button" onclick="FWRecorder.stopRecording('audio');" title="Stop Recording">
<img src="images/stop.png" alt="Stop Recording"/>
</button>
<button class="play_button" onclick="FWRecorder.playBack('audio');" title="Play">
<img src="images/play.png" alt="Play"/>
</button>
<button class="pause_playing_button" onclick="FWRecorder.pausePlayBack('audio');" title="Pause Playing">
<img src="images/pause.png" alt="Pause Playing"/>
</button>
<button class="stop_playing_button" onclick="FWRecorder.stopPlayBack();" title="Stop Playing">
<img src="images/stop.png" alt="Stop Playing"/>
</button>
<div class="level"></div>
</div>
<div id="recorder-audio2" class="control_panel idle">
<button class="record_button" onclick="FWRecorder.record('audio2', 'audio2.wav');" title="Record">
<img src="images/record.png" alt="Record"/>
</button>
<button class="stop_recording_button" onclick="FWRecorder.stopRecording('audio2');" title="Stop Recording">
<img src="images/stop.png" alt="Stop Recording"/>
</button>
<button class="play_button" onclick="FWRecorder.playBack('audio2');" title="Play">
<img src="images/play.png" alt="Play"/>
</button>
<button class="pause_playing_button" onclick="FWRecorder.pausePlayBack('audio2');" title="Pause Playing">
<img src="images/pause.png" alt="Pause Playing"/>
</button>
<button class="stop_playing_button" onclick="FWRecorder.stopPlayBack();" title="Stop Playing">
<img src="images/stop.png" alt="Stop Playing"/>
</button>
<div class="level"></div>
</div>
<div class="details">
<button class="show_level" onclick="FWRecorder.observeLevel();">Show Level</button>
<button class="hide_level" onclick="FWRecorder.stopObservingLevel();" style="display: none;">Hide Level</button>
<span id="save_button">
<span id="flashcontent">
<p>Your browser must have JavaScript enabled and the Adobe Flash Player installed.</p>
</span>
</span>
<div><button class="show_settings" onclick="microphonePermission()">Microphone permission</button></div>
<div id="status">
Recorder Status...
</div>
<div>Duration: <span id="duration"></span></div>
<div>Activity Level: <span id="activity_level"></span></div>
<div>Upload status: <span id="upload_status"></span></div>
</div>
<form id="uploadForm" name="uploadForm" action="upload.php">
<input name="authenticity_token" value="xxxxx" type="hidden">
<input name="upload_file[parent_id]" value="1" type="hidden">
<input name="format" value="json" type="hidden">
</form>
<h4>Configure Microphone</h4>
<form class="mic_config" onsubmit="return false;">
<ul>
<li>
<label for="rate">Rate</label>
<select id="rate" name="rate">
<option value="44" selected>44,100 Hz</option>
<option value="22">22,050 Hz</option>
<option value="11">11,025 Hz</option>
<option value="8">8,000 Hz</option>
<option value="5">5,512 Hz</option>
</select>
</li>
<li>
<label for="gain">Gain</label>
<select id="gain" name="gain">
</select>
</li>
<li>
<label for="silenceLevel">Silence Level</label>
<select id="silenceLevel" name="silenceLevel">
</select>
</li>
<li>
<label for="silenceTimeout">Silence Timeout</label>
<input id="silenceTimeout" name="silenceTimeout" value="2000"/>
</li>
<li>
<input id="useEchoSuppression" name="useEchoSuppression" type="checkbox"/>
<label for="useEchoSuppression">Use Echo Suppression</label>
</li>
<li>
<input id="loopBack" name="loopBack" type="checkbox"/>
<label for="loopBack">Loop Back</label>
</li>
<li>
<button onclick="configureMicrophone();">Configure</button>
</li>
</ul>
</form>
</div>
</body>
</html>
upload.php的
<?php
$save_folder = dirname(__FILE__) . "/speaking_audios";
if(! file_exists($save_folder)) {
if(! mkdir($save_folder)) {
die("failed to create save folder $save_folder");
}
}
function valid_wav_file($file) {
$handle = fopen($file, 'r');
$header = fread($handle, 4);
list($chunk_size) = array_values(unpack('V', fread($handle, 4)));
$format = fread($handle, 4);
fclose($handle);
return $header == 'RIFF' && $format == 'WAVE' && $chunk_size == (filesize($file) - 8);
}
$key = 'filename';
$tmp_name = $_FILES["upload_file"]["tmp_name"][$key];
$upload_name = $_FILES["upload_file"]["name"][$key];
$type = $_FILES["upload_file"]["type"][$key];
$filename = "$save_folder/$upload_name";
$saved = 0;
if($type == 'audio/wav' && preg_match('/^[a-zA-Z0-9_\-]+\.wav$/', $upload_name) && valid_wav_file($tmp_name)) {
$saved = move_uploaded_file($tmp_name, $filename) ? 1 : 0;
}
if($_POST['format'] == 'json') {
header('Content-type: application/json');
print "{\"saved\": $saved}";
} else {
print $saved ? "Saved" : 'Not saved';
}
exit;
?>
JS / main.js
$(function () {
var $uploadStatus = $('#upload_status'),
$showLevelButton = $('.show_level'),
$hideLevelButton = $('.hide_level'),
$level = $('.control_panel .level');
var CLASS_CONTROLS = "control_panel";
var CLASS_RECORDING = "recording";
var CLASS_PLAYBACK_READY = "playback_ready";
var CLASS_PLAYING = "playing";
var CLASS_PLAYBACK_PAUSED = "playback_paused";
// Embedding flash object ---------------------------------------------------------------------------------------------
setUpFormOptions();
var appWidth = 24;
var appHeight = 24;
var flashvars = {'upload_image': 'images/upload.png'};
var params = {};
var attributes = {'id': "recorderApp", 'name': "recorderApp"};
swfobject.embedSWF("recorder.swf", "flashcontent", appWidth, appHeight, "11.0.0", "", flashvars, params, attributes);
// Handling FWR events ------------------------------------------------------------------------------------------------
window.fwr_event_handler = function fwr_event_handler() {
$('#status').text("Last recorder event: " + arguments[0]);
var name, $controls;
switch (arguments[0]) {
case "ready":
var width = parseInt(arguments[1]);
var height = parseInt(arguments[2]);
FWRecorder.uploadFormId = "#uploadForm";
FWRecorder.uploadFieldName = "upload_file[filename]";
FWRecorder.connect("recorderApp", 0);
FWRecorder.recorderOriginalWidth = width;
FWRecorder.recorderOriginalHeight = height;
$('.save_button').css({'width': width, 'height': height});
break;
case "no_microphone_found":
break;
case "microphone_user_request":
recorderEl().addClass("floating");
FWRecorder.showPermissionWindow();
break;
case "microphone_connected":
FWRecorder.isReady = true;
$uploadStatus.css({'color': '#000'});
break;
case "permission_panel_closed":
FWRecorder.defaultSize();
recorderEl().removeClass("floating");
break;
case "microphone_activity":
$('#activity_level').text(arguments[1]);
break;
case "recording":
name = arguments[1];
$controls = controlsEl(name);
FWRecorder.hide();
setControlsClass($controls, CLASS_RECORDING);
break;
case "recording_stopped":
name = arguments[1];
$controls = controlsEl(name);
var duration = arguments[2];
FWRecorder.show();
setControlsClass($controls, CLASS_PLAYBACK_READY);
$('#duration').text(duration.toFixed(4) + " seconds");
break;
case "microphone_level":
$level.css({width: arguments[1] * 50 + '%'});
break;
case "observing_level":
$showLevelButton.hide();
$hideLevelButton.show();
break;
case "observing_level_stopped":
$showLevelButton.show();
$hideLevelButton.hide();
$level.css({width: 0});
break;
case "playing":
name = arguments[1];
$controls = controlsEl(name);
setControlsClass($controls, CLASS_PLAYING);
break;
case "playback_started":
name = arguments[1];
var latency = arguments[2];
break;
case "stopped":
name = arguments[1];
$controls = controlsEl(name);
setControlsClass($controls, CLASS_PLAYBACK_READY);
break;
case "playing_paused":
name = arguments[1];
$controls = controlsEl(name);
setControlsClass($controls, CLASS_PLAYBACK_PAUSED);
break;
case "save_pressed":
FWRecorder.updateForm();
break;
case "saving":
name = arguments[1];
break;
case "saved":
name = arguments[1];
var data = $.parseJSON(arguments[2]);
if (data.saved) {
$('#upload_status').css({'color': '#0F0'}).text(name + " was saved");
} else {
$('#upload_status').css({'color': '#F00'}).text(name + " was not saved");
}
break;
case "save_failed":
name = arguments[1];
var errorMessage = arguments[2];
$uploadStatus.css({'color': '#F00'}).text(name + " failed: " + errorMessage);
break;
case "save_progress":
name = arguments[1];
var bytesLoaded = arguments[2];
var bytesTotal = arguments[3];
$uploadStatus.css({'color': '#000'}).text(name + " progress: " + bytesLoaded + " / " + bytesTotal);
break;
}
};
// Helper functions ---------------------------------------------------------------------------------------------------
function setUpFormOptions() {
var gain = $('#gain')[0];
var silenceLevel = $('#silenceLevel')[0];
for (var i = 0; i <= 100; i++) {
gain.options[gain.options.length] = new Option(100 - i);
silenceLevel.options[silenceLevel.options.length] = new Option(i);
}
}
function setControlsClass($controls, className) {
$controls.attr('class', CLASS_CONTROLS + ' ' + className);
}
function controlsEl(name) {
return $('#recorder-' + name);
}
function recorderEl() {
return $('#recorderApp');
}
// Button actions -----------------------------------------------------------------------------------------------------
window.microphonePermission = function () {
recorderEl().addClass("floating");
FWRecorder.showPermissionWindow({permanent: true});
};
window.configureMicrophone = function () {
if (!FWRecorder.isReady) {
return;
}
FWRecorder.configure($('#rate').val(), $('#gain').val(), $('#silenceLevel').val(), $('#silenceTimeout').val());
FWRecorder.setUseEchoSuppression($('#useEchoSuppression').is(":checked"));
FWRecorder.setLoopBack($('#loopBack').is(":checked"));
};
});
JS / recorder.js
(function(global) {
var Recorder;
var RECORDED_AUDIO_TYPE = "audio/wav";
Recorder = {
recorder: null,
recorderOriginalWidth: 0,
recorderOriginalHeight: 0,
uploadFormId: null,
uploadFieldName: null,
isReady: false,
connect: function(name, attempts) {
if(navigator.appName.indexOf("Microsoft") != -1) {
Recorder.recorder = window[name];
} else {
Recorder.recorder = document[name];
}
if(attempts >= 40) {
return;
}
// flash app needs time to load and initialize
if(Recorder.recorder && Recorder.recorder.init) {
Recorder.recorderOriginalWidth = Recorder.recorder.width;
Recorder.recorderOriginalHeight = Recorder.recorder.height;
if(Recorder.uploadFormId && $) {
var frm = $(Recorder.uploadFormId);
Recorder.recorder.init(frm.attr('action').toString(), Recorder.uploadFieldName, frm.serializeArray());
}
return;
}
setTimeout(function() {Recorder.connect(name, attempts+1);}, 100);
},
playBack: function(name) {
// TODO: Rename to `playback`
Recorder.recorder.playBack(name);
},
pausePlayBack: function(name) {
// TODO: Rename to `pausePlayback`
Recorder.recorder.pausePlayBack(name);
},
playBackFrom: function(name, time) {
// TODO: Rename to `playbackFrom`
Recorder.recorder.playBackFrom(name, time);
},
record: function(name, filename) {
Recorder.recorder.record(name, filename);
},
stopRecording: function() {
Recorder.recorder.stopRecording();
},
stopPlayBack: function() {
// TODO: Rename to `stopPlayback`
Recorder.recorder.stopPlayBack();
},
observeLevel: function() {
Recorder.recorder.observeLevel();
},
stopObservingLevel: function() {
Recorder.recorder.stopObservingLevel();
},
observeSamples: function() {
Recorder.recorder.observeSamples();
},
stopObservingSamples: function() {
Recorder.recorder.stopObservingSamples();
},
resize: function(width, height) {
Recorder.recorder.width = width + "px";
Recorder.recorder.height = height + "px";
},
defaultSize: function() {
Recorder.resize(Recorder.recorderOriginalWidth, Recorder.recorderOriginalHeight);
},
show: function() {
Recorder.recorder.show();
},
hide: function() {
Recorder.recorder.hide();
},
duration: function(name) {
// TODO: rename to `getDuration`
return Recorder.recorder.duration(name || Recorder.uploadFieldName);
},
getBase64: function(name) {
var data = Recorder.recorder.getBase64(name);
return 'data:' + RECORDED_AUDIO_TYPE + ';base64,' + data;
},
getBlob: function(name) {
var base64Data = Recorder.getBase64(name).split(',')[1];
return base64toBlob(base64Data, RECORDED_AUDIO_TYPE);
},
getCurrentTime: function(name) {
return Recorder.recorder.getCurrentTime(name);
},
isMicrophoneAccessible: function() {
return Recorder.recorder.isMicrophoneAccessible();
},
updateForm: function() {
var frm = $(Recorder.uploadFormId);
Recorder.recorder.update(frm.serializeArray());
},
showPermissionWindow: function(options) {
Recorder.resize(240, 160);
// need to wait until app is resized before displaying permissions screen
var permissionCommand = function() {
if (options && options.permanent) {
Recorder.recorder.permitPermanently();
} else {
Recorder.recorder.permit();
}
};
setTimeout(permissionCommand, 1);
},
configure: function(rate, gain, silenceLevel, silenceTimeout) {
rate = parseInt(rate || 22);
gain = parseInt(gain || 100);
silenceLevel = parseInt(silenceLevel || 0);
silenceTimeout = parseInt(silenceTimeout || 4000);
switch(rate) {
case 44:
case 22:
case 11:
case 8:
case 5:
break;
default:
throw("invalid rate " + rate);
}
if(gain < 0 || gain > 100) {
throw("invalid gain " + gain);
}
if(silenceLevel < 0 || silenceLevel > 100) {
throw("invalid silenceLevel " + silenceLevel);
}
if(silenceTimeout < -1) {
throw("invalid silenceTimeout " + silenceTimeout);
}
Recorder.recorder.configure(rate, gain, silenceLevel, silenceTimeout);
},
setUseEchoSuppression: function(val) {
if(typeof(val) != 'boolean') {
throw("invalid value for setting echo suppression, val: " + val);
}
Recorder.recorder.setUseEchoSuppression(val);
},
setLoopBack: function(val) {
if(typeof(val) != 'boolean') {
throw("invalid value for setting loop back, val: " + val);
}
Recorder.recorder.setLoopBack(val);
}
};
function base64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, {type: contentType});
}
global.FWRecorder = Recorder;
})(this);
好吧,我只是想让你专注于upload.php文件,看看我做错了什么。
答案 0 :(得分:1)
处理文件时,需要有效的enctype和POST方法。
因此,您需要更改此表单:
<form id="uploadForm" name="uploadForm" action="upload.php">
对此:
<form enctype="multipart/form-data" method="post" id="uploadForm" name="uploadForm" action="upload.php">
并检查错误并确保您上传的文件夹具有正确的权限。
参考文献: