Solved

google voice sms text using php

Posted on 2013-01-18
9
550 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
9 Comments
 
LVL 36

Expert Comment

by:Loganathan Natarajan
Comment Utility
0
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
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 14

Expert Comment

by:Giovanni Heward
Comment Utility
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
 

Author Comment

by:rgb192
Comment Utility
>> x66_x72_x65_x65
do I need my own sms server box

what does 'flagged' mean
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 14

Expert Comment

by:Giovanni Heward
Comment Utility
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 14

Expert Comment

by:Giovanni Heward
Comment Utility
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
Comment Utility
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 14

Accepted Solution

by:
Giovanni Heward earned 500 total points
Comment Utility
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
Comment Utility
thanks for sms information
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

With voice direction tools, various map viewing styles, the ability to get directions for different means of transportation and great service, Google Maps is simply one of the best navigations app in the market.    However, over the past year, an …
Whether you’re looking to gather data for research or gather feedback on an idea, being able to build and distribute your own online survey is not only cost-effective, but allows you to reach a larger audience and receive results in real-time. Googl…
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.
This Micro Tutorial will demonstrate how marketers can use the Mobile Emulation Tool in Chrome Developer Tool. This will let you preview your site on any mobile device.

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

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

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now