PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/OpenVBX/controllers/audiofiles.php

https://github.com/mdjaman/OpenVBX
PHP | 452 lines | 360 code | 58 blank | 34 comment | 39 complexity | 70e88909be4683c56d65bf09dfeda38c MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. <?php if (!defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * "The contents of this file are subject to the Mozilla Public License
  4. * Version 1.1 (the "License"); you may not use this file except in
  5. * compliance with the License. You may obtain a copy of the License at
  6. * http://www.mozilla.org/MPL/
  7. * Software distributed under the License is distributed on an "AS IS"
  8. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  9. * License for the specific language governing rights and limitations
  10. * under the License.
  11. * The Original Code is OpenVBX, released June 15, 2010.
  12. * The Initial Developer of the Original Code is Twilio Inc.
  13. * Portions created by Twilio Inc. are Copyright (C) 2010.
  14. * All Rights Reserved.
  15. * Contributor(s):
  16. **/
  17. include_once(APPPATH.'libraries/twilio.php');
  18. class AudioFilesException extends Exception {}
  19. class AudioFiles extends User_Controller
  20. {
  21. protected $response;
  22. protected $request;
  23. protected $say_params;
  24. protected $suppress_warnings_notices = true;
  25. function __construct()
  26. {
  27. // This is to support SWFUpload. SWFUpload will scrape all cookies via Javascript
  28. // and send them as POST request params. This enables the file uploader to work
  29. // with a proper session.
  30. foreach ($_POST as $key => $value)
  31. {
  32. // Copy any key that looks like an Openvbx session over to $_COOKIE where it's expected
  33. if (preg_match("/^(\d+\-)?openvbx_session$/", $key))
  34. {
  35. // url-decode the session key, try to preserve "+" in email addresses
  36. $value = $_POST[$key];
  37. $preserve_plus = false;
  38. preg_match("|s:5:\"email\";s:[0-9]+:\"(.*?)\";|", $value, $matches);
  39. if (strpos($matches[1], '+') !== false)
  40. {
  41. $plus_temp = '___plus___';
  42. $preserve_plus = true;
  43. $email = str_replace('+', $plus_temp, $matches[0]);
  44. $value = str_replace($matches[0], $email, $value);
  45. }
  46. $value = urldecode($value);
  47. if ($preserve_plus)
  48. {
  49. $value = str_replace($plus_temp, '+', $value);
  50. }
  51. $_COOKIE[$key] = $value;
  52. }
  53. }
  54. parent::__construct();
  55. $this->load->library('TwimlResponse');
  56. $this->load->model('vbx_audio_file');
  57. $this->say_params = array(
  58. 'voice' => $this->vbx_settings->get('voice', $this->tenant->id),
  59. 'language' => $this->vbx_settings->get('voice_language', $this->tenant->id)
  60. );
  61. }
  62. function index()
  63. {
  64. $this->respond('', 'library', $data);
  65. }
  66. function add_file()
  67. {
  68. $json = array(
  69. 'error' => false,
  70. 'message' => ''
  71. );
  72. if (!empty($_FILES) && isset($_FILES["Filedata"]) && $_FILES["Filedata"]["error"] == UPLOAD_ERR_OK)
  73. {
  74. $file = $_FILES["Filedata"];
  75. $name_parts = explode('.', $file['name']);
  76. $ext = $name_parts[count($name_parts) - 1];
  77. if (in_array(strtolower($ext), array('wav', 'mp3')))
  78. {
  79. // Can we write to our audio upload directory?
  80. $audioUploadsPath = 'audio-uploads/';
  81. if (is_writable($audioUploadsPath))
  82. {
  83. $targetFile = null;
  84. // Make sure we pick a name that's not already in use...
  85. while ($targetFile == null)
  86. {
  87. $candidate = $audioUploadsPath . md5(uniqid($file['name'])) . '.' . $ext;
  88. if (!file_exists($candidate))
  89. {
  90. // We can use this filename
  91. $targetFile = $candidate;
  92. break;
  93. }
  94. }
  95. move_uploaded_file($file['tmp_name'], $targetFile);
  96. // Return the URL for our newly created file
  97. $json['url'] = "vbx-audio-upload://" . basename($targetFile);
  98. $ci =& get_instance();
  99. // And, make a record in the database
  100. $audioFile = new VBX_Audio_File();
  101. $audioFile->label = "Upload of " . $file['name'];
  102. $audioFile->user_id = intval($this->session->userdata('user_id'));
  103. $audioFile->url = $json['url'];
  104. $audioFile->tag = $this->input->post('tag');
  105. $audioFile->save();
  106. // We return the label so that this upload can be added the library UI without
  107. // refreshing the page.
  108. $json['label'] = $audioFile->label;
  109. }
  110. else
  111. {
  112. $json['error'] = true;
  113. $json['message'] = 'Upload directory is not writable';
  114. }
  115. }
  116. else
  117. {
  118. $json['error'] = true;
  119. $json['message'] = 'Unsupported file format. Only MP3 and WAV files are supported.';
  120. }
  121. }
  122. else
  123. {
  124. $json['error'] = true;
  125. $json['message'] = 'No files were found in the upload.';
  126. if(isset($_FILES["Filedata"]))
  127. {
  128. $error = $_FILES["Filedata"]["error"];
  129. switch ($error)
  130. {
  131. case UPLOAD_ERR_INI_SIZE:
  132. $json['message'] = 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
  133. break;
  134. case UPLOAD_ERR_FORM_SIZE:
  135. $json['message'] = 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
  136. break;
  137. case UPLOAD_ERR_PARTIAL:
  138. $json['message'] = 'The uploaded file was only partially uploaded';
  139. break;
  140. case UPLOAD_ERR_NO_FILE:
  141. $json['message'] = 'No file was uploaded';
  142. break;
  143. case UPLOAD_ERR_NO_TMP_DIR:
  144. $json['message'] = 'Missing a temporary folder';
  145. break;
  146. case UPLOAD_ERR_CANT_WRITE:
  147. $json['message'] = 'Failed to write file to disk';
  148. break;
  149. case UPLOAD_ERR_EXTENSION:
  150. $json['message'] = 'File upload stopped by extension';
  151. break;
  152. }
  153. }
  154. }
  155. $data = array();
  156. $data['json'] = $json;
  157. $this->response_type = 'json';
  158. $this->respond('', null, $data);
  159. }
  160. function add_from_twilio_recording()
  161. {
  162. $json = array(
  163. 'error' => false,
  164. 'message' => ''
  165. );
  166. $to = $this->input->post('to');
  167. $callerid = $this->input->post('callerid');
  168. if (strlen($to) == 0)
  169. {
  170. $json['error'] = true;
  171. $json['message'] = "You must provide a number to call.";
  172. }
  173. else if (strlen($callerid) == 0)
  174. {
  175. $json['error'] = true;
  176. $json['message'] = "You must have an incoming number to record a greeting. <a href=\"".site_url('numbers')."\">Get a Number</a>";
  177. }
  178. else
  179. {
  180. $rest_access_token = $this->make_rest_access();
  181. $path = 'audiofiles!prompt_for_recording_twiml';
  182. $recording_url = stripslashes(site_url("twiml/redirect/" . $path . "/$rest_access_token"));
  183. try {
  184. $account = OpenVBX::getAccount();
  185. $call = $account->calls->create(
  186. $callerid,
  187. $to,
  188. $recording_url
  189. );
  190. // Create a place holder for our recording
  191. $audioFile = new VBX_Audio_File((object) Array(
  192. 'label' => 'Recording with '.format_phone($to),
  193. 'user_id' => intval($this->session->userdata('user_id')),
  194. 'recording_call_sid' => $call->sid,
  195. 'tag' => $this->input->post('tag')
  196. ));
  197. $audioFile->save();
  198. $json['id'] = $audioFile->id;
  199. }
  200. catch (Exception $e) {
  201. $json['message'] = $e->getMessage();
  202. $json['error'] = true;
  203. }
  204. }
  205. $data = array();
  206. $data['json'] = $json;
  207. $this->response_type = 'json';
  208. $this->respond('', null, $data);
  209. }
  210. function prompt_for_recording_twiml()
  211. {
  212. validate_rest_request();
  213. $response = new TwimlResponse;
  214. $audioFile = VBX_Audio_File::get(array('recording_call_sid' => $this->input->get_post('CallSid')));
  215. if (!$audioFile->cancelled)
  216. {
  217. $response->say("Re-chord your message after the beep, press the pound key when finished.", $this->say_params);
  218. $response->record(array('action' => site_url('audiofiles/replay_recording_twiml')));
  219. $response->say("We didn't get a recording from you, try again.", $this->say_params);
  220. $response->redirect(site_url('audiofiles/prompt_for_recording_twiml'));
  221. }
  222. else
  223. {
  224. $response->say("The recording was cancelled.", $this->say_params);
  225. $response->hangup();
  226. }
  227. return $response->respond();
  228. }
  229. function replay_recording_twiml()
  230. {
  231. validate_rest_request();
  232. $response = new TwimlResponse;
  233. if ($this->input->get_post('RecordingUrl'))
  234. {
  235. // Stuff this in our session. We'll come get it later when it's time to save!
  236. $recording = $this->input->get_post('RecordingUrl') . '.mp3';
  237. $this->session->set_userdata('current-recording', $recording);
  238. }
  239. $response->pause(array('length' => 1));
  240. $response->say('Recorded the following: ', $this->say_params);
  241. $gather = $response->gather(array('numDigits' => 1,
  242. 'method' => 'POST',
  243. 'action' => site_url('audiofiles/accept_or_reject_recording_twiml')
  244. ));
  245. $gather->play($this->session->userdata('current-recording'));
  246. $gather->say('If you like this message, press 1. ... To record a different message, press 2.', $this->say_params);
  247. // If they don't enter anything at the prompt, do the replay again.
  248. $response->redirect(site_url('audiofiles/replay_recording_twiml'));
  249. return $response->respond();
  250. }
  251. function accept_or_reject_recording_twiml()
  252. {
  253. validate_rest_request();
  254. $response = new TwimlResponse;
  255. $digits = clean_digits($this->input->get_post('Digits'));
  256. $call_sid = $this->input->get_post('CallSid');
  257. switch($digits)
  258. {
  259. case 1:
  260. $audioFile = VBX_Audio_File::get(array('recording_call_sid' => $call_sid));
  261. if ($audioFile == null)
  262. {
  263. trigger_error("That's weird - we can't find the place holder audio file that matches this sid (".$call_sid.")");
  264. }
  265. else
  266. {
  267. $audioFile->url = $this->session->userdata('current-recording');
  268. $audioFile->save();
  269. }
  270. $response->say('Your recording has been saved.', $this->say_params);
  271. $response->hangup();
  272. break;
  273. case 2:
  274. $response->redirect(site_url('audiofiles/prompt_for_recording_twiml'));
  275. default:
  276. $response->redirect(site_url('audiofiles/replay_recording_twiml'));
  277. break;
  278. }
  279. return $response->respond();
  280. }
  281. function hangup_on_cancel()
  282. {
  283. _deprecated_method(__METHOD__, '1.0.4');
  284. validate_rest_request();
  285. $response = new TwimlResponse;
  286. $response->hangup();
  287. return $response->respond();
  288. }
  289. function cancel_recording()
  290. {
  291. $json = array(
  292. 'error' => false,
  293. 'message' => ''
  294. );
  295. $audio_file_id = $this->input->post('id');
  296. if (strlen($audio_file_id) == 0)
  297. {
  298. $json['error'] = true;
  299. $json['message'] = "Missing 'id' parameter.";
  300. }
  301. else
  302. {
  303. $audioFile = VBX_Audio_File::get($audio_file_id);
  304. if (is_null($audioFile))
  305. {
  306. trigger_error("We were given an id for an audio_file, but we can't find the record. That's odd. And, by odd I really mean it should *never* happen.");
  307. }
  308. else if ($audioFile->user_id != $this->session->userdata('user_id'))
  309. {
  310. trigger_error("You can't cancel a recording you didn't start.");
  311. }
  312. else
  313. {
  314. log_message('debug', 'canceling call');
  315. try {
  316. $account = OpenVBX::getAccount();
  317. $call = $account->calls->get($audioFile->recording_call_sid);
  318. if ($call->status == 'ringing') {
  319. $params = array(
  320. 'Status' => 'canceled'
  321. );
  322. }
  323. else {
  324. $params = array(
  325. 'Status' => 'completed'
  326. );
  327. }
  328. $call->update($params);
  329. $audioFile->cancelled = true;
  330. $audioFile->save();
  331. }
  332. catch (Exception $e) {
  333. trigger_error($e->getMessage());
  334. $json['error'] = true;
  335. $json['message'] = $e->getMessage();
  336. }
  337. }
  338. }
  339. $data = array();
  340. $data['json'] = $json;
  341. $this->response_type = 'json';
  342. $this->respond('', null, $data);
  343. }
  344. function check_if_recording_is_finished()
  345. {
  346. $json = array(
  347. 'error' => false,
  348. 'message' => ''
  349. );
  350. $audio_file_id = $this->input->post('id');
  351. if (strlen($audio_file_id) == 0)
  352. {
  353. $json['error'] = true;
  354. $json['message'] = "Missing 'id' parameter.";
  355. }
  356. else
  357. {
  358. $newAudioFile = VBX_Audio_File::get($audio_file_id);
  359. if ($newAudioFile == null)
  360. {
  361. trigger_error("We were given an id for an audio_file, but we can't find the record. That's odd. And, by odd I really mean it should *never* happen.");
  362. }
  363. else
  364. {
  365. if (strlen($newAudioFile->url) > 0)
  366. {
  367. $json['finished'] = true;
  368. $json['url'] = $newAudioFile->url;
  369. // We return the label so that this upload can be added the library UI without
  370. // refreshing the page.
  371. $json['label'] = $newAudioFile->label;
  372. }
  373. else
  374. {
  375. $json['finished'] = false;
  376. }
  377. }
  378. }
  379. $data = array();
  380. $data['json'] = $json;
  381. $this->response_type = 'json';
  382. $this->respond('', null, $data);
  383. }
  384. }