function j_mail($subj, $msg = '') { global $opt_jfb_email_to, $opt_jfb_email_logs, $jfb_log; global $jfb_debug_array; if (get_option($opt_jfb_email_logs) && get_option($opt_jfb_email_to)) { if ($msg) { $msg .= "\n\n"; } if (isset($jfb_log)) { $msg .= "---LOG:---\n" . $jfb_log; } jfb_debug_checkpoint('final'); $count = count($jfb_debug_array); $keys = array_keys($jfb_debug_array); $msg .= "\n---TIME:---\n"; for ($i = 0; $i < $count; $i++) { if ($i == 0) { $msg .= sprintf("%-9s", $keys[$i]) . ") +0s\n"; } else { $msg .= sprintf("%-9s", $keys[$i]) . ") +" . round($jfb_debug_array[$keys[$i]]['time'] - $jfb_debug_array[$keys[$i - 1]]['time'], 2) . "s\n"; } } $msg .= "TOTAL ) " . round($jfb_debug_array[$keys[$count - 1]]['time'] - $jfb_debug_array[$keys[0]]['time'], 2) . "s\n"; $msg .= "\n---MEMORY:---\n"; for ($i = 0; $i < $count; $i++) { $value = $jfb_debug_array[$keys[$i]]['mem']; if ($i == 0) { $msg .= sprintf("%-9s", $keys[$i]) . ") " . round($value / (1024 * 1024), 2) . "M\n"; } else { $msg .= sprintf("%-9s", $keys[$i]) . ") " . round($value / (1024 * 1024), 2) . "M (+" . round(($value - $jfb_debug_array[$keys[$i - 1]]['mem']) / (1024 * 1024), 2) . "M)\n"; } } $msg .= "LIMIT ) " . ini_get('memory_limit') . "\n"; $msg .= "\n---REQUEST:---\n" . print_r($_REQUEST, true); mail(get_option($opt_jfb_email_to), $subj, $msg); } }
* This file handles Facebook Connect login requests. When a user logs in via the FB popup window, * the js_callbackfunc will redirect us here. We then use information from FB to log them into nxt. * See the bottom of this file for notes on the Facebook API */ //A very simple check to avoid people from accessing this script directly. if (!isset($_POST['redirectTo'])) { die("Please do not access this script directly."); } //Make sure we're using PHP5 if (version_compare('5', PHP_VERSION, ">")) { die("Error: This plugin requires PHP5 or better."); } //Include our options and the nxtclass core require_once "__inc_nxt.php"; require_once "__inc_opts.php"; jfb_debug_checkpoint('start'); //If present, include the Premium addon @(include_once realpath(dirname(__FILE__)) . "/../nxt-FB-AutoConnect-Premium.php"); if (!defined('JFB_PREMIUM')) { @(include_once "Premium.php"); } //Start logging $browser = jfb_get_browser(); $jfb_log = "Starting login process (Client: " . $_SERVER['REMOTE_ADDR'] . ", Version: {$jfb_version}, Browser: " . $browser['shortname'] . " " . $browser['version'] . " for " . $browser['platform'] . ")\n"; //Run one hook before ANYTHING happens. do_action('nxtfb_prelogin'); //Check the nonce to make sure this was a valid login attempt (unless the user has disabled nonce checking) if (!get_option($opt_jfb_disablenonce)) { if (nxt_verify_nonce($_REQUEST[$jfb_nonce_name], $jfb_nonce_name) != 1) { //If there's already a user logged in, tell the user and give them a link back to where they were. $currUser = nxt_get_current_user();
function jfb_process_login() { //If this pageload isn't supposed to be handing a login, just stop here. global $jfb_nonce_name; if (!isset($_POST[$jfb_nonce_name])) { return; } //Start logging global $jfb_log, $jfb_version, $opt_jfb_app_id, $jfb_homepage; jfb_debug_checkpoint('start'); $browser = jfb_get_browser(); $jfb_log = "Starting login process (IP: " . $_SERVER['REMOTE_ADDR'] . ", User: "******", App: " . get_option($opt_jfb_app_id) . ", Version: {$jfb_version}, Browser: " . $browser['shortname'] . " " . $browser['version'] . " for " . $browser['platform'] . ")\n"; //Run one hook before ANYTHING happens. $jfb_log .= "WP: Running action wpfb_prelogin\n"; do_action('wpfb_prelogin'); //Check the nonce to make sure this was a valid login attempt (unless the user has disabled nonce checking) global $opt_jfb_disablenonce, $jfb_nonce_name; if (!get_option($opt_jfb_disablenonce)) { if (wp_verify_nonce($_REQUEST[$jfb_nonce_name], $jfb_nonce_name) != 1) { //If there's already a user logged in, tell the user and give them a link back to where they were. $currUser = wp_get_current_user(); if ($currUser->ID) { $msg = "User \"{$currUser->user_login}\" has already logged in via another browser session.\n"; $jfb_log .= $msg; j_mail("FB Double-Login: "******" -> " . get_bloginfo('name')); die($msg . "<br /><br /><a href=\"" . $_POST['redirectTo'] . "\">Continue</a>"); } j_die("Nonce check failed, login aborted.\nThis usually due to your browser's privacy settings or a server-side caching plugin. If you get this error on multiple browsers, please contact the site administrator.\n"); } $jfb_log .= "WP: nonce check passed\n"; } else { $jfb_log .= "WP: nonce check DISABLED\n"; } //Get the redirect URL global $redirectTo; if (!isset($_POST['redirectTo']) || !$_POST['redirectTo']) { j_die("Error: Missing POST Data (redirect)"); } $redirectTo = $_POST['redirectTo']; $jfb_log .= "WP: Found redirect URL ({$redirectTo})\n"; //Get the Facebook access token if (!isset($_POST['access_token']) || !$_POST['access_token']) { j_die("Error: Missing POST Data (access_token).\n\nIf you're receiving this notice via e-mail as a site administrator, it's nearly always safe to ignore (these errors are due to spambots automatically hitting your site). If you're seeing this as a real person attempting to login, please report it to the plugin author at " . $jfb_homepage . "."); } $access_token = $_POST['access_token']; $jfb_log .= "FB: Found access token (" . substr($access_token, 0, 30) . "...)\n"; //Get the basic user info and make sure the access_token is valid $jfb_log .= "FB: Initiating Facebook connection...\n"; $fbuser = jfb_api_get("https://graph.facebook.com/me?access_token={$access_token}"); if (isset($fbuser['error'])) { j_die("Error: Failed to get the Facebook user session (" . $fbuser['error']['message'] . ")"); } $fb_uid = $fbuser['id']; do_action('wpfb_session_established', array('FB_ID' => $fb_uid, 'access_token' => $access_token)); $jfb_log .= "FB: Connected to session (uid {$fb_uid})\n"; //Get some extra stuff (TODO: I should combine these into one query with the above, for better efficiency) $fbuser['profile_url'] = $fbuser['link']; $pic = jfb_api_get("https://graph.facebook.com/fql?q=" . urlencode("SELECT pic_square,pic_big FROM user WHERE uid={$fb_uid}") . "&access_token={$access_token}"); $fbuser['pic_square'] = $pic['data'][0]['pic_square']; $fbuser['pic_big'] = $pic['data'][0]['pic_big']; $jfb_log .= "FB: Got user info (" . $fbuser['name'] . ")\n"; //See if we were given permission to access the user's email //This isn't required, and will only matter if it's a new user without an existing WP account //(since we'll auto-register an account for them, using the contact_email we get from Facebook - if we can...) $userRevealedEmail = false; if (strlen($fbuser['email']) != 0 && strpos($fbuser['email'], 'proxymail.facebook.com') === FALSE) { $jfb_log .= "FB: Email privilege granted (" . $fbuser['email'] . ")\n"; $userRevealedEmail = true; } else { if (strlen($fbuser['email']) != 0) { $jfb_log .= "FB: Email privilege granted, but only for an anonymous proxy address (" . $fbuser['email'] . ")\n"; } else { global $jfb_default_email; $jfb_log .= "FB: Email priviledge denied.\n"; $fbuser['email'] = "FB_" . $fb_uid . $jfb_default_email; } } //Run a hook so users can`examine this Facebook user *before* letting them login. You might use this //to limit logins based on friendship status - if someone isn't your friend, you could redirect them //to an error page (and terminate this script). $jfb_log .= "WP: Running action wpfb_connect\n"; do_action('wpfb_connect', array('FB_ID' => $fb_uid, 'access_token' => $access_token)); //Examine all existing WP users to see if any of them match this Facebook user. //The base query for getting the users comes from get_users_from_blog(), to which I add a subquery //that limits results only to users who also have the appropriate facebook usermeta. global $wp_users, $jfb_uid_meta_name; if (!isset($wp_users)) { global $wpdb, $blog_id; if (empty($id)) { $id = (int) $blog_id; } $blog_prefix = $wpdb->get_blog_prefix($id); $sql = "SELECT user_id, user_id AS ID, user_login, display_name, user_email, meta_value " . "FROM {$wpdb->users}, {$wpdb->usermeta} " . "WHERE {$wpdb->users}.ID = {$wpdb->usermeta}.user_id AND meta_key = '{$blog_prefix}capabilities' " . "AND {$wpdb->users}.ID IN (SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$jfb_uid_meta_name}' AND meta_value = '{$fb_uid}')"; $wp_users = $wpdb->get_results($sql); } //Although $wp_users should only contain the one matching user (or be empty), this "loop" method of searching //for matching usermeta is retained for backwards compatibility with old 3rd party hooks which may've relied on it. //Originally, $wp_users contained the full list of users (not just those with matching usermeta). $jfb_log .= "WP: Searching " . count($wp_users) . " existing candidates by meta...\n"; $user_login_id = false; foreach ($wp_users as $wp_user) { $meta_uid = get_user_meta($wp_user->ID, $jfb_uid_meta_name, true); if ($meta_uid && $meta_uid == $fb_uid) { $user_data = get_userdata($wp_user->ID); $user_login_id = $wp_user->ID; $user_login_name = $user_data->user_login; $jfb_log .= "WP: Found existing user by meta (" . $user_login_name . ")\n"; break; } } //Next, try to lookup their email directly (via Wordpress). Obviously this will only work if they've revealed //their "real" address (vs denying access, or changing it to a "proxy" in the popup) if (!$user_login_id && $userRevealedEmail) { $jfb_log .= "WP: Searching for user by email address...\n"; if ($wp_user = get_user_by('email', $fbuser['email'])) { $user_login_id = $wp_user->ID; $user_data = get_userdata($wp_user->ID); $user_login_name = $user_data->user_login; $jfb_log .= "WP: Found existing user (" . $user_login_name . ") by email (" . $fbuser['email'] . ")\n"; } } //If we found an existing user, check if they'd previously denied access to their email but have now allowed it. //If so, we'll want to update their WP account with their *real* email. global $jfb_default_email; if ($user_login_id) { //Check 1: It was previously denied, but is now allowed $updateEmail = false; if (strpos($user_data->user_email, $jfb_default_email) !== FALSE && strpos($fbuser['email'], $jfb_default_email) === FALSE) { $jfb_log .= "WP: Previously DENIED email has now been allowed; updating to (" . $fbuser['email'] . ")\n"; $updateEmail = true; } //Check 2: It was previously allowed, but only as an anonymous proxy. They've now revealed their "true" email. if (strpos($user_data->user_email, "@proxymail.facebook.com") !== FALSE && strpos($fbuser['email'], "@proxymail.facebook.com") === FALSE) { $jfb_log .= "WP: Previously PROXIED email has now been allowed; updating to (" . $fbuser['email'] . ")\n"; $updateEmail = true; } if ($updateEmail) { $user_upd = array(); $user_upd['ID'] = $user_login_id; $user_upd['user_email'] = $fbuser['email']; wp_update_user($user_upd); } //Run a hook when an existing user logs in $jfb_log .= "WP: Running action wpfb_existing_user\n"; do_action('wpfb_existing_user', array('WP_ID' => $user_login_id, 'FB_ID' => $fb_uid, 'WP_UserData' => $user_data, 'access_token' => $access_token)); } //If we still don't have a user_login_id, the FB user who's logging in has never been to this blog. //We'll auto-register them a new account. Note that if they haven't allowed email permissions, the //account we register will have a bogus email address (but that's OK, since we still know their Facebook ID) if (!$user_login_id) { $jfb_log .= "WP: No user found. Automatically registering (FB_" . $fb_uid . ")\n"; $user_data = array(); $user_data['user_login'] = "******" . $fb_uid; $user_data['user_pass'] = wp_generate_password(); $user_data['user_nicename'] = sanitize_title($user_data['user_login']); $user_data['first_name'] = $fbuser['first_name']; $user_data['last_name'] = $fbuser['last_name']; $user_data['display_name'] = $fbuser['first_name']; $user_data['user_url'] = $fbuser["profile_url"]; $user_data['user_email'] = $fbuser["email"]; //Run a filter so the user can be modified to something different before registration //NOTE: If the user has selected "pretty names", this'll change FB_xxx to i.e. "John.Smith" $jfb_log .= "WP: Applying filters wpfb_insert_user/wpfb_inserting_user\n"; $user_data = apply_filters('wpfb_insert_user', $user_data, $fbuser); $user_data = apply_filters('wpfb_inserting_user', $user_data, array('WP_ID' => $user_login_id, 'FB_ID' => $fb_uid, 'FB_UserData' => $fbuser, 'access_token' => $access_token)); //Insert a new user to our database and make sure it worked $user_login_id = wp_insert_user($user_data); if (is_wp_error($user_login_id)) { j_die("Error: wp_insert_user failed!<br/><br/>" . "If you get this error while running a Wordpress MultiSite installation, it means you'll need to purchase the <a href=\"{$jfb_homepage}#premium\">premium version</a> of this plugin to enable full MultiSite support.<br/><br/>" . "If you're <u><i>not</i></u> using MultiSite, please report this bug to the plugin author on the support page <a href=\"{$jfb_homepage}#feedback\">here</a>.<br /><br />" . "Error message: " . (method_exists($user_login_id, 'get_error_message') ? $user_login_id->get_error_message() : "Undefined") . "<br />" . "WP_ALLOW_MULTISITE: " . (defined('WP_ALLOW_MULTISITE') ? constant('WP_ALLOW_MULTISITE') : "Undefined") . "<br />" . "is_multisite: " . (function_exists('is_multisite') ? is_multisite() : "Undefined")); } //Success! Notify the site admin. $user_login_name = $user_data['user_login']; wp_new_user_notification($user_login_id); //Run an action so i.e. usermeta can be added to a user after registration $jfb_log .= "WP: Running action wpfb_inserted_user\n"; do_action('wpfb_inserted_user', array('WP_ID' => $user_login_id, 'FB_ID' => $fb_uid, 'WP_UserData' => $user_data, 'access_token' => $access_token)); } //Tag the user with our meta so we can recognize them next time, without resorting to email hashes global $jfb_uid_meta_name; update_user_meta($user_login_id, $jfb_uid_meta_name, $fb_uid); $jfb_log .= "WP: Updated usermeta ({$jfb_uid_meta_name})\n"; //Also store the user's facebook avatar(s), in case the user wants to use them later if ($fbuser['pic_square']) { if (isset($fbuser['pic_square']['data']['url'])) { $avatarThumb = $fbuser['pic_square']['data']['url']; } else { $avatarThumb = $fbuser['pic_square']; } if (isset($fbuser['pic_big']['data']['url'])) { $avatarFull = $fbuser['pic_big']['data']['url']; } else { $avatarFull = $fbuser['pic_big']; } update_user_meta($user_login_id, 'facebook_avatar_full', $avatarFull); update_user_meta($user_login_id, 'facebook_avatar_thumb', $avatarThumb); $jfb_log .= "WP: Updated small avatar ({$avatarThumb})\n"; $jfb_log .= "WP: Updated large avatar ({$avatarFull})\n"; } else { update_user_meta($user_login_id, 'facebook_avatar_thumb', ''); update_user_meta($user_login_id, 'facebook_avatar_full', ''); $jfb_log .= "FB: User does not have a profile picture; clearing cached avatar (if present).\n"; } //Log them in $rememberme = apply_filters('wpfb_rememberme', isset($_POST['rememberme']) && $_POST['rememberme']); wp_set_auth_cookie($user_login_id, $rememberme); //Run a custom action. You can use this to modify a logging-in user however you like, //i.e. add them to a "Recent FB Visitors" log, assign a role if they're friends with you on Facebook, etc. $jfb_log .= "WP: Running action wpfb_login\n"; do_action('wpfb_login', array('WP_ID' => $user_login_id, 'FB_ID' => $fb_uid, 'access_token' => $access_token)); do_action('wp_login', $user_login_name, get_userdata($user_login_id)); //Email logs if requested $jfb_log .= "Login complete (rememberme=" . ($rememberme ? "yes" : "no") . ")\n"; $jfb_log .= " WP User : {$user_login_name} (" . admin_url("user-edit.php?user_id={$user_login_id}") . ")\n"; $jfb_log .= " FB User : "******" (" . $fbuser["profile_url"] . ")\n"; $jfb_log .= " Redirect: " . $redirectTo . "\n"; j_mail("FB Login: "******" -> " . get_bloginfo('name')); //Redirect the user back to where they were global $opt_jfb_delay_redir; $delay_redirect = get_option($opt_jfb_delay_redir); if (!isset($delay_redirect) || !$delay_redirect) { header("Location: " . $redirectTo); exit; } ?> <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Logging In...</title> </head> <body> <?php $jfb_log .= "\n---REQUEST:---\n" . print_r($_REQUEST, true); ?> <?php echo "<pre>" . $jfb_log . "</pre>"; ?> <?php echo '<a href="' . $redirectTo . '">Continue</a>'; ?> </body> </html> <?php }