I wanted implement the new facebook API v 4.0.0 on my project laravel.
Setting all the necessary informations and credentials for access to my app, when is time to call the function for the login:
$helper = new FacebookRedirectLoginHelper('http://mywebsite.dev');
$loginUrl = $helper->getLoginUrl();
It throw me an exception
FacebookSDKException 'Session not active, could not store state.'
So I dig in to the SDK class of facebook on that line and there is a check about session precisely this one:
if (session_status() !== PHP_SESSION_ACTIVE) {
throw new FacebookSDKException(
'Session not active, could not store state.'
);
}
Then I didn't know why this happen so i tried to put the same check on a clean route and see the result
Route::get('test',function() {
if (session_status() !== PHP_SESSION_ACTIVE)
{
return "is not active";
}
return "is active";
});
And it return is not active why this happen? in this way I cannot use the new facebook API with laravel?
Sharing how I implemented Facebook SDK V4 on Laravel 4.
Here's what I added on default composer.json
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php"
],
"psr-4" : {
"Facebook\\":"vendor/facebook/php-sdk-v4/src/Facebook/"
}
},
Added Facebook initialization on my index.php, like this :
/*
|--------------------------------------------------------------------------
| Initialized Facebook PHP SDK V4
|--------------------------------------------------------------------------
|
*/
//Initialize
use Facebook\FacebookSession;
FacebookSession::setDefaultApplication(Config::get('facebook.AppId'),Config::get('facebook.AppSecret'));
And for the Session, Laravel doesn't use $_SESSION so you don't need to do session_start at all. For you to be able to use Laravel session on Facebook PHP SDK V4, you need to extend Facebook's FacebookRedirectLoginHelper class.
Here's how how to subclass FacebookRedirectLoginHelper and overwrite Session handling.
class LaravelFacebookRedirectLoginHelper extends \Facebook\FacebookRedirectLoginHelper
{
protected function storeState($state)
{
Session::put('state', $state);
}
protected function loadState()
{
$this->state = Session::get('state');
return $this->state;
}
protected function isValidRedirect()
{
return $this->getCode() && Input::has('state')
&& Input::get('state') == $this->state;
}
protected function getCode()
{
return Input::has('code') ? Input::get('code') : null;
}
//Fix for state value from Auth redirect not equal to session stored state value
//Get FacebookSession via User access token from code
public function getAccessTokenDetails($app_id,$app_secret,$redirect_url,$code)
{
$token_url = "https://graph.facebook.com/oauth/access_token?"
. "client_id=" . $app_id . "&redirect_uri=" . $redirect_url
. "&client_secret=" . $app_secret . "&code=" . $code;
$response = file_get_contents($token_url);
$params = null;
parse_str($response, $params);
return $params;
}
}
And one more step, you need to do a composer command to regenerate autoload files :
composer dump-autoload -o
Ok, if all goes right, you are now ready to start using the SDK, here's a sample
Here's an excerpt from one of my project classes :
namespace Fb\Insights;
//Facebook Classes
use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\FacebookSDKException;
//Our Facebook Controller
use FbController;
class PagePosts extends \Facebook\GraphObject {
/*
Get Page Posts Impression
https://developers.facebook.com/docs/graph-api/reference/v2.0/insights#post_impressions
*/
public static function getPagePostsImpressions($postid = null) {
$fbctrl = new FbController();
$metricNames = array(
'post_impressions',
'post_impressions_unique',
'post_impressions_paid',
'post_impressions_paid_unique',
'post_impressions_fan',
'post_impressions_fan_unique',
'post_impressions_fan_paid',
'post_impressions_fan_paid_unique',
'post_impressions_organic',
'post_impressions_organic_unique',
'post_impressions_viral',
'post_impressions_viral_unique',
'post_impressions_by_story_type',
'post_impressions_by_story_type_unique',
'post_impressions_by_paid_non_paid',
'post_impressions_by_paid_non_paid_unique'
);
$postsInsights = array();
$batch = array();
$limit = $fbctrl->FacebookGraphDateLimit();
//craft our batch API call
for($i=0; $i<count($metricNames); $i++) {
$batch[] = json_encode(array('method' => 'GET','relative_url' => $postid . '/insights/' . $metricNames[$i] . '?since=' . $limit['since'] . '&until=' . $limit['until'] ));
}
$params = array( 'batch' => '[' . implode(',',$batch ) . ']' );
$session = new FacebookSession($fbctrl->userAccessToken);
try {
$res = (new FacebookRequest($session,'POST','/',$params))
->execute()
->getGraphObject();
} catch(FacebookRequestException $ex) {
//log this error
echo $ex->getMessage();
} catch(\Exception $ex) {
//log this error
echo $ex->getMessage();
}
//Collect data
for($i=0; $i<count($batch); $i++) {
$resdata = json_decode(json_encode($res->asArray()[$i]),true);
$fbctrl->batchErrorDataChecker($resdata,$postsInsights,$metricNames[$i]);
}
return $postsInsights;
}
Feel free comment or suggest so I can also improve my code.
Happy coding.
I solve extending that class and overwriting the following 2 methods that require native sessions.
protected function storeState($state)
{
Session::put('facebook.state', $state);
}
protected function loadState()
{
return $this->state = Session::get('facebook.state');
}
I used follow steps using Composer and had problem "Session not active, could not store state" so session_start() fixed my issue.
require_once './vendor/autoload.php';
use Facebook\FacebookSession;
use Facebook\FacebookRedirectLoginHelper;
use Facebook\FacebookRequest;
session_start();
FacebookSession::setDefaultApplication('apid', 'appscret');
$helper = new FacebookRedirectLoginHelper("callbackurl", $apiVersion = NULL);
try {
$session = $helper->getSessionFromRedirect();
} catch (FacebookRequestException $ex) {
// When Facebook returns an error
} catch (\Exception $ex) {
// When validation fails or other local issues
}
if (isset($session)) {
$request = new FacebookRequest($session, 'GET', '/me');
$response = $request->execute();
$graphObject = $response->getGraphObject();
var_dump($graphObject);
} else {
echo 'Login with Facebook';
}
To solve problem call session_start php function after to inizialize FacebookRedirectLoginHelper somthing like this:
session_start();
$helper = new FacebookRedirectLoginHelper('http://mywebsite.dev');
$loginUrl = $helper->getLoginUrl();
kaixersoft's answer really saved my bacon a little while ago, and I got everything to work by following his instructions using the custom LaravelFacebookRedirectLoginHelper class. But today I went to do a 'composer update' and for some reason, it broke everything. I've modified kaixersoft's LaravelFacebookRedirectLoginHelper class so that it works now, specifically the isValidRedirect method. Here is the updated class:
class LaravelFacebookRedirectLoginHelper extends \Facebook\FacebookRedirectLoginHelper
{
protected function storeState($state)
{
Session::put('state', $state);
}
protected function loadState()
{
$this->state = Session::get('state');
return $this->state;
}
protected function isValidRedirect()
{
$savedState = $this->loadState();
if (!$this->getCode() || !isset($_GET['state'])) {
return false;
}
$givenState = $_GET['state'];
$savedLen = mb_strlen($savedState);
$givenLen = mb_strlen($givenState);
if ($savedLen !== $givenLen) {
return false;
}
$result = 0;
for ($i = 0; $i < $savedLen; $i++) {
$result |= ord($savedState[$i]) ^ ord($givenState[$i]);
}
return $result === 0;
}
protected function getCode()
{
return Input::has('code') ? Input::get('code') : null;
}
//Fix for state value from Auth redirect not equal to session stored state value
//Get FacebookSession via User access token from code
public function getAccessTokenDetails($app_id,$app_secret,$redirect_url,$code)
{
$token_url = "https://graph.facebook.com/oauth/access_token?"
. "client_id=" . $app_id . "&redirect_uri=" . $redirect_url
. "&client_secret=" . $app_secret . "&code=" . $code;
$response = file_get_contents($token_url);
$params = null;
parse_str($response, $params);
return $params;
}
}
session_status function is available on (PHP >=5.4.0) version. So if you are using older version of PHP then Please update it Or Just
// change this
if (session_status() !== PHP_SESSION_ACTIVE) {
throw new FacebookSDKException(
'Session not active, could not store state.'
);
}
//into this
if(session_id() === "") {
throw new FacebookSDKException(
'Session not active, could not load state.'
);
}
in template:
<div><fb:registration redirect_uri=http://mydomain/users/register fields="name,birthday,gender,location,email" /></div>
In model and Controller, I have function register() in users model and controller
define('FACEBOOK_APP_ID', ''); // Place your App Id here
define('FACEBOOK_SECRET', ''); // Place your App Secret Here
// No need to change the function body
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, '-_', '+/'));
}
if ($_REQUEST)
{
$response = parse_signed_request($_REQUEST['signed_request'],
FACEBOOK_SECRET);
$name = $response["registration"]["name"];
$email = $response["registration"]["email"];
$password = $response["registration"]["password"];
$country = $response["user"]["country"];
echo $country;
echo $name;
echo $email;
echo $password;
...............
So its working fine and I am getting data from facebook. I want to integrate this code with my cakephp registration code. I am very new to cakephp, so please if any body give me a link, how to integrate facebook registration plugin in cakephp?
Please try this.
http://www.webtechnick.com/blogs/view/229/CakePHP_Facebook_Plugin_Auth_Facebook_and_more
It has many more features to implement various Facebook functionality like login, registration, share, comments etc.
I've used this for login functionality and its working fine.
I have a controller action
public function pagedetailAction(){
$id = $this->_getParam('id',0);
$detail = new Application_Model_Page();
$this->view->detail = $detail->findArr($id);
//CALLING FORM WITH OTHER CONTENTS
$form = new Application_Form_Request();
$this->view->form = $form;
}
To process the form I have this function
public function submitrequestAction(){
if ($this->getRequest()->isPost()) {
$formData = $this->getRequest()->getPost();
if ($form->isValid($formData)) {
$newsadd = new Application_Model_Request($formData);
$newsadd->set_ID(null);
$newsadd->save();
$this->_helper->flashMessenger->addMessage(array('success'=>'Message Sent'));
$this->_redirect('/index/frontmsg');
} else {
$form->populate($formData);
}
}
}
when i click submit i get the error
Notice: Undefined variable: form in E:\xampp\htdocs\sandbox1\application\controllers\IndexController.php on line 84
Fatal error: Call to a member function isValid() on a non-object in E:\xampp\htdocs\sandbox1\application\controllers\IndexController.php on line 84
Please help me so that I can post values to database via this form. Thanks
Use this
public function submitrequestAction(){
if ($this->getRequest()->isPost()) {
$form = new Application_Form_Request();//added this
$formData = $this->getRequest()->getPost();
if ($form->isValid($formData)) {
$newsadd = new Application_Model_Request($formData);
$newsadd->set_ID(null);
$newsadd->save();
$this->_helper->flashMessenger->addMessage(array('success'=>'Message Sent'));
$this->_redirect('/index/frontmsg');
} else {
$form->populate($formData);
}
}
}
Add $form initialization to your submitrequestAction:
$form = new Application_Form_Request();
I am looking to do a reveal tab. When a user goes to a fan page tab it will show a specific tab. When the user likes the page it will reveal a registration form. If user is also registered it will reveal another tab(that is basically after it is liked and registered). Is there a way to access if a user has registered on my page and also liked? Is this even possible?
Thanks
Yep possible. Google "Facebook Fan Gate" and you will find many code examples of how to accomplish this.
Try this
$facebook = new Facebook(array(
'appId' => 'APP_ID',
'secret' => 'APP_SECRET',
'cookie' => true,
));
$session = $facebook->getSession();
$me = null;
if ($session) {
try {
$uid = $facebook->getUser();
$me = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
}
}
$signed_request = $_REQUEST["signed_request"];
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, '-_', '+/'));
}
$data = parse_signed_request($_REQUEST["signed_request"], "APP_SECRET");
if ($data['page']['liked']){
//SHOW REGISTRATION FORM
}else{
//SHOW NO FAN PAGE
}
How Zend_Paginator can work according to the exchange of the variable query?
In line 8 performs a single fetch and does not change even by changing the query variable.
How to do paging function in accordance with the start-index from gdata feed?
The code: http://pastebin.com/rmxSP1Us
$yt = new Zend_Gdata_YouTube();
$limit = 12;
$offset = ($page - 1) * $limit + 1;
$query = "http://gdata.youtube.com/feeds/api/users/aculinario/favorites?start-index=$offset";
$paginator = Zend_Paginator::factory($yt->getVideoFeed($query));
$paginator->setCurrentPageNumber($page);
$paginator->setItemCountPerPage($limit);
$paginator->setPageRange(6);
$this->view->paginator = $paginator;
echo $query // query changes but paginator no, every time Zend_Paginator factory should check the returned array of getVideoFeed, but not this checking
Sry, my poor english, i'm Trying
I got something similar working using a quick & dirty paginator adapter.
It's worth noting there's probably nicer, more generic ways to achieve this. But this will get you going if you're in a hurry.
<?php
class Lib_Paginator_Adapter_YoutubeUser implements Zend_Paginator_Adapter_Interface
{
protected $_username;
protected $_results;
public function __construct($username)
{
$this->_username = $username;
}
public function getItems($offset, $itemCountPerPage)
{
$url = sprintf(
'%s/%s/%s',
Zend_Gdata_YouTube::USER_URI,
$this->_username,
Zend_Gdata_YouTube::UPLOADS_URI_SUFFIX
);
try
{
$query = new Zend_Gdata_Query($url);
$query->setMaxResults($itemCountPerPage)
->setStartIndex($offset);
$youtube = new Zend_Gdata_YouTube();
$this->_results = $youtube->getUserUploads(null, $query);
return $this->_results;
}
catch (Exception $ex)
{
echo $ex->getMessage();
exit;
}
}
public function count()
{
try
{
$youtube = new Zend_Gdata_YouTube();
return $youtube->getUserUploads($this->_username)->getTotalResults()->getText();
}
catch (Exception $ex)
{
echo $ex->getMessage();
exit;
}
}
}
Then in your controller
$page = $this->getRequest()->getParam("page");
$limit = 10;
$username = 'aculinario';
$paginator = new Zend_Paginator(new Lib_Paginator_Adapter_YoutubeUser($username));
$paginator->setItemCountPerPage($limit);
$paginator->setPageRange(10);
$paginator->setCurrentPageNumber($page);
$this->view->youtubeFeed = $paginator;