title: how to upload a recorded audio file using pdo to a website folder
body: <p>I am trying to implement an audio recorder within my website. What I want is to make the user save the recorded file directly to the database and/or to a subfolder in my website (called /speaking_audios). There follows the main files: recorder.php, sync.html, upload.php, js/main.js, js/swfobject.js, js/recorder.js, recorder.swf (I don't know what it is for).</p>
  
  <p>recorder.php</p>
  
  <pre><code> &lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head lang="en"&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;FlashWavRecorder demo&lt;/title&gt;
    &lt;script src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js'&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="js/swfobject.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="js/recorder.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="js/main.js"&gt;&lt;/script&gt;
    &lt;link rel="stylesheet" href="css/style.css"&gt;
  
  &lt;/head&gt;
  
  &lt;body&gt;
    &lt;div class="container"&gt;
  
      &lt;h1&gt;&lt;a href="https://github.com/cykod/FlashWavRecorder"&gt;FlashWavRecorder&lt;/a&gt;&lt;/h1&gt;
      &lt;p&gt;&lt;strong&gt;Upload requires php, i.e. example will not work on github.com&lt;/strong&gt;&lt;/p&gt;
  
  
      &lt;div id="recorder-audio" class="control_panel idle"&gt;
        &lt;button class="record_button" onclick="FWRecorder.record('audio', 'audio.wav');" title="Record"&gt;
          &lt;img src="images/record.png" alt="Record"/&gt;
        &lt;/button&gt;
        &lt;button class="stop_recording_button" onclick="FWRecorder.stopRecording('audio');" title="Stop Recording"&gt;
          &lt;img src="images/stop.png" alt="Stop Recording"/&gt;
        &lt;/button&gt;
        &lt;button class="play_button" onclick="FWRecorder.playBack('audio');" title="Play"&gt;
            &lt;img src="images/play.png" alt="Play"/&gt;
        &lt;/button&gt;
        &lt;button class="pause_playing_button" onclick="FWRecorder.pausePlayBack('audio');" title="Pause Playing"&gt;
            &lt;img src="images/pause.png" alt="Pause Playing"/&gt;
        &lt;/button&gt;
        &lt;button class="stop_playing_button" onclick="FWRecorder.stopPlayBack();" title="Stop Playing"&gt;
          &lt;img src="images/stop.png" alt="Stop Playing"/&gt;
        &lt;/button&gt;
        &lt;div class="level"&gt;&lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div id="recorder-audio2" class="control_panel idle"&gt;
        &lt;button class="record_button" onclick="FWRecorder.record('audio2', 'audio2.wav');" title="Record"&gt;
          &lt;img src="images/record.png" alt="Record"/&gt;
        &lt;/button&gt;
        &lt;button class="stop_recording_button" onclick="FWRecorder.stopRecording('audio2');" title="Stop Recording"&gt;
          &lt;img src="images/stop.png" alt="Stop Recording"/&gt;
        &lt;/button&gt;
        &lt;button class="play_button" onclick="FWRecorder.playBack('audio2');" title="Play"&gt;
          &lt;img src="images/play.png" alt="Play"/&gt;
        &lt;/button&gt;
        &lt;button class="pause_playing_button" onclick="FWRecorder.pausePlayBack('audio2');" title="Pause Playing"&gt;
          &lt;img src="images/pause.png" alt="Pause Playing"/&gt;
        &lt;/button&gt;
        &lt;button class="stop_playing_button" onclick="FWRecorder.stopPlayBack();" title="Stop Playing"&gt;
          &lt;img src="images/stop.png" alt="Stop Playing"/&gt;
        &lt;/button&gt;
        &lt;div class="level"&gt;&lt;/div&gt;
      &lt;/div&gt;
  
      &lt;div class="details"&gt;
        &lt;button class="show_level" onclick="FWRecorder.observeLevel();"&gt;Show Level&lt;/button&gt;
        &lt;button class="hide_level" onclick="FWRecorder.stopObservingLevel();" style="display: none;"&gt;Hide Level&lt;/button&gt;
        &lt;span id="save_button"&gt;
          &lt;span id="flashcontent"&gt;
            &lt;p&gt;Your browser must have JavaScript enabled and the Adobe Flash Player installed.&lt;/p&gt;
          &lt;/span&gt;
        &lt;/span&gt;
        &lt;div&gt;&lt;button class="show_settings" onclick="microphonePermission()"&gt;Microphone permission&lt;/button&gt;&lt;/div&gt;
        &lt;div id="status"&gt;
         Recorder Status...
        &lt;/div&gt;
        &lt;div&gt;Duration: &lt;span id="duration"&gt;&lt;/span&gt;&lt;/div&gt;
        &lt;div&gt;Activity Level: &lt;span id="activity_level"&gt;&lt;/span&gt;&lt;/div&gt;
        &lt;div&gt;Upload status: &lt;span id="upload_status"&gt;&lt;/span&gt;&lt;/div&gt;
      &lt;/div&gt;
  
      &lt;form id="uploadForm" name="uploadForm" action="upload.php"&gt;
        &lt;input name="authenticity_token" value="xxxxx" type="hidden"&gt;
        &lt;input name="upload_file[parent_id]" value="1" type="hidden"&gt;
        &lt;input name="format" value="json" type="hidden"&gt;
      &lt;/form&gt;
  
      &lt;h4&gt;Configure Microphone&lt;/h4&gt;
      &lt;form class="mic_config" onsubmit="return false;"&gt;
        &lt;ul&gt;
          &lt;li&gt;
            &lt;label for="rate"&gt;Rate&lt;/label&gt;
            &lt;select id="rate" name="rate"&gt;
              &lt;option value="44" selected&gt;44,100 Hz&lt;/option&gt;
              &lt;option value="22"&gt;22,050 Hz&lt;/option&gt;
              &lt;option value="11"&gt;11,025 Hz&lt;/option&gt;
              &lt;option value="8"&gt;8,000 Hz&lt;/option&gt;
              &lt;option value="5"&gt;5,512 Hz&lt;/option&gt;
            &lt;/select&gt;
          &lt;/li&gt;
  
          &lt;li&gt;
            &lt;label for="gain"&gt;Gain&lt;/label&gt;
            &lt;select id="gain" name="gain"&gt;
            &lt;/select&gt;
          &lt;/li&gt;
  
          &lt;li&gt;
            &lt;label for="silenceLevel"&gt;Silence Level&lt;/label&gt;
            &lt;select id="silenceLevel" name="silenceLevel"&gt;
            &lt;/select&gt;
          &lt;/li&gt;
  
          &lt;li&gt;
            &lt;label for="silenceTimeout"&gt;Silence Timeout&lt;/label&gt;
            &lt;input id="silenceTimeout" name="silenceTimeout" value="2000"/&gt;
          &lt;/li&gt;
  
          &lt;li&gt;
            &lt;input id="useEchoSuppression" name="useEchoSuppression" type="checkbox"/&gt;
            &lt;label for="useEchoSuppression"&gt;Use Echo Suppression&lt;/label&gt;
          &lt;/li&gt;
  
          &lt;li&gt;
            &lt;input id="loopBack" name="loopBack" type="checkbox"/&gt;
            &lt;label for="loopBack"&gt;Loop Back&lt;/label&gt;
          &lt;/li&gt;
  
          &lt;li&gt;
            &lt;button onclick="configureMicrophone();"&gt;Configure&lt;/button&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/form&gt;
    &lt;/div&gt;
  
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>upload.php</p>
  
  <pre><code>    &lt;?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' &amp;&amp; $format == 'WAVE' &amp;&amp; $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' &amp;&amp; preg_match('/^[a-zA-Z0-9_\-]+\.wav$/', $upload_name) &amp;&amp; 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;
  ?&gt;
  </code></pre>
  
  <p>js/main.js</p>
  
  <pre><code>    $(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 &lt;= 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"));
    };
  
  });
  </code></pre>
  
  <p>js/recorder.js</p>
  
  <pre><code>    (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 &gt;= 40) {
          return;
        }
  
        // flash app needs time to load and initialize
        if(Recorder.recorder &amp;&amp; Recorder.recorder.init) {
          Recorder.recorderOriginalWidth = Recorder.recorder.width;
          Recorder.recorderOriginalHeight = Recorder.recorder.height;
          if(Recorder.uploadFormId &amp;&amp; $) {
            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 &amp;&amp; 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 &lt; 0 || gain &gt; 100) {
          throw("invalid gain " + gain);
        }
  
        if(silenceLevel &lt; 0 || silenceLevel &gt; 100) {
          throw("invalid silenceLevel " + silenceLevel);
        }
  
        if(silenceTimeout &lt; -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 &lt; byteCharacters.length; offset += sliceSize) {
        var slice = byteCharacters.slice(offset, offset + sliceSize);
  
        var byteNumbers = new Array(slice.length);
        for (var i = 0; i &lt; 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);
  </code></pre>
  
  <p>Well, I just want you to concentrate on the upload.php file and see what I'm doing wrong.</p>