OK here is the work so far this is going to be a fairly long post but at the moment this is what happens:
- Displays Facebook connect button
- on click of button user is authenticated against facebook
- A user account is added to modx webusers under facebook group
- user is logged into modx webuser account
- next time user visits they are simply logged into modx webuser account using facebook
So here are the steps:
1) create a face book app account using the details here
http://wiki.developers.facebook.com/index.php/Trying_Out_Facebook_Connect. Make a note of the public and private keys you will need both later.
2) Now back in modx create a plugin with the following code
$e = $modx->Event;
$startscript = '<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js" type="text/javascript"></script> <script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script> ';
$endscript = '<script type="text/javascript"> FB.init("'.$account.'","xd_receiver.htm"); </script> ';
$htmlcode = ' xmlns:fb="http://www.facebook.com/2008/fbml "';
switch ($e->name) {
case "OnWebPagePrerender":
$o = &$modx->documentOutput; // get a reference of the output
$o = str_replace("<body>","<body>".$startscript,$o);
$o = str_replace("</body>",$endscript."</body>",$o);
$o = str_replace("<html","<html".$htmlcode,$o);
break;
default :
return; // stop here - this is very important.
break;
}
Then click on configuration tab of the plugin and paste the following into the plug in configuration box.
then enter your facebook app public api into the paramiter value box.
now click on the system events tab and select OnWebPagePrerender.
3) Create a document in the root of your site called xd_receiver.htm with the following :
a) blank template
b) turn rich text off
c) this code in the content
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<body>
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js" type="text/javascript"></script>
</body>
</html>
4) now create a chuck called connectbutton and paste the following
<script type="text/javascript">
function update_user_box()
Var url = "http://[b]urlofyouraddpage[/b]"; // you will create this page next
{
$.ajax({
type: "POST",
url:url,
data: "save=yes",
success: function(msg){
var user_box = document.getElementById("user");
user_box.innerHTML =msg;
FB.XFBML.Host.parseDomTree();
}
});
}
</script>
<fb:login-button onlogin="update_user_box();"></fb:login-button>
<a href="[+id+]" onclick='FB.Connect.logoutAndRedirect("/test")'>Logout</a>
In the variable you are going to set this to the url of the adduser page that we will now create.
5) create a new page called adduser.php
in the content type [!facebook!] set to blank template and turn rich text off.
make sure you change url in step 4 to match this document.
6) now create a snippet called facebook and paste the following
<?php
// Copyright 2007 Facebook Corp. All Rights Reserved.
//
// Application: edley
// File: 'index.php'
// This is a sample skeleton for your application.
//
require_once 'assets/snippets/facebook/php/facebook.php';
$appapikey = ' '; //enter your public api key here
$appsecret = ''; //enter your private api key here
$facebook = new Facebook($appapikey, $appsecret);
$user_id = $facebook->require_login();
$nlxAdded = '<span> <fb:profile-pic uid='.$user_id.' facebook-logo=true></fb:profile-pic> Welcome, <fb:name uid='.$user_id.' useyou=false></fb:name>. You are signed in with your Facebook account.</span>';
$user_details=$facebook->api_client->users_getStandardInfo($user_id, array('last_name','first_name','proxied_email'));
$data['first_name']=$user_details[0]['first_name'];
$data['last_name']=$user_details[0]['last_name'];
$data['email']=$user_details[0]['proxied_email'];
$usergroup="facebook";
$result = $modx->db->select('username',$modx->getFullTableName('web_users')," username = '".$user_id."'");
if($modx->db->getRecordCount($result) != 1)
{
// add user
$pass = md5($user_id.'facebook'); //change the word facebook to a random set of letters and numbers of your choice
$sql = "INSERT INTO ".$modx->getFullTableName('web_users')." (username,password) VALUES ('".$user_id."', '".$pass."')";
$rs = $modx->db->query($sql);
if(!$rs) {
return '<span class="error">'.$nlxError.'</span><br />' . $nlxForm;
} else {
$uid = $modx->db->getInsertId();
// add data to web_user_attributes
$sql = "INSERT INTO ".$modx->getFullTableName('web_user_attributes')." (internalKey,fullname,email) VALUES (".$uid.",'".$data['first_name']." ".$data['last_name']."','".$data['email']."')";
$rs = $modx->db->query($sql);
if(!$rs) {
$modx->db->delete($modx->getFullTableName('web_users'),"id = ".$uid);
return '<span class="error">'.$nlxError.'</span><br />' . $nlxForm;
} else {
// add user to the group
$result = $modx->db->select('id',$modx->getFullTableName('webgroup_names'),"name = '".$usergroup."'");
if($modx->db->getRecordCount($result) == 1) {
$gid = $modx->db->getValue($result);
}
$sql = "INSERT INTO ".$modx->getFullTableName('web_groups')." (webgroup, webuser) VALUES (".$gid.",".$uid.")";
$result = $modx->db->query($sql);
if($result) {
if(isset($sendadmin)) { sendMail($sendadmin,"admin","in"); }
if($senduser != 0) { sendMail($email,"user","in"); }
login($user_id);
return '<span class="important">'.$nlxAdded.'</span>';
} else {
return '<span class="error">'.$nlxError.'</span><br />' . $nlxForm;
}
}
}
}
else
{
login($user_id);
return '<span class="important">'.$nlxAdded.'</span>';}
function login($user) {
# process login
global $modx;
defined('IN_PARSER_MODE') or die();
$dbase = $modx->dbConfig['dbase'];
$table_prefix = $modx->dbConfig['table_prefix'];
$logindetails = array();
$logindetails['username'] = $user;
$logindetails['givenPass'] = $user.'facebook'; //change the word facebook to a random set of letters and numbers that you set earlier
$username = $modx->db->escape(strip_tags($logindetails['username']));
$givenPassword = $modx->db->escape($logindetails['givenPass']);
//$captcha_code = isset($_POST['captcha_code'])? $_POST['captcha_code']: '';
//$rememberme = $_POST['rememberme'];
// invoke OnBeforeWebLogin event
$modx->invokeEvent("OnBeforeWebLogin",
array(
"username" => $username,
"userpassword" => $givenPassword,
"rememberme" => $rememberme
));
$sql = "SELECT $dbase.`".$table_prefix."web_users`.*, $dbase.`".$table_prefix."web_user_attributes`.* FROM $dbase.`".$table_prefix."web_users`, $dbase.`".$table_prefix."web_user_attributes` WHERE BINARY $dbase.`".$table_prefix."web_users`.username = '".$username."' and $dbase.`".$table_prefix."web_user_attributes`.internalKey=$dbase.`".$table_prefix."web_users`.id;";
$ds = $modx->db->query($sql);
$limit = $modx->db->getRecordCount($ds);
if($limit==0 || $limit>1) {
$output = webLoginAlert("Incorrect username or password entered!");
return;
}
$row = $modx->db->getRow($ds);
$internalKey = $row['internalKey'];
$dbasePassword = $row['password'];
$failedlogins = $row['failedlogincount'];
$blocked = $row['blocked'];
$blockeduntildate = $row['blockeduntil'];
$blockedafterdate = $row['blockedafter'];
$registeredsessionid = $row['sessionid'];
$role = $row['role'];
$lastlogin = $row['lastlogin'];
$nrlogins = $row['logincount'];
$fullname = $row['fullname'];
//$sessionRegistered = checkSession();
$email = $row['email'];
// load user settings
if($internalKey){
$result = $modx->db->query("SELECT setting_name, setting_value FROM ".$dbase.".`".$table_prefix."web_user_settings` WHERE webuser='$internalKey'");
while ($row = $modx->fetchRow($result, 'both')) $modx->config[$row[0]] = $row[1];
}
if($failedlogins>=$modx->config['failed_login_attempts'] && $blockeduntildate>time()) { // blocked due to number of login errors.
session_destroy();
session_unset();
$output = webLoginAlert("Due to too many failed logins, you have been blocked!");
return;
}
if($failedlogins>=$modx->config['failed_login_attempts'] && $blockeduntildate<time()) { // blocked due to number of login errors, but get to try again
$sql = "UPDATE $dbase.`".$table_prefix."web_user_attributes` SET failedlogincount='0', blockeduntil='".(time()-1)."' where internalKey=$internalKey";
$ds = $modx->db->query($sql);
}
if($blocked=="1") { // this user has been blocked by an admin, so no way he's loggin in!
session_destroy();
session_unset();
$output = webLoginAlert("You are blocked and cannot log in!");
return;
}
// blockuntil
if($blockeduntildate>time()) { // this user has a block until date
session_destroy();
session_unset();
$output = webLoginAlert("You are blocked and cannot log in! Please try again later.");
return;
}
// blockafter
if($blockedafterdate>0 && $blockedafterdate<time()) { // this user has a block after date
session_destroy();
session_unset();
$output = webLoginAlert("You are blocked and cannot log in! Please try again later.");
return;
}
// allowed ip
if (isset($modx->config['allowed_ip'])) {
if (strpos($modx->config['allowed_ip'],$_SERVER['REMOTE_ADDR'])===false) {
$output = webLoginAlert("You are not allowed to login from this location.");
return;
}
}
// allowed days
if (isset($modx->config['allowed_days'])) {
$date = getdate();
$day = $date['wday']+1;
if (strpos($modx->config['allowed_days'],"$day")===false) {
$output = webLoginAlert("You are not allowed to login at this time. Please try again later.");
return;
}
}
// invoke OnWebAuthentication event
$rt = $modx->invokeEvent("OnWebAuthentication",
array(
"userid" => $internalKey,
"username" => $username,
"userpassword" => $givenPassword,
"savedpassword" => $dbasePassword,
"rememberme" => $rememberme
));
// check if plugin authenticated the user
if (!$rt||(is_array($rt) && !in_array(TRUE,$rt))) {
// check user password - local authentication
if($dbasePassword != md5($givenPassword)) {
$output = webLoginAlert("Incorrect username or password entered!");
$newloginerror = 1;
}
}
if(isset($modx->config['use_captcha']) && $modx->config['use_captcha']==1) {
if($_SESSION['veriword']!=$captcha_code) {
$output = webLoginAlert("The security code you entered didn't validate! Please try to login again!");
$newloginerror = 1;
}
}
if(isset($newloginerror) && $newloginerror==1) {
$failedlogins += $newloginerror;
if($failedlogins>=$modx->config['failed_login_attempts']) { //increment the failed login counter, and block!
$sql = "update $dbase.`".$table_prefix."web_user_attributes` SET failedlogincount='$failedlogins', blockeduntil='".(time()+($modx->config['blocked_minutes']*60))."' where internalKey=$internalKey";
$ds = $modx->db->query($sql);
} else { //increment the failed login counter
$sql = "update $dbase.`".$table_prefix."web_user_attributes` SET failedlogincount='$failedlogins' where internalKey=$internalKey";
$ds = $modx->db->query($sql);
}
session_destroy();
session_unset();
return;
}
$currentsessionid = session_id();
if(!isset($_SESSION['webValidated'])) {
$sql = "update $dbase.`".$table_prefix."web_user_attributes` SET failedlogincount=0, logincount=logincount+1, lastlogin=thislogin, thislogin=".time().", sessionid='$currentsessionid' where internalKey=$internalKey";
$ds = $modx->db->query($sql);
}
$_SESSION['webShortname']=$username;
$_SESSION['webFullname']=$fullname;
$_SESSION['webEmail']=$email;
$_SESSION['webValidated']=1;
$_SESSION['webInternalKey']=$internalKey;
$_SESSION['webValid']=base64_encode($givenPassword);
$_SESSION['webUser']=base64_encode($username);
$_SESSION['webFailedlogins']=$failedlogins;
$_SESSION['webLastlogin']=$lastlogin;
$_SESSION['webnrlogins']=$nrlogins;
$_SESSION['webUserGroupNames'] = ''; // reset user group names
// get user's document groups
$dg='';$i=0;
$tblug = $dbase.".`".$table_prefix."web_groups`";
$tbluga = $dbase.".`".$table_prefix."webgroup_access`";
$sql = "SELECT uga.documentgroup
FROM $tblug ug
INNER JOIN $tbluga uga ON uga.webgroup=ug.webgroup
WHERE ug.webuser =".$internalKey;
$ds = $modx->db->query($sql);
while ($row = $modx->db->getRow($ds,'num')) $dg[$i++]=$row[0];
$_SESSION['webDocgroups'] = $dg;
if($rememberme) {
$_SESSION['modx.web.session.cookie.lifetime']= intval($modx->config['session.cookie.lifetime']);
} else {
$_SESSION['modx.web.session.cookie.lifetime']= 0;
}
//$log = new logHandler;
//$log->initAndWriteLog("Logged in", $_SESSION['webInternalKey'], $_SESSION['webShortname'], "58", "-", "WebLogin");
// get login home page
$ok=false;
if(isset($modx->config['login_home']) && $id=$modx->config['login_home']) {
if ($modx->getPageInfo($id)) $ok = true;
}
if (!$ok) {
// check if a login home id page was set
foreach($liHomeId as $id) {
$id = trim($id);
if ($modx->getPageInfo($id)) {$ok=true; break;}
}
}
// update active users list if redirectinq to another page
if($id!=$modx->documentIdentifier) {
if (getenv("HTTP_CLIENT_IP")) $ip = getenv("HTTP_CLIENT_IP");else if(getenv("HTTP_X_FORWARDED_FOR")) $ip = getenv("HTTP_X_FORWARDED_FOR");else if(getenv("REMOTE_ADDR")) $ip = getenv("REMOTE_ADDR");else $ip = "UNKNOWN";$_SESSION['ip'] = $ip;
$itemid = isset($_REQUEST['id']) ? $_REQUEST['id'] : 'NULL' ;$lasthittime = time();$a = 998;
if($a!=1) {
// web users are stored with negative id
$sql = "REPLACE INTO $dbase.`".$table_prefix."active_users` (internalKey, username, lasthit, action, id, ip) values(-".$_SESSION['webInternalKey'].", '".$_SESSION['webShortname']."', '".$lasthittime."', '".$a."', ".$itemid.", '$ip')";
if(!$ds = $modx->db->query($sql)) {
$output = "error replacing into active users! SQL: ".$sql;
return;
}
}
}
// invoke OnWebLogin event
$modx->invokeEvent("OnWebLogin",
array(
"userid" => $internalKey,
"username" => $username,
"userpassword" => $givenPassword,
"rememberme" => $_POST['rememberme']
));
// redirect
if(isset($_REQUEST['refurl']) && !empty($_REQUEST['refurl'])) {
// last accessed page
$targetPageId= urldecode($_REQUEST['refurl']);
if (strpos($targetPageId, 'q=') !== false) {
$urlPos = strpos($targetPageId, 'q=')+2;
$alias = substr($targetPageId, $urlPos);
$aliasLength = (strpos($alias, '&'))? strpos($alias, '&'): strlen($alias);
$alias = substr($alias, 0, $aliasLength);
$url = $modx->config['base_url'] . $alias;
} elseif (intval($targetPageId)) {
$url = $modx->makeUrl($targetPageId);
} else {
$url = urldecode($_REQUEST['refurl']);
}
$modx->sendRedirect($url);
}
return;
}
?>
Remember to set both api keys and also a random password in the two places indicated by comments (note: this really should be set by snippet parameters I will add this late)
7) now on the pages you want the login button to appear add the following
<div id="user"> {{connectbutton}} </div>
EDIT : opps forgot to say you need to set up a user and document group called facebook and link the two
EDIT 2 : Also download http://svn.facebook.com/svnroot/platform/clients/packages/facebook-platform.tar.gz unzip and then upload the two folders in side to assets/snipets/facebook you need to be able to reach the folders via /assets/snipets/facebook/php and /assets/snipets/facebook/footprints not /assets/snipets/facebook/facebook-platform/php
So what I am saying is don’t just upload the facebook-platform to the facebook folder upload the 2 folders inside facebook-platform
If that all makes sense
I am pretty sure that was all the steps needed so far if you find this does not work the please post with any error messages and I will recheck if anything is missing.
If you want to see this working please visit
http://www.cww.org.uk
A big thanks to Saidur Rahman at
http://fbcookbook.ofhas.in/2009/02/11/dealing-with-ajax-on-fbconnect/ for the AJAX code.
Raymond Irving for the weblogin code plus those on here who pointed me to the right parts of the weblogin code
And sottwell for the registerX snippet whose user account creation code I borrowed.