问题
I'm trying to implement the Facebook registration script.
The form is getting submitted fine and the server is receiving the signed request. However, it is not able to read/parse the signed request.
I used the script recommended on the registration page https://developers.facebook.com/docs/plugins/registration/ (code below) and all I see for output is:
signed_request contents:
I have verified that the signed_Request is being received. If I pass it to: http://developers.facebook.com/tools/echo?signed_request= I see data.
However on my server with the script below nothing.
The server is http NOT https and using php 5.1.6 (which doesn't have some of the JSON support) Do I need PHP SDK installed? Or the jsonwrapper? I've tried the jsonwrapper but not PHP SDK.
Any help on why the signed_request can not be read would be appreciated.
Code below from facebook
<?php
include ('jsonwrapper/jsonwrapper.php');
define('FACEBOOK_APP_ID', 'XXX');
define('FACEBOOK_SECRET', 'XXX');
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) {
echo '<p>signed_request contents:</p>';
$response = parse_signed_request($_REQUEST['signed_request'],
FACEBOOK_SECRET);
echo '<pre>';
print_r($response);
echo '</pre>';
} else {
echo '$_REQUEST is empty';
}
?>
output is
"signed_request contents:"
If I add: print_r($_REQUEST); to the script I do see the request but can't parse it
回答1:
You don't need the PHP SDK for this. It may make it easier to do this and various other things, but it is not necessary if you want to do the decode yourself.
Are you sure you actually have a json_decode function? I don't think it's usually part of jsonwrapper.php, so I suspect your script is crashing on that function call. You can use the following function as a substitute, just change the call to usr_json_decode
and include the following at the bottom of your script:
function usr_json_decode($json, $assoc=FALSE, $limit=512, $n=0, $state=0, $waitfor=0)
{
$val=NULL;
static $lang_eq = array("true" => TRUE, "false" => FALSE, "null" => NULL);
static $str_eq = array("n"=>"\012", "r"=>"\015", "\\"=>"\\", '"'=>'"', "f"=>"\f", "b"=>"\b", "t"=>"\t", "/"=>"/");
for (; $n<strlen($json); /*n*/)
{
$c=$json[$n];
if ($state==='"')
{
if ($c=='\\')
{
$c=$json[++$n];
if (isset($str_eq[$c]))
$val.=$str_eq[$c];
else if ($c=='u')
{
$hex=hexdec(substr($json, $n+1, 4));
$n+=4;
if ($hex<0x80) $val .= chr($hex);
else if ($hex<0x800) $val.=chr(0xC0+$hex>>6).chr(0x80+$hex&63);
else if ($hex<=0xFFFF) $val.=chr(0xE0+$hex>>12).chr(0x80+($hex>>6)&63).chr(0x80+$hex&63);
}
else
$val.="\\".$c;
}
else if ($c=='"') $state=0;
else $val.=$c;
}
else if ($waitfor && (strpos($waitfor, $c)!==false))
return array($val, $n);
else if ($state===']')
{
list($v, $n)=usr_json_decode($json, $assoc, $limit, $n, 0, ",]");
$val[]=$v;
if ($json[$n]=="]") return array($val, $n);
}
else
{
if (preg_match("/\s/", $c)) { }
else if ($c=='"') $state='"';
else if ($c=="{")
{
list($val, $n)=usr_json_decode($json, $assoc, $limit-1, $n+1, '}', "}");
if ($val && $n) $val=$assoc?(array)$val:(object)$val;
}
else if ($c=="[")
list($val, $n)=usr_json_decode($json, $assoc, $limit-1, $n+1, ']', "]");
elseif (($c=="/") && ($json[$n+1]=="*"))
($n=strpos($json, "*/", $n+1)) or ($n=strlen($json));
elseif (preg_match("#^(-?\d+(?:\.\d+)?)(?:[eE]([-+]?\d+))?#", substr($json, $n), $uu))
{
$val = $uu[1];
$n+=strlen($uu[0])-1;
if (strpos($val, ".")) $val=(float)$val;
else if ($val[0]=="0") $val=octdec($val);
else $val=(int)$val;
if (isset($uu[2])) $val*=pow(10, (int)$uu[2]);
}
else if (preg_match("#^(true|false|null)\b#", substr($json, $n), $uu))
{
$val=$lang_eq[$uu[1]];
$n+=strlen($uu[1])-1;
}
else
{
return $waitfor ? array(NULL, 1<<30) : NULL;
}
}
if ($n===NULL) return NULL;
$n++;
}
return ($val);
}
BTW though, this should be very easy to track down using your error log, turning on extra debugging and adding some echo
or var_dump
statements as necessary.
回答2:
I had something similar with the signed request coming back blank. On your application make sure you first download and inlude the php sdk from http://developers.facebook.com/docs/reference/php/. Next add
require_once("facebook.php");
to your script at the top, or to where you uploaded it to. Now in your application settings for the application, in Facebook, make sure your url to the application has the www in it or not. For example: In the application you have it pointing to example.com/index.php?tab=test but when you put it in the browser it always comes up www,example.com/index.php?tab=test. Not including the www can mess it up.
EDIT - WORKED FOR ME
<?php
#error_reporting(E_ALL);
include ('{{PATH TO facebook.php}}');
$appapikey = 'xxxx';
$appsecret = 'xxxx';
$facebook = new Facebook($appapikey, $appsecret);
function parsePageSignedRequest() {
if (isset($_REQUEST['signed_request'])) {
$encoded_sig = null;
$payload = null;
list($encoded_sig, $payload) = explode('.', $_REQUEST['signed_request'], 2);
$sig = base64_decode(strtr($encoded_sig, '-_', '+/'));
$data = json_decode(base64_decode(strtr($payload, '-_', '+/'), true));
return $data;
}
return false;
}
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 (isset($_REQUEST['signed_request'])) {
echo '<p>signed_request contents:</p>';
$response = parse_signed_request($_REQUEST['signed_request'],
$appsecret);
echo '<pre>';
print_r($response);
echo '</pre>';
} else {
echo '$_REQUEST is empty';
}
?>
<iframe src="https://www.facebook.com/plugins/registration.php?
client_id=134219456661289&
redirect_uri={{YOUR SITE URL ENCODED}}&fields=name,birthday,gender,location,email"
scrolling="auto"
frameborder="no"
style="border:none"
allowTransparency="true"
width="100%"
height="330">
</iframe>
function getDefinedVars($varList, $excludeList)
{
$temp1 = array_values(array_diff(array_keys($varList), $excludeList));
$temp2 = array();
while (list($key, $value) = each($temp1)) {
global $$value;
$temp2[$value] = $$value;
}
return $temp2;
}
To view All SYSTEM Variables (except globals/files/cookies/post/get) to make sure Signed Request is passed you can use this snippet of code
/**
* @desc holds the variable that are to be excluded from the list.
* Add or drop new elements as per your preference.
* @var array
*/
$excludeList = array('GLOBALS', '_FILES', '_COOKIE', '_POST', '_GET', 'excludeList');
//some dummy variables; add your own or include a file.
$firstName = 'kailash';
$lastName = 'Badu';
$test = array('Pratistha', 'sanu', 'fuchhi');
//get all variables defined in current scope
$varList = get_defined_vars();
//Time to call the function
print "<pre>";
print_r(getDefinedVars($varList, $excludeList));
print "</pre>";
来源:https://stackoverflow.com/questions/7631518/how-to-read-parse-data-of-signed-request-from-registration-script-in-php-5-1-6