View source
<?php
define("SIMPLE_FB_CONNECT_DEFAULT_DIMENSIONS_STRING", "1024x1024");
define("SIMPLE_FB_CONNECT_DEFAULT_WIDTH", 1024);
define("SIMPLE_FB_CONNECT_DEFAULT_HEIGHT", 1024);
use Facebook\FacebookRedirectLoginHelper;
use Facebook\FacebookRequest;
use Facebook\FacebookRequestException;
use Facebook\FacebookSession;
use Facebook\GraphObject;
function simple_fb_connect_menu() {
$items['user/simple-fb-connect'] = array(
'title' => 'Facebook login',
'page callback' => 'simple_fb_connect_redirect_to_fb',
'access callback' => 'user_is_anonymous',
'type' => MENU_LOCAL_TASK,
);
$items['user/simple-fb-connect/return'] = array(
'title' => 'Facebook login',
'page callback' => 'simple_fb_connect_return_from_fb',
'access callback' => 'user_is_anonymous',
'type' => MENU_CALLBACK,
);
$items['admin/config/people/simple-fb-connect'] = array(
'title' => 'Simple FB Connect Settings',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'simple_fb_connect_api_keys_settings',
),
'access arguments' => array(
'administer simple fb',
),
'file' => 'simple_fb_connect.admin.inc',
);
return $items;
}
function simple_fb_connect_permission() {
$items = array();
$items['administer simple fb'] = array(
'title' => "Administer Simple Facebook Connect Module settings",
);
return $items;
}
function simple_fb_connect_libraries_info() {
$libraries['facebook-php-sdk-v4'] = array(
'name' => 'Facebook PHP SDK v4',
'vendor url' => 'https://github.com/facebook/facebook-php-sdk-v4',
'download url' => 'https://github.com/facebook/facebook-php-sdk-v4/releases',
'version arguments' => array(
'file' => 'README.md',
'pattern' => '@Stable-(\\d*\\.\\d*\\.\\d*)@',
),
'xautoload' => function ($adapter) {
$adapter
->add('Facebook', 'src');
},
);
return $libraries;
}
function simple_fb_connect_user_logout($account) {
global $base_url;
if (simple_fb_connect_initialize()) {
$fb_session = simple_fb_connect_get_session();
if ($fb_session && variable_get('simple_fb_connect_logout_action')) {
$login_helper = new FacebookRedirectLoginHelper('');
$fb_logout_url =& drupal_static('simple_fb_connect_fb_logout_url');
$fb_logout_url = $login_helper
->getLogoutUrl($fb_session, $base_url . '/');
}
}
}
function simple_fb_connect_drupal_goto_alter(&$path, &$options, &$http_response_code) {
$fb_logout_url =& drupal_static('simple_fb_connect_fb_logout_url');
if (empty($path) && $fb_logout_url) {
$path = $fb_logout_url;
}
drupal_static_reset('simple_fb_connect_fb_logout_url');
}
function simple_fb_connect_redirect_to_fb() {
if (!simple_fb_connect_initialize()) {
drupal_goto('user');
}
drupal_session_start();
$return_url = simple_fb_connect_get_return_url();
$login_helper = new FacebookRedirectLoginHelper($return_url);
$scope = simple_fb_connect_get_scope();
simple_fb_connect_save_post_login_url();
$api_version = simple_fb_connect_get_api_version();
$login_url = $login_helper
->getLoginUrl($scope, $api_version);
if (isset($_SESSION['simple_fb_connect']['reprompt'])) {
$scope = array(
'public_profile',
'email',
);
$login_url = $login_helper
->getReRequestUrl($scope, $api_version);
}
drupal_goto($login_url);
return MENU_ACCESS_DENIED;
}
function simple_fb_connect_return_from_fb() {
if (!simple_fb_connect_initialize()) {
drupal_goto('user');
}
$return_url = simple_fb_connect_get_return_url();
$login_helper = new FacebookRedirectLoginHelper($return_url);
if (!simple_fb_connect_save_session($login_helper)) {
drupal_set_message(t("Facebook login failed."), "error");
drupal_goto('user');
}
if (!($fb_session = simple_fb_connect_get_session())) {
drupal_set_message(t("Facebook login failed."), "error");
simple_fb_connect_destroy_session();
drupal_goto('user');
}
if (!simple_fb_connect_check_permission($fb_session, 'email')) {
$site_name = variable_get('site_name');
if ($site_name) {
drupal_set_message(t("Facebook login failed. @site_name requires permission to get your email address from Facebook. Please try again and give the permission.", array(
'@site_name' => $site_name,
)), "error");
}
else {
drupal_set_message(t("Facebook login failed. This site requires permission to get your email address from Facebook. Please try again and give the permission."), "error");
}
$post_login_url = simple_fb_connect_get_post_login_url();
simple_fb_connect_destroy_session();
$_SESSION['simple_fb_connect']['reprompt'] = TRUE;
$_SESSION['simple_fb_connect']['post_login_url'] = $post_login_url;
drupal_goto('user');
}
if (!($fb_profile = simple_fb_connect_get_fb_profile($fb_session))) {
drupal_set_message(t("Facebook login failed."), "error");
simple_fb_connect_destroy_session();
drupal_goto('user');
}
if (!($email = simple_fb_connect_get_email($fb_profile))) {
drupal_set_message(t('Facebook login failed. This site requires an email address. Please add one in your Facebook profile.'), 'error');
simple_fb_connect_destroy_session();
drupal_goto('user');
}
if ($drupal_user = user_load_by_mail($email)) {
if (simple_fb_connect_login_user($drupal_user)) {
$post_login_url = simple_fb_connect_get_post_login_url();
simple_fb_connect_go_to_redirect_url($post_login_url, $drupal_user);
}
else {
simple_fb_connect_destroy_session();
drupal_goto('user');
}
}
if ($drupal_user = simple_fb_connect_create_user($fb_profile, $fb_session)) {
if (simple_fb_connect_login_user($drupal_user)) {
$redirect_to_user_form = variable_get('simple_fb_connect_redirect_user_form', 0);
if ($redirect_to_user_form) {
drupal_set_message(t("Please take a moment to confirm your account details. Since you logged in with Facebook, you don't need to update your password."));
$post_login_url = 'user/' . $drupal_user->uid . '/edit';
simple_fb_connect_go_to_redirect_url($post_login_url, $drupal_user);
}
$post_login_url = simple_fb_connect_get_post_login_url();
simple_fb_connect_go_to_redirect_url($post_login_url, $drupal_user);
}
else {
drupal_set_message(t('You will receive an email when a site administrator activates your account.'), 'warning');
$post_login_url = simple_fb_connect_get_post_login_url();
simple_fb_connect_destroy_session();
simple_fb_connect_go_to_redirect_url($post_login_url, $drupal_user);
}
}
else {
simple_fb_connect_destroy_session();
drupal_goto('user');
}
return MENU_ACCESS_DENIED;
}
function simple_fb_connect_initialize() {
if (version_compare(phpversion(), '5.4.0', '<')) {
drupal_set_message(t('Simple FB Connect is not configured properly.'), 'error');
watchdog('simple_fb_connect', 'Facebook PHP SDK v4 requires PHP 5.4 or higher. Your PHP version is @version', array(
'@version' => phpversion(),
), WATCHDOG_ERROR);
return FALSE;
}
$sdk = libraries_detect('facebook-php-sdk-v4');
if (!is_array($sdk) || !$sdk['installed'] || $sdk['version'] < '4.0' || $sdk['version'] >= '4.1') {
drupal_set_message(t('The Facebook PHP SDK is not properly installed.'), 'error');
watchdog('simple_fb_connect', 'Facebook PHP SDK 4.0.x not found on sites/all/libraries/facebook-php-sdk-v4', array(), WATCHDOG_ERROR);
return FALSE;
}
$app_id = variable_get('simple_fb_connect_appid', 0);
$app_secret = variable_get('simple_fb_connect_skey', 0);
$api_version = variable_get('simple_fb_connect_api_version', 0);
if (!$app_id || !$app_secret || !$api_version) {
drupal_set_message(t('Simple FB Connect not configured properly.'), 'error');
watchdog('simple_fb_connect', 'Could not initialize FB App. Define App ID, App Secret and API Version on module settings.', array(), WATCHDOG_ERROR);
return FALSE;
}
FacebookSession::setDefaultApplication($app_id, $app_secret);
return TRUE;
}
function simple_fb_connect_save_session(FacebookRedirectLoginHelper $login_helper) {
try {
$fb_session = $login_helper
->getSessionFromRedirect();
if ($fb_session) {
$_SESSION['simple_fb_connect']['user_token'] = $fb_session
->getToken();
return TRUE;
}
else {
watchdog('simple_fb_connect', 'Could not start FB session. User cancelled the dialog in FB or return URL was not valid.', array(), WATCHDOG_ERROR);
}
} catch (FacebookRequestException $ex) {
watchdog('simple_fb_connect', 'Could not save FB session. FacebookRequestException: @message', array(
'@message' => json_encode($ex
->getResponse()),
), WATCHDOG_ERROR);
} catch (\Exception $ex) {
watchdog('simple_fb_connect', 'Could not save FB session. Exception: @message', array(
'@message' => $ex
->getMessage(),
), WATCHDOG_ERROR);
}
return FALSE;
}
function simple_fb_connect_get_session() {
static $fb_session = NULL;
if (is_null($fb_session)) {
if (isset($_SESSION['simple_fb_connect']['user_token'])) {
$user_token = $_SESSION['simple_fb_connect']['user_token'];
try {
$fb_session = new FacebookSession($user_token);
$fb_session
->validate();
return $fb_session;
} catch (FacebookRequestException $ex) {
watchdog('simple_fb_connect', 'Could not load FB session. FacebookRequestException: @message', array(
'@message' => json_encode($ex
->getResponse()),
), WATCHDOG_NOTICE);
} catch (\Exception $ex) {
watchdog('simple_fb_connect', 'Could not load FB session. Exception: @message', array(
'@message' => $ex
->getMessage(),
), WATCHDOG_ERROR);
}
}
$fb_session = FALSE;
}
return $fb_session;
}
function simple_fb_connect_destroy_session() {
foreach ($_SESSION as $key => $value) {
if ($key != 'messages') {
unset($_SESSION[$key]);
}
}
}
function simple_fb_connect_check_permission(FacebookSession $fb_session, $permission_to_check) {
try {
$api_version = simple_fb_connect_get_api_version();
$request = new FacebookRequest($fb_session, 'GET', '/me/permissions', NULL, $api_version);
$permissions = $request
->execute()
->getGraphObject()
->asArray();
foreach ($permissions as $permission) {
if ($permission->permission == $permission_to_check && $permission->status == 'granted') {
return TRUE;
}
}
} catch (FacebookRequestException $ex) {
watchdog('simple_fb_connect', 'Error checking permission: FacebookRequestException. Error details: @message', array(
'@message' => json_encode($ex
->getResponse()),
), WATCHDOG_WARNING);
} catch (\Exception $ex) {
watchdog('simple_fb_connect', 'Error checking permission: Unhandled exception. Error details: @message', array(
'@message' => $ex
->getMessage(),
), WATCHDOG_WARNING);
}
return FALSE;
}
function simple_fb_connect_get_fb_profile(FacebookSession $fb_session) {
try {
$api_version = simple_fb_connect_get_api_version();
$request = new FacebookRequest($fb_session, 'GET', '/me', array(
'fields' => 'id,name,email',
), $api_version);
$object = $request
->execute()
->getGraphObject();
return $object;
} catch (FacebookRequestException $ex) {
watchdog('simple_fb_connect', 'Could not load FB user profile: FacebookRequestException. Error details: @message', array(
'@message' => json_encode($ex
->getResponse()),
), WATCHDOG_ERROR);
} catch (\Exception $ex) {
watchdog('simple_fb_connect', 'Could not load FB user profile: Unhandled exception. Error details: @message', array(
'@message' => $ex
->getMessage(),
), WATCHDOG_ERROR);
}
return FALSE;
}
function simple_fb_connect_get_fb_profile_pic(FacebookSession $fb_session) {
$dimensions_in_text = variable_get('user_picture_dimensions', SIMPLE_FB_CONNECT_DEFAULT_DIMENSIONS_STRING);
$dimensions = explode('x', $dimensions_in_text);
if (count($dimensions) == 2) {
$width = $dimensions[0];
$height = $dimensions[1];
}
else {
$width = SIMPLE_FB_CONNECT_DEFAULT_WIDTH;
$height = SIMPLE_FB_CONNECT_DEFAULT_HEIGHT;
}
$picture_directory = file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures/');
if (!file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY)) {
watchdog('simple_fb_connect', 'Could not save FB profile picture. Directory is not writeable: @picture_directory', array(
'@picture_directory' => $picture_directory,
), WATCHDOG_ERROR);
return FALSE;
}
$api_version = simple_fb_connect_get_api_version();
try {
$request = new FacebookRequest($fb_session, 'GET', '/me/picture', array(
'width' => $width,
'height' => $height,
'redirect' => 'false',
), $api_version);
$graph_object = $request
->execute()
->getGraphObject();
$is_default_picture = (bool) $graph_object
->getProperty('is_silhouette');
if ($is_default_picture) {
return FALSE;
}
$picture_url = $graph_object
->getProperty('url');
$fb_user_id = $fb_session
->getSessionInfo()
->getProperty('user_id');
$destination = file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures') . '/' . check_plain($fb_user_id) . '.jpg';
if ($file = system_retrieve_file($picture_url, $destination, TRUE, FILE_EXISTS_REPLACE)) {
return $file->fid;
}
else {
watchdog('simple_fb_connect', 'Could not save FB profile picture. Check that directory is writeable: @destination', array(
'@destination' => $destination,
), WATCHDOG_ERROR);
}
} catch (FacebookRequestException $ex) {
watchdog('simple_fb_connect', 'Could not load FB profile picture: FacebookRequestException. Error details: @message', array(
'@message' => json_encode($ex
->getResponse()),
), WATCHDOG_ERROR);
} catch (\Exception $ex) {
watchdog('simple_fb_connect', 'Could not load FB profile picture: Unhandled exception. Error details: @message', array(
'@message' => $ex
->getMessage(),
), WATCHDOG_ERROR);
}
return FALSE;
}
function simple_fb_connect_get_email(GraphObject $fb_profile) {
if ($email = $fb_profile
->getProperty('email')) {
return $email;
}
watchdog('simple_fb_connect', 'No email address in FB user profile', array(), WATCHDOG_ERROR);
return FALSE;
}
function simple_fb_connect_get_scope() {
$scope = array();
if (count(module_implements('simple_fb_connect_scope_info')) > 0) {
$scope = module_invoke_all('simple_fb_connect_scope_info', array());
}
$scope[] = 'public_profile';
$scope[] = 'email';
return $scope;
}
function simple_fb_connect_create_user(GraphObject $fb_profile, FacebookSession $fb_session) {
if (!variable_get('user_register', 1)) {
drupal_set_message(t('Creation of new accounts on this site is disabled.'), 'error');
watchdog('simple_fb_connect', 'Failed to create user. User registration is disabled in Drupal account settings.', array(), WATCHDOG_WARNING);
return FALSE;
}
if (variable_get('simple_fb_connect_login_only', 0)) {
drupal_set_message(t('Only registered users can log in with Facebook.'), 'error');
watchdog('simple_fb_connect', 'Failed to create user. User registration is disabled in Simple FB Connect settings.', array(), WATCHDOG_WARNING);
return FALSE;
}
if ($fb_profile && $fb_session) {
$real_name = $fb_profile
->getProperty('name');
$email = $fb_profile
->getProperty('email');
$drupal_username_generated = simple_fb_connect_unique_user_name($real_name);
if ($drupal_username_generated === FALSE) {
watchdog('simple_fb_connect', 'Could not create new user, username contains illegal characters.', array(), WATCHDOG_ERROR);
drupal_set_message(t("Username contains illegal characters."), 'error');
return FALSE;
}
$password = user_password(32);
$fields = array(
'name' => $drupal_username_generated,
'mail' => $email,
'pass' => $password,
'status' => variable_get('user_register', 1) == 1 ? 1 : 0,
'init' => $email,
'roles' => array(
DRUPAL_AUTHENTICATED_RID => 'authenticated user',
),
);
if (drupal_multilingual()) {
global $language;
$fields['language'] = $language->language;
}
drupal_alter("simple_fb_connect_register", $fields, $fb_profile);
$account = user_save('', $fields);
if ($account) {
if (variable_get('user_pictures', 0)) {
if ($fid = simple_fb_connect_get_fb_profile_pic($fb_session)) {
$file = file_load($fid);
$file->uid = $account->uid;
file_save($file);
$edit = array(
'picture' => $file,
);
$account = user_save($account, $edit);
}
}
watchdog('simple_fb_connect', 'New user created: @username', array(
'@username' => $drupal_username_generated,
), WATCHDOG_NOTICE);
drupal_set_message(t("New user account %username created.", array(
'%username' => $drupal_username_generated,
)));
if (module_exists('rules')) {
rules_invoke_event('simple_fb_connect_registration', $account);
}
module_invoke_all('simple_fb_connect_registration', $account);
return $account;
}
}
drupal_set_message(t("Error while creating a new user account."), 'error');
watchdog('simple_fb_connect', 'Could not create new user.', array(), WATCHDOG_ERROR);
return FALSE;
}
function simple_fb_connect_login_user($drupal_user) {
if (simple_fb_connect_login_disabled_for_admin($drupal_user)) {
drupal_set_message(t('FB login is disabled for site administrator. Please login with your local user account.'), 'error');
return FALSE;
}
if (simple_fb_connect_login_disabled_by_role($drupal_user)) {
drupal_set_message(t('FB login is disabled for your role. Please login with your local user account.'), 'error');
return FALSE;
}
if ($drupal_user->status) {
$form_state['uid'] = $drupal_user->uid;
user_login_submit(array(), $form_state);
if (module_exists('rules')) {
rules_invoke_event('simple_fb_connect_login', $drupal_user);
}
module_invoke_all('simple_fb_connect_login', $drupal_user);
if (module_exists('boost')) {
boost_set_cookie($drupal_user->uid);
}
return TRUE;
}
drupal_set_message(t('You could not be logged in because your account %username is not active.', array(
'%username' => $drupal_user->name,
)), 'warning');
watchdog('simple_fb_connect', 'FB login for user %user prevented. Account is blocked.', array(
'%user' => $drupal_user->name,
), WATCHDOG_WARNING);
return FALSE;
}
function simple_fb_connect_login_disabled_for_admin($drupal_user) {
if ($drupal_user->uid == 1 && variable_get('simple_fb_connect_disable_admin_login', 1)) {
watchdog('simple_fb_connect', 'FB login for user %user prevented. FB login for site administrator (user 1) is disabled in module settings.', array(
'%user' => $drupal_user->name,
), WATCHDOG_WARNING);
return TRUE;
}
return FALSE;
}
function simple_fb_connect_login_disabled_by_role($drupal_user) {
$roles = variable_get('simple_fb_connect_disabled_roles', array());
foreach ($drupal_user->roles as $role) {
if (array_key_exists($role, $roles) && !empty($roles[$role])) {
watchdog('simple_fb_connect', 'FB login for user %user prevented. FB login for role %role is disabled in module settings.', array(
'%user' => $drupal_user->name,
'%role' => $role,
), WATCHDOG_WARNING);
return TRUE;
}
}
return FALSE;
}
function simple_fb_connect_unique_user_name($fb_name) {
$fb_name = drupal_substr($fb_name, 0, USERNAME_MAX_LENGTH);
$base = $fb_name;
$i = 1;
$candidate = $base;
while (is_object(user_load_by_name($candidate))) {
$i++;
$max_length_base = USERNAME_MAX_LENGTH - strlen((string) $i) - 1;
$base = drupal_substr($base, 0, $max_length_base);
$candidate = $base . " " . $i;
}
$candidate = trim($candidate);
$candidate = preg_replace('/ {2,}/', ' ', $candidate);
if ($error = user_validate_name($candidate)) {
return FALSE;
}
return $candidate;
}
function simple_fb_connect_get_post_login_url() {
$post_login_url = variable_get('simple_fb_connect_post_login_url', 'user');
if (isset($_SESSION['simple_fb_connect']['post_login_url'])) {
$post_login_url = $_SESSION['simple_fb_connect']['post_login_url'];
}
return $post_login_url;
}
function simple_fb_connect_save_post_login_url() {
$destination = drupal_get_destination();
if (!url_is_external($destination['destination']) && $destination['destination'] != 'user/simple-fb-connect') {
$_SESSION['simple_fb_connect']['post_login_url'] = $destination['destination'];
unset($_GET['destination']);
}
}
function simple_fb_connect_go_to_redirect_url($post_login_url, $account) {
$url_parts = drupal_parse_url($post_login_url);
$path = $url_parts['path'];
$options = array(
'query' => $url_parts['query'],
);
if (count(module_implements('simple_fb_connect_redirect_url')) > 0) {
list($path, $options) = module_invoke_all('simple_fb_connect_redirect_url', $path, $options, $account);
}
drupal_goto($path, $options);
}
function simple_fb_connect_get_return_url() {
$return_url = url('user/simple-fb-connect/return', array(
'absolute' => TRUE,
));
$query_pos = strpos($return_url, '?');
if ($query_pos !== FALSE) {
$url_string = substr($return_url, 0, $query_pos);
$query_string = substr($return_url, $query_pos);
$return_url = $url_string . str_replace('/', '%2F', $query_string);
}
return $return_url;
}
function simple_fb_connect_get_api_version() {
return variable_get('simple_fb_connect_api_version', 0);
}