?
Solved

google voice sms text using php

Posted on 2013-01-18
9
Medium Priority
?
618 Views
Last Modified: 2014-11-12
phpmailer allows a programmer to send an email using smtp instead of gmail client

is there a method to send a google voice text without using google voice client (using php)
0
Comment
Question by:rgb192
[X]
Welcome to Experts Exchange

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

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
9 Comments
 
LVL 36

Expert Comment

by:Loganathan Natarajan
ID: 38793691
0
 
LVL 111

Expert Comment

by:Ray Paseur
ID: 38793986
As Terry Wysocki wrote, "Looking around most of the scripts to send SMS are failing these days. Does this still work for anyone?"

Not picking on CodeCri.me, just noting that the more recent comments are mostly about failures with the scripts or the service.  If you want a professional and dependable solution for SMS applications I would recommend the excellent service from http://www.twilio.com/
0
 
LVL 15

Expert Comment

by:Giovanni Heward
ID: 38795069
I personally use my own SMS server now.  The code I wrote to SMS via Google Voice resulted in my account being flagged in < 24 hours.

Here's the sms function I used.

<?php
function sms($num, $msg, $id = '', $max = 160)	{
	require('class.xhttp.php');
	// verify auth code status
	$filename = "auth.txt";
	$handle = fopen($filename, "x+");
	$contents = fread($handle, filesize($filename));
	fclose($handle);
	$contents = explode("|", $contents);
	if(time() <= $contents[1])	{
		$auth = $contents[0];
		echo "auth code cached\n";
	} else {
		// auth code expired; obtain new
		$data = array();
		$data['post'] = array(
			'accountType' => 'GOOGLE',
			'Email'       => 'account@gtempaccount.com',
			'Passwd'      => 'password',
			'service'     => 'grandcentral',
			'source'      => 'example.com-sms-1.0'
		);
		$response = xhttp::fetch('https://www.google.com/accounts/ClientLogin', $data);
		if(!$response['successful']) {
			echo 'response: '; print_r($response);
			die();
		}
		preg_match('/Auth=(.+)/', $response['body'], $matches);
		$auth = $matches[1];
		$filename = "auth.txt";
		$handle = fopen($filename, "r+");
		fwrite($handle, $auth);
		fwrite($handle, "|");
		fwrite($handle, time() + 300); // write time 5 mins from now
		fclose($handle);
	}
	$data['post'] = null;
	$data['headers'] = array(
		'Authorization' => 'GoogleLogin auth='.$auth
	);
	$response = xhttp::fetch('https://www.google.com/voice/b/0', $data);
	if(!$response['successful']) {
		echo 'response: '; print_r($response);
		die();
	}
	preg_match("/'_rnr_se': '([^']+)'/", $response['body'], $matches);
	$rnrse = $matches[1];
	$data['post'] = array (
		'_rnr_se'     => $rnrse,
		'phoneNumber' => $num,		// country code + area code + phone number (international notation)
		'text'        => substr($msg, 0, $max),
		'id'          => $id		// thread ID of message, GVoice's way of threading the messages like GMail
	);
	$response = xhttp::fetch('https://www.google.com/voice/b/0/sms/send/', $data);
	$value = json_decode($response['body']);
	if($value->ok) {
		echo "SMS message sent! ({$data[post][phoneNumber]}: {$data[post][text]})\n";
	} else {
		echo "Unable to send SMS! Error Code ({$value->data->code})\n\n";
		echo 'response: '; print_r($response);
	}
}
?>

Open in new window


class.xhttp.php
<?php

# Arvin Castro, arvin@sudocode.net
# 19 June 2011
# http://sudocode.net/sources/includes/class-xhttp-php/

/*
	Changelog
	03-03-2011 Added CURLOPT_TIMEOUT = 50 and CURLOPT_CONNECTTIMEOUT = 20 as default setting
	16-04-2011 Added hook: before-curl-execution (curl handle, request data)
	           Moved response parsing to function after_curl_execution
	           * Changes made to support xhttp_multi plugin
	           Added $response['json'] in output if the content-type is application/json
	23-05-2011 Added $response['json'] in output if the content-type is text/javascript
	24-05-2011 Fixed before-curl-execution hook, changed $responseData to $requestData
	26-05-2011 Used http_build_query for the function toQueryString
	19-06-2011 Added hook to pass GET and POST parameters to utf8_encode
*/

class xhttp {

	private static $first_run = true;

	public static $hooks   = array();
	public static $plugins = array();

	public static function init() {
		if(self::$first_run) self::$first_run = false; else return;
		self::$hooks['data-preparation'][8][] = array('xhttp', 'utf8_encode');
	}

	public static function fetch($url, $requestData = array()) {

		$requestData['curl'][CURLOPT_HEADER] = true;
		$requestData['curl'][CURLOPT_RETURNTRANSFER] = true;
		self::addHookToRequest($requestData, 'return-response', array(__CLASS__, 'response_decode'), 2);

		$method = (isset($requestData['method'])) ? $requestData['method']: ((isset($requestData['post'])) ? 'post': 'get');
		return self::request($url, $method, $requestData);
	}

	public static function request($url, $method = 'get', $requestData = array()) {

		self::init();

		# Hook here: xhttp-initialization
		# array(&$urlparts, &$requestData);
		$output = self::runHook('xhttp-initialization', $requestData['hooks'], array(&$url, &$method, &$requestData));
		if($output !== null) return $output;

		# Set URL and Method
		$requestData['method'] = $method;
		$requestData['url'] = $url;

		# Dissect URL
		$urlparts = array_merge(
			array('scheme'=>'http','user'=>'','pass'=>'','host'=>'','port'=>'','path'=>'','query'=>'','fragment'=>''),
			parse_url($url));

		# Set Default Ports
		if(!$urlparts['port']) switch($urlparts['scheme']) {
			case 'http' : $urlparts['port'] =  80; break;
			case 'https': $urlparts['port'] = 443; break;
		}

		# Collect GET
		if($urlparts['query']) {
			if(!isset($requestData['get'])) $requestData['get'] = array();
			$requestData['get'] = array_merge($requestData['get'], self::toQueryArray($urlparts['query']));
			$urlparts['query']	= '';
		}

		# Default Settings
		if(!isset($requestData['curl'][CURLOPT_SSL_VERIFYPEER]))
			$requestData['curl'][CURLOPT_SSL_VERIFYPEER] = false;
		if(!isset($requestData['headers']['Expect']))
			$requestData['headers']['Expect'] = '';
		if(!isset($requestData['curl'][CURLOPT_CONNECTTIMEOUT]))
			$requestData['curl'][CURLOPT_CONNECTTIMEOUT] = 20;
		if(!isset($requestData['curl'][CURLOPT_TIMEOUT]))
			$requestData['curl'][CURLOPT_TIMEOUT] = 50;

		# Hook here: data-preparation
		# array(&$urlparts, &$requestData);
		$output = self::runHook('data-preparation', $requestData['hooks'], array(&$urlparts, &$requestData));
		if($output !== null) return $output;

		# Set GET, POST, COOKIES, HEADERS
		if(isset($requestData['get']))	   $urlparts['query'] = self::toQueryString($requestData['get']);
		if(isset($requestData['post']))    $requestData['curl'][CURLOPT_POSTFIELDS] = $requestData['post'];
		if(isset($requestData['headers'])) $requestData['curl'][CURLOPT_HTTPHEADER] = self::toCurlHeaders($requestData['headers']);
		if(isset($requestData['cookies'])) $requestData['curl'][CURLOPT_COOKIE]     = self::toCookieString($requestData['cookies']);

		# Set username and password
		if($urlparts['user']) {
			if($urlparts['pass']) $urlparts['user'] .= ':'.$urlparts['pass'];
			$requestData['curl'][CURLOPT_USERPWD] = $urlparts['user'];
			$urlparts['pass'] = $urlparts['user'] = '';
		}

		if($requestData['method'] == 'head') {
			$requestData['curl'][CURLOPT_HEADER] = true;
			$requestData['curl'][CURLOPT_NOBODY] = true;
		}

		# Build URL
		$url = $requestData['url'] = self::unparse_url($urlparts);

		# Hook here: curl-initialization
		# array(&$url, &$requestData);
		$output = self::runHook('curl-initialization', $requestData['hooks'], array(&$url, &$requestData));
		if($output !== null) return $output;

		if(!isset($requestData['headers']['User-Agent']))
			$requestData['headers']['User-Agent'] = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18 ( .NET CLR 3.5.30729; .NET4.0C)";

		# Create cURL instance
		$ch = curl_init();

		# Set file uploads
		if(isset($requestData['files'])) {
			$requestData['headers']['Content-Type'] = 'multipart/form-data';
			if(!is_array($requestData['curl'][CURLOPT_POSTFIELDS])) $requestData['curl'][CURLOPT_POSTFIELDS] = array();
			foreach($requestData['files'] as $key => $file) {
				# Check if file is a URL, download and save to a file
				if(strpos($file, 'http') === 0) {
					$requestData['tmpfile'][$key] = tempnam('.', 'xhttp-tmp-');
					file_put_contents($requestData['tmpfile'][$key], file_get_contents($file));
					$file = $requestData['tmpfile'][$key];

				# Check if file is not a file, then dump it to a file first
				} elseif(!file_exists($file)) {
					$requestData['tmpfile'][$key] = tempnam('.', 'xhttp-tmp-');
					file_put_contents($requestData['tmpfile'][$key], $file);
					$file = $requestData['tmpfile'][$key];
				}

				$requestData['curl'][CURLOPT_POSTFIELDS][$key] = (strpos($file, '@') === 0) ? $file: '@'.$file;
			}
		}

		# Format POST fields according to Content-Type
		if(isset($requestData['curl'][CURLOPT_POSTFIELDS]) or isset($requestData['headers']['Content-Type'])) {
			if(!isset($requestData['headers']['Content-Type'])) $requestData['headers']['Content-Type'] = 'application/x-www-form-urlencoded';

			if(strpos($requestData['headers']['Content-Type'], 'application/json') !== false) {
				if(is_array($requestData['curl'][CURLOPT_POSTFIELDS]))
					$requestData['curl'][CURLOPT_POSTFIELDS] = json_encode($requestData['curl'][CURLOPT_POSTFIELDS]);
				elseif(!isset($requestData['curl'][CURLOPT_POSTFIELDS]))
					$requestData['curl'][CURLOPT_POSTFIELDS] = '{}';
			}

			if(strpos($requestData['headers']['Content-Type'], 'application/x-www-form-urlencoded') !== false) {
				if(is_array($requestData['curl'][CURLOPT_POSTFIELDS]))
					$requestData['curl'][CURLOPT_POSTFIELDS] = self::toQueryString($requestData['curl'][CURLOPT_POSTFIELDS]);
			}
		}

		# Set all cURL options
		$optionsSet = curl_setopt_array($ch, $requestData['curl']);

		if($optionsSet) {
			# Set URL and Request Method
			curl_setopt($ch, CURLOPT_URL, $url);
			curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));

			# hook here: before-curl-execution
			# array(&$ch, &$responseData)
			$output = self::runHook('before-curl-execution', $requestData['hooks'], array(&$ch, &$requestData));
			if($output !== null) return $output;

			# Execute cURL Request
			$response = curl_exec($ch);
		}

		return self::after_curl_execution($ch, $response, $requestData);
	}

	public static function after_curl_execution(&$ch, &$response, &$requestData) {

		if(!$ch) {
			trigger_error($requestData['url'], E_USER_WARNING);
		}

		# Initialize response data
		$responseData = array();
		$responseData['url'] = $requestData['url'];
		$responseData['request'] = $requestData;
		$responseData['body'] = $response;

		# Get cURL errors if any
		$responseData['error'] = array('code'=> curl_errno($ch), 'description' => curl_error($ch));
		$responseData['status'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		$responseData['successful'] = ($responseData['status'] >= 200 and $responseData['status'] < 300) ? true: false;

		# hook here: after-curl-execution
		# array(&$ch, &$response, &$responseData)
		$output = self::runHook('after-curl-execution', $requestData['hooks'], array(&$ch, &$response, &$responseData));
		if($output !== null) { curl_close($ch); return $output; }

		# Close cURL handle
		curl_close($ch);

		# Cleanup tempfile
		if(isset($requestData['tmpfile'])) {
			foreach($requestData['tmpfile'] as $key => $file) unlink($file);
		}

		# hook here: return-response
		# array(&$response, &$responseData)
		$output = self::runHook('return-response', $requestData['hooks'], array(&$response, &$responseData));
		if($output !== null) return $output;

		return $responseData;
	}

	public static function utf8_encode(&$urlparts, &$requestData) {
		if(isset($requestData['get'])  and is_array($requestData['get']))  array_walk($requestData['get'],  array(__CLASS__, 'array_utf8_encode'));
		if(isset($requestData['post']) and is_array($requestData['post'])) array_walk($requestData['post'], array(__CLASS__, 'array_utf8_encode'));
	}
	public static function array_utf8_encode(&$item, $key) {
		if('UTF-8' != mb_detect_encoding($item)) $item = utf8_encode($item);
	}

	public static function response_decode(&$response, &$responseData) {

		if($responseData['error']['code'] == 0
			AND isset($responseData['request']['curl'][CURLOPT_RETURNTRANSFER])
			AND $responseData['request']['curl'][CURLOPT_RETURNTRANSFER]
			AND isset($responseData['request']['curl'][CURLOPT_HEADER])
			AND $responseData['request']['curl'][CURLOPT_HEADER]) {

			# Check for HTTP/1.1 100 Continue, skip if it exists
			$continue = stripos($response, 'HTTP/1.1 100 Continue');
			$offset = ($continue === 0) ? strpos($response, "\r\n\r\n")+4: 0;

			$blankline = strpos($response, "\r\n\r\n", $offset);
			$responseData['headers'] = self::toHeaderArray(substr($response, $offset, $blankline - $offset));
			$responseData['body']	 = substr($response, $blankline + 4);

			# Reformat cookies or $responseData['headers']['cookies']
			if(isset($responseData['headers']['set-cookie'])) {
				$responseData['headers']['cookies'] = self::cookie_decode(self::array_flatten_bfs($responseData['headers']['set-cookie']));

				if(!isset($responseData['headers']['cookies']['domain'])) {
					$domain = parse_url($responseData['url'], PHP_URL_HOST);
					if(stripos($domain, 'www.') === 0) $domain = substr($domain, 4);
					$responseData['headers']['cookies']['domain'] = strtolower($domain);
				}
				if(!isset($responseData['headers']['cookies']['path']))
					$responseData['headers']['cookies']['path'] = '/';
				if(isset($responseData['headers']['cookies']['expires']))
					$responseData['headers']['cookies']['expires'] = strtotime($responseData['headers']['cookies']['expires']);
				if(isset($responseData['headers']['cookies']['max-age']))
					$responseData['headers']['cookies']['expires'] = time() + $responseData['headers']['cookies']['max-age'];
			}

			# Reformat content-type and charset info
			if(isset($responseData['headers']['content-type'])) {
				$info = explode(';', $responseData['headers']['content-type'], 2);
				$responseData['headers']['content-type'] = $info[0];
				if(isset($info[1])) {
					preg_match('/charset= *([^; ]+)/i', $info[1], $matches);
					$responseData['headers']['charset'] = $matches[1];
				}
			}

			# Check for special content-types
			if(in_array($responseData['headers']['content-type'], array('application/json', 'text/javascript'))) {
				$responseData['json'] = json_decode($responseData['body'], true);
			}

		} else {
			$responseData['body'] = $response;
		}
	}

	public static function cookie_decode($cookies, $urldecode = false) {
		if(!is_array($cookies)) $cookies = array($cookies);
		$array = array();
		foreach($cookies as $cookie) {
			$crumbles = explode(';', $cookie);
			foreach($crumbles as $crumble) {
				$name_value = explode('=', $crumble, 2);
				if(!isset($name_value[1])) $name_value[1] = true;
				list($name, $value) = $name_value;
				$array[strtolower(trim($name))] = ($urldecode) ? urldecode($value): $value;
			}
		}
		return $array;
	}

	# Helper functions

	public static function unparse_url($urlparts) {
		if($urlparts['port'] == 80	and $urlparts['scheme'] == 'http' ) $urlparts['port'] = '';
		if($urlparts['port'] == 443 and $urlparts['scheme'] == 'https') $urlparts['port'] = '';

		if($urlparts['fragment']) $urlparts['fragment'] = '#'.$urlparts['fragment'];
		if($urlparts['query'])	  $urlparts['query']	= '?'.$urlparts['query'];
		if($urlparts['port'])	  $urlparts['port'] 	= ':'.$urlparts['port'];
		if($urlparts['user']) {
			if($urlparts['pass']) $urlparts['user'] .= ':'.$urlparts['pass'];
			$urlparts['user'] .= '@';
		}
		return $urlparts['scheme'].'://'.$urlparts['user'].$urlparts['host'].$urlparts['port'].$urlparts['path'].$urlparts['query'].$urlparts['fragment'];
	}

	public static function toQueryString($array) {
		return http_build_query($array);
	}

	public static function toQueryArray($string, $urldecode = true) {
		$pairs = explode('&', $string);
		$array = array();
		foreach($pairs as $pair) if(trim($pair)) {
			$keyvalue = explode('=', $pair, 2);
			$key   = trim($keyvalue[0]);
			$value = (isset($keyvalue[1])) ? ($urldecode) ? urldecode($keyvalue[1]): $keyvalue[1]: '';
			if($key) $array[$key] = $value;
		}
		return $array;
	}

	function toCookieString($array) {
		$string = '';
		foreach($array as $key => $value)
			$string .= $key.'='.$value.'; ';
		return $string;
	}

	# http://www.php.net/manual/en/function.http-parse-headers.php#77241
	public static function toHeaderArray($string) {
		$retVal = array();
		$fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $string));
		foreach( $fields as $field ) {
			if( preg_match('/([^:]+): (.+)/m', $field, $match) ) {
				$match[1] = strtolower(preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("\0")', trim($match[1])));
				if( isset($retVal[$match[1]]) ) {
					$retVal[$match[1]] = array($retVal[$match[1]], $match[2]);
				} else {
					$retVal[$match[1]] = trim($match[2]);
				}
			}
		}
		return $retVal;
	}

	public static function toCurlHeaders(&$headers) {
		if(is_string($headers)) {
			return explode("\r\n", $headers);
		} else if(is_array($headers)) {
			if(isset($headers[0])) {
				return $headers;
			} else {
				$array = array();
				foreach($headers as $key => $value)
					if($value !== null) $array[] = "$key: $value";
				return $array;
			}
		}
	}

	public function array_flatten_bfs($array) {
		$flat_array = (is_string($array)) ? array($array): array();
		while(is_array($array) and null !== ($item = array_shift($array))) {
			if(is_array($item)) foreach($item as $i) $array[] = $i;
			else $flat_array[] = $item;
		}
		return $flat_array;
	}

	public static function close_connection($message = '', $headers = array()) {
		ob_end_clean();
		if(function_exists('ini_set'))
			ini_set('zlib.output_compression', 'Off');
		if(!isset($headers['content-type']))
			$headers['content-type'] = 'text/plain';
		if(isset($headers['location'])) {
			if(!isset($headers['status'])) $headers['status'] = 303;
			header('Location: '.$headers['location'], true, $headers['status']);
			unset($headers['location']);
			$message = '';
		}
		header('Connection: close');
		foreach($headers as $name => $value)
			header($name.': '.$value);

		ignore_user_abort(true);
		ob_start();
		echo $message;
		$size = ob_get_length();
		header('Content-Length: '.$size);
		ob_end_flush();
		ob_flush();
		flush();
		ob_end_clean();
		session_write_close();
		sleep(2);
	}

	# plugin system

	public static function runHook($name, &$hooks, $arguments) {

		if(isset($hooks[$name])) $functions =& $hooks[$name]; else $functions = array();

		foreach(range(0, 9) as $priority) {
			# Run global hooks
			if(isset(self::$hooks[$name][$priority])) foreach(self::$hooks[$name][$priority] as $function) {
				$output = call_user_func_array($function, $arguments);
				if($output !== null) return $output;
			}
			# Run hooks included in requestData
			if(isset($functions[$priority])) foreach($functions[$priority] as $function) {
				$output = call_user_func_array($function, $arguments);
				if($output !== null) return $output;
			}
		}
		return null;
	}

	public static function addHook($hook, $function, $priority = 5) {
		self::$hooks[$hook][$priority][] = $function;
		return true;
	}

	public static function addHookToRequest(&$request, $hook, $function, $priority = 5) {
		$request['hooks'][$hook][$priority][] = $function;
		return true;
	}

	public static function abort() {
		return false;
	}

	# Plugin class name: xhttp_NAME (dots are converted to underscores)
	# Plugin class file: plugin.xhttp.NAME.php (underscores are converted to dots)
	public static function load($plugins) {
		$plugins = explode(',', $plugins);
		foreach($plugins as $name) if(false === array_search($name, self::$plugins)) {
			$class	 = str_replace('.', '_', "xhttp_{$name}");
			$filename= str_replace('_', '.', "plugin.xhttp.{$name}.php");

			# Load class file if not loaded
			if(!class_exists($class, false)) require_once $filename;

			# Load plugin
			if(is_callable(array($class, 'load'))) {
				if(call_user_func(array($class, 'load'))) {
					self::$plugins[] = $name;
				}
			}
		}
	}
}

?>

Open in new window

0
7 Extremely Useful Linux Commands for Beginners

Just getting started with Linux? Here's a quick start guide that has 7 commands that we believe will come in handy.

 

Author Comment

by:rgb192
ID: 38795771
>> x66_x72_x65_x65
do I need my own sms server box

what does 'flagged' mean
0
 
LVL 15

Expert Comment

by:Giovanni Heward
ID: 38804010
This means your account is flagged as running an automated script, which results in a captcha phrase requirement to prove your human for each SMS text sent in the future and/or disabling your account from sending SMS altogether for a period of time (which is what happened to me.)

I would purchase  my own SMS server, the single card version isn't too expensive and should be sufficient for most needs.  Just insert an unlimited text messaging SIM card and your up and running.
0
 
LVL 15

Expert Comment

by:Giovanni Heward
ID: 38806199
I wrote a couple functions to interface with the MultiTech SF100-G and the HTTP API (See Page 76) to basically enabling functionality similar to Google Voice.  Specifically, all inbound SMS messages are converted and uploaded to a dedicated Google Apps mailbox (i.e. sms@domain.com) and then forwarded to a sales pipeline inbox (i.e. sales@domain.com).  Replies from the sales inbox are sent to sms@domain.com which are then retrieved and converted to SMS and sent to the intended recipient.  So essentially the sales inbox replies to both email and SMS inquiries through a single interface.
0
 

Author Comment

by:rgb192
ID: 38813206
can I do this code without the purchase of the MultiTech SF100-G

for example can I do this on shared php hosting or dedicated lamp hosting
0
 
LVL 15

Accepted Solution

by:
Giovanni Heward earned 2000 total points
ID: 38840424
No, if you don't want to use your own SMS server than you'll need to use a service which provides access to one (preferably one that provides PHP sample code.)
0
 

Author Closing Comment

by:rgb192
ID: 38849155
thanks for sms information
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

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

Nothing in an HTTP request can be trusted, including HTTP headers and form data.  A form token is a tool that can be used to guard against request forgeries (CSRF).  This article shows an improved approach to form tokens, making it more difficult to…
This article discusses how to implement server side field validation and display customized error messages to the client.
Along with being a a promotional video for my three-day Annielytics Dashboard Seminor, this Micro Tutorial is an intro to Google Analytics API data.
This Micro Tutorial will introduce a Google tool, which is a great way to learn more about dimensions in metrics in Google Analytics, even if you use the interface or the API.
Suggested Courses

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

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

Join & Ask a Question