[Last Call] Learn about multicloud storage options and how to improve your company's cloud strategy. Register Now

x
?
Solved

Where is this Code Igniter page going?

Posted on 2016-09-28
4
Medium Priority
?
241 Views
Last Modified: 2016-10-03
Here's the URL: index.php/twiml/start/voice/1

Based on what I know, I'm thinking index.php would have some kind of "index" function that would point to the twiml controller.

Can't find it.

Here's the index.php page:

<?php
/**
 * "The contents of this file are subject to the Mozilla Public License
 *  Version 1.1 (the "License"); you may not use this file except in
 *  compliance with the License. You may obtain a copy of the License at
 *  http://www.mozilla.org/MPL/

 *  Software distributed under the License is distributed on an "AS IS"
 *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 *  License for the specific language governing rights and limitations
 *  under the License.

 *  The Original Code is OpenVBX, released June 15, 2010.

 *  The Initial Developer of the Original Code is Twilio Inc.
 *  Portions created by Twilio Inc. are Copyright (C) 2010.
 *  All Rights Reserved.

 * Contributor(s):
 **/

// set some base information
$script_dir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])), '/');
define('WEB_ROOT', $script_dir . '/');
define('ASSET_ROOT', $script_dir . '/assets');
unset($script_dir);

// PHP 4 will white screen and not give a
// meaningful error. This allows us to at
// least exit gracefully
if(version_compare(PHP_VERSION, '5', '<'))
{
	include('OpenVBX/errors/php4.php');
	exit;
}

// persist the session if we've exited cleanly
register_shutdown_function("shutdown");
function shutdown()
{
	if(function_exists('get_instance') && !headers_sent())
	{
		$ci = &get_instance();
		if(is_object($ci) && isset($ci->session) && is_object($ci->session))
		{
			$ci->session->persist();
		}
	}
}
/*
|---------------------------------------------------------------
| PHP ERROR REPORTING LEVEL
|---------------------------------------------------------------
|
| By default CI runs with error reporting set to ALL.  For security
| reasons you are encouraged to change this when your site goes live.
| For more info visit:	http://www.php.net/error_reporting
|
*/
error_reporting(E_ALL ^ E_WARNING ^ E_NOTICE ^ E_USER_WARNING);
ini_set('display_errors', 'Off');
ini_set('log_errors', 'On');

/*
 |---------------------------------------------------------------
 | SYSTEM FOLDER NAME
 |---------------------------------------------------------------
 |
 | This variable must contain the name of your "system" folder.
 | Include the path if the folder is not in the same	 directory
 | as this file.
 |
 | NO TRAILING SLASH!
 |
*/
$system_folder = "system";

/*
 |---------------------------------------------------------------
 | APPLICATION FOLDER NAME
 |---------------------------------------------------------------
 |
 | If you want this front controller to use a different "application"
 | folder then the default one you can set its name here. The folder
 | can also be renamed or relocated anywhere on your server.
 | For more info please see the user guide:
 | http://codeigniter.com/user_guide/general/managing_apps.html
 |
 |
 | NO TRAILING SLASH!
 |
*/
$application_folder = dirname(__FILE__) . '/OpenVBX';

/*
 |===============================================================
 | END OF USER CONFIGURABLE SETTINGS
 |===============================================================
*/


/*
 |---------------------------------------------------------------
 | SET THE SERVER PATH
 |---------------------------------------------------------------
 |
 | Let's attempt to determine the full-server path to the "system"
 | folder in order to reduce the possibility of path problems.
 | Note: We only attempt this if the user hasn't specified a
 | full server path.
 |
*/
if (strpos($system_folder, '/') === FALSE)
{
	if (function_exists('realpath') AND @realpath(dirname(__FILE__)) !== FALSE)
	{
		$system_folder = realpath(dirname(__FILE__)).'/'.$system_folder;
	}
}
else
{
	// Swap directory separators to Unix style for consistency
	$system_folder = str_replace("\\", "/", $system_folder);
}

/*
 |---------------------------------------------------------------
 | DEFINE APPLICATION CONSTANTS
 |---------------------------------------------------------------
 |
 | EXT		- The file extension.  Typically ".php"
 | FCPATH	- The full server path to THIS file
 | SELF		- The name of THIS file (typically "index.php")
 | BASEPATH	- The full server path to the "system" folder
 | APPPATH	- The full server path to the "application" folder
 |
*/
define('EXT', '.'.pathinfo(__FILE__, PATHINFO_EXTENSION));
define('FCPATH', __FILE__);
define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));
define('BASEPATH', $system_folder.'/');

if (is_dir($application_folder))
{
	define('APPPATH', $application_folder.'/');
}
else
{
	if ($application_folder == '')
	{
		$application_folder = 'application';
	}

	define('APPPATH', BASEPATH.$application_folder.'/');
}

/*
 |---------------------------------------------------------------
 | LOAD THE FRONT CONTROLLER
 |---------------------------------------------------------------
 |
 | And away we go...
 |
*/
require_once BASEPATH.'codeigniter/CodeIgniter'.EXT;

/* End of file index.php */
/* Location: ./index.php */

Open in new window


I did find the twiml controller, but now I'm looking for a function called "start."

Couldn't find it. I found at function called "start_voice" and I'm wondering if that is what the URL is triggering based on "start/voice."

Bottom line question: How is index.php pointing to twiml.php and where on twiml.php is start / voice?
0
Comment
Question by:brucegust
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
4 Comments
 

Author Comment

by:brucegust
ID: 41820309
Sorry.

Here's the twiml.php page:

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
 * "The contents of this file are subject to the Mozilla Public License
 *  Version 1.1 (the "License"); you may not use this file except in
 *  compliance with the License. You may obtain a copy of the License at
 *  http://www.mozilla.org/MPL/

 *  Software distributed under the License is distributed on an "AS IS"
 *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 *  License for the specific language governing rights and limitations
 *  under the License.

 *  The Original Code is OpenVBX, released June 15, 2010.

 *  The Initial Developer of the Original Code is Twilio Inc.
 *  Portions created by Twilio Inc. are Copyright (C) 2010.
 *  All Rights Reserved.

 * Contributor(s):
 **/

require_once(APPPATH.'libraries/twilio.php'); // @deprecated in 1.1

class TwimlException extends Exception {}

/* This controller handles incomming calls from Twilio and outputs response
*/
class Twiml extends MY_Controller {

	protected $response;

	private $flow;
	private $flow_id;
	private $flow_type = 'voice';
	
	protected $say_params;
	
	// This is an API response controller, suppress warnings & notices
	// to avoid breakage in operation
	protected $suppress_warnings_notices = true;

	public function __construct()
	{
		// this is an API controller, suppress warning & notice output to avoid XML breakage
		ini_set('display_errors', 'Off');
		
		parent::__construct();

		$this->load->helper('cookie');

		$this->load->library('applet');
		$this->load->library('TwimlResponse');

		$this->load->model('vbx_flow');
		$this->load->model('vbx_rest_access');
		$this->load->model('vbx_user');
		$this->load->model('vbx_message');

		$this->say_params = array(
			'voice' => $this->vbx_settings->get('voice', $this->tenant->id),
			'language' => $this->vbx_settings->get('voice_language', $this->tenant->id)
		);

		$this->flow_id = get_cookie('flow_id');
		$this->response = new TwimlResponse;
	}

	function index()
	{
		redirect('');
	}

	function start_sms($flow_id)
	{
		validate_rest_request();

		log_message("info", "Calling SMS Flow $flow_id");
		$body = $this->input->get_post('Body');
		$this->flow_type = 'sms';

		$this->session->set_userdata('sms-body', $body);

		$flow_id = $this->set_flow_id($flow_id);
		$flow = $this->get_flow();
		$flow_data = array();
		if(is_object($flow))
		{
			$flow_data = get_object_vars(json_decode($flow->sms_data));
		}

		$instance = isset($flow_data['start'])? $flow_data['start'] : null;
		if(is_object($instance))
		{
			$this->applet($flow_id, 'start', 'sms');
		}
		else
		{
			$this->response->say('Error 4-oh-4 - Flow not found.', $this->say_params);
			$this->response->respond();
		}
	}

	function start_voice($flow_id)
	{
		validate_rest_request();
		
		log_message("info", "Calling Voice Flow $flow_id");
		$this->flow_type = 'voice';

		$flow_id = $this->set_flow_id($flow_id);
		$flow = $this->get_flow();
		$flow_data = array();
		if(is_object($flow))
		{
			$flow_data = get_object_vars(json_decode($flow->data));
		}

		$instance = isset($flow_data['start'])? $flow_data['start'] : null;
		if(is_object($instance))
		{
			$this->applet($flow_id, 'start');
		}
		else
		{
			$this->response->say('Error 4-oh-4 - Flow not found.', $this->say_params);
			$this->response->respond();
		}
	}

	public function sms($flow_id, $inst_id)
	{
		$this->flow_type = 'sms';
		$redirect = $this->session->userdata('redirect');
		if(!empty($redirect))
		{
			$this->response->redirect($redirect);
			$this->session->set_userdata('last-redirect', $redirect);
			$this->session->unset_userdata('redirect');
			return $this->response->respond();
		}
		return $this->applet($flow_id, $inst_id, 'sms');
	}

	public function voice($flow_id, $inst_id)
	{
		return $this->applet($flow_id, $inst_id, 'voice');
	}

	private function applet_headers($applet, $plugin_dir_name)
	{
		$plugin = Plugin::get($plugin_dir_name);
		$plugin_info = ($plugin)? $plugin->getInfo() : false;

		header("X-OpenVBX-Applet-Version: {$applet->version}");
		if($plugin_info)
		{
			header("X-OpenVBX-Plugin: {$plugin_info['name']}");
			header("X-OpenVBX-Plugin-Version: {$plugin_info['version']}");
		}
		header("X-OpenVBX-Applet: {$applet->name}");
	}

	private function applet($flow_id, $inst_id, $type = 'voice')
	{
		$flow_id = $this->set_flow_id($flow_id);
		$flow = $this->get_flow();
		$instance = null;
		$applet = null;

		try
		{
			switch($type)
			{
				case 'sms':
					if(isset($_REQUEST['Body']) && $inst_id == 'start')
					{
						$_COOKIE['sms-body'] = $_REQUEST['Body'];
						$sms = $_REQUEST['Body'];

						// Expires after three hours
						set_cookie('sms-body', $sms, 60*60*3);
					}
					else
					{
						$sms = isset($_COOKIE['sms-body'])? $_COOKIE['sms-body'] : null;
						set_cookie('sms-body', null, time()-3600);
					}
					$sms_data = $flow->sms_data;
					if(!empty($sms_data))
					{
						$flow_data = get_object_vars(json_decode($sms_data));
						$instance = isset($flow_data[$inst_id])? $flow_data[$inst_id] : null;
					}

					if(!is_null($instance))
					{
						$plugin_dir_name = '';
						$applet_dir_name = '';
						list($plugin_dir_name, $applet_dir_name) = explode('---', $instance->type);

						$applet = Applet::get($plugin_dir_name,
											  $applet_dir_name,
											  null,
											  $instance);
						$applet->flow_type = $type;
						$applet->instance_id = $inst_id;
						$applet->sms = $sms;
						if($sms)
						{
							$_POST['Body'] = $_GET['Body'] = $_REQUEST['Body'] = $sms;
						}
						$this->session->unset_userdata('sms-body');

						$applet->currentURI = site_url("twiml/applet/sms/$flow_id/$inst_id");

						$baseURI = site_url("twiml/applet/sms/$flow_id/");
						$this->applet_headers($applet, $plugin_dir_name);
						echo $applet->twiml($flow, $baseURI, $instance);
					}
					break;
				case 'voice':
					$voice_data = $flow->data;
					if(!empty($voice_data))
					{
						$flow_data = get_object_vars(json_decode($voice_data));
						$instance = isset($flow_data[$inst_id])? $flow_data[$inst_id] : null;
					}

					if(!is_null($instance))
					{
						$plugin_dir_name = '';
						$applet_dir_name = '';
						list($plugin_dir_name, $applet_dir_name) = explode('---', $instance->type);

						$applet = Applet::get($plugin_dir_name,
											  $applet_dir_name,
											  null,
											  $instance);
						$applet->flow_type = $type;
						$applet->instance_id = $inst_id;
						$applet->currentURI = site_url("twiml/applet/voice/$flow_id/$inst_id");
						$baseURI = site_url("twiml/applet/voice/$flow_id/");
						$this->applet_headers($applet, $plugin_dir_name);

						echo $applet->twiml($flow, $baseURI, $instance);
					}
					break;
			}
			
			if(!is_object($applet))
			{
				$this->response->say('Unknown applet instance in flow '.$flow_id, $this->say_params);
				$this->response->respond();
			}

		}
		catch(Exception $ex)
		{
			$this->response->say('Error: ' + $ex->getMessage(), $this->say_params);
			$this->response->respond();
		}
	}

	function whisper()
	{
		$name =	$this->input->get_post('name');
		if(empty($name))
		{
			$name = "Open VeeBee Ex";
		}

		/* If we've received any input */
		$digits = clean_digits($this->input->get_post('Digits'));
		if(strlen($digits) > 0) {
			if($digits != '1') {
				$this->response->hangup();
			}
		} else {
			/* Prompt the user to answer the call */
			$gather = $this->response->gather(array('numDigits' => '1'));
			$say_number = implode(' ', str_split($this->input->get_post('From')));
			$gather->say("This is a call for {$name}. To accept, Press 1.", $this->say_params);
			$this->response->hangup();
		}

		$this->response->respond();
	}

	function redirect($path, $singlepass = false)
	{	
		if(!$this->session->userdata('loggedin')
		   && !$this->login_call($singlepass))
		{
			$this->response->say("Unable to authenticate this call.	Goodbye", $this->say_params);
			$this->response->hangup();
			$this->response->respond();
			return;
		}

		$path = str_replace('!', '/', $path);
		$this->response->redirect(site_url($path), array('method' => 'POST'));
		$this->response->respond();
	}

	/**
	 * Dial
	 * 
	 * Callback method that responds to a Twilio request and provides
	 * a number for Twilio to dial.
	 * 
	 * Overloaded by Twilio Client integration - Twilio Client connection
	 * requests automatically include the "1" Digit to immediately connect
	 * the call
	 *
	 * @return void
	 */
	public function dial()
	{
		validate_rest_request();

		$rest_access = $this->input->get_post('rest_access');
		$to = $this->input->get_post('to');
		$callerid = $this->input->get_post('callerid');

		if(!$this->session->userdata('loggedin')
		   && !$this->login_call($rest_access))
		{
			$this->response->say("Unable to authenticate this call.	Goodbye", $this->say_params);
			$this->response->hangup();
			$this->response->respond();
			return;
		}
		
		// Response
		$user = VBX_User::get($this->session->userdata('user_id'));
		$name = '';
		if(empty($user))
		{
			log_message('error', 'Unable to find user: '.$this->session->userdata('user_id'));
		}
		else
		{
			$name = $user->first_name;
		}

		$digits = clean_digits($this->input->get_post('Digits'));
		if($digits !== false && $digits == 1) 
		{
			$options = array(
				'action' => site_url("twiml/dial_status").'?'.http_build_query(compact('to')),
				'callerId' => $callerid,
				'timeout' => $this->vbx_settings->get('dial_timeout', $this->tenant->id)
			);
			
			if (filter_var($this->input->get_post('to'), FILTER_VALIDATE_EMAIL)) 
			{
				$this->dial_user_by_email($this->input->get_post('to'), $options);
			}
			elseif(preg_match('|client:[0-9]{1,4}|', $this->input->get_post('to')))
			{
				$this->dial_user_by_client_id($this->input->get_post('to'), $options);
			}
			else 
			{
				$to = normalize_phone_to_E164($to);
				$this->response->dial($to, $options);
			}
		} 
		else 
		{
			$gather = $this->response->gather(array('numDigits' => 1));
			$gather->say("Hello {$name}, this is a call from VeeBee Ex, to accept, press 1.", 
						$this->say_params);
		}

		$this->response->respond();
	}
	
	/**
	 * Dial a user by 'client:1' format
	 *
	 * @todo not implemented
	 * @param string $client_id 
	 * @param arrray $options 
	 * @return void
	 */
	protected function dial_user_by_client_id($client_id, $options)
	{
		$user_id = intval(str_replace('client:', '', $client_id));
		
		$user = VBX_User::get(array('id' => $user_id));
		if ($user instanceof VBX_User)
		{		
			$dial = $this->response->dial(NULL, $options);
			$dial->client($user_id);
		}
		else
		{
			$this->reponse->say('Unknown client id: '.$user_id.'. Goodbye.');
			$this->response->hangup();
		}
	}
	
	/**
	 * Dial a user identified by their email address
	 *
	 * Uses $user->setting('online') to determine if user "wants" to be contacted via
	 * Twilio Client. Passed in "online" status via $_POST can override the
	 * attempt to dial Twilio Client even if the person has set their status
	 * to online. The $_POST var should be representative of the Presence 
	 * Status of the user being dialed (if known).
	 * 
	 * @param string $user_email 
	 * @param array $options 
	 * @return void
	 */
	protected function dial_user_by_email($user_email, $options) {
		$user = VBX_User::get(array(
			'email' => $user_email
		));
		
		if ($user instanceof VBX_User)
		{
			$dial_client = ($user->setting('online') == 1);
			
			/**
			 * Only override the user status if we've been given
			 * an explicit opinion on the user's online status
			 */
			$client_status = $this->input->get_post('online');
			if (!empty($client_status) && $client_status == 'offline') 
			{
				$dial_client = false;
			}

			if (count($user->devices))
			{
				$options['sequential'] = 'true';
				$dial = $this->response->dial(NULL, $options);
			
				foreach ($user->devices as $device) 
				{
					if ($device->is_active)
					{
						if (strpos($device->value, 'client:') !== false && $dial_client)
						{
							if ($dial_client) 
							{
								$dial->client($user->id);
							}
						}
						else {
							$dial->number($device->value);
						}
					}
				}
			}
			else 
			{
				$this->response->say("We're sorry, this user is currently not reachable.".
									" Goodbye.");
			}
		}
		else
		{
			$this->response->say("We're sorry, that user doesn't exist in our system.".
								" Please contact your system administrator. Goodbye.");
		}		
	}

	function dial_status()
	{
		if($this->input->get_post('DialCallStatus') == 'failed')
		{
			$this->response->say('The number you have dialed is invalid. Goodbye.', 
								$this->say_params);
		}
		$this->response->hangup();
		$this->response->respond();
	}

	function transcribe()
	{
		// attatch transcription to the recording
		$notify = TRUE;
		$this->load->model('vbx_message');
		try
		{
			$call_sid = $this->input->get_post('CallSid');
			if(empty($call_sid))
			{
				throw new TwimlException('CallSid empty: possible non-twilio client access');
			}

			try
			{
				$message = $this->vbx_message->get_message(array(
													'call_sid' => $this->input->get_post('CallSid')
												));

				$message->content_text = $this->input->get_post('TranscriptionText');
				$this->vbx_message->save($message, $notify);
			}
			catch(VBX_MessageException $e)
			{
				throw new TwimlException($e->getMessage());
			}
		}
		catch(TwimlException $e)
		{
			log_message('error', 'Could not transcribe message: '.$e->getMessage());
		}
	}

	/* Private utility functions here */
	private function login_call($singlepass)
	{
		/* Rest API Authentication - one time pass only */
		if(!empty($singlepass))
		{
			$ra = new VBX_Rest_access();
			$user_id = $ra->auth_key($singlepass);
			unset($_COOKIE['singlepass']);
			if($user_id)
			{
				$this->session->set_userdata('user_id', $user_id);
				$this->session->set_userdata('loggedin', true);
				$this->session->set_userdata('signature', VBX_User::signature($user_id));
				return true;
			}
		}

		return false;
	}

	private function set_flow_id($id)
	{
		$this->session->set_userdata('flow_id', $id);
		if($id != $this->flow_id AND $id > 0) {
			$this->get_flow($id);

			if(!empty($this->flow)) {
				$id = $this->flow->id;
				$this->flow_id = $id;
				set_cookie('flow_id', $id, 0);
			} else {
				$id = -1;
			}
		} else {
			$id = $this->flow_id;
		}
		return $id;
	}

	// fetch the current flow and set up shared objects if necessary
	private function get_flow($flow_id = 0)
	{
		if($flow_id < 1) 
		{
			$flow_id = $this->flow_id;
		}
		
		if(is_null($this->flow)) 
		{
			$this->flow = VBX_Flow::get(array( 'id' => $flow_id, 'numbers' => false));
		}
		
		if($flow_id > 0)
		{
			if(!empty($this->flow))
			{
				if( $this->flow_type == 'sms' )
				{
					// make flow data visible to all applets
					Applet::$flow_data = $this->flow->sms_data;	
				}
				else
				{
					// make flow data visible to all applets
					Applet::$flow_data = $this->flow->data;
				}
			}
		}

		return $this->flow;
	}

}

Open in new window

0
 
LVL 35

Accepted Solution

by:
Terry Woods earned 2000 total points
ID: 41821170
Have you checked the routes file to see if there's any redirection being done?

http://www.codeigniter.com/userguide3/general/routing.html
0
 

Author Comment

by:brucegust
ID: 41826937
Terry, I think you answered my question. Not out of the woods, yet, but certainly closer.

Thanks!
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Password hashing is better than message digests or encryption, and you should be using it instead of message digests or encryption.  Find out why and how in this article, which supplements the original article on PHP Client Registration, Login, Logo‚Ķ
Since pre-biblical times, humans have sought ways to keep secrets, and share the secrets selectively.  This article explores the ways PHP can be used to hide and encrypt information.
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn how to count occurrences of each item in an array.
Suggested Courses

650 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question