diff --git a/README.md b/README.md old mode 100755 new mode 100644 index c9aeefc..9bc9105 --- a/README.md +++ b/README.md @@ -2,17 +2,14 @@ Snapchat for PHP ================ [![Build Status](https://travis-ci.org/JorgenPhi/php-snapchat.png)](https://travis-ci.org/JorgenPhi/php-snapchat) -This library is built to communicate with the Snapchat API. It was nearly -feature complete and lacks some newer functionality available in the latest -versions of the official apps (stories, text messages, and "chat"). +This library is built to communicate with the Snapchat API. It is nearly +feature complete but still lacks some functionality available in the latest +versions of the official apps (namely Stories). It's similar to the [excellent Snaphax library](http://github.com/tlack/snaphax) built by Thomas Lackner <[@tlack](http://twitter.com/tlack)>, but the approach is different enough that I figured it deserved its own repo. -We love it when developers add new features, fix bugs, and submit pull requests. -(We need more pull requests!) - Usage ----- @@ -23,7 +20,12 @@ Include src/snapchat.php via require_once or Composer or whatever, then: register('email','password','birthday'); +$snapchat->registerUsername('email', 'username'); // Get your feed: $snaps = $snapchat->getSnaps(); @@ -33,7 +35,7 @@ $snaps = $snapchat->getFriendStories(); // Download a specific snap: $data = $snapchat->getMedia('122FAST2FURIOUS334r'); -file_put_contents('/home/jorgen/snap.jpg', $data); +file_put_contents('/home/dan/snap.jpg', $data); // Download a specific story: $data = $snapchat->getStory('[story_media_id]', '[story_key]', '[story_iv]'); @@ -53,14 +55,14 @@ $snapchat->markSnapShot('122FAST2FURIOUS334r'); // Upload a snap and send it to me for 8 seconds: $id = $snapchat->upload( Snapchat::MEDIA_IMAGE, - file_get_contents('/home/jorgen/whatever.jpg') + file_get_contents('/home/dan/whatever.jpg') ); -$snapchat->send($id, array('jorgenphi'), 8); +$snapchat->send($id, array('stelljes'), 8); // Upload a video story: $id = $snapchat->upload( Snapchat::MEDIA_VIDEO, - file_get_contents('/home/jorgen/whatever.mov') + file_get_contents('/home/dan/whatever.mov') ); $snapchat->setStory($id, Snapchat::MEDIA_VIDEO); @@ -101,7 +103,7 @@ $snapchat->deleteFriend('bart'); $snapchat->updatePrivacy(Snapchat::PRIVACY_FRIENDS); // You want to change your email: -$snapchat->updateEmail('jorgen@example.com'); +$snapchat->updateEmail('dan@example.com'); // Log out: $snapchat->logout(); @@ -109,6 +111,17 @@ $snapchat->logout(); ?> ``` +Snaptcha +----- + +For the methods on bypassing Snapchat's captcha system see this [gist](https://gist.github.com/hako/adb2ab9419eda2dca62b): +```php +$s->getCaptcha('username', true); +``` + +```php +$s->sendCaptcha('solution', 'captcha_id', 'username'); +``` Documentation ------------ diff --git a/src/snapchat.php b/src/snapchat.php index fe64534..8c92ee0 100755 --- a/src/snapchat.php +++ b/src/snapchat.php @@ -157,27 +157,26 @@ public function logout() { * @todo * Add better validation. * - * @param string $username - * The desired username. - * @param string $password - * The password to associate with the account. * @param string $email * The email address to associate with the account. + * @param string $password + * The password to associate with the account. * @param $birthday string * The user's birthday (yyyy-mm-dd). * * @return mixed - * The data returned by the service or FALSE if registration failed. - * Generally, returns the same result as calling self::getUpdates(). + * The data returned is TRUE if the registration succeeded or + * FALSE if the registration failed. Generally, returns the + * same result as calling self::getUpdates(). */ - public function register($username, $password, $email, $birthday) { + public function register($email, $password, $birthday) { $timestamp = parent::timestamp(); $result = parent::post( '/register', array( - 'birthday' => $birthday, - 'password' => $password, 'email' => $email, + 'password' => $password, + 'birthday' => $birthday, 'timestamp' => $timestamp, ), array( @@ -186,39 +185,137 @@ public function register($username, $password, $email, $birthday) { ) ); - if (!isset($result->token)) { + if (!isset($result->auth_token)) { return FALSE; } - $timestamp = parent::timestamp(); - $result = parent::post( - '/registeru', - array( - 'email' => $email, - 'username' => $username, - 'timestamp' => $timestamp, - ), - array( - parent::STATIC_TOKEN, - $timestamp, - ) - ); - // If registration is successful, set the username and auth_token. if (isset($result->logged) && $result->logged) { $this->auth_token = $result->auth_token; - $this->username = $result->username; $this->cache = new SnapchatCache(); $this->cache->set('updates', $result); - return $result; + return TRUE; } + else { return FALSE; } } + /** + * Registers a username. + * + * @param string $email + * The email address to associate with the account. + * @param string $username + * The desired username for this account. + * + * @return mixed + * TRUE is returned if the username is accepted. + * status integer is returned if the username is either of the following: + * + * 69 - too short + * 70 - too long + * 71 - bad username + * 72 - taken + */ + public function registerUsername($email, $username) { + $timestamp = parent::timestamp(); + $result = parent::post( + '/register_username', + array( + 'username' => $email, + 'selected_username' => $username, + 'timestamp' => $timestamp + ), + array( + $this->auth_token, + $timestamp, + ) + ); + + if(!property_exists($result, "status")) + { + return TRUE; + } + else if($result->status == 69 || 70 || 71 || 72) { + return $result->status; + } + } + + /** + * Gets the captcha associated to the username from snapchat's server. + * + * @param string $username + * The username to get the captcha puzzle, or in this case an email. + * + * @param bool $download + * Download the captcha archive from snapchat. (optional) + * + * @return string + * A string which is the captcha_id. FALSE on failure. + * + */ + public function getCaptcha($username, $download = NULL) { + $timestamp = parent::timestamp(); + $result = parent::post( + '/get_captcha', + array( + 'username' => $username, + 'timestamp' => $timestamp, + 'dl' => $download + ), + array( + $this->auth_token, + $timestamp + ) + ); + return $result; + } + + /** + * Sends the captcha solution to snapchat's server. + * + * @param $captcha_solution + * The binary solution of the captcha. must be 8 chars long. + * + * @param $captcha_id + * The ID of the captcha thats being solved. + * + * @param $username + * The username to be verified. + * + * @return mixed + * returns TRUE if captcha is solved, FALSE otherwise. + * + */ + public function sendCaptcha($captcha_solution, $captcha_id, $username) { + $timestamp = parent::timestamp(); + $result = parent::post( + '/solve_captcha', + array( + 'captcha_solution' => $captcha_solution, + 'captcha_id' => $captcha_id, + 'username' => $username, + 'timestamp' => $timestamp, + ), + array( + $this->auth_token, + $timestamp, + + ) + ); + unlink(".headers.txt"); + if(is_null($result)) { + return TRUE; + } + else if($result == FALSE) { + return FALSE; + } + } + /** * Retrieves general user, friend, and snap updates. * diff --git a/src/snapchat_agent.php b/src/snapchat_agent.php index 1dc22a9..21a6a2b 100644 --- a/src/snapchat_agent.php +++ b/src/snapchat_agent.php @@ -8,20 +8,26 @@ abstract class SnapchatAgent { /* - * App version (as of 2013-11-20). Before updating this value, confirm + * App version (as of 2014-12-5). Before updating this value, confirm * that the library requests everything in the same way as the app. */ - const VERSION = '4.1.07'; + const VERSION = '8.0.1.3'; /* - * The API URL. We're using the /bq endpoint, the one that the iPhone + * The API URL. We're using the /loq endpoint, the one that the iPhone * uses. Android clients still seem to be using the /ph endpoint. + * We still support the /bq endpoint for the captcha. * * @todo * Make library capable of using different endpoints (some of the * resource names are different, so they aren't interchangeable). */ - const URL = 'https://feelinsonice-hrd.appspot.com/bq'; + const URL = 'https://feelinsonice-hrd.appspot.com/loq'; + + /* + * The old API URL. + */ + const OLD_URL = "https://feelinsonice-hrd.appspot.com/bq"; /* * The API secret. Used to create access tokens. @@ -53,7 +59,7 @@ abstract class SnapchatAgent { CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_TIMEOUT => 10, - CURLOPT_USERAGENT => 'Snapchat/4.1.07 (Nexus 4; Android 18; gzip)', + CURLOPT_USERAGENT => 'Snapchat/8.0.1.3 (Nexus 4; Android 18; gzip)', ); /** @@ -286,20 +292,55 @@ public function post($endpoint, $data, $params, $multipart = FALSE) { $data['req_token'] = self::hash($params[0], $params[1]); $data['version'] = self::VERSION; + + if(array_key_exists('dl', $data)) { + $download = $data['dl']; + } if (!$multipart) { $data = http_build_query($data); } + if($endpoint == "/get_captcha" || $endpoint == "/solve_captcha" ) { + + $options = self::$CURL_OPTIONS + array( + CURLOPT_POST => TRUE, + CURLOPT_POSTFIELDS => $data, + CURLOPT_URL => self::OLD_URL . $endpoint, + ); + + curl_setopt($ch, CURLOPT_VERBOSE, true); + file_put_contents(".headers.txt", " "); + curl_setopt($ch, CURLOPT_STDERR, fopen(dirname(__DIR__) . "/.headers.txt", "r+")); + + } else { + $options = self::$CURL_OPTIONS + array( CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $data, CURLOPT_URL => self::URL . $endpoint, ); - curl_setopt_array($ch, $options); + } + + curl_setopt_array($ch, $options); $result = curl_exec($ch); + // upon registration, the captcha sends us a header to download. + if (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) == "application/zip; charset=UTF-8") { + $filename = fopen(dirname(__DIR__) . "/.headers.txt", "r+"); + $stream = stream_get_contents($filename); + $file = preg_match("/(=)(\S+).zip/", $stream, $match); + $group_matched = $match[2] . ".zip"; + $captcha_id = str_replace(".zip", "", $group_matched); + if($download == 1) { + file_put_contents($group_matched, $result); + } + unlink(".headers.txt"); + curl_close($ch); + return $captcha_id; + } + // If cURL doesn't have a bundle of root certificates handy, we provide // ours (see http://curl.haxx.se/docs/sslcerts.html). if (curl_errno($ch) == 60) {