Using the new Facebook Graph API off-line
One of the features of the old Facebook API was “off-line” access – basically where you could interact with Facebook in a “non-interactive” way : in other words a program or script could interact with Facebook on your behalf without you having to have a Facebook window open in your browser.
The new API also supports this but the documentation is not really totally clear on the “process” needed to do it.
So I sat down and worked it out. The code you are about to see is not neat, or tidy. It contains no proper error handling or checking apart from the bare minimum needed to make it work.
Pre-requisites
You will need:
- A Webserver
- PHP V5.x with CURL enabled
- A MySQL Database.
- A Facebook Account (preferably a developer account unless your friends like being spammed)
- A Facebook Application
- The Facebook Graph PHP-SDK which is available from the GitHub repository.
First of all we need to make sure that we have a table to store the session data in. We are actually storing all the session data : this might be overkill but as a lot of this is still undocumented I felt it was safer to store everything.
So at the start of our example lets do the dirty work with the database. If you were doing this properly you’d have this in a function which you called once, for example with a WordPress plugin you’d call it on plugin activation. But we’re not doing that here so …. and don’t forget to change those db_ parameters to match your system.
$db_server = "localhost";
$db_username = "dbuser";
$db_password = "dbpassword";
$db_name = "dbname";
# Lets connect to the Database and set up the table
mysql_connect($db_server,$db_username,$db_password);
mysql_select_db($db_name);
$ct_res = mysql_query("CREATE TABLE IF NOT EXISTS `facebook_user` (
`session_key` VARCHAR( 80 ) NOT NULL ,
`uid` VARCHAR( 80 ) NOT NULL ,
`expires` VARCHAR( 80 ) NOT NULL ,
`secret` VARCHAR( 80 ) NOT NULL ,
`access_token` VARCHAR( 120 ) NOT NULL ,
`sig` VARCHAR( 80 ) NOT NULL
);"
);
OK So that’s the DB work done and each time we run the script it will create the table if its not there. Now we can set up the Facebook side of things. Don’t forget to change the path for the facebook.php file (which you did download didn’t you?). You’ll also need the information about the Facebook Application you set up because I’m not letting you share mine! You may also want to review the permissions that are being granted – the ones in this code are the ones my Wordbooker application uses
# Now lets load the FB GRAPH API
require '../src/facebook.php';
// Create our Application instance.
global $facebook;
$facebook = new Facebook(array(
'appId' => '101001010101010101',
'secret' => 'faafaffdfasdffsafsfsddfasd',
'cookie' => false,
));
# Lets set up the permissions we need and set the login url in case we need it.
$par['req_perms'] = "publish_stream,
offline_access,
user_status,
read_stream,
email,
user_groups";
$loginUrl = $facebook->getLoginUrl($par);
The “heart” of the code is the get_check_session function. This function checks to see if we have a session stored in the database and if we do it returns it. If we don’t have a session but a session is being passed in via the URL it gets it, stores it and then returns it. If neither of these cases are true it returns nothing.
function get_check_session(){
global $facebook;
# This function basically checks for a stored session and if we have one returns it,
#If we have no stored session then it gets one and stores it
# OK lets go to the database and see if we have a session stored
$sid=mysql_query("Select access_token from facebook_user");
$session_id=mysql_fetch_row($sid);
if (is_array($session_id)) {
# We have a session ID so lets not get a new one
# Put some session checking in here to make sure its valid
try {
$attachment = array('access_token' => $session_id[0],);
$ret_code=$facebook->api('/me', 'GET', $attachment);
}
catch (Exception $e) {
# We don't have a good session so
echo "woops";
$res = mysql_query('delete from facebook_user where expires=0');
return;
}
return $session_id[0];
}
{
# Are we coming back from a login with a session set?
$session = $facebook->getSession();
if (is_array($session)) {
# Yes! so lets store it!
$sql="insert into facebook_user (
session_key,
uid,
expires,
secret,
access_token,
sig)
VALUES ('".$session['session_key']."','".
$session['uid']."','".
$session['expires']."','".
$session['secret'] ."','".
$session['access_token']."','".
$session['sig']."');";
$res = mysql_query($sql);
return $session['access_token'];
}
}
}
OK, believe it or not we are just about there with only a few more lines of code to go. Are you ready?
$access_token=get_check_session();
# If we've not got an access_token we need to login.
if ( is_null($access_token) ) {
echo '<a href="'. $loginUrl.'"><
img src="http://static.ak.fbcdn.net/rsrc.php/zB6N8/hash/4li2k73z.gif" alt="" /> ';
}
else {
# This is where you put your code.
$target=1010101010100110;
$attachment = array(
'access_token' => $access_token,
'message' => 'Did a Test Post :',
'name' => "Offline posting using stored tokens",
'link' => "http://blogs.canalplan.org.uk/steve/2010/05/05/using-the-new-facebook-graph-api-off-line/",
'description' => "This post was made using a stored access token",
'picture'=>http://blogs.canalplan.org.uk/steve/files/2010/05/Screenshot-5-300x194.png",
);
$ret_code=$facebook->api('/'.$target.'/feed', 'POST', $attachment);
echo "Returns : ";
var_dump($ret_code);
echo "";
$attachment = array(
'access_token' => $access_token,
'message' => "and this is a comment I've just made on the post using that same stored token",);
$ret_code=$facebook->api('/'.$ret_code['id'].'/comments', 'POST', $attachment);
echo "Returns : ";
var_dump($ret_code);
echo "";
}
Basically any code in the ELSE {} block is executed if you have a Facebook access_token. In the example what we do is post a message to a “target” which is a FB user ID (you can use names rather than numbers), and then we immediately comment on it. Which produces something like:
So there you go. Why not download the code and give it a go.

May 7th, 2010 at 6:21 pm
Hello from portugal.
Thank you Thank you Thank you Thank you Thank you
Does this work Posting to Page walls as the page
Once Again.
Thank you for your post…
May 10th, 2010 at 12:39 am
Thanks Steve. This is really the first tutorial I could find on Graph API. Thank you so much for the detailed steps.
I keep getting the below error though I changed the target_id manually and made the fan to the app.
Fatal error: Uncaught Exception: (#210) User not visible thrown in facebook.php on line 453
Really appreciate and thanks for the article again.
May 10th, 2010 at 9:07 am
I’ve changed some code to make it do a good solid session check (I hope). When I get home I’ll update the post and update the downloadable file.
Does the user you logged in as have access to the target page and is the target page public?
May 10th, 2010 at 9:53 am
Thank you so much, Steve
I will check back.
May 10th, 2010 at 10:34 am
Yes, Steve
I actually trying to publish to the user’s wall. I have create a temp login wiht facebook and became a fan of the app. Pulled the UID of the temp login and used the same UID in the code.
May 10th, 2010 at 6:29 pm
I’ve updated the post to include the code that checks that the session is valid. The error you are reporting is very odd
May 11th, 2010 at 9:56 am
Wow! It works perfectly now. Thanks Steve.
May 11th, 2010 at 11:02 am
Hi Steven,
Thanks for your code it works very well. However, I tried also to add the “to” parameter in the post feeding, and it seems not to use that. Do you happen to know if it is working? (If FB really let the end user select friends before he can send the message – it seems possible not through the api):
$attachment = array(
‘access_token’ => $access_token,
‘message’ => ‘Did a Test Post :’,
‘name’ => “Offline posting using stored tokens”,
‘link’ => “http://blogs.canalplan.org.uk/steve/2010/05/05/using-the-new-facebook-graph-api-off-line/”,
‘description’ => “This post was made using a stored access token”,
‘picture’=>http://blogs.canalplan.org.uk/steve/files/2010/05/Screenshot-5-300×194.png“,
‘to’ => friend_list, // a list of user ids separate by comma
);
thanks
May 11th, 2010 at 7:31 pm
Nil, I’ve no idea – I’ve not looked at the to option. It could well be that its not implemented yet (or buggy)
May 18th, 2010 at 7:27 pm
greetings from Mexico.
Thank you very much steve. this code works very well
May 19th, 2010 at 8:39 am
Hi
Thanks for tutorial. I need some help. I want to get access token in cron job to update my DB for displaying insights. How can i achieve this. Thanks
Regards
Akbar Ali Butt
May 19th, 2010 at 10:12 am
Once yiu have the token stored in the database you can use it anywhere. As long as it doesn’t expire. So basically take that code and replace the login bit of the code with some error reporting anf wrap it all up in a file with the rest of your code and then call that php file from your cron
May 20th, 2010 at 12:38 am
i tried this code with the last version of php sdk but i obtain a error 500 when i execute it.
Could you upload your facebook.php and a detailed how your aplication is configured.
Pleaseeeeee, i am going mad
May 20th, 2010 at 5:44 am
Error 500 is an Apache internal server error. What is showing in your Apache server error logs?
May 20th, 2010 at 10:38 am
Great tutorial Steve!!!
Since I’m a total newbie to FB developing, this question might sound trivial but well….
After applying your tutorial, I used the following my code:
$target=me;
$ret=$facebook->api(‘/’.$target.’/friends?access_token=’.$access_token);
…
With this code I get the friends of the first user who approved the application and not the current user friends.
Whats wrong with it?
May 20th, 2010 at 11:38 am
Hexi – I’ve no idea, and I’ve no idea you could do that, and it does sound like a bug
May 26th, 2010 at 9:59 pm
Steve – thanks for providing this code example. It works great! Can’t tell you how much time this saved, and was superior to Facebook’s own example.php code in the php-sdk.
May 26th, 2010 at 10:36 pm
Ivan. glad you found it useful.
May 26th, 2010 at 11:02 pm
Hi Steve!
I think I’m not understanding completely.
Is this for “internal” use only? I mean, we are saving the last valid token in our DB for personal use, it’s not associated with any user right?
May 27th, 2010 at 7:01 am
Enrique, if you stored the wordpress user_id against the data then it would become WP user specific – which is just what I do with my wordbooker plugin.
June 2nd, 2010 at 5:56 pm
Thank you very much for this article.
June 4th, 2010 at 9:57 pm
Hi Steve! Thanks for the tutorial. I wasted hours on end, trying to post to the feed, because the attachment was being ignored. Thanks to your tutorial, I saw you added the access_token to the attachment. I don’t see any mention of that in any facebook documentation. Where in the world did you think of adding that element to the attachment object?! Now that I added it, it works. Thanks!
June 4th, 2010 at 11:45 pm
Thomas, glad you’ve got it working. Not sure why I added it – I suspect I either found something buried somewhere deep in the mess that is the FB documentation or it was inspired guesswork on my part!
June 7th, 2010 at 7:21 am
wow MAN thanks for the tutorial! Thank you SO much!
June 9th, 2010 at 5:40 am
Hey Steve, one last question.. Do you have any idea of how to post an action link to the attachment in the context of your tutorial? Again, thanks..
June 9th, 2010 at 6:35 am
thanks so much for your sharing! thanks!
June 9th, 2010 at 5:36 pm
Thomas : the Graph API is actually pretty crap. Action links don’t seem to be supported. You can’t have more than one image per post. If you provide a link and no image then FB goes and basically does a “Facebook Share” on the page and pulls in an image off the page (even if you dont want one). Posting to Fan Page walls as the Page doesn’t work…. and so on and so on.
Facebook really screwed up with this. This is why my application only uses Graph for Authentication and uses REST for everything else
Fred : glad I could help.
June 10th, 2010 at 12:00 am
Steve,
So of course I decided to try programming an FB app just as hey changed there API and rendered most tutorials on the way out. Glad I found your page!
I’m wondering what changes I’d need to make in order to authenticate and get an access token for people who are installing an app? When I tried your code on my test application page it presented me with a “connect with FB” button which I’m assuming is more for people interacting with FB on their own sites.
Thanks for any pointers.
June 13th, 2010 at 8:03 am
A question on get_check_session() function. Is there supposed to be an “else” on line 28?
June 13th, 2010 at 8:03 am
I meant line 24
June 13th, 2010 at 8:25 am
Also, a question on this part:
if ( is_null($access_token) ) {
echo ‘ ‘;
}
I’m kind of confused. With this kind of code, then it is presumed that the user(?) must be logged in on facebook to see this link, then click it. After that, what happens? Where is the user redirected? Is a callback script called after logging in that saves the session data after logging in? If I’m running a cron job, this can’t work, so I’m thinking that this would be called through cURL. Is that right?
June 13th, 2010 at 8:41 am
Mives:
What do you mean is there supposed to be an “else” on line 24?
As for the is_null check. No the $loginUrl is basically a link that will log them in and then prompt for the permissions. If you’ve not set up Canvas or Connect URLs in your Facebook application then the Facebook servers do a redirect back to your page.
If you are running in a cron job then you use this code to obtain the offline session tokens which it stores in the database and you can then use those for your cron job. Your cron job should not run any of this cide.
June 13th, 2010 at 9:35 am
I see. Regarding the access token, the one you obtain is the access token for your app right? Does this mean I don’t have to get the access token per user that authorized my app? BTW here is the code I use to get access token per user (called after user authroizes app).
$data = array(‘type’ => ‘client_cred’,'code’ => $_GET['code'], ‘client_id’ => APP_ID,’client_secret’=>APP_SECRET,’ redirect_uri’=>’http://apps.facebook.com/myapp’);
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, ‘https://graph.facebook.com/oauth/access_token’);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$rs = curl_exec($ch);
curl_close($ch);
$data = explode(“=”,$rs);
$token = $data[1];
June 15th, 2010 at 4:57 am
my app id:136830172993807
mycode
$target=136830172993807;
$attachment = array(
‘access_token’ => $access_token,
‘message’ => ‘Did a Test Post :’,
error message
atal error: Uncaught Exception: (#210) User not visible thrown in C:\Inetpub\vhosts\domain\httpdocs\vartolu\facebook.php on line 453
June 15th, 2010 at 7:30 am
Limitation of the Facebook API – you cannot post to application walls from an application.
June 15th, 2010 at 1:49 pm
avaible publis working facebook.php for scripts.
June 26th, 2010 at 5:56 pm
Hello Steve,
Honestly this is the first tutorial which talks about PHP and Graph. Thanks a lot..
Unfortunately I am getting Uncaught CurlException: 60: SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed thrown in src\facebook.php on line 511 ..
Any pointers would be appreciated !
Dhruv
June 26th, 2010 at 6:06 pm
That would look like its a Facebook SSL certificate issue which isn’t something I can do anything about.
June 26th, 2010 at 6:30 pm
Hello Steve,
Great ! Thanks for your quick response. I solved this but have this problem now
Fatal error: Uncaught Exception: (#210) User not visible thrown in src\facebook.php on line 453 …
and I am using
$target=585907026; This is the ID which I get when I make https://graph.facebook.com/dhruvboruah
I thought since i am the developer of the application this app should work !
Really been struggling with GRAPH and confusions with same name of both the Facebook.php names . Any pointers would be appreciated !
Thanks again !
Dhruv
June 26th, 2010 at 6:32 pm
Is 585907026 the ID of the APP you set up?
If so then it wont work because FB don’t support applications posting to their own pages. I know its completely contrary but that’s Facebook for you.
June 26th, 2010 at 6:38 pm
Thanks again !!!
But no no, 585907026 is my user id, which i for making this call https://graph.facebook.com/dhruvboruah
Kind of stuck now!!!
June 26th, 2010 at 6:41 pm
Then it would suggest that the permissions didn’t get applied properly.
June 26th, 2010 at 6:47 pm
Lastly a basic question !!! How do I apply permissions ? and where ?
I apologize but this is crazy !
June 26th, 2010 at 6:57 pm
Go it … Thanks a ton !!!
Everything is perfect !!! Have a great weekend !!
June 26th, 2010 at 8:11 pm
So its all working now?
June 26th, 2010 at 9:28 pm
Yes, it is working. Thanks !
This was the first step.
I intend to authenticate a user from an iphone app and the do the posting etc on his behalf from the server itself. Now I can store his auth details and hope to play around with the same.
Cheers,
Dhruv
June 28th, 2010 at 10:03 pm
Hello Steve,
I just have one question. I’m developing an app that will post on the wall, almost exact like your example. The only problem is that I can’t post swedish special chars like å ä ö Å Ä Ö. They just disapears in the post. Maybe some kind of filter on facebook? Do you know how to encode those swedish chars? I’ve search all over the net but I can’t find any solution.
It works for me and it saved my many hours
June 28th, 2010 at 10:06 pm
You might need to look at your DB and PHP encoding.
Wordbooker (my App) uses the following :
# Database character_set_client : utf8
# Database character_set_connection : utf8
# Database character_set_database : utf8
# Database character_set_filesystem : binary
# Database character_set_results : utf8
# Database character_set_server : utf8
# Database character_set_system : utf8
# Database character_sets_dir : /usr/share/mysql/charsets/
# Database collation_connection : utf8_general_ci
# Database collation_database : utf8_general_ci
# Database collation_server : utf8_general_ci
And I’ve posted Swedish and German and Malaysian test posts with no problems.
June 28th, 2010 at 10:35 pm
I found the solution myself
I had mixed up the to parameter and from
This is working for me:
$MyMessage = mb_convert_encoding($MyMessage,”utf-8″,”iso-8859-1″);
June 29th, 2010 at 7:52 am
Be warned that some PHP installs don’t have multibyte support.
June 29th, 2010 at 8:18 am
Thanks for your sharing! Great solution! One question: is it possible to add video as attachment?
Thanks,
Dimitriy