PageRenderTime 59ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/OpenVBX/libraries/OpenVBX.php

https://bitbucket.org/gegere/openvbx
PHP | 531 lines | 359 code | 53 blank | 119 comment | 47 complexity | 6ee383643f306bd129dc409dae4297fc MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. <?php
  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(APPPATH.'libraries/Services/Twilio.php');
  18. class OpenVBXException extends Exception {}
  19. class OpenVBX {
  20. protected static $version;
  21. protected static $schemaVersion;
  22. public static $currentPlugin = null;
  23. private static $_twilioService;
  24. private static $_twilioValidator;
  25. public static function query($sql)
  26. {
  27. return PluginData::sqlQuery($sql);
  28. }
  29. public static function one($sql)
  30. {
  31. return PluginData::one($sql);
  32. }
  33. public static function isAdmin() {
  34. $ci =& get_instance();
  35. $is_admin = $ci->session->userdata('is_admin');
  36. return ($is_admin == 1);
  37. }
  38. public static function getTwilioAccountType()
  39. {
  40. try
  41. {
  42. $ci =& get_instance();
  43. $ci->load->model('vbx_accounts');
  44. return $ci->vbx_accounts->getAccountType();
  45. }
  46. catch(VBX_AccountsException $e)
  47. {
  48. error_log($e->getMessage());
  49. self::setNotificationMessage($e->getMessage());
  50. return 'Full';
  51. }
  52. }
  53. public static function getCurrentUser()
  54. {
  55. $ci =& get_instance();
  56. $user_id = $ci->session->userdata('user_id');
  57. return VBX_User::get($user_id);
  58. }
  59. /**
  60. * Get the twilio API version from the API endpoint settings
  61. *
  62. * @deprecated url versioning is handled by Twilio Services library
  63. * @return mixes string/null
  64. */
  65. public static function getTwilioApiVersion()
  66. {
  67. $ci =& get_instance();
  68. $url = $ci->vbx_settings->get('twilio_endpoint', VBX_PARENT_TENANT);
  69. if(preg_match('/.*\/([0-9]+-[0-9]+-[0-9]+)$/', $url, $matches))
  70. {
  71. return $matches[1];
  72. }
  73. return null;
  74. }
  75. public static function addCSS($file)
  76. {
  77. $ci =& get_instance();
  78. $plugin = OpenVBX::$currentPlugin;
  79. $info = $plugin->getInfo();
  80. $path = $info['plugin_path'] .'/'. $file;
  81. if(!is_file($path))
  82. error_log("Warning: CSS file does not exists: {$path}");
  83. $url = implode('/', array('plugins', $info['dir_name'], $file));
  84. $ci->template->add_css($url);
  85. }
  86. public static function addJS($file)
  87. {
  88. $ci =& get_instance();
  89. $plugin = OpenVBX::$currentPlugin;
  90. $info = $plugin->getInfo();
  91. $path = $info['plugin_path'] .'/'. $file;
  92. if(!is_file($path))
  93. error_log("Warning: JS script does not exists: {$path}");
  94. $url = implode('/', array('plugins', $info['dir_name'], $file));
  95. $ci->template->add_js($url);
  96. }
  97. public static function setNotificationMessage($message)
  98. {
  99. $ci =& get_instance();
  100. $ci->session->set_flashdata('error', $message);
  101. }
  102. public static function getUsers($options = array(), $limit = -1, $offset = 0)
  103. {
  104. return VBX_User::search($options, $limit, $offset);
  105. }
  106. public static function getGroups($options = array(), $limit = -1, $offset = 0)
  107. {
  108. return VBX_Group::search($options, $limit, $offset);
  109. }
  110. public static function getFlows($options = array(), $limit = -1, $offset = 0)
  111. {
  112. return VBX_Flow::search($options, $limit, $offset);
  113. }
  114. public static function addVoiceMessage($owner, $sid, $to, $from, $recording_url, $duration, $notify = false)
  115. {
  116. return self::addMessage($owner, $sid, $to, $from, $recording_url, $duration, VBX_Message::TYPE_VOICE, null, $notify);
  117. }
  118. public static function addSmsMessage($owner, $sid, $to, $from, $body)
  119. {
  120. return self::addMessage($owner, $sid, $to, $from, '', 0, VBX_Message::TYPE_SMS, $body, true);
  121. }
  122. public static function addMessage($owner,
  123. $sid,
  124. $caller,
  125. $called,
  126. $recording_url,
  127. $duration,
  128. $type = VBX_Message::TYPE_VOICE,
  129. $text = null,
  130. $notify = false)
  131. {
  132. try
  133. {
  134. $ci =& get_instance();
  135. $ci->load->model('vbx_message');
  136. if(!is_object($owner))
  137. {
  138. throw new VBX_MessageException('owner is invalid');
  139. }
  140. $owner_type = get_class($owner);
  141. $owner_type = str_replace('vbx_', '', strtolower($owner_type));
  142. $owner_id = $owner->id;
  143. $message = new VBX_Message();
  144. $message->owner_type = $owner_type;
  145. $message->owner_id = $owner_id;
  146. $message->call_sid = $sid;
  147. $message->caller = $caller;
  148. $message->called = $called;
  149. if(is_string($text))
  150. {
  151. $message->content_text = $text;
  152. }
  153. $message->content_url = $recording_url;
  154. $message->size = $duration;
  155. $message->type = $type;
  156. $message->status = VBX_Message::STATUS_NEW;
  157. return $ci->vbx_message->save($message, $notify);
  158. }
  159. catch(VBX_MessageException $e)
  160. {
  161. error_log($e->getMessage());
  162. return false;
  163. }
  164. }
  165. /**
  166. * Returns the OpenVBX software version
  167. *
  168. * @internal Post 1.1.3 this pulls from the file in `OpenVBX/config/version.php` instead
  169. * of pulling from the database. This way the version number can be known without
  170. * a functional database (ie: install)
  171. * @return string
  172. */
  173. public static function version()
  174. {
  175. if (empty(self::$version))
  176. {
  177. $ci =& get_instance();
  178. $ci->config->load('version');
  179. self::$version = $ci->config->item('version');
  180. }
  181. return self::$version;
  182. }
  183. /**
  184. * Returns the version of the database schema
  185. *
  186. * @static
  187. * @return int
  188. */
  189. public static function schemaVersion()
  190. {
  191. if (empty(self::$schemaVersion))
  192. {
  193. $ci =& get_instance();
  194. if ($ci->db)
  195. {
  196. $ci->load->model('vbx_settings');
  197. if (!$cache && $ci->cache->enabled())
  198. {
  199. $ci->cache->enabled(false);
  200. $reenable_cache = true;
  201. }
  202. self::$schemaVersion = $ci->vbx_settings->get('schema-version', VBX_PARENT_TENANT);
  203. if ($reenable_cache)
  204. {
  205. $ci->cache->enabled(true);
  206. }
  207. }
  208. }
  209. return self::$schemaVersion;
  210. }
  211. /**
  212. * Returns the latest version of the schema on the server,
  213. * regardless if its been imported
  214. *
  215. * @static
  216. * @return array
  217. */
  218. public static function getLatestSchemaVersion()
  219. {
  220. $updates = scandir(VBX_ROOT.'/updates/');
  221. foreach($updates as $i => $update)
  222. {
  223. $updates[$i] = intval(preg_replace('/.(sql|php)$/', '', $update));
  224. }
  225. sort($updates);
  226. return $updates[count($updates)-1];
  227. }
  228. /**
  229. * Set the title of the current page
  230. *
  231. * @static
  232. * @param string $title
  233. * @param bool $overwrite whether to replace or append to the current title
  234. * @return mixed
  235. */
  236. public static function setPageTitle($title, $overwrite = false)
  237. {
  238. $ci =& get_instance();
  239. return $ci->template->write('title', $title, $overwrite);
  240. }
  241. /**
  242. * Get the Twilio Services Account object for communicating with Twilio HQ
  243. *
  244. * Will return the proper account for communications with Twilio.
  245. * This method is sub-account & twilio connect aware
  246. *
  247. * Optional: Pass different Account Sid & Token values to communicate
  248. * with a different Twilio Account
  249. *
  250. * Twilio Connect Aware. Will return the connect account if applicable.
  251. *
  252. * @throws OpenVBXException if invalid parameters are passed in for new object generation
  253. *
  254. * @static
  255. * @param bool/string $twilio_sid Optional - Twilio Account Sid
  256. * @param bool/string $twilio_token Optional - Twilio Account Token
  257. * @param string $api_version - default api version to use
  258. * @return object Services_Twilio_Rest_Account
  259. */
  260. public static function getAccount($twilio_sid = false, $twilio_token = false, $api_version = '2010-04-01')
  261. {
  262. $ci =& get_instance();
  263. // if sid & token are passed, make sure they're not the same as our master
  264. // values. If they are, make a new object, otherwise use the same internal object
  265. if (!empty($twilio_sid) || !empty($twilio_token))
  266. {
  267. if (!empty($twilio_sid) && !empty($twilio_token))
  268. {
  269. if ((empty($ci->twilio_sid) && empty($ci->twilio_token))
  270. || $twilio_sid != $ci->twilio_sid && $twilio_token != $ci->twilio_token)
  271. {
  272. try {
  273. $_http_opts = self::get_http_opts();
  274. $_http = new Services_Twilio_TinyHttp(
  275. $_http_opts['host'],
  276. $_http_opts['opts']
  277. );
  278. $service = new Services_Twilio(
  279. $twilio_sid,
  280. $twilio_token,
  281. $api_version,
  282. $_http
  283. );
  284. return $service->account;
  285. }
  286. catch (Exception $e) {
  287. throw new OpenVBXException($e->getMessage());
  288. }
  289. }
  290. }
  291. else
  292. {
  293. throw new OpenVBXException('Both a Sid & Token are required to get a new Services Object');
  294. }
  295. }
  296. // return standard service object
  297. if (!(self::$_twilioService instanceof Services_Twilio))
  298. {
  299. try {
  300. $_http_opts = self::get_http_opts();
  301. $_http = new Services_Twilio_TinyHttp(
  302. $_http_opts['host'],
  303. $_http_opts['opts']
  304. );
  305. self::$_twilioService = new Services_Twilio(
  306. $ci->twilio_sid,
  307. $ci->twilio_token,
  308. $api_version,
  309. $_http
  310. );
  311. }
  312. catch (Exception $e) {
  313. throw new OpenVBXException($e->getMessage());
  314. }
  315. }
  316. return self::$_twilioService->account;
  317. }
  318. /**
  319. * Get a set of modified http options for TinyHttp so that we
  320. * can modify how the api client identifies itself as well as
  321. * inject some debug options
  322. *
  323. * @return array
  324. */
  325. protected static function get_http_opts()
  326. {
  327. $ci =& get_instance();
  328. $_http_opts = array(
  329. 'host' => 'https://api.twilio.com',
  330. 'opts' => array(
  331. 'curlopts' => array(
  332. CURLOPT_USERAGENT => 'openvbx/'.OpenVBX::version()
  333. )
  334. )
  335. );
  336. // optionally load in the included cert for api communication
  337. if ($use_certificate = $ci->config->item('twilio_use_certificate')) {
  338. $_http_opts['opts']['curlopts'][CURLOPT_CAINFO] = APPPATH . 'libraries/Services/twilio_ssl_certificate.crt';
  339. }
  340. // internal api development override, you'll never need this
  341. if ($_http_settings = $ci->config->item('_http_settings'))
  342. {
  343. if (!empty($_http_settings['host']))
  344. {
  345. $_http_opts['host'] = $_http_settings['host'];
  346. }
  347. }
  348. // set debug mode if applicable
  349. if ($api_debug = $ci->config->item('api_debug'))
  350. {
  351. if ($api_debug === true)
  352. {
  353. $_http_opts['opts']['debug'] = true;
  354. }
  355. }
  356. return $_http_opts;
  357. }
  358. public function getAccounts() {
  359. if (!(self::$_twilioService instanceof Services_Twilio))
  360. {
  361. self::getAccount();
  362. }
  363. return self::$_twilioService->accounts;
  364. }
  365. /**
  366. * Validate that the current request came from Twilio
  367. *
  368. * If no url is passed then the default $_SERVER['REQUEST_URI'] will be passed
  369. * through site_url().
  370. *
  371. * If no post_vars are passed then $_POST will be used directly.
  372. *
  373. * @param bool/string $uri
  374. * @param bool/array $post_vars
  375. * @return bool
  376. */
  377. public static function validateRequest($url = false, $post_vars = false)
  378. {
  379. $ci =& get_instance();
  380. if ($ci->tenant->type == VBX_Settings::AUTH_TYPE_CONNECT)
  381. {
  382. return true;
  383. }
  384. if (!(self::$_twilioValidator instanceof Services_Twilio_RequestValidator))
  385. {
  386. self::$_twilioValidator = new Services_Twilio_RequestValidator($ci->twilio_token);
  387. }
  388. if (empty($url))
  389. {
  390. // we weren't handed a uri, use the default
  391. $url = site_url($ci->uri->uri_string());
  392. }
  393. elseif (strpos($url, '://') === false)
  394. {
  395. // we were handed a relative uri, make it full
  396. $url = site_url($url);
  397. }
  398. // without rewrite enabled we need to ensure that the query string
  399. // is properly appended to the url when being reconstructed
  400. if ($ci->vbx_settings->get('rewrite_enabled', VBX_PARENT_TENANT) < 1 &&
  401. !empty($_SERVER['QUERY_STRING']) && strpos($url, $_SERVER['QUERY_STRING']) === false)
  402. {
  403. $qs = parse_str($_SERVER['QUERY_STRING']);
  404. // make sure that the rewrite var doesn't stay in the query
  405. // string if we're not doing rewriting
  406. if ($ci->vbx_settings->get('rewrite_enabled', VBX_PARENT_TENANT) < 1) {
  407. foreach ($qs as $name => $value) {
  408. if ($name == 'vbxsite') {
  409. unset($qs[$name]);
  410. }
  411. }
  412. }
  413. if (!empty($qs)) {
  414. $url .= '?' . http_build_query($qs);
  415. }
  416. }
  417. if (empty($post_vars))
  418. {
  419. // we weren't handed post-vars, use the default
  420. $post_vars = $_POST;
  421. }
  422. return self::$_twilioValidator->validate(self::getRequestSignature(), $url, $post_vars);
  423. }
  424. /**
  425. * Get the X-Twilio-Signature header value
  426. *
  427. * @todo maybe needs some special love for nginx?
  428. * @return mixed string, boolean false if not found
  429. */
  430. public static function getRequestSignature()
  431. {
  432. $request_signature = false;
  433. if (!empty($_SERVER['HTTP_X_TWILIO_SIGNATURE']))
  434. {
  435. $request_signature = $_SERVER['HTTP_X_TWILIO_SIGNATURE'];
  436. }
  437. return $request_signature;
  438. }
  439. /**
  440. * Verify that we can connect to Twilio using the connect
  441. * tenant's sid & the parent tenant token
  442. *
  443. * @param int $tenant_id
  444. * @return bool
  445. */
  446. public function connectAuthTenant($tenant_id) {
  447. $auth = true;
  448. $ci =& get_instance();
  449. $tenant = $ci->db->get_where('tenants', array('id' => $tenant_id))->result();
  450. if ($tenant
  451. && $tenant[0]->id == $tenant_id
  452. && $tenant[0]->type == VBX_Settings::AUTH_TYPE_CONNECT)
  453. {
  454. try {
  455. $sid = $ci->db->get_where('settings', array(
  456. 'name' => 'twilio_sid',
  457. 'tenant_id' => $tenant[0]->id
  458. ));
  459. $token = $ci->db->get_where('settings', array(
  460. 'name' => 'twilio_token',
  461. 'tenant_id' => VBX_PARENT_TENANT
  462. ));
  463. $account = self::getAccount($sid->value, $token->value);
  464. $account_type = $account->type;
  465. }
  466. catch (Exception $e) {
  467. $auth = false;
  468. // @todo - check for 20006 code, currently returns 20003
  469. log_message('Connect auth failed: '.$e->getMessage().' :: '.$e->getCode());
  470. }
  471. }
  472. return $auth;
  473. }
  474. }