I've created a iframe facebook app and i want to disable the app outside of facebook, that the user can't open the app via direct url. I found a solution with javascript, but i need it in PHP.
I can't use the referrer, because some user have disabled it in there browser...
You can check if there's signed_request param sent in request.
If application is opened inside facebook than signed_request exists.
But there's one more issue.
You should check if signed_request is valid and for that you can use parse_signed_request method
public function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
// decode the data
$sig = $this->base64_url_decode($encoded_sig);
$data = json_decode($this->base64_url_decode($payload), true);
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
error_log('Unknown algorithm. Expected HMAC-SHA256');
return null;
}
// check sig
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
Then you can check if $data['user_id'] exist or is it equal to logged in user.
If not you can redirect like this
echo "< script type='text/javascript' >top.location.href = '$this->loginUrl'; < /script >";
Or find some way to redirect from php. (There was redirect method in the old php sdk)
Your only real option would be to attempt to use the Facebook API somehow, and see if you get any response.
Related
I am having one facebook pagetab application and I am stuck in following situation
I need to check if user login or not
if not then redirect to login url with user_likes,publish_actions,email permissions
and also user has liked page or not.
if not liked then show the like gate
Now in above I am stuck following error which I am getting in FB pagetab (iFRAM)
Refused to display 'https://www.facebook.com/v2.0/dialog/oauth?client_id=839424369402407&redire…c8682d9a9fb5b&sdk=php-sdk-4.0.9&scope=email%2Cuser_likes%2Cpublish_actions' in a frame because it set 'X-Frame-Options' to 'DENY'.
Now I am think to implement the flow with JS sdk, get the access token and then pass it to php code using ajax call
Is there any better way to solve this situation??
here is the code
try {
$session = $helper->getSessionFromRedirect();
} catch(FacebookRequestException $ex) {
error_log($ex->getCode());
error_log($ex->getMessage());
} catch(\Exception $ex) {
error_log($ex->getCode());
error_log($ex->getMessage());
}
if($_GET['error']=="access_denied"){
header("location:/login/");
exit;
}else if (isset($session) || (isset($_SESSION['fb_user_session_access_token'])) && !empty($_SESSION['fb_user_session_access_token'])) {
if(isset($session))
$_SESSION['fb_user_session_access_token'] = $session->getToken();
else{
$access_token = $_SESSION['fb_user_session_access_token'];
$session = new FacebookSession($access_token);
}
try {
$user_profile = (new FacebookRequest(
$session, 'GET', '/me'
))->execute()->getGraphObject(GraphUser::className());
$email = $user_profile->getProperty('email');
$name = $user_profile->getProperty('name');
$fb_id = $user_profile->getProperty('id');
$query = mysql_query("select id, email from ntuc_users where email = '$email'");
$user_found = mysql_num_rows($query);
if(!$user_found){
//code deleted
exit;
} catch(FacebookRequestException $e) {
error_log($e->getCode());
error_log($e->getMessage());
//if token get expired
$loginUrl = $helper->getLoginUrl(array('req_perms' => 'email'));
header("location:".$loginUrl);
exit;
}
}
else
{
$loginUrl = $helper->getLoginUrl(array('req_perms' => 'email'));
header("location:".$loginUrl);
exit;
}
thanks in advanced
After 2 days research, I got this.. here is the flow which I have implemented for my app
#BjörnKaiser mentioned Facebook policy doesn't support LIKEGATE anymore.. and its true ..
So I have go through FB policy and got the following ans
Only incentivize a person to log into your app, like your app’s Page, enter a promotion on your app’s Page, or check-in at a place. Don’t incentivize other actions. Effective November 5th, 2014, you may no longer incentivize people to like your app's Page
FB POLICY
However as ref. to above information, i tried to implement likegate flow but FB hardluck with FB APP review team
But I got one more ref. from the review team
Please note that using "user_likes" to check if someone has liked your Facebook use case is not approvable. User_likes provides information to all of a person's likes, and the entirety of this data should be used to enhance the app experience. If you need to determine who has already liked your page, please use signed requests for Page Tab apps.
FB USER LIKE POLICY
Using signed requests, at least for pagetab it works like a charm :).. but for mobile website, I have removed the it
Here is the code:
if( isset($_REQUEST['signed_request']) )
{
$user_data = $this->parse_signed_request($_REQUEST['signed_request']);
$access_token = $_SESSION['fb_user_session_access_token'];
}
if( (isset($user_data['page']["liked"]) && !empty($user_data['page']["liked"]) && $user_data['page']["liked"]) || $this->deviceType != "computer")//no like gate for mobile
{
//my code ...
}
private function parse_signed_request($signed_request) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
$secret = FB_APP_SECRET; // Use your app secret here
// decode the data
$sig = $this->base64_url_decode($encoded_sig);
$data = json_decode($this->base64_url_decode($payload), true);
// confirm the signature
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
$this->log->write('Bad Signed JSON signature!');
return null;
}
return $data;
}
private function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
I hope it helps someone else...
We developed a facebook application as tab application using FBML. Now Facebook had deprecated the fbml and we are converting our application to iframe. For this the user can create a FB page and add the application to their facebook page. We are taking the user's facebook page id and check in the DB with this page id and showing the data for that particular user. In the FBML tab application we are getting the facebook page id as a request($REQUEST['page_id']). This seems to no longer work.
When we convert the application to IFRAME tab application, FB is not providing the page id. We are not using GRAPH API and there is any authentication before viewing the application. I had read from a forum that facebook signed request, we will get the page id and used the following code and not getting any data.
$sgrequest = $_REQUEST['signed_request'];
$requestVal = parse_signed_request($sgrequest,$secret);
print_r($requestVal);
$_REQUEST['signed_request']['app_data']
function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
// decode the data
$sig = base64_url_decode($encoded_sig);
$data = json_decode(base64_url_decode($payload), true);
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
error_log('Unknown algorithm. Expected HMAC-SHA256');
return null;
}
// check sig
$expected_sig = hash_hmac('vctly987', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
Is there any other way to get the page id of the fan page through javascript or any other method?
have you tried printing out $requestVal[page][id] after parsing the signed request?
according to the documentation, the signed request contains an array called 'page' that contains the key 'id'. This stores the value of the page's id number.
Can you make sure you enable the migration setting signed_request for Canvas in your App https://developers.facebook.com/apps/.
App Settings -> Advanced
So I'm fairly new to Facebook dev and PHP dev so please bare with.
I've created an iframe Facebook application. I have no trouble grabbing a signed request and using that information to do basic tasks on my page.
The real problem happens when I start navigating around my application within Facebook. I seem to lose my signed request information.
I have my PHP code included on every page and I still can't retain my signed request or session.... whatever its called.
I've pasted my basic PHP code below.
<?php
include_once "../lib/facebook.php";
$facebook = new Facebook(array(
"appId" => FACEBOOK_APP_ID,
"secret" => FACEBOOK_SECRET_KEY,
"cookie" => true,
"domain" => SERVER_DOMAIN
));
function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode(".", $signed_request, 2);
// decode the data
$sig = base64_url_decode($encoded_sig);
$data = json_decode(base64_url_decode($payload), true);
if (strtoupper($data["algorithm"]) !== "HMAC-SHA256") {
error_log("Unknown algorithm. Expected HMAC-SHA256");
return null;
}
// check sig
$expected_sig = hash_hmac("sha256", $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log("Bad Signed JSON signature!");
return null;
}
return $data;
}
function base64_url_decode($input) {
return base64_decode(strtr($input, "-_", "+/"));
}
session_start();
if (isset($_SESSION['fb_data'])) {
$data = $_SESSION['fb_data'];
} else {
$data = parse_signed_request($_REQUEST["signed_request"], FACEBOOK_SECRET_KEY);
$_SESSION['fb_data'] = $data;
}
session_write_close();
$page_id = $data["page"]["id"];
$like_status = $data["page"]["liked"];
?>
The signed_request is only passed into your page when it is first loaded as a Facebook Canvas page. The signed_request is passed in as a POST variable. If you are navigating to different pages at the iframe level instead of the top level, you will lose that signed_request parameter.
For example, when user loads this page:
http://apps.facebook.com/test_app/
Facebook will load this inside its IFrame:
http://yourserver.com/test_app/
while passing in signed_request as a POST variable.
If you then navigate to different pages using the following tag:
Page 2
signed_request parameter will be lost.
Instead, you can either pass through the signed_request parameter as a GET variable:
Page 2
Or reload the page at top level:
<a target="_top" href="http://apps.facebook.com/test_app/page2"> Page 2 </a>
In case someone stumbles on this, the latest version of Facebook's php-sdk automatically uses $_SESSION variables to persist the signed_request when it isn't passed in on a Canvas page or Tab request. https://github.com/facebook/php-sdk
when user accepts the facebook application from my website, I am storing the user details and facebook details(access token) in database.
when he removes my application from facebook i want to remove the detail from database. how to do this?
I can give Deauthorize Callback url. if some one removes application, it will redirect to this page. but, wt should be the code here to delete the data from db? I means, when it redirect, will it post the access token details, so that i can charge fro access token and delete that row.
It's clearly stated in the authentication document:
App Deauthorization
When a user of your app removes it in
the App Dashboard or blocks the app in
the News Feed, your app can be
notified by specifying a Deauthorize
Callback URL in the Developer App.
During app removal we will send an
HTTP POST request containing a single
parameter, signed_request, which
contains the user id (UID) of the user
that just removed your app. You will
not receive an user access token in
this request and all existing user
access tokens will be automatically
expired.
So using the signed_request function on its own docuement:
<?php
function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
// decode the data
$sig = base64_url_decode($encoded_sig);
$data = json_decode(base64_url_decode($payload), true);
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
error_log('Unknown algorithm. Expected HMAC-SHA256');
return null;
}
// check sig
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
$result = parse_signed_request($_REQUEST['signed_request'],"APP_SECRET");
$myFile = "deauthorize.txt";
$fh = fopen($myFile, 'w') or die("can't open file");
fwrite($fh, $result["user_id"] . "\n");
fclose($fh);
?>
So all you need to do is get the $result["user_id"] query your DB and remove the record.
P.S: I would recommend adding a new field called active and just deactivate the user instead of removing the record all together.
EDIT:
Facebook will NOT redirect the user to the deauthorize URL! it'll ping it only:
Facebook pings this URL when a user
deauthorizes your app
This code is not working, although it gets called when a user deauthorizes the app the only data passed into the function is a "1" (Tested with test user and my own FB account when app is live)
file_put_contents("test.txt",$fbUserId . " ". print_r($_REQUEST['signed_request']));
in test.txt file " 1"
Scenario
Facebook app which resides on User A's profile (in a tab called Welcome). User A can fill out a Welcome message and update the message.
User B comes to User A's profile, clicks on the Welcome tab and views the Welcome message written by User A.
I understand how to complete the majority of my application and imaging that I will produce the response based on a DB lookup of a field associated with User A's Facebook ID.
What I don't understand is how to grab the User ID value of the user who installed that instance of the APP (User A) or how to grab the User ID of the profile that User B is currently on (Which also happens to be User A).
Any ideas on how best to attack this?
Found the answer. When your application is installed as a tab then the profile of the user along with other parameters are passed in an encoded string. Here is an example of how I pulled the profile_id.
function getProfileID($post){
global $FB_secret;
$SR = $post['signed_request'];
$PSR = parse_signed_request($SR,$FB_secret);
return $PSR['profile_id'];
}
function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
// decode the data
$sig = base64_url_decode($encoded_sig);
$data = json_decode(base64_url_decode($payload), true);
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
error_log('Unknown algorithm. Expected HMAC-SHA256');
return null;
}
// check sig
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
Add those functions then add the following command somewhere:
$profile_user = getProfileID($_POST);
Please note that the script assumes that you will assign the secret key value to $FB_secret to work properly.