Solved

Where is this Code Igniter page going?

Posted on 2016-09-28
4
40 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
  • 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 500 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

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Suggested Solutions

Things That Drive Us Nuts Have you noticed the use of the reCaptcha feature at EE and other web sites?  It wants you to read and retype something that looks like this.Insanity!  It's not EE's fault - that's just the way reCaptcha works.  But it is …
Recently I spent hours debugging an issue in a Rails project where ActiveRecord was causing MySQL errors trying to create a User object of a class at the top level of a Single Table Inheritance model structure.  It turns out `.create` behaves differ…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The purpose of this video is to demonstrate how to set up the WordPress backend so that each page automatically generates a Mailchimp signup form in the sidebar. This will be demonstrated using a Windows 8 PC. Tools Used are Photoshop, Awesome…

758 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now