diff --git a/php/Lib/Twilio.php b/php/Lib/Twilio.php new file mode 100755 index 0000000..25d4e82 --- /dev/null +++ b/php/Lib/Twilio.php @@ -0,0 +1,759 @@ +version = in_array($version, $this->versions) ? $version : end($this->versions); + + if (null === $_http) { + if (!in_array('openssl', get_loaded_extensions())) { + throw new Services_Twilio_HttpException("The OpenSSL extension is required but not currently enabled. For more information, see http://php.net/manual/en/book.openssl.php"); + } + if (in_array('curl', get_loaded_extensions())) { + $_http = new Services_Twilio_TinyHttp( + $this->_getBaseUri(), + array( + "curlopts" => array( + CURLOPT_USERAGENT => self::qualifiedUserAgent(phpversion()), + CURLOPT_HTTPHEADER => array('Accept-Charset: utf-8'), + ), + ) + ); + } else { + $_http = new Services_Twilio_HttpStream( + $this->_getBaseUri(), + array( + "http_options" => array( + "http" => array( + "user_agent" => self::qualifiedUserAgent(phpversion()), + "header" => "Accept-Charset: utf-8\r\n", + ), + "ssl" => array( + 'verify_peer' => true, + 'verify_depth' => 5, + ), + ), + ) + ); + } + } + $_http->authenticate($sid, $token); + $this->http = $_http; + $this->retryAttempts = $retryAttempts; + } + + /** + * Build a query string from query data + * + * :param array $queryData: An associative array of keys and values. The + * values can be a simple type or a list, in which case the list is + * converted to multiple query parameters with the same key. + * :param string $numericPrefix: optional prefix to prepend to numeric keys + * :return: The encoded query string + * :rtype: string + */ + public static function buildQuery($queryData, $numericPrefix = '') { + $query = ''; + // Loop through all of the $query_data + foreach ($queryData as $key => $value) { + // If the key is an int, add the numeric_prefix to the beginning + if (is_int($key)) { + $key = $numericPrefix . $key; + } + + // If the value is an array, we will end up recursing + if (is_array($value)) { + // Loop through the values + foreach ($value as $value2) { + // Add an arg_separator if needed + if ($query !== '') { + $query .= '&'; + } + // Recurse + $query .= self::buildQuery(array($key => $value2), $numericPrefix); + } + } else { + // Add an arg_separator if needed + if ($query !== '') { + $query .= '&'; + } + // Add the key and the urlencoded value (as a string) + $query .= $key . '=' . urlencode((string)$value); + } + } + return $query; + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + $json_path = $full_uri ? $path : "$path.json"; + if (!$full_uri && !empty($params)) { + $query_path = $json_path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $json_path; + } + return $query_path; + } + + /** + * Fully qualified user agent with the current PHP Version. + * + * :return: the user agent + * :rtype: string + */ + public static function qualifiedUserAgent($php_version) { + return self::USER_AGENT . " (php $php_version)"; + } + + /** + * POST to the resource at the specified path. + * + * :param string $path: Path to the resource + * :param array $params: Query string parameters + * + * :return: The object representation of the resource + * :rtype: object + */ + public function createData($path, $params = array(), $full_uri = false) + { + if (!$full_uri) { + $path = "$path.json"; + } + $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); + $response = $this->http->post( + $path, $headers, self::buildQuery($params, '') + ); + return $this->_processResponse($response); + } + + /** + * DELETE the resource at the specified path. + * + * :param string $path: Path to the resource + * :param array $params: Query string parameters + * + * :return: The object representation of the resource + * :rtype: object + */ + public function deleteData($path, $params = array()) + { + $uri = $this->getRequestUri($path, $params); + return $this->_makeIdempotentRequest(array($this->http, 'delete'), + $uri, $this->retryAttempts); + } + + /** + * Get the retry attempt limit used by the rest client + * + * :return: the number of retry attempts + * :rtype: int + */ + public function getRetryAttempts() { + return $this->retryAttempts; + } + + /** + * Get the api version used by the rest client + * + * :return: the API version in use + * :returntype: string + */ + public function getVersion() { + return $this->version; + } + + /** + * GET the resource at the specified path. + * + * :param string $path: Path to the resource + * :param array $params: Query string parameters + * :param boolean $full_uri: Whether the full URI has been passed as an + * argument + * + * :return: The object representation of the resource + * :rtype: object + */ + public function retrieveData($path, $params = array(), + $full_uri = false + ) + { + $uri = $this->getRequestUri($path, $params, $full_uri); + return $this->_makeIdempotentRequest(array($this->http, 'get'), + $uri, $this->retryAttempts); + } + + /** + * Get the base URI for this client. + * + * :return: base URI + * :rtype: string + */ + protected function _getBaseUri() { + return 'https://api.twilio.com'; + } + + /** + * Helper method for implementing request retry logic + * + * :param array $callable: The function that makes an HTTP request + * :param string $uri: The URI to request + * :param int $retriesLeft: Number of times to retry + * + * :return: The object representation of the resource + * :rtype: object + */ + protected function _makeIdempotentRequest($callable, $uri, $retriesLeft) { + $response = call_user_func_array($callable, array($uri)); + list($status, $headers, $body) = $response; + if ($status >= 500 && $retriesLeft > 0) { + return $this->_makeIdempotentRequest($callable, $uri, $retriesLeft - 1); + } else { + return $this->_processResponse($response); + } + } + + /** + * Convert the JSON encoded resource into a PHP object. + * + * :param array $response: 3-tuple containing status, headers, and body + * + * :return: PHP object decoded from JSON + * :rtype: object + * :throws: A :php:class:`Services_Twilio_RestException` if the Response is + * in the 300-500 range of status codes. + */ + private function _processResponse($response) + { + list($status, $headers, $body) = $response; + if ($status === 204) { + return true; + } + $decoded = json_decode($body); + if ($decoded === null) { + throw new Services_Twilio_RestException( + $status, + 'Could not decode response body as JSON. ' . + 'This likely indicates a 500 server error' + ); + } + if (200 <= $status && $status < 300) { + $this->last_response = $decoded; + return $decoded; + } + throw new Services_Twilio_RestException( + $status, + isset($decoded->message) ? $decoded->message : '', + isset($decoded->code) ? $decoded->code : null, + isset($decoded->more_info) ? $decoded->more_info : null + ); + } +} + +/** + * Create a client to talk to the Twilio Rest API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('2008-08-01', '2010-04-01'); + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->accounts = new Services_Twilio_Rest_Accounts($this, "/{$this->version}/Accounts"); + $this->account = $this->accounts->get($sid); + } +} + +/** + * Create a client to talk to the Twilio TaskRouter API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $workspaceSid: + * Workspace SID to work with + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new TaskRouter_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class TaskRouter_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + private $accountSid; + + public function __construct( + $sid, + $token, + $workspaceSid, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->workspaces = new Services_Twilio_Rest_TaskRouter_Workspaces($this, "/{$this->version}/Workspaces"); + $this->workspace = $this->workspaces->get($workspaceSid); + $this->accountSid = $sid; + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + public static function createWorkspace($sid, $token, $friendlyName, array $params = array(), Services_Twilio_TinyHttp $_http = null) + { + $taskrouterClient = new TaskRouter_Services_Twilio($sid, $token, null, null, $_http); + return $taskrouterClient->workspaces->create($friendlyName, $params); + } + + public function getTaskQueuesStatistics(array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/TaskQueues/Statistics", $params); + } + + public function getTaskQueueStatistics($taskQueueSid, array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/TaskQueues/{$taskQueueSid}/Statistics", $params); + } + + public function getWorkersStatistics(array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/Workers/Statistics", $params); + } + + public function getWorkerStatistics($workerSid, array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/Workers/{$workerSid}/Statistics", $params); + } + + public function getWorkflowStatistics($workflowSid, array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/Workflows/{$workflowSid}/Statistics", $params); + } + + public function getWorkspaceStatistics(array $params = array()) + { + return $this->retrieveData("/{$this->version}/Workspaces/{$this->workspace->sid}/Statistics", $params); + } + + protected function _getBaseUri() + { + return 'https://taskrouter.twilio.com'; + } +} + +/** + * Create a client to talk to the Twilio Lookups API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Lookups_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Lookups_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + private $accountSid; + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->accountSid = $sid; + $this->phone_numbers = new Services_Twilio_Rest_Lookups_PhoneNumbers($this, "/{$this->version}/PhoneNumbers"); + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + /** + * Get the base URI for this client. + * + * :return: base URI + * :rtype: string + */ + protected function _getBaseUri() + { + return 'https://lookups.twilio.com'; + } + +} + +/** + * Create a client to talk to the Twilio Pricing API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Pricing_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Pricing_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->voiceCountries = new Services_Twilio_Rest_Pricing_VoiceCountries( + $this, "/{$this->version}/Voice/Countries" + ); + $this->voiceNumbers = new Services_Twilio_Rest_Pricing_VoiceNumbers( + $this, "/{$this->version}/Voice/Numbers" + ); + $this->phoneNumberCountries = new Services_Twilio_Rest_Pricing_PhoneNumberCountries( + $this, "/{$this->version}/PhoneNumbers/Countries" + ); + $this->messagingCountries = new Services_Twilio_Rest_Pricing_MessagingCountries( + $this, "/{$this->version}/Messaging/Countries" + ); + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + protected function _getBaseUri() { + return 'https://pricing.twilio.com'; + } + +} + +/** + * Create a client to talk to the Twilio Monitor API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Monitor_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Monitor_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->events = new Services_Twilio_Rest_Monitor_Events($this, "/{$this->version}/Events"); + $this->alerts = new Services_Twilio_Rest_Monitor_Alerts($this, "/{$this->version}/Alerts"); + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + protected function _getBaseUri() + { + return 'https://monitor.twilio.com'; + } + +} + +/** + * Create a client to talk to the Twilio SIP Trunking API. + * + * + * :param string $sid: Your Account SID + * :param string $token: Your Auth Token from `your dashboard + * `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: + * + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Trunking_Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. + */ +class Trunking_Services_Twilio extends Base_Services_Twilio +{ + protected $versions = array('v1'); + + public function __construct( + $sid, + $token, + $version = null, + Services_Twilio_TinyHttp $_http = null, + $retryAttempts = 1 + ) + { + parent::__construct($sid, $token, $version, $_http, $retryAttempts); + + $this->trunks = new Services_Twilio_Rest_Trunking_Trunks($this, "/{$this->version}/Trunks"); + } + + /** + * Construct a URI based on initial path, query params, and paging + * information + * + * We want to use the query params, unless we have a next_page_uri from the + * API. + * + * :param string $path: The request path (may contain query params if it's + * a next_page_uri) + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri + * + * :return: the URI that should be requested by the library + * :returntype: string + */ + public function getRequestUri($path, $params, $full_uri = false) + { + if (!$full_uri && !empty($params)) { + $query_path = $path . '?' . http_build_query($params, '', '&'); + } else { + $query_path = $path; + } + return $query_path; + } + + protected function _getBaseUri() + { + return 'https://trunking.twilio.com'; + } + +} diff --git a/php/Lib/Twilio/AutoPagingIterator.php b/php/Lib/Twilio/AutoPagingIterator.php new file mode 100755 index 0000000..5aacc49 --- /dev/null +++ b/php/Lib/Twilio/AutoPagingIterator.php @@ -0,0 +1,110 @@ +generator = $generator; + $this->page = $page; + $this->size = $size; + $this->filters = $filters; + $this->next_page_uri = null; + $this->items = array(); + + // Save a backup for rewind() + $this->_args = array( + 'page' => $page, + 'size' => $size, + 'filters' => $filters, + ); + } + + public function current() + { + return current($this->items); + } + + public function key() + { + return key($this->items); + } + + /* + * Return the next item in the list, making another HTTP call to the next + * page of resources if necessary. + */ + public function next() + { + try { + $this->loadIfNecessary(); + return next($this->items); + } + catch (Services_Twilio_RestException $e) { + // 20006 is an out of range paging error, everything else is valid + if ($e->getCode() != 20006) { + throw $e; + } + } + } + + /* + * Restore everything to the way it was before we began paging. This gets + * called at the beginning of any foreach() loop + */ + public function rewind() + { + foreach ($this->_args as $arg => $val) { + $this->$arg = $val; + } + $this->items = array(); + $this->next_page_uri = null; + } + + public function count() + { + throw new BadMethodCallException('Not allowed'); + } + + public function valid() + { + try { + $this->loadIfNecessary(); + return key($this->items) !== null; + } + catch (Services_Twilio_RestException $e) { + // 20006 is an out of range paging error, everything else is valid + if ($e->getCode() != 20006) { + throw $e; + } + } + return false; + } + + /* + * Fill $this->items with a new page from the API, if necessary. + */ + protected function loadIfNecessary() + { + if (// Empty because it's the first time or last page was empty + empty($this->items) + // null key when the items list is iterated over completely + || key($this->items) === null + ) { + $page = call_user_func_array($this->generator, array( + $this->page, + $this->size, + $this->filters, + $this->next_page_uri, + )); + $this->next_page_uri = $page->next_page_uri; + $this->items = $page->getItems(); + $this->page = $this->page + 1; + } + } +} diff --git a/php/Lib/Twilio/Capability.php b/php/Lib/Twilio/Capability.php new file mode 100755 index 0000000..f41956a --- /dev/null +++ b/php/Lib/Twilio/Capability.php @@ -0,0 +1,185 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_Capability +{ + public $accountSid; + public $authToken; + public $scopes; + + /** + * Create a new TwilioCapability with zero permissions. Next steps are to + * grant access to resources by configuring this token through the + * functions allowXXXX. + * + * @param $accountSid the account sid to which this token is granted access + * @param $authToken the secret key used to sign the token. Note, this auth + * token is not visible to the user of the token. + */ + public function __construct($accountSid, $authToken) + { + $this->accountSid = $accountSid; + $this->authToken = $authToken; + $this->scopes = array(); + $this->clientName = false; + } + + /** + * If the user of this token should be allowed to accept incoming + * connections then configure the TwilioCapability through this method and + * specify the client name. + * + * @param $clientName + */ + public function allowClientIncoming($clientName) + { + + // clientName must be a non-zero length alphanumeric string + if (preg_match('/\W/', $clientName)) { + throw new InvalidArgumentException( + 'Only alphanumeric characters allowed in client name.'); + } + + if (strlen($clientName) == 0) { + throw new InvalidArgumentException( + 'Client name must not be a zero length string.'); + } + + $this->clientName = $clientName; + $this->allow('client', 'incoming', + array('clientName' => $clientName)); + } + + /** + * Allow the user of this token to make outgoing connections. + * + * @param $appSid the application to which this token grants access + * @param $appParams signed parameters that the user of this token cannot + * overwrite. + */ + public function allowClientOutgoing($appSid, array $appParams=array()) + { + $this->allow('client', 'outgoing', array( + 'appSid' => $appSid, + 'appParams' => http_build_query($appParams, '', '&'))); + } + + /** + * Allow the user of this token to access their event stream. + * + * @param $filters key/value filters to apply to the event stream + */ + public function allowEventStream(array $filters=array()) + { + $this->allow('stream', 'subscribe', array( + 'path' => '/2010-04-01/Events', + 'params' => http_build_query($filters, '', '&'), + )); + } + + /** + * Generates a new token based on the credentials and permissions that + * previously has been granted to this token. + * + * @param $ttl the expiration time of the token (in seconds). Default + * value is 3600 (1hr) + * @return the newly generated token that is valid for $ttl seconds + */ + public function generateToken($ttl = 3600) + { + $payload = array( + 'scope' => array(), + 'iss' => $this->accountSid, + 'exp' => time() + $ttl, + ); + $scopeStrings = array(); + + foreach ($this->scopes as $scope) { + if ($scope->privilege == "outgoing" && $this->clientName) + $scope->params["clientName"] = $this->clientName; + $scopeStrings[] = $scope->toString(); + } + + $payload['scope'] = implode(' ', $scopeStrings); + return JWT::encode($payload, $this->authToken, 'HS256'); + } + + protected function allow($service, $privilege, $params) { + $this->scopes[] = new ScopeURI($service, $privilege, $params); + } +} + +/** + * Scope URI implementation + * + * Simple way to represent configurable privileges in an OAuth + * friendly way. For our case, they look like this: + * + * scope::? + * + * For example: + * scope:client:incoming?name=jonas + * + * @author Jeff Lindsay + */ +class ScopeURI +{ + public $service; + public $privilege; + public $params; + + public function __construct($service, $privilege, $params = array()) + { + $this->service = $service; + $this->privilege = $privilege; + $this->params = $params; + } + + public function toString() + { + $uri = "scope:{$this->service}:{$this->privilege}"; + if (count($this->params)) { + $uri .= "?".http_build_query($this->params, '', '&'); + } + return $uri; + } + + /** + * Parse a scope URI into a ScopeURI object + * + * @param string $uri The scope URI + * @return ScopeURI The parsed scope uri + */ + public static function parse($uri) + { + if (strpos($uri, 'scope:') !== 0) { + throw new UnexpectedValueException( + 'Not a scope URI according to scheme'); + } + + $parts = explode('?', $uri, 1); + $params = null; + + if (count($parts) > 1) { + parse_str($parts[1], $params); + } + + $parts = explode(':', $parts[0], 2); + + if (count($parts) != 3) { + throw new UnexpectedValueException( + 'Not enough parts for scope URI'); + } + + list($scheme, $service, $privilege) = $parts; + return new ScopeURI($service, $privilege, $params); + } + +} \ No newline at end of file diff --git a/php/Lib/Twilio/CapabilityAPI.php b/php/Lib/Twilio/CapabilityAPI.php new file mode 100755 index 0000000..3541375 --- /dev/null +++ b/php/Lib/Twilio/CapabilityAPI.php @@ -0,0 +1,154 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_API_Capability +{ + protected $accountSid; + protected $authToken; + private $version; + private $friendlyName; + private $policies; + + public function __construct($accountSid, $authToken, $version, $friendlyName) + { + $this->accountSid = $accountSid; + $this->authToken = $authToken; + $this->version = $version; + $this->friendlyName = $friendlyName; + $this->policies = array(); + } + + public function addPolicyDeconstructed($url, $method, $queryFilter = array(), $postFilter = array(), $allow = true) { + $policy = new Policy($url, $method, $queryFilter, $postFilter, $allow); + array_push($this->policies, $policy); + return $policy; + } + + public function allow($url, $method, $queryFilter = array(), $postFilter = array()) { + $this->addPolicyDeconstructed($url, $method, $queryFilter, $postFilter, true); + } + + public function deny($url, $method, $queryFilter = array(), $postFilter = array()) { + $this->addPolicyDeconstructed($url, $method, $queryFilter, $postFilter, false); + } + + /** + * @deprecated Please use {Services_Twilio_API_Capability.allow, Services_Twilio_API_Capability.disallow} instead + */ + public function addPolicy($policy) { + array_push($this->policies, $policy); + } + + /** + * @deprecated Please use {Services_Twilio_API_Capability.allow, Services_Twilio_API_Capability.disallow} instead + */ + public function generatePolicy($url, $method, $queryFilter = array(), $postFilter = array(), $allow = true) + { + return $this->addPolicyDeconstructed($url, $method, $queryFilter, $postFilter, $allow); + } + + /** + * @deprecated Please use {Services_Twilio_API_Capability.allow, Services_Twilio_API_Capability.disallow} instead + */ + public function generateAndAddPolicy($url, $method, $queryFilter = array(), $postFilter = array(), $allow = true) { + $this->addPolicyDeconstructed($url, $method, $queryFilter, $postFilter, $allow); + } + + /** + * Generates a new token based on the credentials and permissions that + * previously has been granted to this token. + * + * @param $ttl the expiration time of the token (in seconds). Default + * value is 3600 (1hr) + * @param $extraAttributes extra attributes to be tied to the jwt. + * @return the newly generated token that is valid for $ttl seconds + */ + public function generateToken($ttl = 3600, $extraAttributes = null) + { + $payload = array( + 'version' => $this->version, + 'friendly_name' => $this->friendlyName, + 'policies' => array(), + 'iss' => $this->accountSid, + 'exp' => time() + $ttl + ); + if(isset($extraAttributes)) { + foreach ($extraAttributes as $key => $value) { + $payload[$key] = $value; + } + } + + $policyStrings = array(); + + foreach ($this->policies as $policy) { + $policyStrings[] = $policy->toArray(); + } + + $payload['policies'] = $policyStrings; + return JWT::encode($payload, $this->authToken, 'HS256'); + } +} + +/** + * Twilio API Policy constructor + * + * @category Services + * @package Services_Twilio + * @author Justin Witz + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Policy +{ + private $url; + private $method; + private $queryFilter; + private $postFilter; + private $allow; + + public function __construct($url, $method, $queryFilter = array(), $postFilter = array(), $allow = true) + { + $this->url = $url; + $this->method = $method; + $this->queryFilter = $queryFilter; + $this->postFilter = $postFilter; + $this->allow = $allow; + } + + public function addQueryFilter($queryFilter) + { + array_push($this->queryFilter, $queryFilter); + } + + public function addPostFilter($postFilter) + { + array_push($this->postFilter, $postFilter); + } + + public function toArray() { + $policy_array = array('url' => $this->url, 'method' => $this->method, 'allow' => $this->allow); + if (!is_null($this->queryFilter)) { + if (count($this->queryFilter) > 0 ) { + $policy_array['query_filter'] = $this->queryFilter; + } else { + $policy_array['query_filter'] = new stdClass(); + } + } + + if (!is_null($this->postFilter)) { + if (count($this->postFilter) > 0 ) { + $policy_array['post_filter'] = $this->postFilter; + } else { + $policy_array['post_filter'] = new stdClass(); + } + } + + return $policy_array; + } +} diff --git a/php/Lib/Twilio/CapabilityTaskRouter.php b/php/Lib/Twilio/CapabilityTaskRouter.php new file mode 100755 index 0000000..942feb2 --- /dev/null +++ b/php/Lib/Twilio/CapabilityTaskRouter.php @@ -0,0 +1,252 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_TaskRouter_Capability extends Services_Twilio_API_Capability +{ + protected $baseUrl = 'https://taskrouter.twilio.com/v1'; + protected $baseWsUrl = 'https://event-bridge.twilio.com/v1/wschannels'; + protected $version = 'v1'; + + protected $workspaceSid; + protected $channelId; + protected $resourceUrl; + + protected $required = array("required" => true); + protected $optional = array("required" => false); + + public function __construct($accountSid, $authToken, $workspaceSid, $channelId, $resourceUrl = null, $overrideBaseUrl = null, $overrideBaseWSUrl = null) { + parent::__construct($accountSid, $authToken, $this->version, $channelId); + + $this->workspaceSid = $workspaceSid; + $this->channelId = $channelId; + if(isset($overrideBaseUrl)) { + $this->baseUrl = $overrideBaseUrl; + } + if(isset($overrideBaseWSUrl)) { + $this->baseWsUrl = $overrideBaseWSUrl; + } + $this->baseUrl = $this->baseUrl.'/Workspaces/'.$workspaceSid; + + $this->validateJWT(); + + if(!isset($resourceUrl)) { + $this->setupResource(); + } + + //add permissions to GET and POST to the event-bridge channel + $this->allow($this->baseWsUrl."/".$this->accountSid."/".$this->channelId, "GET", null, null); + $this->allow($this->baseWsUrl."/".$this->accountSid."/".$this->channelId, "POST", null, null); + + //add permissions to fetch the instance resource + $this->allow($this->resourceUrl, "GET", null, null); + } + + protected function setupResource() { + if(substr($this->channelId,0,2) == 'WS') { + $this->resourceUrl = $this->baseUrl; + }else if(substr($this->channelId,0,2) == 'WK') { + $this->resourceUrl = $this->baseUrl.'/Workers/'.$this->channelId; + + //add permissions to fetch the list of activities and list of worker reservations + $activityUrl = $this->baseUrl.'/Activities'; + $this->allow($activityUrl, "GET", null, null); + + $reservationsUrl = $this->baseUrl.'/Tasks/**'; + $this->allow($reservationsUrl, "GET", null, null); + + }else if(substr($this->channelId,0,2) == 'WQ') { + $this->resourceUrl = $this->baseUrl.'/TaskQueues/'.$this->channelId; + } + } + + private function validateJWT() { + if(!isset($this->accountSid) || substr($this->accountSid,0,2) != 'AC') { + throw new Exception("Invalid AccountSid provided: ".$this->accountSid); + } + if(!isset($this->workspaceSid) || substr($this->workspaceSid,0,2) != 'WS') { + throw new Exception("Invalid WorkspaceSid provided: ".$this->workspaceSid); + } + if(!isset($this->channelId)) { + throw new Exception("ChannelId not provided"); + } + $prefix = substr($this->channelId,0,2); + if($prefix != 'WS' && $prefix != 'WK' && $prefix != 'WQ') { + throw new Exception("Invalid ChannelId provided: ".$this->channelId); + } + } + + public function allowFetchSubresources() { + $method = 'GET'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl.'/**', $method, $queryFilter, $postFilter); + } + + public function allowUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + public function allowUpdatesSubresources() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl.'/**', $method, $queryFilter, $postFilter); + } + + public function allowDelete() { + $method = 'DELETE'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + public function allowDeleteSubresources() { + $method = 'DELETE'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl.'/**', $method, $queryFilter, $postFilter); + } + + /** + * @deprecated Please use {Services_Twilio_TaskRouter_Worker_Capability.allowActivityUpdates} instead + */ + public function allowWorkerActivityUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array("ActivitySid" => $this->required); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + /** + * @deprecated Please use {Services_Twilio_TaskRouter_Worker_Capability} instead; added automatically in constructor + */ + public function allowWorkerFetchAttributes() { + $method = 'GET'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + /** + * @deprecated Please use {Services_Twilio_TaskRouter_Worker_Capability.allowReservationUpdates} instead + */ + public function allowTaskReservationUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array(); + $reservationsUrl = $this->baseUrl.'/Tasks/**'; + $this->allow($reservationsUrl, $method, $queryFilter, $postFilter); + } + + public function generateToken($ttl = 3600, $extraAttributes = null) { + $taskRouterAttributes = array( + 'account_sid' => $this->accountSid, + 'channel' => $this->channelId, + 'workspace_sid' => $this->workspaceSid + ); + + if(substr($this->channelId,0,2) == 'WK') { + $taskRouterAttributes['worker_sid'] = $this->channelId; + }else if(substr($this->channelId,0,2) == 'WQ') { + $taskRouterAttributes['taskqueue_sid'] = $this->channelId; + } + + return parent::generateToken($ttl, $taskRouterAttributes); + } +} + + +/** + * Twilio TaskRouter Worker Capability assigner + * + * @category Services + * @package Services_Twilio + * @author Justin Witz + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_TaskRouter_Worker_Capability extends Services_Twilio_TaskRouter_Capability +{ + private $reservationsUrl; + private $activityUrl; + + public function __construct($accountSid, $authToken, $workspaceSid, $workerSid, $overrideBaseUrl = null, $overrideBaseWSUrl = null) + { + parent::__construct($accountSid, $authToken, $workspaceSid, $workerSid, null, $overrideBaseUrl, $overrideBaseWSUrl); + + $this->reservationsUrl = $this->baseUrl.'/Tasks/**'; + $this->activityUrl = $this->baseUrl.'/Activities'; + + //add permissions to fetch the list of activities and list of worker reservations + $this->allow($this->activityUrl, "GET", null, null); + $this->allow($this->reservationsUrl, "GET", null, null); + } + + protected function setupResource() { + $this->resourceUrl = $this->baseUrl.'/Workers/'.$this->channelId; + } + + public function allowActivityUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array("ActivitySid" => $this->required); + $this->allow($this->resourceUrl, $method, $queryFilter, $postFilter); + } + + public function allowReservationUpdates() { + $method = 'POST'; + $queryFilter = array(); + $postFilter = array(); + $this->allow($this->reservationsUrl, $method, $queryFilter, $postFilter); + } +} + +/** + * Twilio TaskRouter TaskQueue Capability assigner + * + * @category Services + * @package Services_Twilio + * @author Justin Witz + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_TaskRouter_TaskQueue_Capability extends Services_Twilio_TaskRouter_Capability +{ + public function __construct($accountSid, $authToken, $workspaceSid, $taskQueueSid, $overrideBaseUrl = null, $overrideBaseWSUrl = null) + { + parent::__construct($accountSid, $authToken, $workspaceSid, $taskQueueSid, null, $overrideBaseUrl, $overrideBaseWSUrl); + } + + protected function setupResource() { + $this->resourceUrl = $this->baseUrl.'/TaskQueues/'.$this->channelId; + } +} + +/** + * Twilio TaskRouter Workspace Capability assigner + * + * @category Services + * @package Services_Twilio + * @author Justin Witz + * @license http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_TaskRouter_Workspace_Capability extends Services_Twilio_TaskRouter_Capability +{ + public function __construct($accountSid, $authToken, $workspaceSid, $overrideBaseUrl = null, $overrideBaseWSUrl = null) + { + parent::__construct($accountSid, $authToken, $workspaceSid, $workspaceSid, null, $overrideBaseUrl, $overrideBaseWSUrl); + } + + protected function setupResource() { + $this->resourceUrl = $this->baseUrl; + } +} \ No newline at end of file diff --git a/php/Lib/Twilio/HttpException.php b/php/Lib/Twilio/HttpException.php new file mode 100755 index 0000000..b79a357 --- /dev/null +++ b/php/Lib/Twilio/HttpException.php @@ -0,0 +1,3 @@ + array( + "headers" => "", + "timeout" => 60, + "follow_location" => true, + "ignore_errors" => true, + ), + "ssl" => array(), + ); + private $options = array(); + + public function __construct($uri = '', $kwargs = array()) { + $this->uri = $uri; + if (isset($kwargs['debug'])) { + $this->debug = true; + } + if (isset($kwargs['http_options'])) { + $this->options = $kwargs['http_options'] + self::$default_options; + } else { + $this->options = self::$default_options; + } + } + + public function __call($name, $args) { + list($res, $req_headers, $req_body) = $args + array(0, array(), ''); + + if (strpos($res, 'http') === 0) { + $url = $res; + } else { + $url = $this->uri . $res; + } + + $request_options = $this->options; + + if (isset($req_body) && strlen($req_body) > 0) { + $request_options['http']['content'] = $req_body; + } + + foreach($req_headers as $key => $value) { + $request_options['http']['header'] .= sprintf("%s: %s\r\n", $key, $value); + } + + if (isset($this->auth_header)) { + $request_options['http']['header'] .= $this->auth_header; + } + + $request_options['http']['method'] = strtoupper($name); + $request_options['http']['ignore_errors'] = true; + + if ($this->debug) { + error_log(var_export($request_options, true)); + } + $ctx = stream_context_create($request_options); + $result = file_get_contents($url, false, $ctx); + + if (false === $result) { + throw new Services_Twilio_HttpStreamException( + "Unable to connect to service"); + } + + $status_header = array_shift($http_response_header); + if (1 !== preg_match('#HTTP/\d+\.\d+ (\d+)#', $status_header, $matches)) { + throw new Services_Twilio_HttpStreamException( + "Unable to detect the status code in the HTTP result."); + } + + $status_code = intval($matches[1]); + $response_headers = array(); + + foreach($http_response_header as $header) { + list($key, $val) = explode(":", $header); + $response_headers[trim($key)] = trim($val); + } + + return array($status_code, $response_headers, $result); + } + + public function authenticate($user, $pass) { + if (isset($user) && isset($pass)) { + $this->auth_header = sprintf("Authorization: Basic %s", + base64_encode(sprintf("%s:%s", $user, $pass))); + } else { + $this->auth_header = null; + } + } +} diff --git a/php/Lib/Twilio/InstanceResource.php b/php/Lib/Twilio/InstanceResource.php new file mode 100755 index 0000000..0d4932d --- /dev/null +++ b/php/Lib/Twilio/InstanceResource.php @@ -0,0 +1,84 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ + +/** + * Abstraction of an instance resource from the Twilio API. + */ +abstract class Services_Twilio_InstanceResource extends Services_Twilio_Resource { + + /** + * Make a request to the API to update an instance resource + * + * :param mixed $params: An array of updates, or a property name + * :param mixed $value: A value with which to update the resource + * + * :rtype: null + * :throws: a :php:class:`RestException ` if + * the update fails. + */ + public function update($params, $value = null) + { + if (!is_array($params)) { + $params = array($params => $value); + } + $decamelizedParams = $this->client->createData($this->uri, $params); + $this->updateAttributes($decamelizedParams); + } + + /** + * Add all properties from an associative array (the JSON response body) as + * properties on this instance resource, except the URI + * + * :param stdClass $params: An object containing all of the parameters of + * this instance + * :return: Nothing, this is purely side effecting + * :rtype: null + */ + public function updateAttributes($params) { + unset($params->uri); + foreach ($params as $name => $value) { + $this->$name = $value; + } + } + + /** + * Get the value of a property on this resource. + * + * Instead of defining all of the properties of an object directly, we rely + * on the API to tell us which properties an object has. This method will + * query the API to retrieve a property for an object, if it is not already + * set on the object. + * + * If the call is to a subresource, eg ``$client->account->messages``, no + * request is made. + * + * To help with lazy HTTP requests, we don't actually retrieve an object + * from the API unless you really need it. Hence, this function may make API + * requests even if the property you're requesting isn't available on the + * resource. + * + * :param string $key: The property name + * + * :return mixed: Could be anything. + * :throws: a :php:class:`RestException ` if + * the update fails. + */ + public function __get($key) + { + if ($subresource = $this->getSubresources($key)) { + return $subresource; + } + if (!isset($this->$key)) { + $params = $this->client->retrieveData($this->uri); + $this->updateAttributes($params); + } + return $this->$key; + } +} diff --git a/php/Lib/Twilio/JWT.php b/php/Lib/Twilio/JWT.php new file mode 100755 index 0000000..1b22a2d --- /dev/null +++ b/php/Lib/Twilio/JWT.php @@ -0,0 +1,162 @@ + + */ +class JWT +{ + /** + * @param string $jwt The JWT + * @param string|null $key The secret key + * @param bool $verify Don't skip verification process + * + * @return object The JWT's payload as a PHP object + */ + public static function decode($jwt, $key = null, $verify = true) + { + $tks = explode('.', $jwt); + if (count($tks) != 3) { + throw new UnexpectedValueException('Wrong number of segments'); + } + list($headb64, $payloadb64, $cryptob64) = $tks; + if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64))) + ) { + throw new UnexpectedValueException('Invalid segment encoding'); + } + if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($payloadb64)) + ) { + throw new UnexpectedValueException('Invalid segment encoding'); + } + $sig = JWT::urlsafeB64Decode($cryptob64); + if ($verify) { + if (empty($header->alg)) { + throw new DomainException('Empty algorithm'); + } + if ($sig != JWT::sign("$headb64.$payloadb64", $key, $header->alg)) { + throw new UnexpectedValueException('Signature verification failed'); + } + } + return $payload; + } + + /** + * @param object|array $payload PHP object or array + * @param string $key The secret key + * @param string $algo The signing algorithm + * + * @return string A JWT + */ + public static function encode($payload, $key, $algo = 'HS256') + { + $header = array('typ' => 'JWT', 'alg' => $algo); + + $segments = array(); + $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header)); + $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload)); + $signing_input = implode('.', $segments); + + $signature = JWT::sign($signing_input, $key, $algo); + $segments[] = JWT::urlsafeB64Encode($signature); + + return implode('.', $segments); + } + + /** + * @param string $msg The message to sign + * @param string $key The secret key + * @param string $method The signing algorithm + * + * @return string An encrypted message + */ + public static function sign($msg, $key, $method = 'HS256') + { + $methods = array( + 'HS256' => 'sha256', + 'HS384' => 'sha384', + 'HS512' => 'sha512', + ); + if (empty($methods[$method])) { + throw new DomainException('Algorithm not supported'); + } + return hash_hmac($methods[$method], $msg, $key, true); + } + + /** + * @param string $input JSON string + * + * @return object Object representation of JSON string + */ + public static function jsonDecode($input) + { + $obj = json_decode($input); + if (function_exists('json_last_error') && $errno = json_last_error()) { + JWT::handleJsonError($errno); + } + else if ($obj === null && $input !== 'null') { + throw new DomainException('Null result with non-null input'); + } + return $obj; + } + + /** + * @param object|array $input A PHP object or array + * + * @return string JSON representation of the PHP object or array + */ + public static function jsonEncode($input) + { + $json = json_encode($input); + if (function_exists('json_last_error') && $errno = json_last_error()) { + JWT::handleJsonError($errno); + } + else if ($json === 'null' && $input !== null) { + throw new DomainException('Null result with non-null input'); + } + return $json; + } + + /** + * @param string $input A base64 encoded string + * + * @return string A decoded string + */ + public static function urlsafeB64Decode($input) + { + $padlen = 4 - strlen($input) % 4; + $input .= str_repeat('=', $padlen); + return base64_decode(strtr($input, '-_', '+/')); + } + + /** + * @param string $input Anything really + * + * @return string The base64 encode of what you passed in + */ + public static function urlsafeB64Encode($input) + { + return str_replace('=', '', strtr(base64_encode($input), '+/', '-_')); + } + + /** + * @param int $errno An error number from json_last_error() + * + * @return void + */ + private static function handleJsonError($errno) + { + $messages = array( + JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', + JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', + JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON' + ); + throw new DomainException(isset($messages[$errno]) + ? $messages[$errno] + : 'Unknown JSON error: ' . $errno + ); + } +} \ No newline at end of file diff --git a/php/Lib/Twilio/ListResource.php b/php/Lib/Twilio/ListResource.php new file mode 100755 index 0000000..dad1c0d --- /dev/null +++ b/php/Lib/Twilio/ListResource.php @@ -0,0 +1,182 @@ +`_ and the `Countable + * `_ interfaces. + * + */ +abstract class Services_Twilio_ListResource extends Services_Twilio_Resource + implements IteratorAggregate +{ + + public function __construct($client, $uri) { + $name = $this->getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + + /** + * Gets a resource from this list. + * + * :param string $sid: The resource SID + * :return: The resource + * :rtype: :php:class:`InstanceResource ` + */ + public function get($sid) { + $instance = new $this->instance_name( + $this->client, $this->uri . "/$sid" + ); + // XXX check if this is actually a sid in all cases. + $instance->sid = $sid; + return $instance; + } + + /** + * Construct an :php:class:`InstanceResource + * ` with the specified params. + * + * :param array $params: usually a JSON HTTP response from the API + * :return: An instance with properties + * initialized to the values in the params array. + * :rtype: :php:class:`InstanceResource ` + */ + public function getObjectFromJson($params, $idParam = "sid") + { + if (isset($params->{$idParam})) { + $uri = $this->uri . "/" . $params->{$idParam}; + } else { + $uri = $this->uri; + } + return new $this->instance_name($this->client, $uri, $params); + } + + /** + * Deletes a resource from this list. + * + * :param string $sid: The resource SID + * :rtype: null + */ + public function delete($sid, $params = array()) + { + $this->client->deleteData($this->uri . '/' . $sid, $params); + } + + /** + * Create a resource on the list and then return its representation as an + * InstanceResource. + * + * :param array $params: The parameters with which to create the resource + * + * :return: The created resource + * :rtype: :php:class:`InstanceResource ` + */ + protected function _create($params) + { + $params = $this->client->createData($this->uri, $params); + /* Some methods like verified caller ID don't return sids. */ + if (isset($params->sid)) { + $resource_uri = $this->uri . '/' . $params->sid; + } else { + $resource_uri = $this->uri; + } + return new $this->instance_name($this->client, $resource_uri, $params); + } + + /** + * Returns a page of :php:class:`InstanceResources + * ` from this list. + * + * :param int $page: The start page + * :param int $size: Number of items per page + * :param array $filters: Optional filters + * :param string $deep_paging_uri: if provided, the $page and $size + * parameters will be ignored and this URI will be requested directly. + * + * :return: A page of resources + * :rtype: :php:class:`Services_Twilio_Page` + */ + public function getPage( + $page = 0, $size = 50, $filters = array(), $deep_paging_uri = null + ) { + $list_name = $this->getResourceName(); + if ($deep_paging_uri !== null) { + $page = $this->client->retrieveData($deep_paging_uri, array(), true); + } else { + $page = $this->client->retrieveData($this->uri, array( + 'Page' => $page, + 'PageSize' => $size, + ) + $filters); + } + + /* create a new PHP object for each json obj in the api response. */ + $page->$list_name = array_map( + array($this, 'getObjectFromJson'), + $page->$list_name + ); + if (isset($page->next_page_uri)) { + $next_page_uri = $page->next_page_uri; + } else { + $next_page_uri = null; + } + return new Services_Twilio_Page($page, $list_name, $next_page_uri); + } + + /** + * Returns an iterable list of + * :php:class:`instance resources `. + * + * :param int $page: The start page + * :param int $size: Number of items per page + * :param array $filters: Optional filters. + * The filter array can accept full datetimes when StartTime or DateCreated + * are used. Inequalities should be within the key portion of the array and + * multiple filter parameters can be combined for more specific searches. + * + * .. code-block:: php + * + * array('DateCreated>' => '2011-07-05 08:00:00', 'DateCreated<' => '2011-08-01') + * + * .. code-block:: php + * + * array('StartTime<' => '2011-07-05 08:00:00') + * + * :return: An iterator + * :rtype: :php:class:`Services_Twilio_AutoPagingIterator` + */ + public function getIterator( + $page = 0, $size = 50, $filters = array() + ) { + return new Services_Twilio_AutoPagingIterator( + array($this, 'getPageGenerator'), $page, $size, $filters + ); + } + + /** + * Retrieve a new page of API results, and update iterator parameters. This + * function is called by the paging iterator to retrieve a new page and + * shouldn't be called directly. + */ + public function getPageGenerator( + $page, $size, $filters = array(), $deep_paging_uri = null + ) { + return $this->getPage($page, $size, $filters, $deep_paging_uri); + } +} + diff --git a/php/Lib/Twilio/LookupsInstanceResource.php b/php/Lib/Twilio/LookupsInstanceResource.php new file mode 100755 index 0000000..63685ea --- /dev/null +++ b/php/Lib/Twilio/LookupsInstanceResource.php @@ -0,0 +1,15 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + +} diff --git a/php/Lib/Twilio/LookupsListResource.php b/php/Lib/Twilio/LookupsListResource.php new file mode 100755 index 0000000..856d31b --- /dev/null +++ b/php/Lib/Twilio/LookupsListResource.php @@ -0,0 +1,39 @@ +getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_Lookups_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + + /** + * Gets a resource from this list. Overridden to add + * filter parameters. + * + * :param string $number: The phone number + * :return: The resource + * :rtype: :php:class:`InstanceResource ` + */ + public function get($number, $filters = array()) { + $number = rawurlencode($number); + $full_path = $this->uri . "/$number"; + if (!empty($filters)) { + $full_path .= '?' . http_build_query($filters, '', '&'); + } + + $instance = new $this->instance_name( + $this->client, $full_path + ); + return $instance; + } +} diff --git a/php/Lib/Twilio/MonitorInstanceResource.php b/php/Lib/Twilio/MonitorInstanceResource.php new file mode 100755 index 0000000..bf4c300 --- /dev/null +++ b/php/Lib/Twilio/MonitorInstanceResource.php @@ -0,0 +1,15 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + +} diff --git a/php/Lib/Twilio/MonitorListResource.php b/php/Lib/Twilio/MonitorListResource.php new file mode 100755 index 0000000..70604e3 --- /dev/null +++ b/php/Lib/Twilio/MonitorListResource.php @@ -0,0 +1,18 @@ +getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_Monitor_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } +} diff --git a/php/Lib/Twilio/NextGenInstanceResource.php b/php/Lib/Twilio/NextGenInstanceResource.php new file mode 100755 index 0000000..dd17dfe --- /dev/null +++ b/php/Lib/Twilio/NextGenInstanceResource.php @@ -0,0 +1,23 @@ +` if + * the update fails. + */ + public function update($params, $value = null) + { + if (!is_array($params)) { + $params = array($params => $value); + } + $decamelizedParams = $this->client->createData($this->uri, $params, true); + $this->updateAttributes($decamelizedParams); + } +} \ No newline at end of file diff --git a/php/Lib/Twilio/NextGenListResource.php b/php/Lib/Twilio/NextGenListResource.php new file mode 100755 index 0000000..8822d1b --- /dev/null +++ b/php/Lib/Twilio/NextGenListResource.php @@ -0,0 +1,60 @@ +client->retrieveData($deep_paging_uri, array(), true); + } else if ($page == 0) { + $page = $this->client->retrieveData($this->uri, array('Page' => $page, 'PageSize' => $size) + $filters); + } else { + return $this->emptyPage(); + } + + $list_name = $page->meta->key; + if (!isset($list_name) || $list_name === '') { + throw new Services_Twilio_HttpException("Couldn't find list key in response"); + } + + $page->$list_name = array_map( + array($this, 'getObjectFromJson'), + $page->$list_name + ); + $page->next_page_uri = $page->meta->next_page_url; + + return new Services_Twilio_Page($page, $list_name, $page->meta->next_page_url); + } + + private function emptyPage() { + $page = new stdClass(); + $page->empty = array(); + return new Services_Twilio_Page($page, 'empty'); + } + + /** + * Create a resource on the list and then return its representation as an + * InstanceResource. + * + * :param array $params: The parameters with which to create the resource + * + * :return: The created resource + * :rtype: :php:class:`InstanceResource ` + */ + protected function _create($params) + { + $params = $this->client->createData($this->uri, $params, true); + /* Some methods like verified caller ID don't return sids. */ + if (isset($params->sid)) { + $resource_uri = $this->uri . '/' . $params->sid; + } else { + $resource_uri = $this->uri; + } + return new $this->instance_name($this->client, $resource_uri, $params); + } + + public function count() { + throw new BadMethodCallException("Counting is not supported by this resource"); + } + +} diff --git a/php/Lib/Twilio/NumberType.php b/php/Lib/Twilio/NumberType.php new file mode 100755 index 0000000..0683d99 --- /dev/null +++ b/php/Lib/Twilio/NumberType.php @@ -0,0 +1,35 @@ +instance_name = 'Services_Twilio_Rest_IncomingPhoneNumber'; + return $camelized ? 'IncomingPhoneNumbers' : 'incoming_phone_numbers'; + } + + /** + * Purchase a new phone number. + * + * Example usage: + * + * .. code-block:: php + * + * $marlosBurner = '+14105551234'; + * $client->account->incoming_phone_numbers->local->purchase($marlosBurner); + * + * :param string $phone_number: The phone number to purchase + * :param array $params: An optional array of parameters to pass along with + * the request (to configure the phone number) + */ + public function purchase($phone_number, array $params = array()) { + $postParams = array( + 'PhoneNumber' => $phone_number + ); + return $this->create($postParams + $params); + } + + public function create(array $params = array()) { + return parent::_create($params); + } + +} diff --git a/php/Lib/Twilio/Page.php b/php/Lib/Twilio/Page.php new file mode 100755 index 0000000..61ddb07 --- /dev/null +++ b/php/Lib/Twilio/Page.php @@ -0,0 +1,68 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +class Services_Twilio_Page + implements IteratorAggregate +{ + + /** + * The item list. + * + * @var array $items + */ + protected $items; + + /** + * Constructs a page. + * + * @param object $page The page object + * @param string $name The key of the item list + */ + public function __construct($page, $name, $next_page_uri = null) + { + $this->page = $page; + $this->items = $page->{$name}; + $this->next_page_uri = $next_page_uri; + } + + /** + * The item list of the page. + * + * @return array A list of instance resources + */ + public function getItems() + { + return $this->items; + } + + /** + * Magic method to allow retrieving the properties of the wrapped page. + * + * @param string $prop The property name + * + * @return mixed Could be anything + */ + public function __get($prop) + { + return $this->page->$prop; + } + + /** + * Implementation of IteratorAggregate::getIterator(). + * + * @return Traversable + */ + public function getIterator() + { + return $this->getItems(); + } +} + diff --git a/php/Lib/Twilio/PartialApplicationHelper.php b/php/Lib/Twilio/PartialApplicationHelper.php new file mode 100755 index 0000000..639ca51 --- /dev/null +++ b/php/Lib/Twilio/PartialApplicationHelper.php @@ -0,0 +1,41 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +class Services_Twilio_PartialApplicationHelper +{ + private $callbacks; + + public function __construct() + { + $this->callbacks = array(); + } + + public function set($method, $callback, array $args) + { + if (!is_callable($callback)) { + return FALSE; + } + $this->callbacks[$method] = array($callback, $args); + } + + public function __call($method, $args) + { + if (!isset($this->callbacks[$method])) { + throw new Exception("Method not found: $method"); + } + list($callback, $cb_args) = $this->callbacks[$method]; + return call_user_func_array( + $callback, + array_merge($cb_args, $args) + ); + } +} diff --git a/php/Lib/Twilio/PricingInstanceResource.php b/php/Lib/Twilio/PricingInstanceResource.php new file mode 100755 index 0000000..6ae1e18 --- /dev/null +++ b/php/Lib/Twilio/PricingInstanceResource.php @@ -0,0 +1,14 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } +} diff --git a/php/Lib/Twilio/PricingListResource.php b/php/Lib/Twilio/PricingListResource.php new file mode 100755 index 0000000..cc663e4 --- /dev/null +++ b/php/Lib/Twilio/PricingListResource.php @@ -0,0 +1,14 @@ +getResourceName(true); + + if (!isset($this->instance_name)) { + $this->instance_name = 'Services_Twilio_Rest_Pricing_'. rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + +} diff --git a/php/Lib/Twilio/RequestValidator.php b/php/Lib/Twilio/RequestValidator.php new file mode 100755 index 0000000..8bfa0db --- /dev/null +++ b/php/Lib/Twilio/RequestValidator.php @@ -0,0 +1,67 @@ +AuthToken = $token; + } + + public function computeSignature($url, $data = array()) + { + // sort the array by keys + ksort($data); + + // append them to the data string in order + // with no delimiters + foreach($data as $key => $value) + $url .= "$key$value"; + + // This function calculates the HMAC hash of the data with the key + // passed in + // Note: hash_hmac requires PHP 5 >= 5.1.2 or PECL hash:1.1-1.5 + // Or http://pear.php.net/package/Crypt_HMAC/ + return base64_encode(hash_hmac("sha1", $url, $this->AuthToken, true)); + } + + public function validate($expectedSignature, $url, $data = array()) + { + return self::compare( + $this->computeSignature($url, $data), + $expectedSignature + ); + } + + /** + * Time insensitive compare, function's runtime is governed by the length + * of the first argument, not the difference between the arguments. + * @param $a string First part of the comparison pair + * @param $b string Second part of the comparison pair + * @return bool True if $a == $b, false otherwise. + */ + public static function compare($a, $b) { + $result = true; + + if (strlen($a) != strlen($b)) { + return false; + } + + if (!$a && !$b) { + return true; + } + + $limit = strlen($a); + + for ($i = 0; $i < $limit; ++$i) { + if ($a[$i] != $b[$i]) { + $result = false; + } + } + + return $result; + } + +} diff --git a/php/Lib/Twilio/Resource.php b/php/Lib/Twilio/Resource.php new file mode 100755 index 0000000..e6f1feb --- /dev/null +++ b/php/Lib/Twilio/Resource.php @@ -0,0 +1,134 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +abstract class Services_Twilio_Resource { + protected $subresources; + + public function __construct($client, $uri, $params = array()) + { + $this->subresources = array(); + $this->client = $client; + + foreach ($params as $name => $param) { + $this->$name = $param; + } + + $this->uri = $uri; + $this->init($client, $uri); + } + + protected function init($client, $uri) + { + // Left empty for derived classes to implement + } + + public function getSubresources($name = null) { + if (isset($name)) { + return isset($this->subresources[$name]) + ? $this->subresources[$name] + : null; + } + return $this->subresources; + } + + protected function setupSubresources() + { + foreach (func_get_args() as $name) { + $constantized = ucfirst(self::camelize($name)); + $type = "Services_Twilio_Rest_" . $constantized; + $this->subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + + /* + * Get the resource name from the classname + * + * Ex: Services_Twilio_Rest_Accounts -> Accounts + * + * @param boolean $camelized Whether to return camel case or not + */ + public function getResourceName($camelized = false) + { + $name = get_class($this); + $parts = explode('_', $name); + $basename = end($parts); + if ($camelized) { + return $basename; + } else { + return self::decamelize($basename); + } + } + + public static function decamelize($word) + { + $callback = create_function('$matches', + 'return strtolower(strlen("$matches[1]") ? "$matches[1]_$matches[2]" : "$matches[2]");'); + + return preg_replace_callback( + '/(^|[a-z])([A-Z])/', + $callback, + $word + ); + } + + /** + * Return camelized version of a word + * Examples: sms_messages => SMSMessages, calls => Calls, + * incoming_phone_numbers => IncomingPhoneNumbers + * + * @param string $word The word to camelize + * @return string + */ + public static function camelize($word) { + $callback = create_function('$matches', 'return strtoupper("$matches[2]");'); + + return preg_replace_callback('/(^|_)([a-z])/', + $callback, + $word); + } + + /** + * Get the value of a property on this resource. + * + * @param string $key The property name + * @return mixed Could be anything. + */ + public function __get($key) { + if ($subresource = $this->getSubresources($key)) { + return $subresource; + } + return $this->$key; + } + + /** + * Print a JSON representation of this object. Strips the HTTP client + * before returning. + * + * Note, this should mainly be used for debugging, and is not guaranteed + * to correspond 1:1 with the JSON API output. + * + * Note that echoing an object before an HTTP request has been made to + * "fill in" its properties may return an empty object + */ + public function __toString() { + $out = array(); + foreach ($this as $key => $value) { + if ($key !== 'client' && $key !== 'subresources') { + $out[$key] = $value; + } + } + return json_encode($out, true); + } + +} + diff --git a/php/Lib/Twilio/Rest/Account.php b/php/Lib/Twilio/Rest/Account.php new file mode 100755 index 0000000..dc137d3 --- /dev/null +++ b/php/Lib/Twilio/Rest/Account.php @@ -0,0 +1,36 @@ +setupSubresources( + 'applications', + 'available_phone_numbers', + 'outgoing_caller_ids', + 'calls', + 'conferences', + 'incoming_phone_numbers', + 'keys', + 'media', + 'messages', + 'notifications', + 'outgoing_callerids', + 'recordings', + 'sms_messages', + 'short_codes', + 'tokens', + 'transcriptions', + 'connect_apps', + 'authorized_connect_apps', + 'usage_records', + 'usage_triggers', + 'queues', + 'sip', + 'addresses' + ); + + $this->sandbox = new Services_Twilio_Rest_Sandbox( + $client, $uri . '/Sandbox' + ); + } +} diff --git a/php/Lib/Twilio/Rest/Accounts.php b/php/Lib/Twilio/Rest/Accounts.php new file mode 100755 index 0000000..0e7ea0a --- /dev/null +++ b/php/Lib/Twilio/Rest/Accounts.php @@ -0,0 +1,25 @@ +`_ documentation. + */ +class Services_Twilio_Rest_Accounts extends Services_Twilio_ListResource { + + /** + * Create a new subaccount. + * + * :param array $params: An array of parameters describing the new + * subaccount. The ``$params`` array can contain the following keys: + * + * *FriendlyName* + * A description of this account, up to 64 characters long + * + * :returns: The new subaccount + * :rtype: :php:class:`Services_Twilio_Rest_Account` + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/php/Lib/Twilio/Rest/Address.php b/php/Lib/Twilio/Rest/Address.php new file mode 100755 index 0000000..1110257 --- /dev/null +++ b/php/Lib/Twilio/Rest/Address.php @@ -0,0 +1,12 @@ +setupSubresources( + 'dependent_phone_numbers' + ); + } +} diff --git a/php/Lib/Twilio/Rest/Addresses.php b/php/Lib/Twilio/Rest/Addresses.php new file mode 100755 index 0000000..93a6040 --- /dev/null +++ b/php/Lib/Twilio/Rest/Addresses.php @@ -0,0 +1,6 @@ + $name + ) + $params); + } +} diff --git a/php/Lib/Twilio/Rest/AuthorizedConnectApp.php b/php/Lib/Twilio/Rest/AuthorizedConnectApp.php new file mode 100755 index 0000000..0372629 --- /dev/null +++ b/php/Lib/Twilio/Rest/AuthorizedConnectApp.php @@ -0,0 +1,6 @@ +set( + 'getList', + array($this, 'getList'), + array($country, 'Local') + ); + return $curried; + } + public function getTollFree($country) { + $curried = new Services_Twilio_PartialApplicationHelper(); + $curried->set( + 'getList', + array($this, 'getList'), + array($country, 'TollFree') + ); + return $curried; + } + + public function getMobile($country) + { + $curried = new Services_Twilio_PartialApplicationHelper(); + $curried->set( + 'getList', + array($this, 'getList'), + array($country, 'Mobile') + ); + return $curried; + } + + /** + * Get a list of available phone numbers. + * + * @param string $country The 2-digit country code you'd like to search for + * numbers e.g. ('US', 'CA', 'GB') + * @param string $type The type of number ('Local', 'TollFree', or 'Mobile') + * @return object The object representation of the resource + */ + public function getList($country, $type, array $params = array()) + { + return $this->client->retrieveData($this->uri . "/$country/$type", $params); + } + + public function getResourceName($camelized = false) { + // You can't page through the list of available phone numbers. + $this->instance_name = 'Services_Twilio_Rest_AvailablePhoneNumber'; + return $camelized ? 'Countries' : 'countries'; + } +} diff --git a/php/Lib/Twilio/Rest/Call.php b/php/Lib/Twilio/Rest/Call.php new file mode 100755 index 0000000..1a9f696 --- /dev/null +++ b/php/Lib/Twilio/Rest/Call.php @@ -0,0 +1,116 @@ +`_ documentation. + * + * .. php:attr:: sid + * + * A 34 character string that uniquely identifies this resource. + * + * .. php:attr:: parent_call_sid + * + * A 34 character string that uniquely identifies the call that created this leg. + * + * .. php:attr:: date_created + * + * The date that this resource was created, given as GMT in RFC 2822 format. + * + * .. php:attr:: date_updated + * + * The date that this resource was last updated, given as GMT in RFC 2822 format. + * + * .. php:attr:: account_sid + * + * The unique id of the Account responsible for creating this call. + * + * .. php:attr:: to + * + * The phone number that received this call. e.g., +16175551212 (E.164 format) + * + * .. php:attr:: from + * + * The phone number that made this call. e.g., +16175551212 (E.164 format) + * + * .. php:attr:: phone_number_sid + * + * If the call was inbound, this is the Sid of the IncomingPhoneNumber that + * received the call. If the call was outbound, it is the Sid of the + * OutgoingCallerId from which the call was placed. + * + * .. php:attr:: status + * + * A string representing the status of the call. May be `QUEUED`, `RINGING`, + * `IN-PROGRESS`, `COMPLETED`, `FAILED`, `BUSY` or `NO_ANSWER`. + * + * .. php:attr:: start_time + * + * The start time of the call, given as GMT in RFC 2822 format. Empty if the call has not yet been dialed. + * + * .. php:attr:: end_time + * + * The end time of the call, given as GMT in RFC 2822 format. Empty if the call did not complete successfully. + * + * .. php:attr:: duration + * + * The length of the call in seconds. This value is empty for busy, failed, unanswered or ongoing calls. + * + * .. php:attr:: price + * + * The charge for this call in USD. Populated after the call is completed. May not be immediately available. + * + * .. php:attr:: direction + * + * A string describing the direction of the call. inbound for inbound + * calls, outbound-api for calls initiated via the REST API or + * outbound-dial for calls initiated by a verb. + * + * .. php:attr:: answered_by + * + * If this call was initiated with answering machine detection, either human or machine. Empty otherwise. + * + * .. php:attr:: forwarded_from + * + * If this call was an incoming call forwarded from another number, the + * forwarding phone number (depends on carrier supporting forwarding). + * Empty otherwise. + * + * .. php:attr:: caller_name + * + * If this call was an incoming call from a phone number with Caller ID Lookup enabled, the caller's name. Empty otherwise. + */ +class Services_Twilio_Rest_Call extends Services_Twilio_InstanceResource { + + /** + * Hang up the call + */ + public function hangup() { + $this->update('Status', 'completed'); + } + + /** + * Redirect the call to a new URL + * + * :param string $url: the new URL to retrieve call flow from. + */ + public function route($url) { + $this->update('Url', $url); + } + + protected function init($client, $uri) { + $this->setupSubresources( + 'notifications', + 'recordings', + 'feedback' + ); + } + + /** + * Make a request to delete the specified resource. + * + * :rtype: boolean + */ + public function delete() + { + return $this->client->deleteData($this->uri); + } +} diff --git a/php/Lib/Twilio/Rest/Calls.php b/php/Lib/Twilio/Rest/Calls.php new file mode 100755 index 0000000..a140654 --- /dev/null +++ b/php/Lib/Twilio/Rest/Calls.php @@ -0,0 +1,77 @@ +setupSubresources( + 'feedback_summary' + ); + } + + public static function isApplicationSid($value) + { + return strlen($value) == 34 + && !(strpos($value, "AP") === false); + } + + public function create($from, $to, $url, array $params = array()) + { + + $params["To"] = $to; + $params["From"] = $from; + + if (self::isApplicationSid($url)) { + $params["ApplicationSid"] = $url; + } else { + $params["Url"] = $url; + } + + return parent::_create($params); + } + + /** + * Create a feedback for a call. + * + * @param $callSid + * @param $qualityScore + * @param array $issue + * @return Services_Twilio_Rest_Feedback + */ + public function createFeedback($callSid, $qualityScore, array $issue = array()) + { + $params["QualityScore"] = $qualityScore; + $params["Issue"] = $issue; + + $feedbackUri = $this->uri . '/' . $callSid . '/Feedback'; + + $response = $this->client->createData($feedbackUri, $params); + return new Services_Twilio_Rest_Feedback($this->client, $feedbackUri, $response); + } + + /** + * Delete a feedback for a call. + * + * @param $callSid + */ + public function deleteFeedback($callSid) + { + $feedbackUri = $this->uri . '/' . $callSid . '/Feedback'; + $this->client->deleteData($feedbackUri); + } + + /** + * Get a feedback for a call. + * + * @param $callSid + * @return Services_Twilio_Rest_Feedback + */ + public function getFeedback($callSid) + { + $feedbackUri = $this->uri . '/' . $callSid . '/Feedback'; + $response = $this->client->retrieveData($feedbackUri); + return new Services_Twilio_Rest_Feedback($this->client, $feedbackUri, $response); + } +} diff --git a/php/Lib/Twilio/Rest/Conference.php b/php/Lib/Twilio/Rest/Conference.php new file mode 100755 index 0000000..9a36916 --- /dev/null +++ b/php/Lib/Twilio/Rest/Conference.php @@ -0,0 +1,12 @@ +setupSubresources( + 'participants' + ); + } +} diff --git a/php/Lib/Twilio/Rest/Conferences.php b/php/Lib/Twilio/Rest/Conferences.php new file mode 100755 index 0000000..5e92e37 --- /dev/null +++ b/php/Lib/Twilio/Rest/Conferences.php @@ -0,0 +1,6 @@ +setupSubresources( + 'credentials' + ); + } +} + diff --git a/php/Lib/Twilio/Rest/CredentialListMapping.php b/php/Lib/Twilio/Rest/CredentialListMapping.php new file mode 100755 index 0000000..3f9c305 --- /dev/null +++ b/php/Lib/Twilio/Rest/CredentialListMapping.php @@ -0,0 +1,37 @@ +setupSubresources( + 'credentials' + ); + } +} diff --git a/php/Lib/Twilio/Rest/CredentialListMappings.php b/php/Lib/Twilio/Rest/CredentialListMappings.php new file mode 100755 index 0000000..ab34f60 --- /dev/null +++ b/php/Lib/Twilio/Rest/CredentialListMappings.php @@ -0,0 +1,24 @@ +account->sip->domains->get('SDXXX')->credential_list_mappings->create("CLXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + * + * :param string $credential_list_sid: the sid of the CredentialList you're adding to this domain. + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($credential_list_sid, $params = array()) { + return parent::_create(array( + 'CredentialListSid' => $credential_list_sid, + ) + $params); + } +} + diff --git a/php/Lib/Twilio/Rest/CredentialLists.php b/php/Lib/Twilio/Rest/CredentialLists.php new file mode 100755 index 0000000..e8eb1a6 --- /dev/null +++ b/php/Lib/Twilio/Rest/CredentialLists.php @@ -0,0 +1,24 @@ +account->sip->credential_lists->create("MyFriendlyName"); + * + * :param string $friendly_name: the friendly name of this credential list + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($friendly_name, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + ) + $params); + } + +} diff --git a/php/Lib/Twilio/Rest/Credentials.php b/php/Lib/Twilio/Rest/Credentials.php new file mode 100755 index 0000000..129a44d --- /dev/null +++ b/php/Lib/Twilio/Rest/Credentials.php @@ -0,0 +1,28 @@ +account->sip->credential_lists->get('CLXXX')->credentials->create( + * "AwesomeUsername", "SuperSecretPassword", + * ); + * + * :param string $username: the username for the new Credential object + * :param string $password: the password for the new Credential object + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($username, $password, $params = array()) { + return parent::_create(array( + 'Username' => $username, + 'Password' => $password, + ) + $params); + } + +} diff --git a/php/Lib/Twilio/Rest/DependentPhoneNumber.php b/php/Lib/Twilio/Rest/DependentPhoneNumber.php new file mode 100755 index 0000000..a9402d0 --- /dev/null +++ b/php/Lib/Twilio/Rest/DependentPhoneNumber.php @@ -0,0 +1,6 @@ +setupSubresources( + 'ip_access_control_list_mappings', + 'credential_list_mappings' + ); + } +} diff --git a/php/Lib/Twilio/Rest/Domains.php b/php/Lib/Twilio/Rest/Domains.php new file mode 100755 index 0000000..041c080 --- /dev/null +++ b/php/Lib/Twilio/Rest/Domains.php @@ -0,0 +1,28 @@ +account->sip->domains->create( + * "MyFriendlyName", "MyDomainName" + * ); + * + * :param string $friendly_name: the friendly name of this domain + * :param string $domain_name: the domain name for this domain + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($friendly_name, $domain_name, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + 'DomainName' => $domain_name, + ) + $params); + } +} + diff --git a/php/Lib/Twilio/Rest/Feedback.php b/php/Lib/Twilio/Rest/Feedback.php new file mode 100755 index 0000000..ed210f6 --- /dev/null +++ b/php/Lib/Twilio/Rest/Feedback.php @@ -0,0 +1,34 @@ +instance_name = "Services_Twilio_Rest_Feedback"; + return parent::__construct($client, $uri, $params); + } + + /** + * Create feedback for the parent call + */ + public function create(array $params = array()) { + $params = $this->client->createData($this->uri, $params); + return new $this->instance_name($this->client, $this->uri, $params); + } + + /** + * Delete feedback for the parent call + */ + public function delete() { + $this->client->deleteData($this->uri); + } + + /** + * Fetch the feedback for the parent call + */ + public function get() { + return new $this->instance_name( + $this->client, $this->uri + ); + } + +} diff --git a/php/Lib/Twilio/Rest/FeedbackSummary.php b/php/Lib/Twilio/Rest/FeedbackSummary.php new file mode 100755 index 0000000..e6e49e0 --- /dev/null +++ b/php/Lib/Twilio/Rest/FeedbackSummary.php @@ -0,0 +1,33 @@ +instance_name = "Services_Twilio_Rest_FeedbackSummary"; + return parent::__construct($client, $uri, $params); + } + + /** + * Create feedback summary for calls + */ + public function create(array $params = array()) { + $params = $this->client->createData($this->uri, $params); + return new $this->instance_name($this->client, $this->uri, $params); + } + + /** + * Delete a feedback summary + */ + public function delete($sid) { + $this->client->deleteData($this->uri . '/' . $sid); + } + + /** + * Get a feedback summary + */ + public function get($sid) { + return new $this->instance_name( + $this->client, $this->uri . '/' . $sid + ); + } +} diff --git a/php/Lib/Twilio/Rest/IncomingPhoneNumber.php b/php/Lib/Twilio/Rest/IncomingPhoneNumber.php new file mode 100755 index 0000000..37658fa --- /dev/null +++ b/php/Lib/Twilio/Rest/IncomingPhoneNumber.php @@ -0,0 +1,95 @@ +`_ + * documentation. + * + * .. php:attr:: sid + * + * A 34 character string that uniquely idetifies this resource. + * + * .. php:attr:: date_created + * + * The date that this resource was created, given as GMT RFC 2822 format. + * + * .. php:attr:: date_updated + * + * The date that this resource was last updated, given as GMT RFC 2822 format. + * + * .. php:attr:: friendly_name + * + * A human readable descriptive text for this resource, up to 64 + * characters long. By default, the FriendlyName is a nicely formatted + * version of the phone number. + * + * .. php:attr:: account_sid + * + * The unique id of the Account responsible for this phone number. + * + * .. php:attr:: phone_number + * + * The incoming phone number. e.g., +16175551212 (E.164 format) + * + * .. php:attr:: api_version + * + * Calls to this phone number will start a new TwiML session with this + * API version. + * + * .. php:attr:: voice_caller_id_lookup + * + * Look up the caller's caller-ID name from the CNAM database (additional charges apply). Either true or false. + * + * .. php:attr:: voice_url + * + * The URL Twilio will request when this phone number receives a call. + * + * .. php:attr:: voice_method + * + * The HTTP method Twilio will use when requesting the above Url. Either GET or POST. + * + * .. php:attr:: voice_fallback_url + * + * The URL that Twilio will request if an error occurs retrieving or executing the TwiML requested by Url. + * + * .. php:attr:: voice_fallback_method + * + * The HTTP method Twilio will use when requesting the VoiceFallbackUrl. Either GET or POST. + * + * .. php:attr:: status_callback + * + * The URL that Twilio will request to pass status parameters (such as call ended) to your application. + * + * .. php:attr:: status_callback_method + * + * The HTTP method Twilio will use to make requests to the StatusCallback URL. Either GET or POST. + * + * .. php:attr:: sms_url + * + * The URL Twilio will request when receiving an incoming SMS message to this number. + * + * .. php:attr:: sms_method + * + * The HTTP method Twilio will use when making requests to the SmsUrl. Either GET or POST. + * + * .. php:attr:: sms_fallback_url + * + * The URL that Twilio will request if an error occurs retrieving or executing the TwiML from SmsUrl. + * + * .. php:attr:: sms_fallback_method + * + * The HTTP method Twilio will use when requesting the above URL. Either GET or POST. + * + * .. php:attr:: beta + * + * Whether this number is new to Twilio's inventory. + * + * .. php:attr:: uri + * + * The URI for this resource, relative to https://api.twilio.com. + */ +class Services_Twilio_Rest_IncomingPhoneNumber + extends Services_Twilio_InstanceResource +{ +} diff --git a/php/Lib/Twilio/Rest/IncomingPhoneNumbers.php b/php/Lib/Twilio/Rest/IncomingPhoneNumbers.php new file mode 100755 index 0000000..48ce4ca --- /dev/null +++ b/php/Lib/Twilio/Rest/IncomingPhoneNumbers.php @@ -0,0 +1,59 @@ +`_ + * documentation at twilio.com. + */ +class Services_Twilio_Rest_IncomingPhoneNumbers extends Services_Twilio_ListResource { + function init($client, $uri) { + $this->setupSubresources( + 'local', + 'toll_free', + 'mobile' + ); + } + + function create(array $params = array()) { + return parent::_create($params); + } + + function getList($type, array $params = array()) + { + return $this->client->retrieveData($this->uri . "/$type", $params); + } + + /** + * Return a phone number instance from its E.164 representation. If more + * than one number matches the search string, returns the first one. + * + * Example usage: + * + * .. code-block:: php + * + * $number = $client->account->incoming_phone_numbers->getNumber('+14105551234'); + * echo $number->sid; + * + * :param string $number: The number in E.164 format, eg "+684105551234" + * :return: A :php:class:`Services_Twilio_Rest_IncomingPhoneNumber` object, or null + * :raises: a A :php:class:`Services_Twilio_RestException` if the number is + * invalid, not provided in E.164 format or for any other API exception. + */ + public function getNumber($number) { + $page = $this->getPage(0, 1, array( + 'PhoneNumber' => $number + )); + $items = $page->getItems(); + if (is_null($items) || empty($items)) { + return null; + } + return $items[0]; + } +} + +class Services_Twilio_Rest_Local extends Services_Twilio_NumberType { } + +class Services_Twilio_Rest_Mobile extends Services_Twilio_NumberType { } + +class Services_Twilio_Rest_TollFree extends Services_Twilio_NumberType { } diff --git a/php/Lib/Twilio/Rest/IpAccessControlList.php b/php/Lib/Twilio/Rest/IpAccessControlList.php new file mode 100755 index 0000000..5ba83f3 --- /dev/null +++ b/php/Lib/Twilio/Rest/IpAccessControlList.php @@ -0,0 +1,40 @@ +setupSubresources( + 'ip_addresses' + ); + } +} diff --git a/php/Lib/Twilio/Rest/IpAccessControlListMapping.php b/php/Lib/Twilio/Rest/IpAccessControlListMapping.php new file mode 100755 index 0000000..ce5bc5a --- /dev/null +++ b/php/Lib/Twilio/Rest/IpAccessControlListMapping.php @@ -0,0 +1,37 @@ +setupSubresources( + 'ip_addresses' + ); + } +} + diff --git a/php/Lib/Twilio/Rest/IpAccessControlListMappings.php b/php/Lib/Twilio/Rest/IpAccessControlListMappings.php new file mode 100755 index 0000000..f58e1b9 --- /dev/null +++ b/php/Lib/Twilio/Rest/IpAccessControlListMappings.php @@ -0,0 +1,25 @@ +account->sip->domains->get('SDXXX')->ip_access_control_list_mappings->create("ALXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + * + * :param string $ip_access_control_list_sid: the sid of the IpAccessControList + * you're adding to this domain. + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($ip_access_control_list_sid, $params = array()) { + return parent::_create(array( + 'IpAccessControlListSid' => $ip_access_control_list_sid, + ) + $params); + } +} + diff --git a/php/Lib/Twilio/Rest/IpAccessControlLists.php b/php/Lib/Twilio/Rest/IpAccessControlLists.php new file mode 100755 index 0000000..88b9d14 --- /dev/null +++ b/php/Lib/Twilio/Rest/IpAccessControlLists.php @@ -0,0 +1,27 @@ +account->sip->ip_access_control_lists->create("MyFriendlyName"); + * + * :param string $friendly_name: the friendly name of this ip access control list + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * :return: the created list + * :rtype: :class:`Services_Twilio_Rest_IpAccessControlList` + * + */ + public function create($friendly_name, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + ) + $params); + } + +} diff --git a/php/Lib/Twilio/Rest/IpAddress.php b/php/Lib/Twilio/Rest/IpAddress.php new file mode 100755 index 0000000..38b716e --- /dev/null +++ b/php/Lib/Twilio/Rest/IpAddress.php @@ -0,0 +1,34 @@ +instance_name = "Services_Twilio_Rest_IpAddress"; + parent::__construct($client, $uri); + } + + /** + * Creates a new IpAddress instance + * + * Example usage: + * + * .. code-block:: php + * + * $client->account->sip->ip_access_control_lists->get('ALXXX')->ip_addresses->create( + * "FriendlyName", "127.0.0.1" + * ); + * + * :param string $friendly_name: the friendly name for the new IpAddress object + * :param string $ip_address: the ip address for the new IpAddress object + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($friendly_name, $ip_address, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + 'IpAddress' => $ip_address, + ) + $params); + } +} + diff --git a/php/Lib/Twilio/Rest/Key.php b/php/Lib/Twilio/Rest/Key.php new file mode 100755 index 0000000..4750f5b --- /dev/null +++ b/php/Lib/Twilio/Rest/Key.php @@ -0,0 +1,5 @@ +` objects. + * For the definitive reference, see the `Twilio Media List Documentation + * `_. + */ +class Services_Twilio_Rest_Media extends Services_Twilio_ListResource { + + + // This is overridden because the list key in the Twilio response + // is "media_list", not "media". + public function getResourceName($camelized = false) + { + if ($camelized) { + return "MediaList"; + } else { + return "media_list"; + } + } + + // We manually set the instance name here so that the parent + // constructor doesn't attempt to figure out it. It would do it + // incorrectly because we override getResourceName above. + public function __construct($client, $uri) { + $this->instance_name = "Services_Twilio_Rest_MediaInstance"; + parent::__construct($client, $uri); + } + +} + diff --git a/php/Lib/Twilio/Rest/MediaInstance.php b/php/Lib/Twilio/Rest/MediaInstance.php new file mode 100755 index 0000000..1a152b2 --- /dev/null +++ b/php/Lib/Twilio/Rest/MediaInstance.php @@ -0,0 +1,37 @@ +`_. + * + * .. php:attr:: sid + * + * A 34 character string that identifies this object + * + * .. php:attr:: account_sid + * + * A 34 character string representing the account that sent the message + * + * .. php:attr:: parent_sid + * + * The sid of the message that created this media. + * + * .. php:attr:: date_created + * + * The date the message was created + * + * .. php:attr:: date_updated + * + * The date the message was updated + * + * .. php:attr:: content_type + * + * The content-type of the media. + */ +class Services_Twilio_Rest_MediaInstance extends Services_Twilio_InstanceResource { + public function __construct($client, $uri) { + $uri = str_replace('MediaInstance', 'Media', $uri); + parent::__construct($client, $uri); + } +} + diff --git a/php/Lib/Twilio/Rest/Member.php b/php/Lib/Twilio/Rest/Member.php new file mode 100755 index 0000000..8067cdd --- /dev/null +++ b/php/Lib/Twilio/Rest/Member.php @@ -0,0 +1,22 @@ + $url, + 'Method' => $method, + )); + } +} diff --git a/php/Lib/Twilio/Rest/Members.php b/php/Lib/Twilio/Rest/Members.php new file mode 100755 index 0000000..61e05de --- /dev/null +++ b/php/Lib/Twilio/Rest/Members.php @@ -0,0 +1,28 @@ +instance_name($this->client, $this->uri . '/Front'); + } + + /* Participants are identified by CallSid, not like ME123 */ + public function getObjectFromJson($params, $idParam = 'sid') { + return parent::getObjectFromJson($params, 'call_sid'); + } + + public function getResourceName($camelized = false) + { + // The JSON property name is atypical. + return $camelized ? 'Members' : 'queue_members'; + } +} + diff --git a/php/Lib/Twilio/Rest/Message.php b/php/Lib/Twilio/Rest/Message.php new file mode 100755 index 0000000..2ca32e8 --- /dev/null +++ b/php/Lib/Twilio/Rest/Message.php @@ -0,0 +1,68 @@ +setupSubresources( + 'media' + ); + } + + public function redact() { + $postParams = array('Body' => ''); + self::update($postParams); + } + + /** + * Make a request to delete the specified resource. + * + * :rtype: boolean + */ + public function delete() + { + return $this->client->deleteData($this->uri); + } +} + diff --git a/php/Lib/Twilio/Rest/Messages.php b/php/Lib/Twilio/Rest/Messages.php new file mode 100755 index 0000000..355fce0 --- /dev/null +++ b/php/Lib/Twilio/Rest/Messages.php @@ -0,0 +1,73 @@ +account->messages->create(array( + * "Body" => "foo", + * "From" => "+14105551234", + * "To" => "+14105556789", + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. You may find it easier to use the + * sendMessage helper instead of this function. + * + */ + public function create($params = array()) { + return parent::_create($params); + } + + /** + * Send a message + * + * .. code-block:: php + * + * $client = new Services_Twilio('AC123', '123'); + * $message = $client->account->messages->sendMessage( + * '+14105551234', // From a Twilio number in your account + * '+14105556789', // Text any number + * 'Come at the king, you best not miss.' // Message body (if any) + * array('https://demo.twilio.com/owl.png'), // An array of MediaUrls + * ); + * + * :param string $from: the from number for the message, this must be a + * number you purchased from Twilio + * :param string $to: the message recipient's phone number + * :param $mediaUrls: the URLs of images to send in this MMS + * :type $mediaUrls: null (don't include media), a single URL, or an array + * of URLs to send as media with this message + * :param string $body: the text to include along with this MMS + * :param array $params: Any additional params (callback, etc) you'd like to + * send with this request, these are serialized and sent as POST + * parameters + * + * :return: The created :class:`Services_Twilio_Rest_Message` + * :raises: :class:`Services_Twilio_RestException` + * An exception if the parameters are invalid (for example, the from + * number is not a Twilio number registered to your account, or is + * unable to send MMS) + */ + public function sendMessage($from, $to, $body = null, $mediaUrls = null, + $params = array() + ) { + $postParams = array( + 'From' => $from, + 'To' => $to, + ); + // When the request is made, this will get serialized into MediaUrl=a&MediaUrl=b + if (!is_null($mediaUrls)) { + $postParams['MediaUrl'] = $mediaUrls; + } + if (!is_null($body)) { + $postParams['Body'] = $body; + } + return self::create($postParams + $params); + } +} diff --git a/php/Lib/Twilio/Rest/Monitor/Alert.php b/php/Lib/Twilio/Rest/Monitor/Alert.php new file mode 100755 index 0000000..31bc1b4 --- /dev/null +++ b/php/Lib/Twilio/Rest/Monitor/Alert.php @@ -0,0 +1,5 @@ + $phoneNumber, + ) + $params); + } +} diff --git a/php/Lib/Twilio/Rest/Participant.php b/php/Lib/Twilio/Rest/Participant.php new file mode 100755 index 0000000..b62920b --- /dev/null +++ b/php/Lib/Twilio/Rest/Participant.php @@ -0,0 +1,10 @@ +update('Muted', 'true'); + } +} diff --git a/php/Lib/Twilio/Rest/Participants.php b/php/Lib/Twilio/Rest/Participants.php new file mode 100755 index 0000000..3b0464e --- /dev/null +++ b/php/Lib/Twilio/Rest/Participants.php @@ -0,0 +1,10 @@ +instance_name = "Services_Twilio_Rest_Pricing_MessagingCountry"; + parent::__construct($client, $uri); + } + + public function get($isoCountry) { + $instance = new $this->instance_name($this->client, $this->uri . "/$isoCountry"); + $instance->iso_country = $isoCountry; + return $instance; + } +} diff --git a/php/Lib/Twilio/Rest/Pricing/MessagingCountry.php b/php/Lib/Twilio/Rest/Pricing/MessagingCountry.php new file mode 100755 index 0000000..e39cc4e --- /dev/null +++ b/php/Lib/Twilio/Rest/Pricing/MessagingCountry.php @@ -0,0 +1,5 @@ +instance_name = 'Services_Twilio_Rest_Pricing_PhoneNumberCountry'; + parent::__construct($client, $uri); + } + + public function getResourceName($camelized = false) { + if ($camelized) { + return 'Countries'; + } + return 'countries'; + } + + public function get($isoCountry) { + $instance = new $this->instance_name($this->client, $this->uri . "/$isoCountry"); + $instance->iso_country = $isoCountry; + return $instance; + } +} \ No newline at end of file diff --git a/php/Lib/Twilio/Rest/Pricing/PhoneNumberCountry.php b/php/Lib/Twilio/Rest/Pricing/PhoneNumberCountry.php new file mode 100755 index 0000000..ac840b8 --- /dev/null +++ b/php/Lib/Twilio/Rest/Pricing/PhoneNumberCountry.php @@ -0,0 +1,4 @@ +instance_name = "Services_Twilio_Rest_Pricing_VoiceCountry"; + parent::__construct($client, $uri); + } + + public function get($isoCountry) { + $instance = new $this->instance_name($this->client, $this->uri . "/$isoCountry"); + $instance->iso_country = $isoCountry; + return $instance; + } +} \ No newline at end of file diff --git a/php/Lib/Twilio/Rest/Pricing/VoiceCountry.php b/php/Lib/Twilio/Rest/Pricing/VoiceCountry.php new file mode 100755 index 0000000..5252694 --- /dev/null +++ b/php/Lib/Twilio/Rest/Pricing/VoiceCountry.php @@ -0,0 +1,5 @@ +instance_name($this->client, $this->uri . "/$number"); + $instance->number = $number; + return $instance; + } +} \ No newline at end of file diff --git a/php/Lib/Twilio/Rest/Queue.php b/php/Lib/Twilio/Rest/Queue.php new file mode 100755 index 0000000..fa0f2f7 --- /dev/null +++ b/php/Lib/Twilio/Rest/Queue.php @@ -0,0 +1,10 @@ +setupSubresources('members'); + } +} + diff --git a/php/Lib/Twilio/Rest/Queues.php b/php/Lib/Twilio/Rest/Queues.php new file mode 100755 index 0000000..bc35c83 --- /dev/null +++ b/php/Lib/Twilio/Rest/Queues.php @@ -0,0 +1,19 @@ + $friendly_name, + ) + $params); + } +} + diff --git a/php/Lib/Twilio/Rest/Recording.php b/php/Lib/Twilio/Rest/Recording.php new file mode 100755 index 0000000..a76014c --- /dev/null +++ b/php/Lib/Twilio/Rest/Recording.php @@ -0,0 +1,9 @@ +setupSubresources('transcriptions'); + } +} diff --git a/php/Lib/Twilio/Rest/Recordings.php b/php/Lib/Twilio/Rest/Recordings.php new file mode 100755 index 0000000..47ec0d5 --- /dev/null +++ b/php/Lib/Twilio/Rest/Recordings.php @@ -0,0 +1,6 @@ +setupSubresources( + 'domains', + 'ip_access_control_lists', + 'credential_lists' + ); + } + + public function getResourceName($camelized = false) { + return "SIP"; + } +} diff --git a/php/Lib/Twilio/Rest/SmsMessage.php b/php/Lib/Twilio/Rest/SmsMessage.php new file mode 100755 index 0000000..6bd3f9c --- /dev/null +++ b/php/Lib/Twilio/Rest/SmsMessage.php @@ -0,0 +1,6 @@ + $from, + 'To' => $to, + 'Body' => $body + ) + $params); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/Activities.php b/php/Lib/Twilio/Rest/TaskRouter/Activities.php new file mode 100755 index 0000000..9b1f90f --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/Activities.php @@ -0,0 +1,15 @@ +instance_name = "Services_Twilio_Rest_TaskRouter_Activity"; + parent::__construct($client, $uri); + } + + public function create($friendlyName, $available) { + $params['FriendlyName'] = $friendlyName; + $params['Available'] = $available; + return parent::_create($params); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/Activity.php b/php/Lib/Twilio/Rest/TaskRouter/Activity.php new file mode 100755 index 0000000..08f0633 --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/Activity.php @@ -0,0 +1,5 @@ +client->retrieveData($this->uri, $filters); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/Task.php b/php/Lib/Twilio/Rest/TaskRouter/Task.php new file mode 100755 index 0000000..ace660b --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/Task.php @@ -0,0 +1,9 @@ +setupSubresources('reservations'); + } + +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/TaskQueue.php b/php/Lib/Twilio/Rest/TaskRouter/TaskQueue.php new file mode 100755 index 0000000..2e6fae6 --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/TaskQueue.php @@ -0,0 +1,8 @@ +setupSubresource('statistics'); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/TaskQueueStatistics.php b/php/Lib/Twilio/Rest/TaskRouter/TaskQueueStatistics.php new file mode 100755 index 0000000..73ce98e --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/TaskQueueStatistics.php @@ -0,0 +1,5 @@ +setupSubresource('statistics'); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/TaskQueuesStatistics.php b/php/Lib/Twilio/Rest/TaskRouter/TaskQueuesStatistics.php new file mode 100755 index 0000000..e2b25b5 --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/TaskQueuesStatistics.php @@ -0,0 +1,9 @@ +instance_name = "Services_Twilio_Rest_TaskRouter_TaskQueueStatistics"; + parent::__construct($client, $uri); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/Tasks.php b/php/Lib/Twilio/Rest/TaskRouter/Tasks.php new file mode 100755 index 0000000..d9d193b --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/Tasks.php @@ -0,0 +1,11 @@ +setupSubresource('statistics'); + $this->setupSubresources('reservations'); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/WorkerStatistics.php b/php/Lib/Twilio/Rest/TaskRouter/WorkerStatistics.php new file mode 100755 index 0000000..4c8c26a --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/WorkerStatistics.php @@ -0,0 +1,5 @@ +setupSubresource('statistics'); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/WorkersStatistics.php b/php/Lib/Twilio/Rest/TaskRouter/WorkersStatistics.php new file mode 100755 index 0000000..95455dd --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/WorkersStatistics.php @@ -0,0 +1,5 @@ +setupSubresource('statistics'); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/WorkflowStatistics.php b/php/Lib/Twilio/Rest/TaskRouter/WorkflowStatistics.php new file mode 100755 index 0000000..98b9693 --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/WorkflowStatistics.php @@ -0,0 +1,5 @@ +setupSubresources( + 'activities', + 'events', + 'tasks', + 'task_queues', + 'workers', + 'workflows' + ); + $this->setupSubresource('statistics'); + } +} diff --git a/php/Lib/Twilio/Rest/TaskRouter/WorkspaceStatistics.php b/php/Lib/Twilio/Rest/TaskRouter/WorkspaceStatistics.php new file mode 100755 index 0000000..f5eae06 --- /dev/null +++ b/php/Lib/Twilio/Rest/TaskRouter/WorkspaceStatistics.php @@ -0,0 +1,5 @@ +account->tokens->create(array( + * "Ttl" => 100, + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } + +} diff --git a/php/Lib/Twilio/Rest/Transcription.php b/php/Lib/Twilio/Rest/Transcription.php new file mode 100755 index 0000000..83c139c --- /dev/null +++ b/php/Lib/Twilio/Rest/Transcription.php @@ -0,0 +1,6 @@ +trunks->get('TK123')->credential_lists->create(array( + * "CredentialListSid" => "CL1234xxxxx", + * .... + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/php/Lib/Twilio/Rest/Trunking/IpAccessControlList.php b/php/Lib/Twilio/Rest/Trunking/IpAccessControlList.php new file mode 100755 index 0000000..f66eae6 --- /dev/null +++ b/php/Lib/Twilio/Rest/Trunking/IpAccessControlList.php @@ -0,0 +1,5 @@ +trunks->get('TK123')->ip_access_control_lists->create(array( + * "IpAccessControlListSid" => "AL1234xxxx", + * .... + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/php/Lib/Twilio/Rest/Trunking/OriginationUrl.php b/php/Lib/Twilio/Rest/Trunking/OriginationUrl.php new file mode 100755 index 0000000..0d56c78 --- /dev/null +++ b/php/Lib/Twilio/Rest/Trunking/OriginationUrl.php @@ -0,0 +1,5 @@ +trunks->get('TK123')->origination_urls->create(array( + * "FriendlyName" => "TestUrl", + * .... + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/php/Lib/Twilio/Rest/Trunking/PhoneNumber.php b/php/Lib/Twilio/Rest/Trunking/PhoneNumber.php new file mode 100755 index 0000000..9495f81 --- /dev/null +++ b/php/Lib/Twilio/Rest/Trunking/PhoneNumber.php @@ -0,0 +1,5 @@ +trunks->get('TK123')->phone_numbers->create(array( + * "PhoneNumberSid" => "PN1234xxxx" + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/php/Lib/Twilio/Rest/Trunking/Trunk.php b/php/Lib/Twilio/Rest/Trunking/Trunk.php new file mode 100755 index 0000000..0d93b9e --- /dev/null +++ b/php/Lib/Twilio/Rest/Trunking/Trunk.php @@ -0,0 +1,13 @@ +setupSubresources( + 'credential_lists', + 'ip_access_control_lists', + 'origination_urls', + 'phone_numbers' + ); + } +} diff --git a/php/Lib/Twilio/Rest/Trunking/Trunks.php b/php/Lib/Twilio/Rest/Trunking/Trunks.php new file mode 100755 index 0000000..9c76ef2 --- /dev/null +++ b/php/Lib/Twilio/Rest/Trunking/Trunks.php @@ -0,0 +1,5 @@ +setupSubresources( + 'today', + 'yesterday', + 'all_time', + 'this_month', + 'last_month', + 'daily', + 'monthly', + 'yearly' + ); + } +} + +class Services_Twilio_Rest_Today extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_Yesterday extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_LastMonth extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_ThisMonth extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_AllTime extends Services_Twilio_TimeRangeResource { } + +class Services_Twilio_Rest_Daily extends Services_Twilio_UsageResource { } + +class Services_Twilio_Rest_Monthly extends Services_Twilio_UsageResource { } + +class Services_Twilio_Rest_Yearly extends Services_Twilio_UsageResource { } diff --git a/php/Lib/Twilio/Rest/UsageTrigger.php b/php/Lib/Twilio/Rest/UsageTrigger.php new file mode 100755 index 0000000..44c8cf5 --- /dev/null +++ b/php/Lib/Twilio/Rest/UsageTrigger.php @@ -0,0 +1,5 @@ +`_. + * @param string $value Fire the trigger when usage crosses this value. + * @param string $url The URL to request when the trigger fires. + * @param array $params Optional parameters for this trigger. A full list of parameters can be found in the `Usage Trigger documentation `_. + * @return Services_Twilio_Rest_UsageTrigger The created trigger + */ + function create($category, $value, $url, array $params = array()) { + return parent::_create(array( + 'UsageCategory' => $category, + 'TriggerValue' => $value, + 'CallbackUrl' => $url, + ) + $params); + } + +} + diff --git a/php/Lib/Twilio/RestException.php b/php/Lib/Twilio/RestException.php new file mode 100755 index 0000000..c7de16c --- /dev/null +++ b/php/Lib/Twilio/RestException.php @@ -0,0 +1,44 @@ +status = $status; + $this->info = $info; + parent::__construct($message, $code); + } + + /** + * Get the HTTP status code + */ + public function getStatus() { + return $this->status; + } + + /** + * Get a link to more information + */ + public function getInfo() { + return $this->info; + } +} diff --git a/php/Lib/Twilio/SIPListResource.php b/php/Lib/Twilio/SIPListResource.php new file mode 100755 index 0000000..1e63b67 --- /dev/null +++ b/php/Lib/Twilio/SIPListResource.php @@ -0,0 +1,14 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + + protected function setupSubresource($name) { + $constantized = ucfirst(self::camelize($name)); + $type = get_class($this) . $constantized; + $this->subresources[$name] = new $type( + $this->client, $this->uri . "/". $constantized + ); + } +} diff --git a/php/Lib/Twilio/TaskRouterListResource.php b/php/Lib/Twilio/TaskRouterListResource.php new file mode 100755 index 0000000..156e190 --- /dev/null +++ b/php/Lib/Twilio/TaskRouterListResource.php @@ -0,0 +1,26 @@ +getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_TaskRouter_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + + protected function setupSubresource($name) { + $constantized = ucfirst(self::camelize($name)); + $type = get_class($this) . $constantized; + $this->subresources[$name] = new $type( + $this->client, $this->uri . "/". $constantized + ); + } +} diff --git a/php/Lib/Twilio/TimeRangeResource.php b/php/Lib/Twilio/TimeRangeResource.php new file mode 100755 index 0000000..ebf1990 --- /dev/null +++ b/php/Lib/Twilio/TimeRangeResource.php @@ -0,0 +1,31 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +class Services_Twilio_TimeRangeResource extends Services_Twilio_UsageResource { + + /** + * Return a UsageRecord corresponding to the given category. + * + * @param string $category The category of usage to retrieve. For a full + * list of valid categories, please see the documentation at + * http://www.twilio.com/docs/api/rest/usage-records#usage-all-categories + * @return Services_Twilio_Rest_UsageRecord + * @throws Services_Twilio_RestException + */ + public function getCategory($category) { + $page = $this->getPage(0, 1, array( + 'Category' => $category, + )); + $items = $page->getItems(); + if (!is_array($items) || count($items) === 0) { + throw new Services_Twilio_RestException( + 400, "Usage record data is unformattable."); + } + return $items[0]; + } +} diff --git a/php/Lib/Twilio/TinyHttp.php b/php/Lib/Twilio/TinyHttp.php new file mode 100755 index 0000000..b6ccfe2 --- /dev/null +++ b/php/Lib/Twilio/TinyHttp.php @@ -0,0 +1,134 @@ + array( + * CURLOPT_USERAGENT => self::USER_AGENT, + * CURLOPT_HTTPHEADER => array('Accept-Charset: utf-8'), + * CURLOPT_CAINFO => dirname(__FILE__) . '/cacert.pem', + * )) + * ); + */ +class Services_Twilio_TinyHttp { + var $user, $pass, $scheme, $host, $port, $debug, $curlopts; + + public function __construct($uri = '', $kwargs = array()) { + foreach (parse_url($uri) as $name => $value) $this->$name = $value; + $this->debug = isset($kwargs['debug']) ? !!$kwargs['debug'] : NULL; + $this->curlopts = isset($kwargs['curlopts']) ? $kwargs['curlopts'] : array(); + } + + public function __call($name, $args) { + list($res, $req_headers, $req_body) = $args + array(0, array(), ''); + + if (strpos($res, 'http') === 0) { + // We got handed a complete URL, just use it + $url = $res; + } else { + // Build from path and default scheme/host. + $url = "$this->scheme://$this->host$res"; + } + + $opts = $this->curlopts + array( + CURLOPT_URL => $url, + CURLOPT_HEADER => TRUE, + CURLOPT_RETURNTRANSFER => TRUE, + CURLOPT_INFILESIZE => -1, + CURLOPT_POSTFIELDS => NULL, + CURLOPT_TIMEOUT => 60, + ); + + foreach ($req_headers as $k => $v) $opts[CURLOPT_HTTPHEADER][] = "$k: $v"; + if ($this->port) $opts[CURLOPT_PORT] = $this->port; + if ($this->debug) $opts[CURLINFO_HEADER_OUT] = TRUE; + if ($this->user && $this->pass) $opts[CURLOPT_USERPWD] = "$this->user:$this->pass"; + switch ($name) { + case 'get': + $opts[CURLOPT_HTTPGET] = TRUE; + break; + case 'post': + $opts[CURLOPT_POST] = TRUE; + $opts[CURLOPT_POSTFIELDS] = $req_body; + break; + case 'put': + $opts[CURLOPT_PUT] = TRUE; + if (strlen($req_body)) { + if ($buf = fopen('php://memory', 'w+')) { + fwrite($buf, $req_body); + fseek($buf, 0); + $opts[CURLOPT_INFILE] = $buf; + $opts[CURLOPT_INFILESIZE] = strlen($req_body); + } else throw new Services_Twilio_TinyHttpException('unable to open temporary file'); + } + break; + case 'head': + $opts[CURLOPT_NOBODY] = TRUE; + break; + default: + $opts[CURLOPT_CUSTOMREQUEST] = strtoupper($name); + break; + } + try { + if ($curl = curl_init()) { + if (curl_setopt_array($curl, $opts)) { + if ($response = curl_exec($curl)) { + $parts = explode("\r\n\r\n", $response, 3); + list($head, $body) = ($parts[0] == 'HTTP/1.1 100 Continue') + ? array($parts[1], $parts[2]) + : array($parts[0], $parts[1]); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + if ($this->debug) { + error_log( + curl_getinfo($curl, CURLINFO_HEADER_OUT) . + $req_body + ); + } + $header_lines = explode("\r\n", $head); + array_shift($header_lines); + foreach ($header_lines as $line) { + list($key, $value) = explode(":", $line, 2); + $headers[$key] = trim($value); + } + curl_close($curl); + if (isset($buf) && is_resource($buf)) { + fclose($buf); + } + return array($status, $headers, $body); + } else { + throw new Services_Twilio_TinyHttpException(curl_error($curl)); + } + } else throw new Services_Twilio_TinyHttpException(curl_error($curl)); + } else throw new Services_Twilio_TinyHttpException('unable to initialize cURL'); + } catch (ErrorException $e) { + if (is_resource($curl)) curl_close($curl); + if (isset($buf) && is_resource($buf)) fclose($buf); + throw $e; + } + } + + public function authenticate($user, $pass) { + $this->user = $user; + $this->pass = $pass; + } +} diff --git a/php/Lib/Twilio/TrunkingInstanceResource.php b/php/Lib/Twilio/TrunkingInstanceResource.php new file mode 100755 index 0000000..505fe94 --- /dev/null +++ b/php/Lib/Twilio/TrunkingInstanceResource.php @@ -0,0 +1,15 @@ +subresources[$name] = new $type( + $this->client, $this->uri . "/$constantized" + ); + } + } + +} diff --git a/php/Lib/Twilio/TrunkingListResource.php b/php/Lib/Twilio/TrunkingListResource.php new file mode 100755 index 0000000..dc51ede --- /dev/null +++ b/php/Lib/Twilio/TrunkingListResource.php @@ -0,0 +1,38 @@ +getResourceName(true); + /* + * By default trim the 's' from the end of the list name to get the + * instance name (ex Accounts -> Account). This behavior can be + * overridden by child classes if the rule doesn't work. + */ + if (!isset($this->instance_name)) { + $this->instance_name = "Services_Twilio_Rest_Trunking_" . rtrim($name, 's'); + } + + parent::__construct($client, $uri); + } + + /** + * Create a new Trunk instance + * + * Example usage: + * + * .. code-block:: php + * + * $trunkingClient->trunks->create(array( + * "FriendlyName" => "TestTrunk", + * "DomainName" => "test.pstn.twilio.com" + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * + */ + public function create($params = array()) { + return parent::_create($params); + } +} diff --git a/php/Lib/Twilio/Twiml.php b/php/Lib/Twilio/Twiml.php new file mode 100755 index 0000000..6a021ca --- /dev/null +++ b/php/Lib/Twilio/Twiml.php @@ -0,0 +1,137 @@ + + * License: http://creativecommons.org/licenses/MIT/ MIT + */ +class Services_Twilio_Twiml { + + protected $element; + + /** + * Constructs a Twiml response. + * + * :param SimpleXmlElement|array $arg: Can be any of + * + * - the element to wrap + * - attributes to add to the element + * - if null, initialize an empty element named 'Response' + */ + public function __construct($arg = null) { + switch (true) { + case $arg instanceof SimpleXmlElement: + $this->element = $arg; + break; + case $arg === null: + $this->element = new SimpleXmlElement(''); + break; + case is_array($arg): + $this->element = new SimpleXmlElement(''); + foreach ($arg as $name => $value) { + $this->element->addAttribute($name, $value); + } + break; + default: + throw new Services_Twilio_TwimlException('Invalid argument'); + } + } + + /** + * Converts method calls into Twiml verbs. + * + * A basic example: + * + * .. code-block:: php + * + * php> print $this->say('hello'); + * hello + * + * An example with attributes: + * + * .. code-block:: php + * + * print $this->say('hello', array('voice' => 'woman')); + * hello + * + * You could even just pass in an attributes array, omitting the noun: + * + * .. code-block:: php + * + * print $this->gather(array('timeout' => '20')); + * + * + * :param string $verb: The Twiml verb. + * :param array $args: + * - (noun string) + * - (noun string, attributes array) + * - (attributes array) + * + * :return: A SimpleXmlElement + * :rtype: SimpleXmlElement + */ + public function __call($verb, array $args) + { + list($noun, $attrs) = $args + array('', array()); + if (is_array($noun)) { + list($attrs, $noun) = array($noun, ''); + } + /* addChild does not escape XML, while addAttribute does. This means if + * you pass unescaped ampersands ("&") to addChild, you will generate + * an error. + * + * Some inexperienced developers will pass in unescaped ampersands, and + * we want to make their code work, by escaping the ampersands for them + * before passing the string to addChild. (with htmlentities) + * + * However other people will know what to do, and their code + * already escapes ampersands before passing them to addChild. We don't + * want to break their existing code by turning their &'s into + * &amp; + * + * We also want to use numeric entities, not named entities so that we + * are fully compatible with XML + * + * The following lines accomplish the desired behavior. + */ + $decoded = html_entity_decode($noun, ENT_COMPAT, 'UTF-8'); + $normalized = htmlspecialchars($decoded, ENT_COMPAT, 'UTF-8', false); + $child = empty($noun) + ? $this->element->addChild(ucfirst($verb)) + : $this->element->addChild(ucfirst($verb), $normalized); + foreach ($attrs as $name => $value) { + /* Note that addAttribute escapes raw ampersands by default, so we + * haven't touched its implementation. So this is the matrix for + * addAttribute: + * + * & turns into & + * & turns into &amp; + */ + if (is_bool($value)) { + $value = ($value === true) ? 'true' : 'false'; + } + $child->addAttribute($name, $value); + } + return new static($child); + } + + /** + * Returns the object as XML. + * + * :return: The response as an XML string + * :rtype: string + */ + public function __toString() + { + $xml = $this->element->asXml(); + return str_replace( + '', + '', $xml); + } +} diff --git a/php/Lib/Twilio/UsageResource.php b/php/Lib/Twilio/UsageResource.php new file mode 100755 index 0000000..b9b929c --- /dev/null +++ b/php/Lib/Twilio/UsageResource.php @@ -0,0 +1,20 @@ + + * @license http://creativecommons.org/licenses/MIT/ MIT + * @link http://pear.php.net/package/Services_Twilio + */ +class Services_Twilio_UsageResource extends Services_Twilio_ListResource { + public function getResourceName($camelized = false) { + $this->instance_name = 'Services_Twilio_Rest_UsageRecord'; + return $camelized ? 'UsageRecords' : 'usage_records'; + } + + public function __construct($client, $uri) { + $uri = preg_replace("#UsageRecords#", "Usage/Records", $uri); + parent::__construct($client, $uri); + } +} + diff --git a/php/Lib/Twilio/WorkflowConfiguration.php b/php/Lib/Twilio/WorkflowConfiguration.php new file mode 100755 index 0000000..1d26b4a --- /dev/null +++ b/php/Lib/Twilio/WorkflowConfiguration.php @@ -0,0 +1,88 @@ +filters = $filters; + $this->default_filter = $default_filter; + } + + public function toJSON() { + return json_encode($this); + } + + public static function parse($json) { + return json_decode($json); + } + + public function jsonSerialize() { + $json = array(); + $task_routing = array(); + $task_routing["filters"] = $this->filters; + $task_routing["default_filter"] = $this->default_filter; + $json["task_routing"] = $task_routing; + return $json; + } +} + +class WorkflowRule implements JsonSerializable { + public $expression; + public $friendly_name; + public $targets; + + public function __construct($expression, $targets, $friendly_name = null) + { + $this->expression = $expression; + $this->targets = $targets; + $this->friendly_name = $friendly_name; + } + + public function jsonSerialize() { + $json = array(); + $json["expression"] = $this->expression; + $json["targets"] = $this->targets; + if($this->friendly_name != null) { + $json["friendly_name"] = $this->friendly_name; + } + return $json; + } +} + +class WorkflowRuleTarget implements JsonSerializable { + public $queue; + public $expression; + public $priority; + public $timeout; + + public function __construct($queue, $priority = null, $timeout = null, $expression = null) + { + $this->queue = $queue; + $this->priority = $priority; + $this->timeout = $timeout; + $this->expression = $expression; + } + + public function jsonSerialize() { + $json = array(); + $json["queue"] = $this->queue; + if($this->priority != null) { + $json["priority"] = $this->priority; + } + if($this->timeout != null) { + $json["timeout"] = $this->timeout; + } + if($this->expression != null) { + $json["expression"] = $this->expression; + } + return $json; + } +} \ No newline at end of file diff --git a/php/smack_my_bitch_up.php b/php/smack_my_bitch_up.php new file mode 100644 index 0000000..7340040 --- /dev/null +++ b/php/smack_my_bitch_up.php @@ -0,0 +1,137 @@ +twilio = new Services_Twilio($this->TWILIO_ACCOUNT_SID, $this->TWILIO_AUTH_TOKEN); + + /** + * Once we have completed this, we can send message! + */ + + $this->SendMessage( function(){ + + /** + * Log message + */ + + echo "Message sent at: ".date('d/m/Y - g:i:s a', time())." | Reason: ".$this->reason; + + /** + * Unset + */ + + unset( $this->twilio ); + }); + + /** + * Return tue + */ + + return true; + } + + /** + * Sends our message + * + * @param $callback + */ + + public function SendMessage( $callback ) + { + + if( $this->twilio != null ) + { + + /** + * Get random reason + */ + + $this->reason = $this->reason[array_rand($this->reason)]; + + /** + * Send message + */ + + $this->twilio->account->messages->create(array( + "From" => $this->my_number, + "To" => $this->her_number, + "Body" => "Late at work. ".$this->reason, + )); + + /** + * Execute our callback + */ + + call_user_func( $callback ); + } + } + +} \ No newline at end of file