├── .gitignore ├── INSTALL ├── COPYING ├── README.sosumi ├── playnice.php ├── class.google.php └── class.sosumi.php /.gitignore: -------------------------------------------------------------------------------- 1 | google-cookie.txt 2 | mobile-me-password.txt 3 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | All users: make sure the Latitude widget is installed on your iGoogle 2 | page. Make sure you have PHP5. 3 | 4 | Debian/Ubuntu: make sure you have the ca-certificates package and the 5 | php5 package installed. 6 | 7 | Windows: This script doesn't work on windows. 8 | 9 | Mac: this script should work out of the box. 10 | 11 | 12 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2009 Nat Friedman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.sosumi: -------------------------------------------------------------------------------- 1 | Sosumi 2 | ========= 3 | 4 | A MobileMe web scraper that exposes Apple's Find My iPhone service to the command line. This allows you to programmatically retrieve your phone's current location and push messages (and an optional alarm) to the remote device. 5 | 6 | Much love to the MobileMe team for a wonderful service :-) 7 | 8 | FEATURES 9 | -------- 10 | 11 | * Retrieve your device's current location and margin of error. 12 | * Push a custom text message to the device and an optional audible alarm. 13 | 14 | INSTALL 15 | ------- 16 | 17 | This script requires PHP 5.2 and the JSON extension, which should be included by default. PHP's CURL extension (with SSL support) is also required. 18 | 19 | UPDATES 20 | ------- 21 | 22 | Code is hosted at GitHub: [http://github.com/tylerhall/sosumi](http://github.com/tylerhall/sosumi) 23 | 24 | LICENSE 25 | ------- 26 | 27 | The MIT License 28 | 29 | Copyright (c) 2009 Tyler Hall 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy 32 | of this software and associated documentation files (the "Software"), to deal 33 | in the Software without restriction, including without limitation the rights 34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35 | copies of the Software, and to permit persons to whom the Software is 36 | furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be included in 39 | all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47 | THE SOFTWARE. 48 | -------------------------------------------------------------------------------- /playnice.php: -------------------------------------------------------------------------------- 1 | . 9 | // 10 | // Nat Friedman 11 | // 12 | // August 22nd, 2009 13 | // 14 | // MIT license. 15 | // 16 | 17 | include 'class.google.php'; 18 | include 'class.sosumi.php'; 19 | 20 | $mobileMePasswordFile = "./mobile-me-password.txt"; 21 | 22 | $google = new iGoogle(); 23 | 24 | function promptForLogin($serviceName) 25 | { 26 | echo "$serviceName username: "; 27 | $username = trim(fgets(STDIN)); 28 | 29 | if (empty($username)) { 30 | die("Error: No username specified.\n"); 31 | } 32 | 33 | echo "$serviceName password: "; 34 | system ('stty -echo'); 35 | $password = trim(fgets(STDIN)); 36 | system ('stty echo'); 37 | // add a new line since the users CR didn't echo 38 | echo "\n"; 39 | 40 | if (empty ($password)) { 41 | die ("Error: No password specified.\n"); 42 | } 43 | 44 | return array ($username, $password); 45 | } 46 | 47 | if (! file_exists ($mobileMePasswordFile)) { 48 | echo "You will need to type your MobileMe username/password. They will be\n"; 49 | echo "saved in $mobileMePasswordFile so you don't have to type them again.\n"; 50 | echo "If you're not cool with this, you probably want to delete that file\n"; 51 | echo "at some point (they are stored in plaintext).\n\n"; 52 | echo "You do need a working MobileMe account for playnice to work, and you\n"; 53 | echo "need to have enabled the Find My iPhone feature on your phone.\n\n"; 54 | 55 | 56 | list($mobileMeUsername, $mobileMePassword) = promptForLogin("MobileMe"); 57 | 58 | $f = fopen ($mobileMePasswordFile, "w"); 59 | fwrite ($f, "\n"); 60 | fclose ($f); 61 | chmod($mobileMePasswordFile, 0600); 62 | 63 | echo "\n"; 64 | 65 | } else { 66 | @include($mobileMePasswordFile); 67 | } 68 | 69 | if (! $google->haveCookie()) { 70 | echo "No Google cookie found. You will need to authenticate with your\n"; 71 | echo "Google username/password. You should only need to do this once;\n"; 72 | echo "we will save the session cookie for the future.\n\n"; 73 | echo "Please note that you need to have the Latitude widget on your main\n"; 74 | echo "iGoogle page for this to work.\n\n"; 75 | 76 | list($username, $password) = promptForLogin("Google"); 77 | 78 | echo "Acquiring Google session cookie..."; 79 | $google->login($username, $password); 80 | echo "got it.\n"; 81 | } 82 | 83 | // Get the iPhone location from MobileMe 84 | echo "Fetching iPhone location..."; 85 | $mobileMe = new Sosumi ($mobileMeUsername, $mobileMePassword); 86 | if (! $mobileMe->authenticated) { 87 | echo "Unable to authenticate to MobileMe. Is your password correct?\n"; 88 | exit; 89 | } 90 | 91 | if (count ($mobileMe->devices) == 0) { 92 | echo "No iPhones found in your MobileMe account.\n"; 93 | exit; 94 | } 95 | $iphoneLocation = $mobileMe->locate(); 96 | echo "got it.\n"; 97 | 98 | echo "iPhone location: $iphoneLocation->latitude, $iphoneLocation->longitude\n"; 99 | 100 | // Now update Google Latitude 101 | echo "Updating Google Latitude..."; 102 | $google->updateLatitude($iphoneLocation->latitude, $iphoneLocation->longitude, 103 | $iphoneLocation->accuracy); 104 | 105 | // All done. 106 | echo "Done!\n"; 107 | -------------------------------------------------------------------------------- /class.google.php: -------------------------------------------------------------------------------- 1 | 8 | // Jack Catchpoole 9 | // 10 | // MIT license. 11 | // 12 | 13 | class iGoogle 14 | { 15 | private $cookieFile = "./google-cookie.txt"; // Where we store the Google session cookie 16 | private $latitudeToken = null; // The Google latitude security token 17 | 18 | // Where to login ? 19 | private $loginUrl="https://www.google.com/accounts/ServiceLoginAuth"; 20 | 21 | // What page do we scrape the latitude security token from? 22 | private $targetPage="https://www.google.com/ig?gl=us"; 23 | 24 | // What URL do we use to proxy the Latitude update request? 25 | private $latitudeProxyUrl = "http://lfkq9vbe9u4sg98ip8rfvf00l7atcn3d.ig.ig.gmodules.com/gadgets/makeRequest"; 26 | 27 | // What URL do we use to update Latitude? 28 | private $latitudeUpdateUrlPrefix = "http://www.google.com/glm/mmap/ig?t=ul&"; 29 | 30 | public function __construct() 31 | { 32 | } 33 | 34 | public function updateLatitude($lat, $lng, $accuracy) 35 | { 36 | $this->getLatitudeToken (); 37 | 38 | $ig = curl_init(); 39 | 40 | $post_data = "OAUTH_SERVICE_NAME=google&"; 41 | $post_data .= "authz=oauth&"; 42 | $post_data .= "httpMethod=GET&"; 43 | $post_data .= "st=" . urlencode($this->latitudeToken) . "&"; 44 | $post_data .= "url=" . urlencode($this->latitudeUpdateUrlPrefix . "lat=$lat&lng=$lng&accuracy=$accuracy"); 45 | 46 | curl_setopt($ig, CURLOPT_URL, $this->latitudeProxyUrl); 47 | curl_setopt($ig, CURLOPT_COOKIEFILE, $this->cookieFile); // Where to read cookie info from 48 | curl_setopt($ig, CURLOPT_COOKIEJAR, $this->cookieFile); // Where to save next cookie info 49 | curl_setopt($ig, CURLOPT_RETURNTRANSFER, TRUE); // Don't output results of transfer, instead send as return val 50 | 51 | //curl_setopt($ig, CURLOPT_HEADER, TRUE); // Include headers in output, for debugging 52 | //curl_setopt($ig, CURLOPT_VERBOSE, TRUE); // Verbose output for debugging 53 | 54 | curl_setopt($ig, CURLOPT_POST, TRUE); // We're going to be POSTing 55 | curl_setopt($ig, CURLOPT_POSTFIELDS, $post_data); // Send our login data 56 | 57 | $junk = curl_exec ($ig); 58 | chmod($this->cookieFile, 0600); 59 | } 60 | 61 | public function getLatitudeToken () 62 | { 63 | $ig = curl_init(); 64 | 65 | // Now we're logged in, grab the /ig page 66 | curl_setopt($ig, CURLOPT_URL, $this->targetPage); 67 | curl_setopt($ig, CURLOPT_COOKIEFILE, $this->cookieFile); // Where to read cookie info from 68 | curl_setopt($ig, CURLOPT_COOKIEJAR, $this->cookieFile); // Where to save next cookie info 69 | curl_setopt($ig, CURLOPT_RETURNTRANSFER, TRUE); // Don't output results of transfer, instead send as return val 70 | 71 | // Execute the curl call 72 | $output = curl_exec($ig); 73 | 74 | // Display retreived output 75 | // echo str_pad(" $this->targetPage Content Follows ",72,"-",STR_PAD_BOTH) . "\n\n"; 76 | // echo $output . "\n\n"; 77 | 78 | // If "Sign out" does not appear in output, login must have failed 79 | if (strpos($output,"Sign out")===FALSE) { 80 | die ("It looks like log in to Google failed\n"); 81 | } 82 | 83 | curl_close ($ig); 84 | 85 | // -------------------------------------------------------------------- 86 | // Now analyse the output, and pull out the required Google Latitude data 87 | // 88 | // Latitude must be a gadget on the page; Gadgets and tabs are defined 89 | // in a block of JS starting with "_IG_MD_Generate" which AFAICT is unique on 90 | // the page. 91 | 92 | // First grab the list of tabs and gadgets, bail out if nothing found 93 | if (! preg_match("/_IG_MD_Generate(.+?)<\/script>/",$output,$tabs_and_gadgets)) { 94 | die ("No gadgets identified on iGoogle home page\n"); 95 | } 96 | 97 | // Now all gadgets are in $tabs_and_gadgets[1], examine them. 98 | /* 99 | * For me, the format here looks something like this : 100 | * 101 | * ... some stuff ... 102 | * dt: [0, 1, 2, 3], 103 | * m: [ 104 | * {... gadget 1 stuff ...} 105 | * {... gadget 2 stuff ...} 106 | * {... gadget 3 stuff ... 107 | * view: {...max_u: "..."} 108 | * } 109 | * ...etc... 110 | * ] 111 | * }); 112 | * 113 | */ 114 | 115 | // First strip of the list of tabs, so we have just gadgets 116 | if (! preg_match("/dt:\[.+?\],m:\[(.+)]/",$tabs_and_gadgets[1],$gadgets)) { 117 | die ("\nCouldn't parse out individual gadget variables\n"); 118 | } 119 | 120 | // Now seperate out each gadget block 121 | if (! preg_match_all("/{(.+?)}/",$gadgets[1],$gadget_blocks)) { 122 | die ("\nCouldn't separate gadget variable blocks\n"); 123 | } 124 | 125 | // Now loop through each individual gadget and look for the Latitude gadget, 126 | // identified by ti:"Google Latitude" 127 | foreach ($gadget_blocks[1] as $var) { 128 | 129 | if (strstr ($var,"ti:\"Google Latitude\"")) { 130 | // This is the one we want. Pull out the max_u var 131 | preg_match ("/max_u:\"(.+?)\"/",$var,$url); 132 | $cleaned_url = str_replace("\\x26","&",$url[1]); 133 | parse_str ($cleaned_url,$params); 134 | 135 | // echo "Parameters of the max_u: URL for the Google Latitude gadget are : \n"; 136 | // print_r($params); 137 | 138 | $st = str_replace("core:core.io:core.iglegacy#","",$params["libs"]); 139 | } 140 | } 141 | 142 | if (!empty($st)) { 143 | $this->latitudeToken = str_replace("st=", "", $st); 144 | } else { 145 | die ("\nError: The Google Latitude security token could not be found.\nIs the Latitude widget on your iGoogle page?\n"); 146 | } 147 | 148 | echo "\n"; 149 | } 150 | 151 | // Login to google and save the cookie in $cookieFile 152 | public function login($username, $password) 153 | { 154 | $ig = curl_init(); 155 | $post_data = "continue=http://www.google.com/ig"; 156 | $post_data .= "&followup=http://www.google.com/ig"; 157 | $post_data .= "&service=ig"; 158 | $post_data .= "&Email=$username"; 159 | $post_data .= "&Passwd=$password"; 160 | $post_data .= "&submit=Sign in"; 161 | curl_setopt($ig, CURLOPT_URL, $this->loginUrl); 162 | 163 | //curl_setopt($ig, CURLOPT_VERBOSE, TRUE); // Verbose output for debugging 164 | //curl_setopt($ig, CURLOPT_HEADER, TRUE); // Include headers in output, for debugging 165 | 166 | curl_setopt($ig, CURLOPT_FOLLOWLOCATION, TRUE); // Follow any Location: headers 167 | curl_setopt($ig, CURLOPT_POST, TRUE); // We're going to be POSTing 168 | curl_setopt($ig, CURLOPT_POSTFIELDS, $post_data); // Send our login data 169 | curl_setopt($ig, CURLOPT_COOKIEJAR, $this->cookieFile); // Where to save cookie info for next time 170 | curl_setopt($ig, CURLOPT_RETURNTRANSFER, TRUE); // Don't output results of transfer, instead send as return val 171 | 172 | // Execute the curl call 173 | $junk = curl_exec($ig); 174 | if (strpos ($junk, "Sign in") != FALSE) { 175 | die ("\nGoogle login failed. Did you mistype something?\n"); 176 | } 177 | } 178 | 179 | public function haveCookie() 180 | { 181 | return file_exists($this->cookieFile); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /class.sosumi.php: -------------------------------------------------------------------------------- 1 | 7 | // http://github.com/tylerhall/sosumi/tree/master 8 | // 9 | // Usage: 10 | // $ssm = new Sosumi('username', 'password'); 11 | // $location_info = $ssm->locate(); 12 | // $ssm->sendMessage('Daisy, daisy...'); 13 | // 14 | // TODO: Need to see how many HTTP requests we can remove. The current 15 | // implementation hasn't been minified yet. 16 | 17 | class Sosumi 18 | { 19 | public $authenticated; // True if we logged in successfully 20 | public $devices; // An array of all devices on this MobileMe account 21 | private $lastURL; // The previous URL as visited by curl 22 | private $tmpFile; // Where we store our cookies 23 | private $lsc; // Associative array of Apple auth tokens 24 | private $deviceId; // The device ID to ping 25 | 26 | public function __construct($mobile_me_username, $mobile_me_password) 27 | { 28 | $this->authenticated = false; 29 | $this->tmpFile = tempnam('/tmp', 'sosumi'); 30 | $this->lsc = array(); 31 | $this->devices = array(); 32 | 33 | // Load the HTML login page and also get the init cookies set 34 | $html = $this->curlGet("https://auth.me.com/authenticate?service=account&ssoNamespace=primary-me&reauthorize=Y&returnURL=aHR0cHM6Ly9zZWN1cmUubWUuY29tL2FjY291bnQvI2ZpbmRteWlwaG9uZQ==&anchor=findmyiphone"); 35 | 36 | // Parse out the hidden fields 37 | preg_match_all('!hidden.*?name=["\'](.*?)["\'].*?value=["\'](.*?)["\']!ms', $html, $hidden); 38 | 39 | // Build the form post data 40 | $post = ''; 41 | for($i = 0; $i < count($hidden[1]); $i++) 42 | $post .= $hidden[1][$i] . '=' . urlencode($hidden[2][$i]) . '&'; 43 | $post .= 'username=' . urlencode($mobile_me_username) . '&password=' . urlencode($mobile_me_password); 44 | 45 | // Login 46 | $action_url = $this->match('!action=["\'](.*?)["\']!ms', $html, 1); 47 | $html = $this->curlPost('https://auth.me.com/authenticate', $post, $this->lastURL); 48 | $html = $this->curlGet('https://secure.me.com/account/', $this->lastURL); 49 | 50 | $headers = array('X-Mobileme-Version: 1.0'); 51 | $html = $this->curlGet('https://secure.me.com/wo/WebObjects/Account2.woa?lang=en&anchor=findmyiphone', $this->lastURL, $headers); 52 | 53 | if (count ($this->lsc) > 0) { 54 | $this->authenticated = true; 55 | $this->getDevices(); 56 | } 57 | } 58 | 59 | public function __destruct() 60 | { 61 | if(file_exists($this->tmpFile)) 62 | unlink($this->tmpFile); 63 | } 64 | 65 | // Returns a stdClass object of location information. Example... 66 | // stdClass Object 67 | // ( 68 | // [isLocationAvailable] => 1 69 | // [longitude] => -121.010392 70 | // [accuracy] => 47.421634 71 | // [time] => 9:24 PM 72 | // [isOldLocationResult] => 1 73 | // [isRecent] => 1 74 | // [statusString] => locate status available 75 | // [status] => 1 76 | // [isLocateFinished] => 77 | // [latitude] => 38.319117 78 | // [date] => June 22, 2009 79 | // [isAccurate] => 80 | // ) 81 | public function locate($the_device = null) 82 | { 83 | // Grab the first device is none is specified 84 | if(is_null($the_device)) 85 | { 86 | reset($this->devices); 87 | $the_device = current($this->devices); 88 | } 89 | 90 | $arr = array('deviceId' => $the_device['deviceId'], 'deviceOsVersion' => $the_device['deviceOsVersion']); 91 | 92 | $post = 'postBody=' . json_encode($arr); 93 | 94 | $headers = array('Accept: text/javascript, text/html, application/xml, text/xml, */*', 95 | 'X-Requested-With: XMLHttpRequest', 96 | 'X-Prototype-Version: 1.6.0.3', 97 | 'Content-Type: application/json; charset=UTF-8', 98 | 'X-Mobileme-Version: 1.0', 99 | 'X-Mobileme-Isc: ' . $this->lsc['secure.me.com']); 100 | $html = $this->curlPost('https://secure.me.com/wo/WebObjects/DeviceMgmt.woa/wa/LocateAction/locateStatus', $post, 'https://secure.me.com/account/', $headers); 101 | $json = json_decode(array_pop(explode("\n", $html))); 102 | return $json; 103 | } 104 | 105 | // Send a message to the device with an optional alarm sound 106 | public function sendMessage($msg, $alarm = false, $the_device = null) 107 | { 108 | // Grab the first device is none is specified 109 | if(is_null($the_device)) 110 | { 111 | reset($this->devices); 112 | $the_device = current($this->devices); 113 | } 114 | 115 | $arr = array('deviceId' => $the_device['deviceId'], 116 | 'message' => $msg, 117 | 'playAlarm' => $alarm ? 'Y' : 'N', 118 | 'deviceType' => $the_device['deviceType'], 119 | 'deviceClass' => $the_device['deviceClass'], 120 | 'deviceOsVersion' => $the_device['deviceOsVersion']); 121 | 122 | $post = 'postBody=' . json_encode($arr); 123 | 124 | $headers = array('Accept: text/javascript, text/html, application/xml, text/xml, */*', 125 | 'X-Requested-With: XMLHttpRequest', 126 | 'X-Prototype-Version: 1.6.0.3', 127 | 'Content-Type: application/json; charset=UTF-8', 128 | 'X-Mobileme-Version: 1.0', 129 | 'X-Mobileme-Isc: ' . $this->lsc['secure.me.com']); 130 | 131 | $html = $this->curlPost('https://secure.me.com/wo/WebObjects/DeviceMgmt.woa/wa/SendMessageAction/sendMessage', $post, 'https://secure.me.com/account/', $headers); 132 | 133 | $json = json_decode(array_pop(explode("\n", $html))); 134 | return ($json !== false) && isset($json->statusString) && ($json->statusString == 'message sent'); 135 | } 136 | 137 | public function remoteWipe() 138 | { 139 | // Remotely wiping a device is an exercise best 140 | // left to the reader. 141 | } 142 | 143 | // Grab the details for each device on the MobileMe account 144 | // (We could also use this opportunity to parse out the last know lat/lng of the device 145 | // and save a couple round trips in the future.) 146 | private function getDevices() 147 | { 148 | $headers = array('Accept: text/javascript, text/html, application/xml, text/xml, */*', 149 | 'X-Requested-With: XMLHttpRequest', 150 | 'X-Prototype-Version: 1.6.0.3', 151 | 'X-Mobileme-Version: 1.0', 152 | 'X-Mobileme-Isc: ' . $this->lsc['secure.me.com']); 153 | $html = $this->curlPost('https://secure.me.com/device_mgmt/en', null, 'https://secure.me.com/account/', $headers); 154 | 155 | $headers = array('Accept: text/javascript, text/html, application/xml, text/xml, */*', 156 | 'X-Requested-With: XMLHttpRequest', 157 | 'X-Prototype-Version: 1.6.0.3', 158 | 'X-Mobileme-Version: 1.0', 159 | 'X-Mobileme-Isc: ' . $this->lsc['secure.me.com']); 160 | $html = $this->curlPost('https://secure.me.com/wo/WebObjects/DeviceMgmt.woa/?lang=en', null, 'https://secure.me.com/account/', $headers); 161 | 162 | // Grab all of the devices 163 | preg_match_all('/new Device\((.*?)\)/ms', $html, $matches); 164 | for($i = 0; $i < count($matches[0]); $i++) 165 | { 166 | $values = str_replace("'", '', $matches[1][$i]); 167 | list($unknown, $id, $type, $class, $os) = explode(',', $values); 168 | $this->devices[$id] = array('deviceId' => $id, 'deviceType' => $type, 'deviceClass' => $class, 'deviceOsVersion' => $os); 169 | } 170 | } 171 | 172 | private function curlGet($url, $referer = null, $headers = null) 173 | { 174 | $ch = curl_init($url); 175 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 176 | curl_setopt($ch, CURLOPT_COOKIEFILE, $this->tmpFile); 177 | curl_setopt($ch, CURLOPT_COOKIEJAR, $this->tmpFile); 178 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 179 | curl_setopt($ch, CURLOPT_AUTOREFERER, true); 180 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 181 | curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9"); 182 | if(!is_null($referer)) curl_setopt($ch, CURLOPT_REFERER, $referer); 183 | if(!is_null($headers)) curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 184 | 185 | curl_setopt($ch, CURLOPT_HEADER, true); 186 | // curl_setopt($ch, CURLOPT_VERBOSE, true); 187 | 188 | $html = curl_exec($ch); 189 | 190 | if(curl_errno($ch) != 0) 191 | { 192 | throw new Exception("Error during GET of '$url': " . curl_error($ch)); 193 | } 194 | 195 | $this->lastURL = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); 196 | 197 | preg_match_all('/[li]sc-(.*?)=([a-f0-9]+);/i', $html, $matches); 198 | for($i = 0; $i < count($matches[0]); $i++) 199 | $this->lsc[$matches[1][$i]] = $matches[2][$i]; 200 | 201 | return $html; 202 | } 203 | 204 | private function curlPost($url, $post_vars = null, $referer = null, $headers = null) 205 | { 206 | $ch = curl_init($url); 207 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 208 | curl_setopt($ch, CURLOPT_COOKIEFILE, $this->tmpFile); 209 | curl_setopt($ch, CURLOPT_COOKIEJAR, $this->tmpFile); 210 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 211 | curl_setopt($ch, CURLOPT_AUTOREFERER, true); 212 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 213 | curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9"); 214 | if(!is_null($referer)) curl_setopt($ch, CURLOPT_REFERER, $referer); 215 | curl_setopt($ch, CURLOPT_POST, true); 216 | if(!is_null($post_vars)) curl_setopt($ch, CURLOPT_POSTFIELDS, $post_vars); 217 | if(!is_null($headers)) curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 218 | 219 | curl_setopt($ch, CURLOPT_HEADER, true); 220 | // curl_setopt($ch, CURLOPT_VERBOSE, true); 221 | 222 | $html = curl_exec($ch); 223 | 224 | if(curl_errno($ch) != 0) 225 | { 226 | throw new Exception("Error during POST of '$url': " . curl_error($ch)); 227 | } 228 | 229 | $this->lastURL = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); 230 | 231 | preg_match_all('/[li]sc-(.*?)=([a-f0-9]+);/i', $html, $matches); 232 | for($i = 0; $i < count($matches[0]); $i++) 233 | $this->lsc[$matches[1][$i]] = $matches[2][$i]; 234 | 235 | return $html; 236 | } 237 | 238 | private function match($regex, $str, $i = 0) 239 | { 240 | return preg_match($regex, $str, $match) == 1 ? $match[$i] : false; 241 | } 242 | } 243 | ?> 244 | --------------------------------------------------------------------------------