/** * Retrieves the currently logged-in user from the session. * If the user was not originally retrieved from the database, * inserts a new one. * Thus, this can also be used to turn visitors into registered * users. * * @param string $platform * Currently only supports the value "facebook". * @param int $app_id * The id of the app within the specified platform. * Used for storing app-specific session information. * @param string $password * Sometimes, if the authentication isn't to be trusted, * a password is required. Pass true here to bypass * password checking and log in the user regardless. * Otherwise, this string is hashed and tested. */ static function authenticate($platform, $app_id = null, $password = null) { if (!isset($app_id)) { $app = Pie_Config::expect('pie', 'app'); $app_id = Pie_Config::expect('users', 'facebookApps', $app, 'appId'); } $return = null; $return = Pie::event('users/auth', compact('platform', 'app_id', 'password'), 'before'); if (isset($return)) { return $return; } if (!isset($platform) or $platform != 'facebook') { throw new Pie_Exception_WrongType(array('field' => 'platform', 'type' => '"facebook"')); } if (!isset($app_id)) { throw new Pie_Exception_WrongType(array('field' => 'app_id', 'type' => 'integer')); } Pie_Session::start(); // First, see if we've already logged in somehow if ($user = self::loggedInUser()) { // Get logged in user from session $user_was_logged_in = true; } else { // Get an existing user or create a new one $user = new Users_User(); switch ($platform) { case 'facebook': if (!Users::facebook($app_id)) { return false; } if (!Users::facebook($app_id)->user) { return false; // no one logged in } $user->fb_uid = Users::facebook($app_id)->user; break; default: return false; // not sure how to log this user in } $retrieved = $user->retrieve(); // Now save this user in the session as the logged-in user self::setLoggedInUser($user); $session_id = Pie_Session::id(); if ($retrieved) { // User exists in database. Do we need to update it? if (!isset($user->session_key) or $user->session_key != $session_id) { Pie::event('users/authUpdateUser', compact('user'), 'before'); $user->session_key = $session_id; $user->save(); // update session_key in user Pie::event('users/authUpdateUser', compact('user'), 'after'); } } else { // No user in database. Will insert a new one! // These users might be shared across apps. Pie::event('users/authInsertUser', compact('user'), 'before'); $user->session_key = $session_id; $user->save(); $_SESSION['users']['user'] = $user; Pie::event('users/authInsertUser', compact('user'), 'after'); $inserted_new_user = true; } } // Now make sure our master session contains the // session info for the platform app. if ($platform == 'facebook') { $fb_prefix = 'fb_sig_'; if (!Users::facebook($app_id)) { return false; } $facebook = Users::facebook($app_id); if (isset($_SESSION['users']['facebookAppUser'][$app_id])) { // Facebook app user exists. Do we need to update it? (Probably not!) $app_user = $_SESSION['users']['facebookAppUser'][$app_id]; $app_user->state = 'added'; if (!isset($app_user->session_key) or $facebook->api_client->session_key != $app_user->session_key) { Pie::event('users/authUpdateAppUser', compact('user'), 'before'); $app_user->session_key = $facebook->api_client->session_key; $app_user->save(); // update session_key in app_user Pie::event('users/authUpdateAppUser', compact('user'), 'after'); } } else { // We have to put the session info in $app_user = new Users_AppUser(); $app_user->user_id = $user->id; $app_user->platform = 'facebook'; $app_user->app_id = $app_id; if ($app_user->retrieve()) { // App user exists in database. Do we need to update it? if (!isset($app_user->session_key) or $app_user->session_key != $facebook->api_client->session_key) { Pie::event('users/authUpdateAppUser', compact('user'), 'before'); $app_user->session_key = $facebook->api_client->session_key; $app_user->save(); // update session_key in app_user Pie::event('users/authUpdateAppUser', compact('user'), 'after'); } } else { $app_user->state = 'added'; $app_user->session_key = $facebook->api_client->session_key; $app_user->platform_uid = $user->fb_uid; Pie::event('users/authInsertAppUser', compact('user'), 'before'); $app_user->save(); Pie::event('users/authInsertAppUser', compact('user'), 'after'); } } $_SESSION['users']['facebookAppUser'][$app_id] = $app_user; } Pie::event('users/auth', compact('platform', 'app_id', 'password'), 'after'); // At this point, $user is set. return $user; }
/** * Retrieves the currently logged-in user from the session. * If the user was not originally retrieved from the database, * inserts a new one. * Thus, this can also be used to turn visitors into registered * users. * @method authenticate * @static * @param {string} $provider Currently only supports the value "facebook". * @param {integer} [$appId=null] The id of the app within the specified provider. * Used for storing app-specific session information. * @param {&boolean} [$authenticated=null] If authentication fails, puts false here. * Otherwise, puts one of the following: * 'registered' if user just registered, * 'adopted' if a futureUser was just adopted, * 'connected' if a logged-in user just connected the provider account for the first time, * 'authorized' if a logged-in user was connected to provider but just authorized this app for the first time * or true otherwise. * @param {boolean} [$import_emailAddress=false] If true, and the user's email address is not set yet, * imports the email address from the provider if it is available, * and sets it as the user's email address without requiring verification. * @return {Users_User} */ static function authenticate($provider, $appId = null, &$authenticated = null, $import_emailAddress = false) { if (!isset($appId)) { $app = Q_Config::expect('Q', 'app'); $appId = Q_Config::expect('Users', 'facebookApps', $app, 'appId'); } $authenticated = null; $during = 'authenticate'; $return = null; /** * @event Users/authenticate {before} * @param {string} provider * @param {string} appId * @return {Users_User} */ $return = Q::event('Users/authenticate', compact('provider', 'appId'), 'before'); if (isset($return)) { return $return; } if (!isset($provider) or $provider != 'facebook') { throw new Q_Exception_WrongType(array('field' => 'provider', 'type' => '"facebook"')); } if (!isset($appId)) { throw new Q_Exception_WrongType(array('field' => 'appId', 'type' => 'a valid facebook app id')); } Q_Session::start(); // First, see if we've already logged in somehow if ($user = self::loggedInUser()) { // Get logged in user from session $user_was_logged_in = true; $retrieved = true; } else { // Get an existing user or create a new one $user_was_logged_in = false; $retrieved = false; $user = new Users_User(); } $authenticated = false; $emailAddress = null; // Try authenticating the user with the specified provider switch ($provider) { case 'facebook': $facebook = Users::facebook($appId); if (!$facebook or !$facebook->getUser()) { // no facebook authentication is happening return $user_was_logged_in ? $user : false; } if (empty($user->emailAddress)) { $queries = array(array('method' => 'GET', 'relative_url' => '/me/permissions'), array('method' => 'GET', 'relative_url' => '/me')); $batchResponse = $facebook->api('?batch=' . Q::json_encode($queries), 'POST'); $permissions = json_decode($batchResponse[0]['body'], true); if (Q::ifset($permissions, 'data', 0, 'email', false)) { $userData = json_decode($batchResponse[1]['body'], true); if (!empty($userData['email'])) { $emailAddress = $userData['email']; } } } $authenticated = true; $fb_uid = $facebook->getUser(); $re_save_user = false; if ($retrieved) { if (empty($user->fb_uid)) { // this is a logged-in user who was never authenticated with facebook. // First, let's find any other user who has authenticated with this facebook uid, // and set their fb_uid to NULL. $authenticated = 'connected'; $ui = Users::identify('facebook', $fb_uid); if ($ui) { Users_User::update()->set(array('fb_uid' => 0))->where(array('id' => $ui->userId))->execute(); $ui->remove(); } // Now, let's associate their account with this facebook uid. $user->fb_uid = $fb_uid; $user->save(); // Save the identifier in the quick lookup table $ui = new Users_Identify(); $ui->identifier = "facebook:{$fb_uid}"; $ui->state = 'verified'; $ui->userId = $user->id; $ui->save(true); } else { if ($user->fb_uid !== $fb_uid) { // The logged-in user was authenticated with facebook already, // and associated with a different facebook id. // Most likely, a completely different person has logged into facebook // at this computer. So rather than changing the associated facebook uid // for the logged-in user, simply log out and essentially run this function // from the beginning again. Users::logout(); $user_was_logged_in = false; $user = new Users_User(); $retrieved = false; } } } if (!$retrieved) { $ui = Users::identify('facebook', $fb_uid, null); if ($ui) { $user = new Users_User(); $user->id = $ui->userId; $exists = $user->retrieve(); if (!$exists) { throw new Q_Exception("Users_Identify for fb_uid {$fb_uid} exists but not user with id {$ui->userId}"); } $retrieved = true; if ($ui->state === 'future') { $authenticated = 'adopted'; $user->fb_uid = $fb_uid; $user->signedUpWith = 'facebook'; // should have been "none" before this /** * @event Users/adoptFutureUser {before} * @param {Users_User} user * @param {string} during * @return {Users_User} */ $ret = Q::event('Users/adoptFutureUser', compact('user', 'during'), 'before'); if ($ret) { $user = $ret; } $user->save(); $ui->state = 'verified'; $ui->save(); /** * @event Users/adoptFutureUser {after} * @param {Users_User} user * @param {array} links * @param {string} during * @return {Users_User} */ Q::event('Users/adoptFutureUser', compact('user', 'links', 'during'), 'after'); } else { // If we are here, that simply means that we already verified the // $fb_uid => $userId mapping for some existing user who signed up // and has been using the system. So there is nothing more to do besides // setting this user as the logged-in user below. } } else { // user is logged out and no user corresponding to $fb_uid yet $authenticated = 'registered'; // If we can import email address from facebook, // try retrieving it quietly if ($import_emailAddress) { // DELAY: The following call may take some time, // but once the user is saved, it will not happen again // for this facebook user, because it would be identified by fb_uid $userData = $facebook->api('/me'); if (!empty($userData['email'])) { $emailAddress = $userData['email']; } Users::$cache['facebookUserData'] = $userData; } if (!empty($emailAddress)) { $ui = Users::identify('email', $emailAddress, 'verified'); if ($ui) { // existing user identified from verified email address // load it into $user $user = new Users_User(); $user->id = $ui->userId; $user->retrieve(null, null, true)->caching()->resume(); } } $user->fb_uid = $fb_uid; /** * @event Users/insertUser {before} * @param {Users_User} user * @param {string} during * @return {Users_User} */ $ret = Q::event('Users/insertUser', compact('user', 'during'), 'before'); if (isset($ret)) { $user = $ret; } if (!$user->wasRetrieved()) { // Register a new user basically and give them an empty username for now $user->username = ""; $user->icon = 'default'; $user->signedUpWith = 'facebook'; $user->save(); // Save the identifier in the quick lookup table $ui = new Users_Identify(); $ui->identifier = "facebook:{$fb_uid}"; $ui->state = 'verified'; $ui->userId = $user->id; $ui->save(true); // Download and save facebook icon for the user $sizes = Q_Config::expect('Users', 'icon', 'sizes'); sort($sizes); $icon = array(); foreach ($sizes as $size) { $parts = explode('x', $size); $width = Q::ifset($parts, 0, ''); $height = Q::ifset($parts, 1, ''); $width = $width ? $width : $height; $height = $height ? $height : $width; $icon["{$size}.png"] = "https://graph.facebook.com/{$fb_uid}/picture?width={$width}&height={$height}"; } if (!Q_Config::get('Users', 'register', 'icon', 'leaveDefault', false)) { self::importIcon($user, $icon); $user->save(); } } } } Users::$cache['user'] = $user; Users::$cache['authenticated'] = $authenticated; // Checking if user email is not set, and we have facebook "email" permission, // try retrieving it from facebook and verifying the email for the user if (!empty($emailAddress)) { $emailSubject = Q_Config::get('Users', 'transactional', 'authenticated', 'subject', false); $emailView = Q_Config::get('Users', 'transactional', 'authenticated', 'body', false); if ($emailSubject !== false and $emailView) { $user->addEmail($emailAddress, $emailSubject, $emailView); } // After this, we automatically verify their email, // even if they never clicked the confirmation link, // because we trust the authentication provider. $user->setEmailAddress($emailAddress, true); } break; default: // not sure how to log this user in return $user_was_logged_in ? $user : false; } if (!$user_was_logged_in) { self::setLoggedInUser($user); } if ($retrieved) { /** * @event Users/updateUser {after} * @param {Users_User} user * @param {string} during */ Q::event('Users/updateUser', compact('user', 'during'), 'after'); } else { /** * @event Users/insertUser {after} * @param {string} during * @param {Users_User} 'user' */ Q::event('Users/insertUser', compact('user', 'during'), 'after'); } // Now make sure our master session contains the // session info for the provider app. if ($provider == 'facebook') { $access_token = $facebook->getAccessToken(); if (isset($_SESSION['Users']['appUsers']['facebook_' . $appId])) { // Facebook app user exists. Do we need to update it? (Probably not!) $pk = $_SESSION['Users']['appUsers']['facebook_' . $appId]; $app_user = Users_AppUser::select('*')->where($pk)->fetchDbRow(); if (empty($app_user)) { // somehow this app_user disappeared from the database throw new Q_Exception_MissingRow(array('table' => 'AppUser', 'criteria' => http_build_query($pk, null, ' & '))); } if (empty($app_user->state) or $app_user->state !== 'added') { $app_user->state = 'added'; } if (!isset($app_user->access_token) or $access_token != $app_user->access_token) { /** * @event Users/authenticate/updateAppUser {before} * @param {Users_User} user */ Q::event('Users/authenticate/updateAppUser', compact('user', 'app_user'), 'before'); $app_user->access_token = $access_token; $app_user->save(); // update access_token in app_user /** * @event Users/authenticate/updateAppUser {after} * @param {Users_User} user */ Q::event('Users/authenticate/updateAppUser', compact('user', 'app_user'), 'after'); } } else { // We have to put the session info in $app_user = new Users_AppUser(); $app_user->userId = $user->id; $app_user->provider = 'facebook'; $app_user->appId = $appId; if ($app_user->retrieve()) { // App user exists in database. Do we need to update it? if (!isset($app_user->access_token) or $app_user->access_token != $access_token) { /** * @event Users/authenticate/updateAppUser {before} * @param {Users_User} user */ Q::event('Users/authenticate/updateAppUser', compact('user', 'app_user'), 'before'); $app_user->access_token = $access_token; $app_user->save(); // update access_token in app_user /** * @event Users/authenticate/updateAppUser {after} * @param {Users_User} user */ Q::event('Users/authenticate/updateAppUser', compact('user', 'app_user'), 'after'); } } else { if (empty($app_user->state) or $app_user->state !== 'added') { $app_user->state = 'added'; } $app_user->access_token = $access_token; $app_user->provider_uid = $user->fb_uid; /** * @event Users/insertAppUser {before} * @param {Users_User} user * @param {string} 'during' */ Q::event('Users/insertAppUser', compact('user', 'during'), 'before'); // The following may update an existing app_user row // in the rare event that someone tries to tie the same // provider account to two different accounts. // A provider account can only reference one account, so the // old connection will be dropped, and the new connection saved. $app_user->save(true); /** * @event Users/authenticate/insertAppUser {after} * @param {Users_User} user */ Q::event('Users/authenticate/insertAppUser', compact('user'), 'after'); $authenticated = 'authorized'; } } $_SESSION['Users']['appUsers']['facebook_' . $appId] = $app_user->getPkValue(); } Users::$cache['authenticated'] = $authenticated; /** * @event Users/authenticate {after} * @param {string} provider * @param {string} appId */ Q::event('Users/authenticate', compact('provider', 'appId'), 'after'); // At this point, $user is set. return $user; }
function Users_importContacts_providers_yahoo($params) { #Url fetching function $fetch = function ($url) use($params) { /** @var $client Zend_Oauth_Client */ $client = $params['client']; $client->setUri($url); $client->setParameterGet('format', 'json'); $response = $client->request(Zend_Http_Client::GET); if ($response->getStatus() != 200) { #TODO: Should we only throw Users_Exception_OAuthTokenInvalid on error 401? throw new Users_Exception_OAuthTokenInvalid(); } return $response->getBody(); }; #Find out user's Yahoo GUID #Do we have the GUID saved? $cu = Users::loggedInUser(); $user = new Users_AppUser(); $user->userId = $cu->id; $user->provider = 'yahoo'; $user->appId = Q_Config::expect('Users', 'oAuthProviders', 'yahoo', 'appId'); $user->retrieve('*', true); if (!empty($user->provider_uid)) { #We have user's Yahoo GUID saved $guid = $user->provider_uid; } else { $guidjson = json_decode($fetch('http://social.yahooapis.com/v1/me/guid')); $guid = $guidjson->guid->value; $user->provider_uid = $guid; $user->save(true); } #Request contacts $res = json_decode($fetch("http://social.yahooapis.com/v1/user/{$guid}/contacts")); echo '<pre>'; foreach ($res->contacts->contact as $c) { $givenName = null; $familyName = null; $nickName = null; $email = null; $groups = array(); foreach ($c->fields as $f) { switch ($f->type) { case 'nickname': $nickName = $f->value; break; case 'email': if (empty($email)) { $email = $f->value; } break; case 'name': if (!empty($f->value->givenName)) { $givenName = $f->value->givenName; } if (!empty($f->value->familyName)) { $familyName = $f->value->familyName; } break; } } if (!$email) { continue; } #Detect groups foreach ($c->categories as $g) { $groups[] = $g->name; } #Save user $alr = Users::addLink($email, 'email', array('firstName' => $givenName, 'lastName' => $familyName, 'labels' => $groups)); echo $givenName . ($familyName ? ' ' . $familyName : '') . ' [' . $email . ']' . ($groups ? ' (' . implode(', ', $groups) . ')' : '') . ' -> ' . ($alr === true ? 'ADDED' : ($alr ? 'EXISTS: ' . $alr : 'EXISTS')) . PHP_EOL; } return true; }