├── LICENSE ├── example.php ├── README.md └── GoogleVoice.php /LICENSE: -------------------------------------------------------------------------------- 1 | http://creativecommons.org/licenses/BSD/ 2 | 3 | Copyright (c) 2009, Aaron Parecki 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of Aaron Parecki nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY AARON PARECKI ''AS IS'' AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL AARON PARECKI BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | -------------------------------------------------------------------------------- /example.php: -------------------------------------------------------------------------------- 1 | callNumber('9995551212', '5558675309', 'mobile'); 10 | 11 | // Cancel in-progress call placed using callNumber. 12 | $gv->cancelCall('9995551212', '5558675309', 'mobile'); 13 | 14 | // Send an SMS to a phone number. 15 | $gv->sendSMS('9995551212', 'Sending a message!'); 16 | 17 | // Get all unread SMSs from your Google Voice Inbox. 18 | $sms = $gv->getUnreadSMS(); 19 | $msgIDs = array(); 20 | foreach($sms as $s) { 21 | echo 'Message from: '.$s->phoneNumber.' on '.$s->displayStartDateTime.': '.$s->messageText."

\n"; 22 | if(!in_array($s->id, $msgIDs)) { 23 | // Mark the message as read in your Google Voice Inbox. 24 | $gv->markMessageRead($s->id); 25 | $msgIDs[] = $s->id; 26 | } 27 | } 28 | 29 | // Get all unread messages from your Google Voice Voicemail. 30 | $voice_mails = $gv->getUnreadVoicemail(); 31 | $msgIDs = array(); 32 | foreach($voice_mails as $v) { 33 | echo 'Message from: '.$v->phoneNumber.' on '.$v->displayStartDateTime.': '.$v->messageText."

\n"; 34 | if(!in_array($v->id, $msgIDs)) { 35 | // Mark the message as read in your Google Voice Voicemail. 36 | $gv->markMessageRead($v->id); 37 | $msgIDs[] = $v->id; 38 | } 39 | } 40 | 41 | // Download all unread Google Voice voicemails as indididual MP3 files. 42 | $voice_mails = $gv->getUnreadVoicemail(); 43 | $msgIDs = array(); 44 | foreach($voice_mails as $v) { 45 | // Uncomment next line if you want message texts displayed as in previous example. 46 | // echo 'Message from: '.$v->phoneNumber.' on '.$v->displayStartDateTime.': '.$v->messageText."

\n"; 47 | // Download individual voicemail. 48 | $mp3 = $gv->getVoicemailMP3($v->id); 49 | // construct mp3 filename using message id as filename. 50 | $mp3file = $v->id.".mp3"; 51 | // write mp3 file to disk. 52 | $fh = fopen($mp3file, 'w') or die("can't open file"); 53 | fwrite($fh, $mp3); 54 | fclose($fh); 55 | if(!in_array($v->id, $msgIDs)) { 56 | // Mark the message as read in your Google Voice Voicemail. 57 | $gv->markMessageRead($v->id); 58 | $msgIDs[] = $v->id; 59 | } 60 | } 61 | 62 | ?> 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) 2 | 3 | Google Voice PHP API 4 | ==================== 5 | 6 | An API to interact with Google Voice using PHP. 7 | 8 | Currently the API can place calls, cancel previously placed calls, send and 9 | receive SMS messages, add a note to or remove a note from a message or voicemail, 10 | mark a message or voicemail as read or unread, and download transcriptions and/or 11 | MP3 files of voicemail. Feel free to implement new functionality and send me your 12 | changes so I can incorporate them into this library! 13 | 14 | getUnreadSMS, getReadSMS, getUnreadVoicemail, and getReadVoicemail all return 15 | an array of JSON objects. Each object has the following attributes, example 16 | values included: 17 | 18 | $msg->id = c3716aa447a19c7e2e7347f443dd29091401ae13 19 | $msg->phoneNumber = +15555555555 20 | $msg->displayNumber = (555) 555-5555 21 | $msg->startTime = 1359918736555 22 | $msg->displayStartDateTime = 2/3/13 5:55 PM 23 | $msg->displayStartTime = 5:55 PM 24 | $msg->relativeStartTime = 5 hours ago 25 | $msg->note = 26 | $msg->isRead = true 27 | $msg->isSpam = false 28 | $msg->isTrash = false 29 | $msg->star: = alse 30 | $msg->messageText = Hello, cellphone. 31 | $msg->labels = [sms,all] 32 | $msg->type = 11 33 | $msg->children = 34 | 35 | Note: Receiving SMSs and voicemails is mostly unnecessary via this API since 36 | Google now allows SMSs to be forwarded to an email address. It is a better 37 | idea to parse those incoming emails with a script. 38 | 39 | SMS and Voice Integration 40 | ========================= 41 | 42 | For better SMS and voice integration with your web app, check out Tropo 43 | at [tropo.com](http://tropo.com). Tropo is free for development, and you will 44 | get better results than using unsupported Google Voice API calls. 45 | 46 | Check out some [sample apps built with Tropo](https://www.tropo.com/docs/scripting/tutorials.htm) 47 | 48 | Disclaimer 49 | ========== 50 | 51 | This code is provided for educational purposes only. This code may stop 52 | working at any time if Google changes their login mechanism or their web 53 | pages. You agree that by downloading this code you agree to use it solely 54 | at your own risk. 55 | 56 | License 57 | ======= 58 | 59 | Copyright 2009 by Aaron Parecki 60 | [http://aaronparecki.com](http://aaronparecki.com) 61 | 62 | See LICENSE 63 | 64 | -------------------------------------------------------------------------------- /GoogleVoice.php: -------------------------------------------------------------------------------- 1 | _login = $login; 24 | $this->_pass = $pass; 25 | $this->_cookieFile = '/tmp/gvCookies.txt'; 26 | 27 | $this->_ch = curl_init(); 28 | curl_setopt($this->_ch, CURLOPT_COOKIEJAR, $this->_cookieFile); 29 | curl_setopt($this->_ch, CURLOPT_FOLLOWLOCATION, TRUE); 30 | curl_setopt($this->_ch, CURLOPT_RETURNTRANSFER, TRUE); 31 | curl_setopt($this->_ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"); //was "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko" 32 | } 33 | 34 | 35 | 36 | private function _logIn() { 37 | global $conf; 38 | 39 | if($this->_loggedIn) 40 | return TRUE; 41 | 42 | // Fetch the Google Voice login page input fields 43 | $URL='https://accounts.google.com/ServiceLogin?service=grandcentral&passive=1209600&continue=https://www.google.com/voice/b/0/redirection/voice&followup=https://www.google.com/voice/b/0/redirection/voice#inbox'; //adding login to GET prefills with username "&Email=$this->_login" 44 | curl_setopt($this->_ch, CURLOPT_URL, $URL); 45 | $html = curl_exec($this->_ch); 46 | 47 | // Send HTTP POST service login request using captured input information. 48 | $URL='https://accounts.google.com/signin/challenge/sl/password'; // This is the second page of the two page signin 49 | curl_setopt($this->_ch, CURLOPT_URL, $URL); 50 | $postarray = $this->dom_get_input_tags($html); // Using DOM keeps the order of the name/value from breaking the code. 51 | 52 | // Parse the returned webpage for the "GALX" token, needed for POST requests. 53 | if((!isset($postarray['GALX']) || $postarray['GALX']=='') && (!isset($postarray['gxf']) || $postarray['gxf']=='')){ 54 | $pi1 = var_export($postarray, TRUE); 55 | error_log("Could not parse for GALX or gxf token. Inputs from page:\n" . $pi1 . "\n\nHTML from page:" . $html); 56 | throw new Exception("Could not parse for GALX or gxf token. Inputs from page:\n" . $pi1); 57 | } 58 | 59 | $postarray['Email'] = $this->_login; //Add login to POST array 60 | $postarray['Passwd'] = $this->_pass; //Add password to POST array 61 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 62 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, $postarray); 63 | $html = curl_exec($this->_ch); 64 | 65 | // Test if the service login was successful. 66 | $postarray = $this->dom_get_input_tags($html); // Using DOM keeps the order of the name/value from breaking the code. 67 | if(isset($postarray['_rnr_se']) && $postarray['_rnr_se']!='') { 68 | $this->_rnr_se = $postarray['_rnr_se']; 69 | $this->_loggedIn = TRUE; 70 | } else { 71 | $pi2 = var_export($postarray, TRUE); 72 | error_log("Could not log in to Google Voice with username: " . $this->_login . 73 | "\n\nMay need to change scraping. Here are the inputs from the page:\n". $pi2 74 | ); //add POST action information from DOM. May help hunt down single or dual sign on page changes. 75 | throw new Exception("Could not log in to Google Voice with username: " . $this->_login . "\nLook at error log for detailed input information.\n"); 76 | } 77 | } 78 | 79 | 80 | 81 | /** 82 | * Place a call to $number connecting first to $fromNumber. 83 | * @param $number The 10-digit phone number to call (formatted with parens and hyphens or none). 84 | * @param $fromNumber The 10-digit number on your account to connect the call (no hyphens or spaces). 85 | * @param $phoneType (mobile, work, home) The type of phone the $fromNumber is. The call will not be connected without this value. 86 | */ 87 | public function callNumber($number, $from_number, $phone_type = 'mobile') { 88 | $types = array( 89 | 'mobile' => 2, 90 | 'work' => 3, 91 | 'home' => 1 92 | ); 93 | 94 | // Make sure phone type is set properly. 95 | if(!array_key_exists($phone_type, $types)) 96 | throw new Exception('Phone type must be mobile, work, or home'); 97 | 98 | // Login to the service if not already done. 99 | $this->_logIn(); 100 | 101 | // Send HTTP POST request. 102 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/call/connect/'); 103 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 104 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 105 | '_rnr_se' => $this->_rnr_se, 106 | 'forwardingNumber' => '+1'.$from_number, 107 | 'outgoingNumber' => $number, 108 | 'phoneType' => $types[$phone_type], 109 | 'remember' => 0, 110 | 'subscriberNumber' => 'undefined' 111 | )); 112 | curl_exec($this->_ch); 113 | } 114 | 115 | 116 | 117 | /** 118 | * Cancel a call to $number connecting first to $fromNumber. 119 | * @param $number The 10-digit phone number to call (formatted with parens and hyphens or none). 120 | * @param $fromNumber The 10-digit number on your account to connect the call (no hyphens or spaces). 121 | * @param $phoneType (mobile, work, home) The type of phone the $fromNumber is. The call will not be connected without this value. 122 | */ 123 | public function cancelCall($number, $from_number, $phone_type = 'mobile') { 124 | $types = array( 125 | 'mobile' => 2, 126 | 'work' => 3, 127 | 'home' => 1 128 | ); 129 | 130 | // Make sure phone type is set properly. 131 | if(!array_key_exists($phone_type, $types)) 132 | throw new Exception('Phone type must be mobile, work, or home'); 133 | 134 | // Login to the service if not already done. 135 | $this->_logIn(); 136 | 137 | // Send HTTP POST request. 138 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/call/cancel/'); 139 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 140 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 141 | '_rnr_se' => $this->_rnr_se, 142 | 'forwardingNumber' => '+1'.$from_number, 143 | 'outgoingNumber' => $number, 144 | 'phoneType' => $types[$phone_type], 145 | 'remember' => 0, 146 | 'subscriberNumber' => 'undefined' 147 | )); 148 | curl_exec($this->_ch); 149 | } 150 | 151 | 152 | 153 | /** 154 | * Send an SMS to $number containing $message. 155 | * @param $number The 10-digit phone number to send the message to (formatted with parens and hyphens or none). 156 | * @param $message The message to send within the SMS. 157 | */ 158 | public function sendSMS($number, $message) { 159 | // Login to the service if not already done. 160 | $this->_logIn(); 161 | 162 | // Send HTTP POST request. 163 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/sms/send/'); 164 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 165 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 166 | '_rnr_se' => $this->_rnr_se, 167 | 'phoneNumber' => '+1'.$number, 168 | 'text' => $message 169 | )); 170 | curl_exec($this->_ch); 171 | } 172 | 173 | 174 | 175 | public function getNewSMS() 176 | { 177 | $this->_logIn(); 178 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/recent/sms/'); 179 | curl_setopt($this->_ch, CURLOPT_POST, FALSE); 180 | curl_setopt($this->_ch, CURLOPT_RETURNTRANSFER, TRUE); 181 | $xml = curl_exec($this->_ch); 182 | 183 | $dom = new DOMDocument(); 184 | 185 | // load the "wrapper" xml (contains two elements, json and html) 186 | $dom->loadXML($xml); 187 | $json = $dom->documentElement->getElementsByTagName("json")->item(0)->nodeValue; 188 | $json = json_decode($json); 189 | 190 | // now make a dom parser which can parse the contents of the HTML tag 191 | $html = $dom->documentElement->getElementsByTagName("html")->item(0)->nodeValue; 192 | // replace all "&" with "&" so it can be parsed 193 | $html = str_replace("&", "&", $html); 194 | $dom->loadHTML($html); 195 | $xpath = new DOMXPath($dom); 196 | 197 | $results = array(); 198 | 199 | foreach( $json->messages as $mid=>$convo ) 200 | { 201 | $elements = $xpath->query("//div[@id='$mid']//div[@class='gc-message-sms-row']"); 202 | if(!is_null($elements)) 203 | { 204 | if( in_array('unread', $convo->labels) ) 205 | { 206 | foreach($elements as $i=>$element) 207 | { 208 | $XMsgFrom = $xpath->query("span[@class='gc-message-sms-from']", $element); 209 | $msgFrom = ''; 210 | foreach($XMsgFrom as $m) 211 | $msgFrom = trim($m->nodeValue); 212 | 213 | if( $msgFrom != "Me:" ) 214 | { 215 | $XMsgText = $xpath->query("span[@class='gc-message-sms-text']", $element); 216 | $msgText = ''; 217 | foreach($XMsgText as $m) 218 | $msgText = trim($m->nodeValue); 219 | 220 | $XMsgTime = $xpath->query("span[@class='gc-message-sms-time']", $element); 221 | $msgTime = ''; 222 | foreach($XMsgTime as $m) 223 | $msgTime = trim($m->nodeValue); 224 | 225 | $results[] = array('msgID'=>$mid, 'phoneNumber'=>$convo->phoneNumber, 'message'=>$msgText, 'date'=>date('Y-m-d H:i:s', strtotime(date('m/d/Y ',intval($convo->startTime/1000)).$msgTime))); 226 | } 227 | } 228 | } 229 | else 230 | { 231 | //echo "This message is not unread\n"; 232 | } 233 | } 234 | else 235 | { 236 | //echo "gc-message-sms-row query failed\n"; 237 | } 238 | } 239 | 240 | return $results; 241 | } 242 | 243 | 244 | 245 | public function markSMSRead($msgID) 246 | { 247 | $this->_logIn(); 248 | 249 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/mark/'); 250 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 251 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 252 | '_rnr_se'=>$this->_rnr_se, 253 | 'messages'=>$msgID, 254 | 'read'=>1 255 | )); 256 | curl_exec($this->_ch); 257 | } 258 | 259 | 260 | 261 | public function markSMSDeleted($msgID) 262 | { 263 | $this->_logIn(); 264 | 265 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/deleteMessages/'); 266 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 267 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 268 | '_rnr_se'=>$this->_rnr_se, 269 | 'messages'=>$msgID, 270 | 'trash'=>1 271 | )); 272 | curl_exec($this->_ch); 273 | } 274 | 275 | 276 | 277 | /** 278 | * Add a note to a message in a Google Voice Inbox or Voicemail. 279 | * @param $message_id The id of the message to update. 280 | * @param $note The message to send within the SMS. 281 | */ 282 | public function addNote($message_id, $note) { 283 | // Login to the service if not already done. 284 | $this->_logIn(); 285 | 286 | // Send HTTP POST request. 287 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/savenote/'); 288 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 289 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 290 | '_rnr_se' => $this->_rnr_se, 291 | 'id' => $message_id, 292 | 'note' => $note 293 | )); 294 | curl_exec($this->_ch); 295 | } 296 | 297 | 298 | 299 | /** 300 | * Removes a note from a message in a Google Voice Inbox or Voicemail. 301 | * @param $message_id The id of the message to update. 302 | */ 303 | public function removeNote($message_id, $note) { 304 | // Login to the service if not already done. 305 | $this->_logIn(); 306 | 307 | // Send HTTP POST request. 308 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/deletenote/'); 309 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 310 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 311 | '_rnr_se' => $this->_rnr_se, 312 | 'id' => $message_id, 313 | )); 314 | curl_exec($this->_ch); 315 | } 316 | 317 | 318 | 319 | /** 320 | * Get all of the unread SMS messages in a Google Voice inbox. 321 | */ 322 | public function getUnreadSMS() { 323 | // Login to the service if not already done. 324 | $this->_logIn(); 325 | 326 | // Send HTTP POST request. 327 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/recent/sms/'); 328 | curl_setopt($this->_ch, CURLOPT_POST, FALSE); 329 | curl_setopt($this->_ch, CURLOPT_RETURNTRANSFER, TRUE); 330 | $xml = curl_exec($this->_ch); 331 | 332 | // Load the "wrapper" xml (contains two elements, json and html). 333 | $dom = new DOMDocument(); 334 | $dom->loadXML($xml); 335 | $json = $dom->documentElement->getElementsByTagName("json")->item(0)->nodeValue; 336 | $json = json_decode($json); 337 | 338 | // Loop through all of the messages. 339 | $results = array(); 340 | foreach($json->messages as $mid=>$convo) { 341 | if($convo->isRead == FALSE) { 342 | $results[] = $convo; 343 | } 344 | } 345 | return $results; 346 | } 347 | 348 | 349 | 350 | /** 351 | * Get all of the read SMS messages in a Google Voice inbox. 352 | */ 353 | public function getReadSMS() { 354 | // Login to the service if not already done. 355 | $this->_logIn(); 356 | 357 | // Send HTTP POST request. 358 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/recent/sms/'); 359 | curl_setopt($this->_ch, CURLOPT_POST, FALSE); 360 | curl_setopt($this->_ch, CURLOPT_RETURNTRANSFER, TRUE); 361 | $xml = curl_exec($this->_ch); 362 | 363 | // Load the "wrapper" xml (contains two elements, json and html). 364 | $dom = new DOMDocument(); 365 | $dom->loadXML($xml); 366 | $json = $dom->documentElement->getElementsByTagName("json")->item(0)->nodeValue; 367 | $json = json_decode($json); 368 | 369 | // Loop through all of the messages. 370 | $results = array(); 371 | foreach($json->messages as $mid=>$convo) { 372 | if($convo->isRead == TRUE) { 373 | $results[] = $convo; 374 | } 375 | } 376 | return $results; 377 | } 378 | 379 | 380 | 381 | /** 382 | * Get all of the unread SMS messages from a Google Voice Voicemail. 383 | */ 384 | public function getUnreadVoicemail() { 385 | // Login to the service if not already done. 386 | $this->_logIn(); 387 | 388 | // Send HTTP POST request. 389 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/recent/voicemail/'); 390 | curl_setopt($this->_ch, CURLOPT_POST, FALSE); 391 | curl_setopt($this->_ch, CURLOPT_RETURNTRANSFER, TRUE); 392 | $xml = curl_exec($this->_ch); 393 | 394 | // Load the "wrapper" xml (contains two elements, json and html) 395 | $dom = new DOMDocument(); 396 | $dom->loadXML($xml); 397 | $json = $dom->documentElement->getElementsByTagName("json")->item(0)->nodeValue; 398 | $json = json_decode($json); 399 | 400 | // Loop through all of the messages. 401 | $results = array(); 402 | foreach($json->messages as $mid=>$convo) { 403 | if($convo->isRead == FALSE) { 404 | $results[] = $convo; 405 | } 406 | } 407 | return $results; 408 | } 409 | 410 | 411 | 412 | /** 413 | * Get all of the unread SMS messages from a Google Voice Voicemail. 414 | */ 415 | public function getReadVoicemail() { 416 | // Login to the service if not already done. 417 | $this->_logIn(); 418 | 419 | // Send HTTP POST request. 420 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/recent/voicemail/'); 421 | curl_setopt($this->_ch, CURLOPT_POST, FALSE); 422 | curl_setopt($this->_ch, CURLOPT_RETURNTRANSFER, TRUE); 423 | $xml = curl_exec($this->_ch); 424 | 425 | // load the "wrapper" xml (contains two elements, json and html) 426 | $dom = new DOMDocument(); 427 | $dom->loadXML($xml); 428 | $json = $dom->documentElement->getElementsByTagName("json")->item(0)->nodeValue; 429 | $json = json_decode($json); 430 | 431 | // Loop through all of the messages. 432 | $results = array(); 433 | foreach( $json->messages as $mid=>$convo ) { 434 | if( $convo->isRead == TRUE ) { 435 | $results[] = $convo; 436 | } 437 | } 438 | return $results; 439 | } 440 | 441 | 442 | 443 | /** 444 | * Get MP3 of a Google Voice Voicemail. 445 | */ 446 | public function getVoicemailMP3($message_id) { 447 | // Login to the service if not already done. 448 | $this->_logIn(); 449 | 450 | // Send HTTP POST request. 451 | curl_setopt($this->_ch, CURLOPT_URL, "https://www.google.com/voice/media/send_voicemail/$message_id/"); 452 | curl_setopt($this->_ch, CURLOPT_POST, FALSE); 453 | curl_setopt($this->_ch, CURLOPT_RETURNTRANSFER, TRUE); 454 | $results = curl_exec($this->_ch); 455 | 456 | return $results; 457 | } 458 | 459 | 460 | 461 | /** 462 | * Mark a message in a Google Voice Inbox or Voicemail as read. 463 | * @param $message_id The id of the message to update. 464 | * @param $note The message to send within the SMS. 465 | */ 466 | public function markMessageRead($message_id) { 467 | // Login to the service if not already done. 468 | $this->_logIn(); 469 | 470 | // Send HTTP POST request. 471 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/mark/'); 472 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 473 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 474 | '_rnr_se' => $this->_rnr_se, 475 | 'messages' => $message_id, 476 | 'read' => '1' 477 | )); 478 | curl_exec($this->_ch); 479 | } 480 | 481 | 482 | 483 | /** 484 | * Mark a message in a Google Voice Inbox or Voicemail as unread. 485 | * @param $message_id The id of the message to update. 486 | * @param $note The message to send within the SMS. 487 | */ 488 | public function markMessageUnread($message_id) { 489 | // Login to the service if not already done. 490 | $this->_logIn(); 491 | 492 | // Send HTTP POST request. 493 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/mark/'); 494 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 495 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 496 | '_rnr_se' => $this->_rnr_se, 497 | 'messages' => $message_id, 498 | 'read' => '0' 499 | )); 500 | curl_exec($this->_ch); 501 | } 502 | 503 | 504 | 505 | /** 506 | * Delete a message or conversation. 507 | * @param $message_id The ID of the conversation to delete. 508 | */ 509 | public function deleteMessage($message_id) { 510 | $this->_logIn(); 511 | 512 | curl_setopt($this->_ch, CURLOPT_URL, 'https://www.google.com/voice/inbox/deleteMessages/'); 513 | curl_setopt($this->_ch, CURLOPT_POST, TRUE); 514 | curl_setopt($this->_ch, CURLOPT_POSTFIELDS, array( 515 | '_rnr_se' => $this->_rnr_se, 516 | 'messages' => $message_id, 517 | 'trash' => 1 518 | )); 519 | 520 | curl_exec($this->_ch); 521 | } 522 | 523 | 524 | 525 | public function dom_dump($obj) { 526 | if ($classname = get_class($obj)) { 527 | $retval = "Instance of $classname, node list: \n"; 528 | switch (TRUE) { 529 | case ($obj instanceof DOMDocument): 530 | $retval .= "XPath: {$obj->getNodePath()}\n".$obj->saveXML($obj); 531 | break; 532 | case ($obj instanceof DOMElement): 533 | $retval .= "XPath: {$obj->getNodePath()}\n".$obj->ownerDocument->saveXML($obj); 534 | break; 535 | case ($obj instanceof DOMAttr): 536 | $retval .= "XPath: {$obj->getNodePath()}\n".$obj->ownerDocument->saveXML($obj); 537 | break; 538 | case ($obj instanceof DOMNodeList): 539 | for ($i = 0; $i < $obj->length; $i++) { 540 | $retval .= "Item #$i, XPath: {$obj->item($i)->getNodePath()}\n"."{$obj->item($i)->ownerDocument->saveXML($obj->item($i))}\n"; 541 | } 542 | break; 543 | default: 544 | return "Instance of unknown class"; 545 | } 546 | } 547 | else { 548 | return 'no elements...'; 549 | } 550 | return htmlspecialchars($retval); 551 | } 552 | 553 | /** 554 | * Source from http://www.binarytides.com/php-get-name-and-value-of-all-input-tags-on-a-page-with-domdocument/ 555 | * Generic function to fetch all input tags (name and value) on a page 556 | * Useful when writing automatic login bots/scrapers 557 | */ 558 | private function dom_get_input_tags($html) 559 | { 560 | $post_data = array(); 561 | 562 | // a new dom object 563 | $dom = new DomDocument; 564 | 565 | //load the html into the object 566 | @$dom->loadHTML($html); //@suppresses warnings 567 | //discard white space 568 | $dom->preserveWhiteSpace = FALSE; 569 | 570 | //all input tags as a list 571 | $input_tags = $dom->getElementsByTagName('input'); 572 | 573 | //get all rows from the table 574 | for ($i = 0; $i < $input_tags->length; $i++) 575 | { 576 | if( is_object($input_tags->item($i)) ) 577 | { 578 | $name = $value = ''; 579 | $name_o = $input_tags->item($i)->attributes->getNamedItem('name'); 580 | if(is_object($name_o)) 581 | { 582 | $name = $name_o->value; 583 | 584 | $value_o = $input_tags->item($i)->attributes->getNamedItem('value'); 585 | if(is_object($value_o)) 586 | { 587 | $value = $input_tags->item($i)->attributes->getNamedItem('value')->value; 588 | } 589 | 590 | $post_data[$name] = $value; 591 | } 592 | } 593 | } 594 | 595 | return $post_data; 596 | } 597 | 598 | } 599 | 600 | ?> 601 | --------------------------------------------------------------------------------