/*********
* Twitter App credentials
*/
define('CONSUMER_KEY', 'cOT3cwrSltpOHBKCwAXVA');
define('CONSUMER_SECRET', 'VAS1Q6g0t8PURzOaKTO0s1hkSk8MFHqUCdSIw8VF4');
if (strstr($_SERVER[SERVER_NAME],"matraex"))
define('OAUTH_CALLBACK', 'http://'.$_SERVER[SERVER_NAME].'/accountsettings.php?tab=socialsetup');
else
define('OAUTH_CALLBACK', 'https://riogenesis.com/accountsettings.php?tab=socialsetup');
define('FREODOCUMENTBOXEMAIL','upload.Rio_Upl.z9satcjp5f@u.box.com');
define('FREODOCUMENTBOXEMAIL_FROM','noreply@riogenesis.com');
if ($_SESSION[developer][SOAP_SandBOX]){
global $application_variables_set;
$application_variables_set['setting_freoapi_sandbox']='1';
}
/*****
* End of Twitter App setup.
*/
/**
* @name oauth_verified
* @param string $oauthuserprovider
* @param string $loginid
* @return boolean
*/
function oauth_verified($oauthuserprovider='',$loginid=''){
$sql = "SELECT * FROM tbloauthuser WHERE oauthuserprovider='$oauthuserprovider' AND loginid=$loginid ";
$qry = db_query($sql);
if($qry[0][oauthuserkey] && $qry[0][oauthusersecret]){
return true;
}
else{
return false;
}
}
/**
* @name api_error
* @param string $value
* @return boolean
*/
function api_error($value)
{
$exit = ob_get_clean();
echo "$value";
exit_wrapper ();
}
/**
* @name saveoauthuserinfo
*/
function saveoauthuserinfo(
$loginid='',
$oauthuseremailaddress='',
$oauthuserkey='',
$oauthusersecret='',
$oauthuserprovider='',
$oauthuserproviderusername='',
$oauthuserproviderref='',
$oauthuserprovideravatarurl=''
){
if(empty($loginid) || empty($oauthuserkey) || empty($oauthuserprovider)){
return '';
}
$oauthuser = getoauthuserinfo($loginid,$oauthuseremailaddress,$oauthuserprovider);
if($oauthuser[oauthuserid]==''){
$sql = "
INSERT INTO tbloauthuser
(
oauthuserprovider,
oauthuserkey,
oauthusersecret,
loginid,
";
if($oauthuseremailaddress){
$sql .= "
oauthuseremailaddress,
";
}
if($oauthuserprovideravatarurl){
$sql .= "
oauthuserprovideravatarurl,
";
}
$sql .= "
oauthuserproviderusername,
oauthuserproviderref
)
VALUES
(
'$oauthuserprovider',
'".addslashes($oauthuserkey)."',
'".addslashes($oauthusersecret)."',
'$loginid',
";
if($oauthuseremailaddress){
$sql .= "
'".addslashes($oauthuseremailaddress)."',
";
}
if($oauthuserprovideravatarurl){
$sql .= "
'".addslashes($oauthuserprovideravatarurl)."',
";
}
$sql .= "
'$oauthuserproviderusername',
'$oauthuserproviderref'
)
";
if(db_exec($sql)){
return true;
}
else{
return false;
}
}
else{
$sql = "
UPDATE
tbloauthuser
SET
oauthuserkey='".addslashes($oauthuserkey)."',
oauthusersecret='".addslashes($oauthusersecret)."'
WHERE
loginid='$loginid' AND
oauthuserprovider='$oauthuserprovider' AND
oauthuseremailaddress='".addslashes($oauthuseremailaddress)."'
";
if(db_exec($sql)){
return true;
}
else{
return false;
}
}
}
/**
* @name getoauthuserinfo
* @param integer $loginid
* @param string $oauthuseremailaddress
* @param string $oauthuserprovider
* @param integer $oauthuserid
* @param integer $oauthuserproviderref
* @return boolean
*/
function getoauthuserinfo($loginid='',$oauthuseremailaddress='',$oauthuserprovider='',$oauthuserid=0,$oauthuserproviderref=0){
$sql = "
select *
from tbloauthuser
where 1=1 ";
if($loginid){
$sql .= " AND loginid ='$loginid' ";
}
if($oauthuserid){
$sql .= " AND oauthuserid ='$oauthuserid' ";
}
if(is_array($oauthuserprovider)){
$oauthuserprovider_counter = 0;
$sql .= " AND (";
foreach($oauthuserprovider as $key=>$provider){
if($oauthuserprovider_counter>0){
$sql .= " OR ";
}
$sql .= " oauthuserprovider ='$provider' ";
$oauthuserprovider_counter++;
}
$sql .= ")";
}else if($$oauthuserprovider!=0){
$sql .= "
AND oauthuserprovider ='$oauthuserprovider'
";
}
if($oauthuseremailaddress){
$sql .= "
AND
oauthuseremailaddress ='$oauthuseremailaddress'
";
}
if($oauthuserproviderref){
$sql .= "
AND
oauthuserproviderref ='$oauthuserproviderref'
";
}
$oauthuser = db_query($sql);
d_dev('getoauthuserinfo', array('sql' => $sql, 'qry' => $oauthuser));
if(count($oauthuser)>0){
return $oauthuser;
}
else{
return false;
}
}
###########
# Geneeric Social Posting Functions
###########
/**
* @name social_verify
* @param integer $oauthuserid
* @param integer $loginid
* @return boolean
*/
function social_verify($oauthuserid,$loginid=0){
if(!is_numeric($oauthuserid)){
return "Invalid oauthuserid, must be numeric.";
}
$sql = "SELECT * FROM tbloauthuser
WHERE
oauthuserid = $oauthuserid
";
if($loginid && is_numeric($loginid)){
$sql .= "AND
loginid = $loginid
";
}
$sql .= "
LIMIT 1
";
$oauth = db_query($sql);
if(trim($oauth[0][oauthuserprovider])=="twitter"){
return twitter_verify($oauthuserid);
} else if(trim($oauth[0][oauthuserprovider])=="facebook"){
return facebook_verify($oauthuserid);
} else {
return false;
}
}
/**
* @name social_verify_own
* @param integer $oauthuserid
* @param integer $loginid
* @return boolean
*/
function social_verify_own($oauthuserid,$loginid=0){
if(!is_numeric($oauthuserid)){
return "Invalid oauthuserid, must be numeric.";
}
$sql = "SELECT * FROM tbloauthuser
WHERE
oauthuserid = $oauthuserid
";
if($loginid && is_numeric($loginid)){
$sql .= "AND
loginid = $loginid
";
}
$sql .= "
LIMIT 1
";
//d(sql,$sql)
$oauth = db_query($sql);
//d($oauth);
if($oauth[0][oauthuserid]==$oauthuserid){
return true;
} else {
return false;
}
}
/**
* @name social_update_avatar
* @param integer $oauthuserid
* @param string $url
* @return boolean
*/
function social_update_avatar($oauthuserid='',$url){
if(!is_numeric($oauthuserid)){
return false;
}
$sql = "
UPDATE
tbloauthuser
SET
oauthuserprovideravatarurl='".addslashes($url)."'
WHERE
oauthuserid='$oauthuserid'
";
if(db_exec($sql)){
return true;
}
else{
return false;
}
}
/**
* @name social_post
* @param integer $oauthuserid
* @param string $postmessage
* @param integer $attachment
* @return boolean
*/
function social_post($oauthuserid,$postmessage,$attachment=0){
if(!social_verify($oauthuserid)){
d(oathid,$oauthuserid);
return false;
}
if(!is_numeric($oauthuserid)){
return "Invalid oauthuserid, must be numeric.";
}
$sql = "SELECT * FROM tbloauthuser
WHERE
oauthuserid = $oauthuserid
LIMIT 1";
$oauth = db_first($sql);
d(oauth,$oauth);
d(msg,$postmessage);
//exit;
if(trim($oauth[oauthuserprovider])=="twitter"){
$twitterresult = twitter_post($oauthuserid,$postmessage);
if($twitterresult){
return $twitterresult;
} else {
return false;
}
} else if(trim($oauth[oauthuserprovider])=="facebook"){
$facebookresult = facebook_post($oauthuserid,$postmessage,$attachment);
if($facebookresult){
return $facebookresult;
} else {
return false;
}
}
}
/**
* @name social_delete
* @param integer $oauthuserid
* @return boolean
*/
function social_delete($oauthuserid){
if(!is_numeric($oauthuserid)){
return "Invalid oauthuserid, must be numeric.";
}
$loginid= loginid();
if(!social_verify_own($oauthuserid,$loginid)){
return false;
}
$sql = "DELETE
FROM
tbloauthuser
WHERE
oauthuserid = $oauthuserid
";
$deleteresult = db_query($sql);
//d(deletesql,$sql);
//d(deleteresult,$deleteresult);
return true;
}
###########
# Twitter Start
##########
/**
* @name twitter_post
* @param integer $oauthuserid
* @param string $messagetopost
* @return boolean
*/
function twitter_post($oauthuserid='',$messagetopost=''){
$oauth_accounts = getoauthuserinfo(0,0,0,$oauthuserid);
d(oath_accnts,$oauth_accounts);
if($oauth_accounts[0][oauthuserkey] && $oauth_accounts[0][oauthusersecret]){
//this is token and token secret for the USERS oauth authentication
$token = trim($oauth_accounts[0][oauthuserkey]);
$tokensecret = trim($oauth_accounts[0][oauthusersecret]);
$twcon = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET,$token,$tokensecret);
$content = $twcon->get('account/verify_credentials');
d(content,$content);
d(msg,$messagetopost);
$posted = $twcon->post('statuses/update', array('status' => $messagetopost));
//this is for debugging, if needed
//$lastapicall = $twcon->lastAPICall();
d(posted,$posted);
//exit;
if($posted->id_str){
return $posted->id_str;
} else {
return false;
}
}else{
return false;
}
}
/**
* @name twitter_verify
* @param integer $oauthuserid
* @return boolean
*/
function twitter_verify($oauthuserid=''){
$oauth_accounts = getoauthuserinfo(0,0,0,$oauthuserid);
if(trim($oauth_accounts[0][oauthuserprovider])!="twitter"){
return false;
}
if($oauth_accounts[0][oauthuserkey] && $oauth_accounts[0][oauthusersecret]){
//this is token and token secret for the USERS oauth authentication
$token = trim($oauth_accounts[0][oauthuserkey]);
$tokensecret = trim($oauth_accounts[0][oauthusersecret]);
$twcon = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET,$token,$tokensecret );
$twittercred = $twcon->get('account/verify_credentials');
// d(twittercred,$twittercred);
global $twitterdata;
$twitterdata= (array) $twittercred;
if($twittercred->id_str){
$twitter_avatar_url = $twittercred->profile_image_url_https;
if($twitter_avatar_url){
social_update_avatar($oauthuserid,$twitter_avatar_url);
}
return true;
} else {
return false;
}
}else{
return false;
}
}
/**
* Method for creating a base string from an array and base URI.
* @param string $twitter_baseURI the URI of the request to twitter
* @param array $params the OAuth associative array
* @return string the encoded base string
**/
/**
* @name twitter_buildBaseString
* @param string $twitter_baseURI
* @param array $params
* @return boolean
*/
function twitter_buildBaseString($twitter_baseURI, $params){
$r = array(); //temporary array
if(is_array($params)){
ksort($params); //sort params alphabetically by keys
foreach($params as $key=>$value){
$r[] = "$key=" . rawurlencode($value); //create key=value strings
}//end foreach
}
return "POST&" . rawurlencode($twitter_baseURI) . '&' . rawurlencode(implode('&', $r)); //return complete base string
}//end twitter_buildBaseString()
/**
* Method for creating the composite key.
* @param string $twitter_consumerSecret the consumer secret authorized by Twitter
* @param string $requestToken the request token from Twitter
* @return string the composite key.
**/
/**
* @name twitter_getCompositeKey
* @param string $twitter_consumerSecret
* @param string $requestToken
* @return boolean
*/
function twitter_getCompositeKey($twitter_consumerSecret, $requestToken){
return rawurlencode($twitter_consumerSecret) . '&' . rawurlencode($requestToken);
}//end getCompositeKey()
/**
* Method for building the OAuth header.
* @param array $twitter_oauth the oauth array.
* @return string the authorization header.
**/
/**
* @name twitter_buildAuthorizationHeader
* @param string $twitter_oauth
* @return boolean
*/
function twitter_buildAuthorizationHeader($twitter_oauth){
$r = 'Authorization: OAuth '; //header prefix
$values = array(); //temporary key=value array
foreach($twitter_oauth as $key=>$value)
$values[] = "$key=\"" . rawurlencode($value) . "\""; //encode key=value string
$r .= implode(', ', $values); //reassemble
return $r; //return full authorization header
}//end buildAuthorizationHeader()
/**
* Method for sending a request to Twitter.
* @param array $twitter_oauth the oauth array
* @param string $twitter_baseURI the request URI
* @return string the response from Twitter
**/
/**
* @name twitter_sendRequest
* @param string $twitter_oauth
* @param string $twitter_baseURI
* @return boolean
*/
function twitter_sendRequest($twitter_oauth, $twitter_baseURI)
{
if (!$twitter_baseURI)
$twitter_baseURI="https://riogenesis.com/desktop.php";
$header = array( twitter_buildAuthorizationHeader($twitter_oauth), 'Expect:'); //create header array and add 'Expect:'
$options = array(CURLOPT_HTTPHEADER => $header, //use our authorization and expect header
CURLOPT_HEADER => false, //don't retrieve the header back from Twitter
CURLOPT_URL => $twitter_baseURI, //the URI we're sending the request to
CURLOPT_POST => true, //this is going to be a POST - required
CURLOPT_RETURNTRANSFER => true, //return content as a string, don't echo out directly
CURLOPT_SSL_VERIFYPEER => false, //don't verify SSL certificate, just do it
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_CONNECTTIMEOUT =>10); // Set connection timeout to 10 sec.
$ch = curl_init(); //get a channel
curl_setopt_array($ch, $options); //set options
$response = curl_exec($ch); //make the call
curl_close($ch); //hang up
return $response;
}//end sendRequest()
//get request token
$twitter_baseURI = 'https://api.twitter.com/oauth/request_token';
$twitter_accesTokenURI = 'https://api.twitter.com/oauth/access_token';
$twitter_authorizeURI = 'https://api.twitter.com/oauth/authorize';
$twitter_nonce = time();
$twitter_timestamp = time();
$twitter_consumerSecret = 'VAS1Q6g0t8PURzOaKTO0s1hkSk8MFHqUCdSIw8VF4'; //put your actual consumer secret here, it will look something like 'MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98'
if($_GET[setupoauth_twitter]=="1"){
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
$temporary_credentials = $connection->getRequestToken();
/* Request access tokens from twitter */
$_SESSION[twitter]=$temporary_credentials;
$redirect_url = $connection->getAuthorizeURL($temporary_credentials);
header('Location: '.$redirect_url);
}
else if($_GET[setupoauth_twitter]=="2"){
$twitter_oauth = array(
'oauth_callback' => 'http://' . $_SERVER['HTTP_HOST'].'/accountsettings.php?tab=socialsetup&twittercallback1=1',
'oauth_token' => $_GET['oauth_token'],
'oauth_verifier' => $_GET['oauth_verifier'],
'oauth_nonce' => $twitter_nonce,
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => $twitter_timestamp,
'oauth_version' => '1.0'
);
$twitter_baseStringAccess = twitter_buildBaseString($twitter_accesTokenURI, $oauth);
$twitter_compositeKey = twitter_getCompositeKey($consumerSecret, $_GET['oauth_token']);
$twitter_oauth_signature = base64_encode(hash_hmac('sha1', $twitter_baseStringAccess , $twitter_compositeKey, true)); //sign the base string
$twitter_oauth['oauth_signature'] = $twitter_oauth_signature;
$twitter_response = twitter_sendRequest($twitter_oauth, $twitter_accesTokenURI); //getting the access tokens � up to this point it works great
$twitter_responseArray = array();
$twitter_parts = explode('&', $twitter_response);
foreach($twitter_parts as $p){
$p = explode('=', $p);
$twitter_responseArray[$p[0]] = $p[1];
}
echo $response;
echo "
";
print_r($twitter_responseArray);
echo "
";
}
###########
# Twitter End
##########
#######################################################
# TwitterOauth Start
########################################
/**
* Twitter OAuth class
*/
class TwitterOAuth {
/* Contains the last HTTP status code returned. */
public $http_code;
/* Contains the last API call. */
public $url;
/* Set up the API root URL. */
public $host = "https://api.twitter.com/1.1/";
/* Set timeout default. */
public $timeout = 30;
/* Set connect timeout. */
public $connecttimeout = 30;
/* Verify SSL Cert. */
public $ssl_verifypeer = FALSE;
/* Respons format. */
public $format = 'json';
/* Decode returned json data. */
public $decode_json = TRUE;
/* Contains the last HTTP headers returned. */
public $http_info;
/* Set the useragnet. */
public $useragent = 'TwitterOAuth v0.2.0-beta2';
/* Immediately retry the API call if the response was not successful. */
//public $retry = TRUE;
/**
* Set API URLS
*/
function accessTokenURL() { return 'https://api.twitter.com/oauth/access_token'; }
function authenticateURL() { return 'https://twitter.com/oauth/authenticate'; }
function authorizeURL() { return 'https://twitter.com/oauth/authorize'; }
function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; }
/**
* Debug helpers
*/
function lastStatusCode() { return $this->http_status; }
function lastAPICall() { return $this->last_api_call; }
/**
* construct TwitterOAuth object
*/
function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
$this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
$this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
if (!empty($oauth_token) && !empty($oauth_token_secret)) {
$this->token = new OAuthConsumer($oauth_token, $oauth_token_secret);
} else {
$this->token = NULL;
}
}
/**
* Get a request_token from Twitter
*
* @returns a key/value array containing oauth_token and oauth_token_secret
*/
function getRequestToken($oauth_callback = NULL) {
$parameters = array();
if (!empty($oauth_callback)) {
$parameters['oauth_callback'] = $oauth_callback;
}
$request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
$token = OAuthUtil::parse_parameters($request);
$this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
return $token;
}
/**
* Get the authorize URL
*
* @returns a string
*/
function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) {
if (is_array($token)) {
$token = $token['oauth_token'];
}
if (empty($sign_in_with_twitter)) {
return $this->authorizeURL() . "?oauth_token={$token}";
} else {
return $this->authenticateURL() . "?oauth_token={$token}";
}
}
/**
* Exchange request token and secret for an access token and
* secret, to sign API calls.
*
* @returns array("oauth_token" => "the-access-token",
* "oauth_token_secret" => "the-access-secret",
* "user_id" => "9436992",
* "screen_name" => "abraham")
*/
function getAccessToken($oauth_verifier = FALSE) {
$parameters = array();
if (!empty($oauth_verifier)) {
$parameters['oauth_verifier'] = $oauth_verifier;
}
$request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
$token = OAuthUtil::parse_parameters($request);
$this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
return $token;
}
/**
* One time exchange of username and password for access token and secret.
*
* @returns array("oauth_token" => "the-access-token",
* "oauth_token_secret" => "the-access-secret",
* "user_id" => "9436992",
* "screen_name" => "abraham",
* "x_auth_expires" => "0")
*/
function getXAuthToken($username, $password) {
$parameters = array();
$parameters['x_auth_username'] = $username;
$parameters['x_auth_password'] = $password;
$parameters['x_auth_mode'] = 'client_auth';
$request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters);
$token = OAuthUtil::parse_parameters($request);
$this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
return $token;
}
/**
* GET wrapper for oAuthRequest.
*/
function get($url, $parameters = array()) {
$response = $this->oAuthRequest($url, 'GET', $parameters);
if ($this->format === 'json' && $this->decode_json) {
return json_decode($response);
}
return $response;
}
/**
* POST wrapper for oAuthRequest.
*/
function post($url, $parameters = array()) {
$response = $this->oAuthRequest($url, 'POST', $parameters);
if ($this->format === 'json' && $this->decode_json) {
return json_decode($response);
}
return $response;
}
/**
* DELETE wrapper for oAuthReqeust.
*/
function delete($url, $parameters = array()) {
$response = $this->oAuthRequest($url, 'DELETE', $parameters);
if ($this->format === 'json' && $this->decode_json) {
return json_decode($response);
}
return $response;
}
/**
* Format and sign an OAuth / API request
*/
function oAuthRequest($url, $method, $parameters) {
if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {
$url = "{$this->host}{$url}.{$this->format}";
}
$request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters);
$request->sign_request($this->sha1_method, $this->consumer, $this->token);
switch ($method) {
case 'GET':
return $this->http($request->to_url(), 'GET');
default:
return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata());
}
}
/**
* Make an HTTP request
*
* @return API results
*/
function http($url, $method, $postfields = NULL) {
$this->http_info = array();
$ci = curl_init();
/* Curl settings */
curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
curl_setopt($ci, CURLOPT_HEADER, FALSE);
switch ($method) {
case 'POST':
curl_setopt($ci, CURLOPT_POST, TRUE);
if (!empty($postfields)) {
curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
}
break;
case 'DELETE':
curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
if (!empty($postfields)) {
$url = "{$url}?{$postfields}";
}
}
curl_setopt($ci, CURLOPT_URL, $url);
$response = curl_exec($ci);
$this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
$this->http_info = array_merge($this->http_info, curl_getinfo($ci));
$this->url = $url;
curl_close ($ci);
return $response;
}
/**
* Get the header info to store.
*/
function getHeader($ch, $header) {
$i = strpos($header, ':');
if (!empty($i)) {
$key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
$value = trim(substr($header, $i + 2));
$this->http_header[$key] = $value;
}
return strlen($header);
}
}
#######################################################
# TwitterOauth End
#########################################################
############################################
# Oauth Start
##################################################
/* Generic exception class
*/
class OAuthException extends Exception {
// pass
}
class OAuthConsumer {
public $key;
public $secret;
function __construct($key, $secret, $callback_url=NULL) {
$this->key = $key;
$this->secret = $secret;
$this->callback_url = $callback_url;
}
function __toString() {
return "OAuthConsumer[key=$this->key,secret=$this->secret]";
}
}
class OAuthToken {
// access tokens and request tokens
public $key;
public $secret;
/**
* key = the token
* secret = the token secret
*/
function __construct($key, $secret) {
$this->key = $key;
$this->secret = $secret;
}
/**
* generates the basic string serialization of a token that a server
* would respond to request_token and access_token calls with
*/
function to_string() {
return "oauth_token=" .
OAuthUtil::urlencode_rfc3986($this->key) .
"&oauth_token_secret=" .
OAuthUtil::urlencode_rfc3986($this->secret);
}
function __toString() {
return $this->to_string();
}
}
/**
* A class for implementing a Signature Method
* See section 9 ("Signing Requests") in the spec
*/
abstract class OAuthSignatureMethod {
/**
* Needs to return the name of the Signature Method (ie HMAC-SHA1)
* @return string
*/
abstract public function get_name();
/**
* Build up the signature
* NOTE: The output of this function MUST NOT be urlencoded.
* the encoding is handled in OAuthRequest when the final
* request is serialized
* @param OAuthRequest $request
* @param OAuthConsumer $consumer
* @param OAuthToken $token
* @return string
*/
abstract public function build_signature($request, $consumer, $token);
/**
* Verifies that a given signature is correct
* @param OAuthRequest $request
* @param OAuthConsumer $consumer
* @param OAuthToken $token
* @param string $signature
* @return bool
*/
public function check_signature($request, $consumer, $token, $signature) {
$built = $this->build_signature($request, $consumer, $token);
return $built == $signature;
}
}
/**
* The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
* where the Signature Base String is the text and the key is the concatenated values (each first
* encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
* character (ASCII code 38) even if empty.
* - Chapter 9.2 ("HMAC-SHA1")
*/
class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
function get_name() {
return "HMAC-SHA1";
}
public function build_signature($request, $consumer, $token) {
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
$key_parts = array(
$consumer->secret,
($token) ? $token->secret : ""
);
$key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
$key = implode('&', $key_parts);
return base64_encode(hash_hmac('sha1', $base_string, $key, true));
}
}
/**
* The PLAINTEXT method does not provide any security protection and SHOULD only be used
* over a secure channel such as HTTPS. It does not use the Signature Base String.
* - Chapter 9.4 ("PLAINTEXT")
*/
class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
public function get_name() {
return "PLAINTEXT";
}
/**
* oauth_signature is set to the concatenated encoded values of the Consumer Secret and
* Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
* empty. The result MUST be encoded again.
* - Chapter 9.4.1 ("Generating Signatures")
*
* Please note that the second encoding MUST NOT happen in the SignatureMethod, as
* OAuthRequest handles this!
*/
public function build_signature($request, $consumer, $token) {
$key_parts = array(
$consumer->secret,
($token) ? $token->secret : ""
);
$key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
$key = implode('&', $key_parts);
$request->base_string = $key;
return $key;
}
}
/**
* The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
* [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
* EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
* verified way to the Service Provider, in a manner which is beyond the scope of this
* specification.
* - Chapter 9.3 ("RSA-SHA1")
*/
abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
public function get_name() {
return "RSA-SHA1";
}
// Up to the SP to implement this lookup of keys. Possible ideas are:
// (1) do a lookup in a table of trusted certs keyed off of consumer
// (2) fetch via http using a url provided by the requester
// (3) some sort of specific discovery code based on request
//
// Either way should return a string representation of the certificate
protected abstract function fetch_public_cert(&$request);
// Up to the SP to implement this lookup of keys. Possible ideas are:
// (1) do a lookup in a table of trusted certs keyed off of consumer
//
// Either way should return a string representation of the certificate
protected abstract function fetch_private_cert(&$request);
public function build_signature($request, $consumer, $token) {
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
// Fetch the private key cert based on the request
$cert = $this->fetch_private_cert($request);
// Pull the private key ID from the certificate
$privatekeyid = openssl_get_privatekey($cert);
// Sign using the key
$ok = openssl_sign($base_string, $signature, $privatekeyid);
// Release the key resource
openssl_free_key($privatekeyid);
return base64_encode($signature);
}
public function check_signature($request, $consumer, $token, $signature) {
$decoded_sig = base64_decode($signature);
$base_string = $request->get_signature_base_string();
// Fetch the public key cert based on the request
$cert = $this->fetch_public_cert($request);
// Pull the public key ID from the certificate
$publickeyid = openssl_get_publickey($cert);
// Check the computed signature against the one passed in the query
$ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
// Release the key resource
openssl_free_key($publickeyid);
return $ok == 1;
}
}
class OAuthRequest {
private $parameters;
private $http_method;
private $http_url;
// for debug purposes
public $base_string;
public static $version = '1.0';
public static $POST_INPUT = 'php://input';
function __construct($http_method, $http_url, $parameters=NULL) {
@$parameters or $parameters = array();
$parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
$this->parameters = $parameters;
$this->http_method = $http_method;
$this->http_url = $http_url;
}
/**
* attempt to build up a request from what was passed to the server
*/
public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
$scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
? 'http'
: 'https';
@$http_url or $http_url = $scheme .
'://' . $_SERVER['HTTP_HOST'] .
':' .
$_SERVER['SERVER_PORT'] .
$_SERVER['REQUEST_URI'];
@$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
// We weren't handed any parameters, so let's find the ones relevant to
// this request.
// If you run XML-RPC or similar you should use this to provide your own
// parsed parameter-list
if (!$parameters) {
// Find request headers
$request_headers = OAuthUtil::get_headers();
// Parse the query-string to find GET parameters
$parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
// It's a POST request of the proper content-type, so parse POST
// parameters and add those overriding any duplicates from GET
if ($http_method == "POST"
&& @strstr($request_headers["Content-Type"],
"application/x-www-form-urlencoded")
) {
$post_data = OAuthUtil::parse_parameters(
file_get_contents(self::$POST_INPUT)
);
$parameters = array_merge($parameters, $post_data);
}
// We have a Authorization-header with OAuth data. Parse the header
// and add those overriding any duplicates from GET or POST
if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
$header_parameters = OAuthUtil::split_header(
$request_headers['Authorization']
);
$parameters = array_merge($parameters, $header_parameters);
}
}
return new OAuthRequest($http_method, $http_url, $parameters);
}
/**
* pretty much a helper function to set up the request
*/
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
@$parameters or $parameters = array();
$defaults = array("oauth_version" => OAuthRequest::$version,
"oauth_nonce" => OAuthRequest::generate_nonce(),
"oauth_timestamp" => OAuthRequest::generate_timestamp(),
"oauth_consumer_key" => $consumer->key);
if ($token)
$defaults['oauth_token'] = $token->key;
$parameters = array_merge($defaults, $parameters);
return new OAuthRequest($http_method, $http_url, $parameters);
}
public function set_parameter($name, $value, $allow_duplicates = true) {
if ($allow_duplicates && isset($this->parameters[$name])) {
// We have already added parameter(s) with this name, so add to the list
if (is_scalar($this->parameters[$name])) {
// This is the first duplicate, so transform scalar (string)
// into an array so we can add the duplicates
$this->parameters[$name] = array($this->parameters[$name]);
}
$this->parameters[$name][] = $value;
} else {
$this->parameters[$name] = $value;
}
}
public function get_parameter($name) {
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
}
public function get_parameters() {
return $this->parameters;
}
public function unset_parameter($name) {
unset($this->parameters[$name]);
}
/**
* The request parameters, sorted and concatenated into a normalized string.
* @return string
*/
public function get_signable_parameters() {
// Grab all parameters
$params = $this->parameters;
// Remove oauth_signature if present
// Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
if (isset($params['oauth_signature'])) {
unset($params['oauth_signature']);
}
return OAuthUtil::build_http_query($params);
}
/**
* Returns the base string of this request
*
* The base string defined as the method, the url
* and the parameters (normalized), each urlencoded
* and the concated with &.
*/
public function get_signature_base_string() {
$parts = array(
$this->get_normalized_http_method(),
$this->get_normalized_http_url(),
$this->get_signable_parameters()
);
$parts = OAuthUtil::urlencode_rfc3986($parts);
return implode('&', $parts);
}
/**
* just uppercases the http method
*/
public function get_normalized_http_method() {
return strtoupper($this->http_method);
}
/**
* parses the url and rebuilds it to be
* scheme://host/path
*/
public function get_normalized_http_url() {
$parts = parse_url($this->http_url);
$port = @$parts['port'];
$scheme = $parts['scheme'];
$host = $parts['host'];
$path = @$parts['path'];
$port or $port = ($scheme == 'https') ? '443' : '80';
if (($scheme == 'https' && $port != '443')
|| ($scheme == 'http' && $port != '80')) {
$host = "$host:$port";
}
return "$scheme://$host$path";
}
/**
* builds a url usable for a GET request
*/
public function to_url() {
$post_data = $this->to_postdata();
$out = $this->get_normalized_http_url();
if ($post_data) {
$out .= '?'.$post_data;
}
return $out;
}
/**
* builds the data one would send in a POST request
*/
public function to_postdata() {
return OAuthUtil::build_http_query($this->parameters);
}
/**
* builds the Authorization: header
*/
public function to_header($realm=null) {
$first = true;
if($realm) {
$out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
$first = false;
} else
$out = 'Authorization: OAuth';
$total = array();
foreach ($this->parameters as $k => $v) {
if (substr($k, 0, 5) != "oauth") continue;
if (is_array($v)) {
throw new OAuthException('Arrays not supported in headers');
}
$out .= ($first) ? ' ' : ',';
$out .= OAuthUtil::urlencode_rfc3986($k) .
'="' .
OAuthUtil::urlencode_rfc3986($v) .
'"';
$first = false;
}
return $out;
}
public function __toString() {
return $this->to_url();
}
public function sign_request($signature_method, $consumer, $token) {
$this->set_parameter(
"oauth_signature_method",
$signature_method->get_name(),
false
);
$signature = $this->build_signature($signature_method, $consumer, $token);
$this->set_parameter("oauth_signature", $signature, false);
}
public function build_signature($signature_method, $consumer, $token) {
$signature = $signature_method->build_signature($this, $consumer, $token);
return $signature;
}
/**
* util function: current timestamp
*/
private static function generate_timestamp() {
return time();
}
/**
* util function: current nonce
*/
private static function generate_nonce() {
$mt = microtime();
$rand = mt_rand();
return md5($mt . $rand); // md5s look nicer than numbers
}
}
class OAuthServer {
protected $timestamp_threshold = 300; // in seconds, five minutes
protected $version = '1.0'; // hi blaine
protected $signature_methods = array();
protected $data_store;
function __construct($data_store) {
$this->data_store = $data_store;
}
public function add_signature_method($signature_method) {
$this->signature_methods[$signature_method->get_name()] =
$signature_method;
}
// high level functions
/**
* process a request_token request
* returns the request token on success
*/
public function fetch_request_token(&$request) {
$this->get_version($request);
$consumer = $this->get_consumer($request);
// no token required for the initial token request
$token = NULL;
$this->check_signature($request, $consumer, $token);
// Rev A change
$callback = $request->get_parameter('oauth_callback');
$new_token = $this->data_store->new_request_token($consumer, $callback);
return $new_token;
}
/**
* process an access_token request
* returns the access token on success
*/
public function fetch_access_token(&$request) {
$this->get_version($request);
$consumer = $this->get_consumer($request);
// requires authorized request token
$token = $this->get_token($request, $consumer, "request");
$this->check_signature($request, $consumer, $token);
// Rev A change
$verifier = $request->get_parameter('oauth_verifier');
$new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
return $new_token;
}
/**
* verify an api call, checks all the parameters
*/
public function verify_request(&$request) {
$this->get_version($request);
$consumer = $this->get_consumer($request);
$token = $this->get_token($request, $consumer, "access");
$this->check_signature($request, $consumer, $token);
return array($consumer, $token);
}
// Internals from here
/**
* version 1
*/
private function get_version(&$request) {
$version = $request->get_parameter("oauth_version");
if (!$version) {
// Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
// Chapter 7.0 ("Accessing Protected Ressources")
$version = '1.0';
}
if ($version !== $this->version) {
throw new OAuthException("OAuth version '$version' not supported");
}
return $version;
}
/**
* figure out the signature with some defaults
*/
private function get_signature_method(&$request) {
$signature_method =
@$request->get_parameter("oauth_signature_method");
if (!$signature_method) {
// According to chapter 7 ("Accessing Protected Ressources") the signature-method
// parameter is required, and we can't just fallback to PLAINTEXT
throw new OAuthException('No signature method parameter. This parameter is required');
}
if (!in_array($signature_method,
array_keys($this->signature_methods))) {
throw new OAuthException(
"Signature method '$signature_method' not supported " .
"try one of the following: " .
implode(", ", array_keys($this->signature_methods))
);
}
return $this->signature_methods[$signature_method];
}
/**
* try to find the consumer for the provided request's consumer key
*/
private function get_consumer(&$request) {
$consumer_key = @$request->get_parameter("oauth_consumer_key");
if (!$consumer_key) {
throw new OAuthException("Invalid consumer key");
}
$consumer = $this->data_store->lookup_consumer($consumer_key);
if (!$consumer) {
throw new OAuthException("Invalid consumer");
}
return $consumer;
}
/**
* try to find the token for the provided request's token key
*/
private function get_token(&$request, $consumer, $token_type="access") {
$token_field = @$request->get_parameter('oauth_token');
$token = $this->data_store->lookup_token(
$consumer, $token_type, $token_field
);
if (!$token) {
throw new OAuthException("Invalid $token_type token: $token_field");
}
return $token;
}
/**
* all-in-one function to check the signature on a request
* should guess the signature method appropriately
*/
private function check_signature(&$request, $consumer, $token) {
// this should probably be in a different method
$timestamp = @$request->get_parameter('oauth_timestamp');
$nonce = @$request->get_parameter('oauth_nonce');
$this->check_timestamp($timestamp);
$this->check_nonce($consumer, $token, $nonce, $timestamp);
$signature_method = $this->get_signature_method($request);
$signature = $request->get_parameter('oauth_signature');
$valid_sig = $signature_method->check_signature(
$request,
$consumer,
$token,
$signature
);
if (!$valid_sig) {
throw new OAuthException("Invalid signature");
}
}
/**
* check that the timestamp is new enough
*/
private function check_timestamp($timestamp) {
if( ! $timestamp )
throw new OAuthException(
'Missing timestamp parameter. The parameter is required'
);
// verify that timestamp is recentish
$now = time();
if (abs($now - $timestamp) > $this->timestamp_threshold) {
throw new OAuthException(
"Expired timestamp, yours $timestamp, ours $now"
);
}
}
/**
* check that the nonce is not repeated
*/
private function check_nonce($consumer, $token, $nonce, $timestamp) {
if( ! $nonce )
throw new OAuthException(
'Missing nonce parameter. The parameter is required'
);
// verify that the nonce is uniqueish
$found = $this->data_store->lookup_nonce(
$consumer,
$token,
$nonce,
$timestamp
);
if ($found) {
throw new OAuthException("Nonce already used: $nonce");
}
}
}
class OAuthDataStore {
function lookup_consumer($consumer_key) {
// implement me
}
function lookup_token($consumer, $token_type, $token) {
// implement me
}
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
// implement me
}
function new_request_token($consumer, $callback = null) {
// return a new token attached to this consumer
}
function new_access_token($token, $consumer, $verifier = null) {
// return a new access token attached to this consumer
// for the user associated with this token if the request token
// is authorized
// should also invalidate the request token
}
}
class OAuthUtil {
public static function urlencode_rfc3986($input) {
if (is_array($input)) {
return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
} else if (is_scalar($input)) {
return str_replace(
'+',
' ',
str_replace('%7E', '~', rawurlencode($input))
);
} else {
return '';
}
}
// This decode function isn't taking into consideration the above
// modifications to the encoding process. However, this method doesn't
// seem to be used anywhere so leaving it as is.
public static function urldecode_rfc3986($string) {
return urldecode($string);
}
// Utility function for turning the Authorization: header into
// parameters, has to do some unescaping
// Can filter out any non-oauth parameters if needed (default behaviour)
public static function split_header($header, $only_allow_oauth_parameters = true) {
$pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
$offset = 0;
$params = array();
while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
$match = $matches[0];
$header_name = $matches[2][0];
$header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) {
$params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content);
}
$offset = $match[1] + strlen($match[0]);
}
if (isset($params['realm'])) {
unset($params['realm']);
}
return $params;
}
// helper to try to sort out headers for people who aren't running apache
public static function get_headers() {
if (function_exists('apache_request_headers')) {
// we need this to get the actual Authorization: header
// because apache tends to tell us it doesn't exist
$headers = apache_request_headers();
// sanitize the output of apache_request_headers because
// we always want the keys to be Cased-Like-This and arh()
// returns the headers in the same case as they are in the
// request
$out = array();
foreach( $headers AS $key => $value ) {
$key = str_replace(
" ",
"-",
ucwords(strtolower(str_replace("-", " ", $key)))
);
$out[$key] = $value;
}
} else {
// otherwise we don't have apache and are just going to have to hope
// that $_SERVER actually contains what we need
$out = array();
if( isset($_SERVER['CONTENT_TYPE']) )
$out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
if( isset($_ENV['CONTENT_TYPE']) )
$out['Content-Type'] = $_ENV['CONTENT_TYPE'];
foreach ($_SERVER as $key => $value) {
if (substr($key, 0, 5) == "HTTP_") {
// this is chaos, basically it is just there to capitalize the first
// letter of every word that is not an initial HTTP and strip HTTP
// code from przemek
$key = str_replace(
" ",
"-",
ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
);
$out[$key] = $value;
}
}
}
return $out;
}
// This function takes a input like a=b&a=c&d=e and returns the parsed
// parameters like this
// array('a' => array('b','c'), 'd' => 'e')
public static function parse_parameters( $input ) {
if (!isset($input) || !$input) return array();
$pairs = explode('&', $input);
$parsed_parameters = array();
foreach ($pairs as $pair) {
$split = explode('=', $pair, 2);
$parameter = OAuthUtil::urldecode_rfc3986($split[0]);
$value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
if (isset($parsed_parameters[$parameter])) {
// We have already recieved parameter(s) with this name, so add to the list
// of parameters with this name
if (is_scalar($parsed_parameters[$parameter])) {
// This is the first duplicate, so transform scalar (string) into an array
// so we can add the duplicates
$parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
}
$parsed_parameters[$parameter][] = $value;
} else {
$parsed_parameters[$parameter] = $value;
}
}
return $parsed_parameters;
}
public static function build_http_query($params) {
if (!$params) return '';
// Urlencode both keys and values
$keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
$values = OAuthUtil::urlencode_rfc3986(array_values($params));
$params = array_combine($keys, $values);
// Parameters are sorted by name, using lexicographical byte value ordering.
// Ref: Spec: 9.1.1 (1)
uksort($params, 'strcmp');
$pairs = array();
foreach ($params as $parameter => $value) {
if (is_array($value)) {
// If two or more parameters share the same name, they are sorted by their value
// Ref: Spec: 9.1.1 (1)
natsort($value);
foreach ($value as $duplicate_value) {
$pairs[] = $parameter . '=' . $duplicate_value;
}
} else {
$pairs[] = $parameter . '=' . $value;
}
}
// For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
// Each name-value pair is separated by an '&' character (ASCII code 38)
return implode('&', $pairs);
}
}
###########
# Oauth End
##########
#######################################################
# FACEBOOKOAUTH START
###############################################
/**
* Extends the BaseFacebook class with the intent of using
* PHP sessions to store user ids and access tokens.
*/
class Facebook extends BaseFacebook
{
/**
* Identical to the parent constructor, except that
* we start a PHP session to store the user ID and
* access token if during the course of execution
* we discover them.
*
* @param Array $config the application configuration.
* @see BaseFacebook::__construct in facebook.php
*/
public function __construct($config) {
if (!session_id()) {
session_start();
}
parent::__construct($config);
}
protected static $kSupportedKeys =
array('state', 'code', 'access_token', 'user_id');
/**
* Provides the implementations of the inherited abstract
* methods. The implementation uses PHP sessions to maintain
* a store for authorization codes, user ids, CSRF states, and
* access tokens.
*/
protected function setPersistentData($key, $value) {
if (!in_array($key, self::$kSupportedKeys)) {
self::errorLog('Unsupported key passed to setPersistentData.');
return;
}
$session_var_name = $this->constructSessionVariableName($key);
$_SESSION[$session_var_name] = $value;
}
protected function getPersistentData($key, $default = false) {
if (!in_array($key, self::$kSupportedKeys)) {
self::errorLog('Unsupported key passed to getPersistentData.');
return $default;
}
$session_var_name = $this->constructSessionVariableName($key);
return isset($_SESSION[$session_var_name]) ?
$_SESSION[$session_var_name] : $default;
}
protected function clearPersistentData($key) {
if (!in_array($key, self::$kSupportedKeys)) {
self::errorLog('Unsupported key passed to clearPersistentData.');
return;
}
$session_var_name = $this->constructSessionVariableName($key);
unset($_SESSION[$session_var_name]);
}
protected function clearAllPersistentData() {
foreach (self::$kSupportedKeys as $key) {
$this->clearPersistentData($key);
}
}
protected function constructSessionVariableName($key) {
return implode('_', array('fb',
$this->getAppId(),
$key));
}
}
/**
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
if (!function_exists('curl_init')) {
throw new Exception('Facebook needs the CURL PHP extension.');
}
if (!function_exists('json_decode')) {
throw new Exception('Facebook needs the JSON PHP extension.');
}
/**
* Thrown when an API call returns an exception.
*
* @author Naitik Shah
*/
class FacebookApiException extends Exception
{
/**
* The result from the API server that represents the exception information.
*/
protected $result;
/**
* Make a new API Exception with the given result.
*
* @param array $result The result from the API server
*/
public function __construct($result) {
$this->result = $result;
$code = isset($result['error_code']) ? $result['error_code'] : 0;
if (isset($result['error_description'])) {
// OAuth 2.0 Draft 10 style
$msg = $result['error_description'];
} else if (isset($result['error']) && is_array($result['error'])) {
// OAuth 2.0 Draft 00 style
$msg = $result['error']['message'];
} else if (isset($result['error_msg'])) {
// Rest server style
$msg = $result['error_msg'];
} else {
$msg = 'Unknown Error. Check getResult()';
}
parent::__construct($msg, $code);
}
/**
* Return the associated result object returned by the API server.
*
* @return array The result from the API server
*/
public function getResult() {
return $this->result;
}
/**
* Returns the associated type for the error. This will default to
* 'Exception' when a type is not available.
*
* @return string
*/
public function getType() {
if (isset($this->result['error'])) {
$error = $this->result['error'];
if (is_string($error)) {
// OAuth 2.0 Draft 10 style
return $error;
} else if (is_array($error)) {
// OAuth 2.0 Draft 00 style
if (isset($error['type'])) {
return $error['type'];
}
}
}
return 'Exception';
}
/**
* To make debugging easier.
*
* @return string The string representation of the error
*/
public function __toString() {
$str = $this->getType() . ': ';
if ($this->code != 0) {
$str .= $this->code . ': ';
}
return $str . $this->message;
}
}
/**
* Provides access to the Facebook Platform. This class provides
* a majority of the functionality needed, but the class is abstract
* because it is designed to be sub-classed. The subclass must
* implement the four abstract methods listed at the bottom of
* the file.
*
* @author Naitik Shah
*/
abstract class BaseFacebook
{
/**
* Version.
*/
const VERSION = '3.1.1';
/**
* Default options for curl.
*/
public static $CURL_OPTS = array(
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_USERAGENT => 'facebook-php-3.1',
);
/**
* List of query parameters that get automatically dropped when rebuilding
* the current URL.
*/
protected static $DROP_QUERY_PARAMS = array(
'code',
'state',
'signed_request',
);
/**
* Maps aliases to Facebook domains.
*/
public static $DOMAIN_MAP = array(
'api' => 'https://api.facebook.com/',
'api_video' => 'https://api-video.facebook.com/',
'api_read' => 'https://api-read.facebook.com/',
'graph' => 'https://graph.facebook.com/',
'www' => 'https://www.facebook.com/',
);
/**
* The Application ID.
*
* @var string
*/
protected $appId;
/**
* The Application API Secret.
*
* @var string
*/
protected $apiSecret;
/**
* The ID of the Facebook user, or 0 if the user is logged out.
*
* @var integer
*/
protected $user;
/**
* The data from the signed_request token.
*/
protected $signedRequest;
/**
* A CSRF state variable to assist in the defense against CSRF attacks.
*/
protected $state;
/**
* The OAuth access token received in exchange for a valid authorization
* code. null means the access token has yet to be determined.
*
* @var string
*/
protected $accessToken = null;
/**
* Indicates if the CURL based @ syntax for file uploads is enabled.
*
* @var boolean
*/
protected $fileUploadSupport = false;
/**
* Initialize a Facebook Application.
*
* The configuration:
* - appId: the application ID
* - secret: the application secret
* - fileUpload: (optional) boolean indicating if file uploads are enabled
*
* @param array $config The application configuration
*/
public function __construct($config) {
$this->setAppId($config['appId']);
$this->setApiSecret($config['secret']);
if (isset($config['fileUpload'])) {
$this->setFileUploadSupport($config['fileUpload']);
}
$state = $this->getPersistentData('state');
if (!empty($state)) {
$this->state = $this->getPersistentData('state');
}
}
/**
* Set the Application ID.
*
* @param string $appId The Application ID
* @return BaseFacebook
*/
public function setAppId($appId) {
$this->appId = $appId;
return $this;
}
/**
* Get the Application ID.
*
* @return string the Application ID
*/
public function getAppId() {
return $this->appId;
}
/**
* Set the API Secret.
*
* @param string $apiSecret The API Secret
* @return BaseFacebook
*/
public function setApiSecret($apiSecret) {
$this->apiSecret = $apiSecret;
return $this;
}
/**
* Get the API Secret.
*
* @return string the API Secret
*/
public function getApiSecret() {
return $this->apiSecret;
}
/**
* Set the file upload support status.
*
* @param boolean $fileUploadSupport The file upload support status.
* @return BaseFacebook
*/
public function setFileUploadSupport($fileUploadSupport) {
$this->fileUploadSupport = $fileUploadSupport;
return $this;
}
/**
* Get the file upload support status.
*
* @return boolean true if and only if the server supports file upload.
*/
public function useFileUploadSupport() {
return $this->fileUploadSupport;
}
/**
* Sets the access token for api calls. Use this if you get
* your access token by other means and just want the SDK
* to use it.
*
* @param string $access_token an access token.
* @return BaseFacebook
*/
public function setAccessToken($access_token) {
$this->accessToken = $access_token;
return $this;
}
/**
* Determines the access token that should be used for API calls.
* The first time this is called, $this->accessToken is set equal
* to either a valid user access token, or it's set to the application
* access token if a valid user access token wasn't available. Subsequent
* calls return whatever the first call returned.
*
* @return string The access token
*/
public function getAccessToken() {
if ($this->accessToken !== null) {
// we've done this already and cached it. Just return.
return $this->accessToken;
}
// first establish access token to be the application
// access token, in case we navigate to the /oauth/access_token
// endpoint, where SOME access token is required.
$this->setAccessToken($this->getApplicationAccessToken());
$user_access_token = $this->getUserAccessToken();
if ($user_access_token) {
$this->setAccessToken($user_access_token);
}
return $this->accessToken;
}
/**
* Determines and returns the user access token, first using
* the signed request if present, and then falling back on
* the authorization code if present. The intent is to
* return a valid user access token, or false if one is determined
* to not be available.
*
* @return string A valid user access token, or false if one
* could not be determined.
*/
protected function getUserAccessToken() {
// first, consider a signed request if it's supplied.
// if there is a signed request, then it alone determines
// the access token.
$signed_request = $this->getSignedRequest();
if ($signed_request) {
// apps.facebook.com hands the access_token in the signed_request
if (array_key_exists('oauth_token', $signed_request)) {
$access_token = $signed_request['oauth_token'];
$this->setPersistentData('access_token', $access_token);
return $access_token;
}
// the JS SDK puts a code in with the redirect_uri of ''
if (array_key_exists('code', $signed_request)) {
$code = $signed_request['code'];
$access_token = $this->getAccessTokenFromCode($code, '');
if ($access_token) {
$this->setPersistentData('code', $code);
$this->setPersistentData('access_token', $access_token);
return $access_token;
}
}
// signed request states there's no access token, so anything
// stored should be cleared.
$this->clearAllPersistentData();
return false; // respect the signed request's data, even
// if there's an authorization code or something else
}
$code = $this->getCode();
if ($code && $code != $this->getPersistentData('code')) {
$access_token = $this->getAccessTokenFromCode($code);
if ($access_token) {
$this->setPersistentData('code', $code);
$this->setPersistentData('access_token', $access_token);
return $access_token;
}
// code was bogus, so everything based on it should be invalidated.
$this->clearAllPersistentData();
return false;
}
// as a fallback, just return whatever is in the persistent
// store, knowing nothing explicit (signed request, authorization
// code, etc.) was present to shadow it (or we saw a code in $_REQUEST,
// but it's the same as what's in the persistent store)
return $this->getPersistentData('access_token');
}
/**
* Retrieve the signed request, either from a request parameter or,
* if not present, from a cookie.
*
* @return string the signed request, if available, or null otherwise.
*/
public function getSignedRequest() {
if (!$this->signedRequest) {
if (isset($_REQUEST['signed_request'])) {
$this->signedRequest = $this->parseSignedRequest(
$_REQUEST['signed_request']);
} else if (isset($_COOKIE[$this->getSignedRequestCookieName()])) {
$this->signedRequest = $this->parseSignedRequest(
$_COOKIE[$this->getSignedRequestCookieName()]);
}
}
return $this->signedRequest;
}
/**
* Get the UID of the connected user, or 0
* if the Facebook user is not connected.
*
* @return string the UID if available.
*/
public function getUser() {
if ($this->user !== null) {
// we've already determined this and cached the value.
return $this->user;
}
return $this->user = $this->getUserFromAvailableData();
}
/**
* Determines the connected user by first examining any signed
* requests, then considering an authorization code, and then
* falling back to any persistent store storing the user.
*
* @return integer The id of the connected Facebook user,
* or 0 if no such user exists.
*/
protected function getUserFromAvailableData() {
// if a signed request is supplied, then it solely determines
// who the user is.
$signed_request = $this->getSignedRequest();
if ($signed_request) {
if (array_key_exists('user_id', $signed_request)) {
$user = $signed_request['user_id'];
$this->setPersistentData('user_id', $signed_request['user_id']);
return $user;
}
// if the signed request didn't present a user id, then invalidate
// all entries in any persistent store.
$this->clearAllPersistentData();
return 0;
}
$user = $this->getPersistentData('user_id', $default = 0);
$persisted_access_token = $this->getPersistentData('access_token');
// use access_token to fetch user id if we have a user access_token, or if
// the cached access token has changed.
$access_token = $this->getAccessToken();
if ($access_token &&
$access_token != $this->getApplicationAccessToken() &&
!($user && $persisted_access_token == $access_token)) {
$user = $this->getUserFromAccessToken();
if ($user) {
$this->setPersistentData('user_id', $user);
} else {
$this->clearAllPersistentData();
}
}
return $user;
}
/**
* Get a Login URL for use with redirects. By default, full page redirect is
* assumed. If you are using the generated URL with a window.open() call in
* JavaScript, you can pass in display=popup as part of the $params.
*
* The parameters:
* - redirect_uri: the url to go to after a successful login
* - scope: comma separated list of requested extended perms
*
* @param array $params Provide custom parameters
* @return string The URL for the login flow
*/
public function getLoginUrl($params=array()) {
$this->establishCSRFTokenState();
$currentUrl = $this->getCurrentUrl();
$currentUrl = ($_SERVER[SERVER_PORT]==80 ? "http://".$_SERVER[SERVER_NAME] : "https://".$_SERVER[SERVER_NAME])."/accountsettings.php?tab=socialsetup&setupoauth_facebook=2";
// if 'scope' is passed as an array, convert to comma separated list
$scopeParams = isset($params['scope']) ? $params['scope'] : null;
if ($scopeParams && is_array($scopeParams)) {
$params['scope'] = implode(',', $scopeParams);
}
return $this->getUrl(
'www',
'dialog/oauth',
array_merge(array(
'client_id' => $this->getAppId(),
'redirect_uri' => $currentUrl, // possibly overwritten
'state' => $this->state),
$params));
}
/**
* Get a Logout URL suitable for use with redirects.
*
* The parameters:
* - next: the url to go to after a successful logout
*
* @param array $params Provide custom parameters
* @return string The URL for the logout flow
*/
public function getLogoutUrl($params=array()) {
return $this->getUrl(
'www',
'logout.php',
array_merge(array(
'next' => $this->getCurrentUrl(),
'access_token' => $this->getAccessToken(),
), $params)
);
}
/**
* Get a login status URL to fetch the status from Facebook.
*
* The parameters:
* - ok_session: the URL to go to if a session is found
* - no_session: the URL to go to if the user is not connected
* - no_user: the URL to go to if the user is not signed into facebook
*
* @param array $params Provide custom parameters
* @return string The URL for the logout flow
*/
public function getLoginStatusUrl($params=array()) {
return $this->getUrl(
'www',
'extern/login_status.php',
array_merge(array(
'api_key' => $this->getAppId(),
'no_session' => $this->getCurrentUrl(),
'no_user' => $this->getCurrentUrl(),
'ok_session' => $this->getCurrentUrl(),
'session_version' => 3,
), $params)
);
}
/**
* Make an API call.
*
* @return mixed The decoded response
*/
public function api(/* polymorphic */) {
$args = func_get_args();
if (is_array($args[0])) {
return $this->_restserver($args[0]);
} else {
return call_user_func_array(array($this, '_graph'), $args);
}
}
/**
* Constructs and returns the name of the cookie that
* potentially houses the signed request for the app user.
* The cookie is not set by the BaseFacebook class, but
* it may be set by the JavaScript SDK.
*
* @return string the name of the cookie that would house
* the signed request value.
*/
protected function getSignedRequestCookieName() {
return 'fbsr_'.$this->getAppId();
}
/**
* Get the authorization code from the query parameters, if it exists,
* and otherwise return false to signal no authorization code was
* discoverable.
*
* @return mixed The authorization code, or false if the authorization
* code could not be determined.
*/
protected function getCode() {
if (isset($_REQUEST['code'])) {
if ($this->state !== null &&
isset($_REQUEST['state']) &&
$this->state === $_REQUEST['state']) {
// CSRF state has done its job, so clear it
$this->state = null;
$this->clearPersistentData('state');
return $_REQUEST['code'];
} else {
self::errorLog('CSRF state token does not match one provided.');
return false;
}
}
return false;
}
/**
* Retrieves the UID with the understanding that
* $this->accessToken has already been set and is
* seemingly legitimate. It relies on Facebook's Graph API
* to retrieve user information and then extract
* the user ID.
*
* @return integer Returns the UID of the Facebook user, or 0
* if the Facebook user could not be determined.
*/
protected function getUserFromAccessToken() {
try {
$user_info = $this->api('/me');
return $user_info['id'];
} catch (FacebookApiException $e) {
return 0;
}
}
/**
* Returns the access token that should be used for logged out
* users when no authorization code is available.
*
* @return string The application access token, useful for gathering
* public information about users and applications.
*/
protected function getApplicationAccessToken() {
return $this->appId.'|'.$this->apiSecret;
}
/**
* Lays down a CSRF state token for this process.
*
* @return void
*/
protected function establishCSRFTokenState() {
if ($this->state === null) {
$this->state = md5(uniqid(mt_rand(), true));
$this->setPersistentData('state', $this->state);
}
}
/**
* Retrieves an access token for the given authorization code
* (previously generated from www.facebook.com on behalf of
* a specific user). The authorization code is sent to graph.facebook.com
* and a legitimate access token is generated provided the access token
* and the user for which it was generated all match, and the user is
* either logged in to Facebook or has granted an offline access permission.
*
* @param string $code An authorization code.
* @return mixed An access token exchanged for the authorization code, or
* false if an access token could not be generated.
*/
protected function getAccessTokenFromCode($code, $redirect_uri = null) {
if (empty($code)) {
return false;
}
if ($redirect_uri === null) {
$redirect_uri = $this->getCurrentUrl();
}
try {
// need to circumvent json_decode by calling _oauthRequest
// directly, since response isn't JSON format.
$access_token_response =
$this->_oauthRequest(
$this->getUrl('graph', '/oauth/access_token'),
$params = array('client_id' => $this->getAppId(),
'client_secret' => $this->getApiSecret(),
'redirect_uri' => $redirect_uri,
'code' => $code));
} catch (FacebookApiException $e) {
// most likely that user very recently revoked authorization.
// In any event, we don't have an access token, so say so.
return false;
}
if (empty($access_token_response)) {
return false;
}
$response_params = array();
parse_str($access_token_response, $response_params);
if (!isset($response_params['access_token'])) {
return false;
}
return $response_params['access_token'];
}
/**
* Invoke the old restserver.php endpoint.
*
* @param array $params Method call object
*
* @return mixed The decoded response object
* @throws FacebookApiException
*/
protected function _restserver($params) {
// generic application level parameters
$params['api_key'] = $this->getAppId();
$params['format'] = 'json-strings';
$result = json_decode($this->_oauthRequest(
$this->getApiUrl($params['method']),
$params
), true);
// results are returned, errors are thrown
if (is_array($result) && isset($result['error_code'])) {
$this->throwAPIException($result);
}
if ($params['method'] === 'auth.expireSession' ||
$params['method'] === 'auth.revokeAuthorization') {
$this->destroySession();
}
return $result;
}
/**
* Invoke the Graph API.
*
* @param string $path The path (required)
* @param string $method The http method (default 'GET')
* @param array $params The query/post data
*
* @return mixed The decoded response object
* @throws FacebookApiException
*/
protected function _graph($path, $method = 'GET', $params = array()) {
if (is_array($method) && empty($params)) {
$params = $method;
$method = 'GET';
}
$params['method'] = $method; // method override as we always do a POST
$result = json_decode($this->_oauthRequest(
$this->getUrl('graph', $path),
$params
), true);
// results are returned, errors are thrown
if (is_array($result) && isset($result['error'])) {
$this->throwAPIException($result);
}
return $result;
}
/**
* Make a OAuth Request.
*
* @param string $url The path (required)
* @param array $params The query/post data
*
* @return string The decoded response object
* @throws FacebookApiException
*/
protected function _oauthRequest($url, $params) {
if (!isset($params['access_token'])) {
$params['access_token'] = $this->getAccessToken();
}
// json_encode all params values that are not strings
foreach ($params as $key => $value) {
if (!is_string($value)) {
$params[$key] = json_encode($value);
}
}
return $this->makeRequest($url, $params);
}
/**
* Makes an HTTP request. This method can be overridden by subclasses if
* developers want to do fancier things or use something other than curl to
* make the request.
*
* @param string $url The URL to make the request to
* @param array $params The parameters to use for the POST body
* @param CurlHandler $ch Initialized curl handle
*
* @return string The response text
*/
protected function makeRequest($url, $params, $ch=null) {
if (!$ch) {
$ch = curl_init();
}
$opts = self::$CURL_OPTS;
if ($this->useFileUploadSupport()) {
$opts[CURLOPT_POSTFIELDS] = $params;
} else {
$opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
}
$opts[CURLOPT_URL] = $url;
// disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
// for 2 seconds if the server does not support this header.
if (isset($opts[CURLOPT_HTTPHEADER])) {
$existing_headers = $opts[CURLOPT_HTTPHEADER];
$existing_headers[] = 'Expect:';
$opts[CURLOPT_HTTPHEADER] = $existing_headers;
} else {
$opts[CURLOPT_HTTPHEADER] = array('Expect:');
}
curl_setopt_array($ch, $opts);
$result = curl_exec($ch);
if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT
self::errorLog('Invalid or no certificate authority found, '.
'using bundled information');
curl_setopt($ch, CURLOPT_CAINFO,
dirname(__FILE__) . '/fb_ca_chain_bundle.crt');
$result = curl_exec($ch);
}
if ($result === false) {
$e = new FacebookApiException(array(
'error_code' => curl_errno($ch),
'error' => array(
'message' => curl_error($ch),
'type' => 'CurlException',
),
));
curl_close($ch);
throw $e;
}
curl_close($ch);
return $result;
}
/**
* Parses a signed_request and validates the signature.
*
* @param string $signed_request A signed token
* @return array The payload inside it or null if the sig is wrong
*/
protected function parseSignedRequest($signed_request) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
// decode the data
$sig = self::base64UrlDecode($encoded_sig);
$data = json_decode(self::base64UrlDecode($payload), true);
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
self::errorLog('Unknown algorithm. Expected HMAC-SHA256');
return null;
}
// check sig
$expected_sig = hash_hmac('sha256', $payload,
$this->getApiSecret(), $raw = true);
if ($sig !== $expected_sig) {
self::errorLog('Bad Signed JSON signature!');
return null;
}
return $data;
}
/**
* Build the URL for api given parameters.
*
* @param $method String the method name.
* @return string The URL for the given parameters
*/
protected function getApiUrl($method) {
static $READ_ONLY_CALLS =
array('admin.getallocation' => 1,
'admin.getappproperties' => 1,
'admin.getbannedusers' => 1,
'admin.getlivestreamvialink' => 1,
'admin.getmetrics' => 1,
'admin.getrestrictioninfo' => 1,
'application.getpublicinfo' => 1,
'auth.getapppublickey' => 1,
'auth.getsession' => 1,
'auth.getsignedpublicsessiondata' => 1,
'comments.get' => 1,
'connect.getunconnectedfriendscount' => 1,
'dashboard.getactivity' => 1,
'dashboard.getcount' => 1,
'dashboard.getglobalnews' => 1,
'dashboard.getnews' => 1,
'dashboard.multigetcount' => 1,
'dashboard.multigetnews' => 1,
'data.getcookies' => 1,
'events.get' => 1,
'events.getmembers' => 1,
'fbml.getcustomtags' => 1,
'feed.getappfriendstories' => 1,
'feed.getregisteredtemplatebundlebyid' => 1,
'feed.getregisteredtemplatebundles' => 1,
'fql.multiquery' => 1,
'fql.query' => 1,
'friends.arefriends' => 1,
'friends.get' => 1,
'friends.getappusers' => 1,
'friends.getlists' => 1,
'friends.getmutualfriends' => 1,
'gifts.get' => 1,
'groups.get' => 1,
'groups.getmembers' => 1,
'intl.gettranslations' => 1,
'links.get' => 1,
'notes.get' => 1,
'notifications.get' => 1,
'pages.getinfo' => 1,
'pages.isadmin' => 1,
'pages.isappadded' => 1,
'pages.isfan' => 1,
'permissions.checkavailableapiaccess' => 1,
'permissions.checkgrantedapiaccess' => 1,
'photos.get' => 1,
'photos.getalbums' => 1,
'photos.gettags' => 1,
'profile.getinfo' => 1,
'profile.getinfooptions' => 1,
'stream.get' => 1,
'stream.getcomments' => 1,
'stream.getfilters' => 1,
'users.getinfo' => 1,
'users.getloggedinuser' => 1,
'users.getstandardinfo' => 1,
'users.hasapppermission' => 1,
'users.isappuser' => 1,
'users.isverified' => 1,
'video.getuploadlimits' => 1);
$name = 'api';
if (isset($READ_ONLY_CALLS[strtolower($method)])) {
$name = 'api_read';
} else if (strtolower($method) == 'video.upload') {
$name = 'api_video';
}
return self::getUrl($name, 'restserver.php');
}
/**
* Build the URL for given domain alias, path and parameters.
*
* @param $name string The name of the domain
* @param $path string Optional path (without a leading slash)
* @param $params array Optional query parameters
*
* @return string The URL for the given parameters
*/
protected function getUrl($name, $path='', $params=array()) {
$url = self::$DOMAIN_MAP[$name];
if ($path) {
if ($path[0] === '/') {
$path = substr($path, 1);
}
$url .= $path;
}
if ($params) {
$url .= '?' . http_build_query($params, null, '&');
}
return $url;
}
/**
* Returns the Current URL, stripping it of known FB parameters that should
* not persist.
*
* @return string The current URL
*/
protected function getCurrentUrl() {
if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1)
|| isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'
) {
$protocol = 'https://';
}
else {
$protocol = 'http://';
}
$currentUrl = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$parts = parse_url($currentUrl);
$query = '';
if (!empty($parts['query'])) {
// drop known fb params
$params = explode('&', $parts['query']);
$retained_params = array();
foreach ($params as $param) {
if ($this->shouldRetainParam($param)) {
$retained_params[] = $param;
}
}
if (!empty($retained_params)) {
$query = '?'.implode($retained_params, '&');
}
}
// use port if non default
$port =
isset($parts['port']) &&
(($protocol === 'http://' && $parts['port'] !== 80) ||
($protocol === 'https://' && $parts['port'] !== 443))
? ':' . $parts['port'] : '';
// rebuild
return $protocol . $parts['host'] . $port . $parts['path'] . $query;
}
/**
* Returns true if and only if the key or key/value pair should
* be retained as part of the query string. This amounts to
* a brute-force search of the very small list of Facebook-specific
* params that should be stripped out.
*
* @param string $param A key or key/value pair within a URL's query (e.g.
* 'foo=a', 'foo=', or 'foo'.
*
* @return boolean
*/
protected function shouldRetainParam($param) {
foreach (self::$DROP_QUERY_PARAMS as $drop_query_param) {
if (strpos($param, $drop_query_param.'=') === 0) {
return false;
}
}
return true;
}
/**
* Analyzes the supplied result to see if it was thrown
* because the access token is no longer valid. If that is
* the case, then the persistent store is cleared.
*
* @param $result array A record storing the error message returned
* by a failed API call.
*/
protected function throwAPIException($result) {
$e = new FacebookApiException($result);
switch ($e->getType()) {
// OAuth 2.0 Draft 00 style
case 'OAuthException':
// OAuth 2.0 Draft 10 style
case 'invalid_token':
// REST server errors are just Exceptions
case 'Exception':
$message = $e->getMessage();
if ((strpos($message, 'Error validating access token') !== false) ||
(strpos($message, 'Invalid OAuth access token') !== false)) {
$this->setAccessToken(null);
$this->user = 0;
$this->clearAllPersistentData();
}
}
throw $e;
}
/**
* Prints to the error log if you aren't in command line mode.
*
* @param string $msg Log message
*/
protected static function errorLog($msg) {
// disable error log if we are running in a CLI environment
// @codeCoverageIgnoreStart
if (php_sapi_name() != 'cli') {
error_log($msg);
}
// uncomment this if you want to see the errors on the page
// print 'error_log: '.$msg."\n";
// @codeCoverageIgnoreEnd
}
/**
* Base64 encoding that doesn't need to be urlencode()ed.
* Exactly the same as base64_encode except it uses
* - instead of +
* _ instead of /
*
* @param string $input base64UrlEncoded string
* @return string
*/
protected static function base64UrlDecode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
/**
* Destroy the current session
*/
public function destroySession() {
$this->setAccessToken(null);
$this->user = 0;
$this->clearAllPersistentData();
}
/**
* Each of the following four methods should be overridden in
* a concrete subclass, as they are in the provided Facebook class.
* The Facebook class uses PHP sessions to provide a primitive
* persistent store, but another subclass--one that you implement--
* might use a database, memcache, or an in-memory cache.
*
* @see Facebook
*/
/**
* Stores the given ($key, $value) pair, so that future calls to
* getPersistentData($key) return $value. This call may be in another request.
*
* @param string $key
* @param array $value
*
* @return void
*/
abstract protected function setPersistentData($key, $value);
/**
* Get the data for $key, persisted by BaseFacebook::setPersistentData()
*
* @param string $key The key of the data to retrieve
* @param boolean $default The default value to return if $key is not found
*
* @return mixed
*/
abstract protected function getPersistentData($key, $default = false);
/**
* Clear the data with $key from the persistent storage
*
* @param string $key
* @return void
*/
abstract protected function clearPersistentData($key);
/**
* Clear all data from the persistent storage
*
* @return void
*/
abstract protected function clearAllPersistentData();
}
#######################
# Facebookoauth End
################################################
##################################################
# Facebook Start
#####################
if($_GET[setupoauth_facebook]=="1")
{
//this is for RIOGenesis app
if (strstr($_SERVER[SERVER_NAME],"matraex"))
{
//$facebook_appid = "102933686492124";
//$facebook_appsecret = "f418cb9472f1e8c14a17739b0e433b81";
// updated with new app 07302015 JT
$facebook_appid = "1506568339635093";
$facebook_appsecret = "eeceb917384971fba3ec131d22e3cbf3";
}
else
{
//$facebook_appid = "490524621009706";
//$facebook_appsecret = " d49b751e9db5fd31a0a7b1c145d35139";
// updated with new app 07302015 JT
$facebook_appid = "1506568339635093";
$facebook_appsecret = "eeceb917384971fba3ec131d22e3cbf3";
}
$facebook_appaccesstoken = $facebook_appid."|".$facebook_appsecret;
$facebook = new Facebook(array(
'appId' => $facebook_appid,
'secret' => $facebook_appsecret,
'cookie' => true
));
$current_accesstoken = $facebook->getAccessToken();
if($current_accesstoken==$facebook_appaccesstoken)
{
$fb_loginUrl = $facebook->getLoginUrl(array(
'canvas' => 1,
'fbconnect' => 0,
'scope' => 'publish_actions'
));
}
else
{
$fb_user = $facebook->getUser();
$fb_logoutUrl = $facebook->getLogoutUrl();
}
if ($fb_user)
{
try
{
// Proceed knowing you have a logged in user who's authenticated.
$facebook_user_data = $facebook->api('/me');
$facebook_user_accesstoken = $facebook->getAccessToken();
print_r($facebook_user_data);
}
catch (FacebookApiException $e)
{
error_log($e);
$user = null;
}
}
else
{
if($fb_loginUrl)
{
header('Location: '.$fb_loginUrl);
exit_wrapper ();
}
}
}
// $attachment has the following options:
// $attachment[name] - this is the title or the post, such as story title when posting a story link
// $attachment[caption] - Caption of the Post
// $attachment[link] - URL or where the name/title links to
// $attachment[description] - description/text of the post
// $attachment[picture] - description/text of the post
function facebook_post($oauthuserid='',$messagetopost='',$attachment=0){
$oauth_accounts = getoauthuserinfo(0,0,0,$oauthuserid);
if($oauth_accounts[0][oauthuserkey]){
//this is token and token secret for the USERS oauth authentication
$facebook_access_token = trim($oauth_accounts[0][oauthuserkey]);
$facebook_userid = trim($oauth_accounts[0][oauthuserproviderref]);
$params[access_token] = $facebook_access_token;
$params[message] = $messagetopost;
if(count($attachment)>0){
$params[name] = $attachment[name];
$params[caption] = $attachment[caption];
$params[link] = $attachment[link];
$params[description] = $attachment[description];
$params[picture] = $attachment[picture];
}
$url = "https://graph.facebook.com/$facebook_userid/feed";
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_POSTFIELDS => $params,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_VERBOSE => true
));
$result = curl_exec($ch);
$result = json_decode($result);
if($result->id){
return $result->id;
} else {
return false;
}
}else{
return false;
}
}
function facebook_verify($oauthuserid=''){
$oauth_accounts = getoauthuserinfo(0,0,0,$oauthuserid);
if(trim($oauth_accounts[0][oauthuserprovider])!="facebook"){
return false;
}
if($oauth_accounts[0][oauthuserkey]){
//this is token and token secret for the USERS oauth authentication
$facebook_access_token = trim($oauth_accounts[0][oauthuserkey]);
$facebook_userid = trim($oauth_accounts[0][oauthuserproviderref]);
//$params[access_token] = $facebook_access_token;
$url = "https://graph.facebook.com/me?access_token=".$facebook_access_token;
$facebook_returned = @file_get_contents($url);
if($facebook_returned === FALSE)
{
"";//we have an error//echo "Social Sharing Service Unavailable at this time.";
}
$picture_url = "https://graph.facebook.com/".$facebook_userid."/picture";
social_update_avatar($oauthuserid,$picture_url);
$result = json_decode($facebook_returned);
//d(facebook_verifyresult,$result);
if($result->id){
return true;
} else {
return false;
}
}else{
return false;
}
}
##################################################
# Facebook End
#####################
#################################################
# Bit.ly Bitly Start
###########################
$bitly_riogenesis_username = "riogenesis";
$bitly_riogenesis_apikey = "R_f56673c05f4ec2f37b2cf664b3e82908";
function getBitlyShortUrl($url=''){
global $bitly_riogenesis_username,$bitly_riogenesis_apikey;
return get_bitly_short_url($url,$bitly_riogenesis_username,$bitly_riogenesis_apikey,'txt');
}
function get_bitly_short_url($url,$login,$appkey,$format='txt') {
$connectURL = 'http://api.bit.ly/v3/shorten?login='.$login.'&apiKey='.$appkey.'&uri='.urlencode($url).'&format='.$format;
return curl_get_result($connectURL);
}
/* returns expanded url */
function get_bitly_long_url($url,$login,$appkey,$format='txt') {
$connectURL = 'http://api.bit.ly/v3/expand?login='.$login.'&apiKey='.$appkey.'&shortUrl='.urlencode($url).'&format='.$format;
return curl_get_result($connectURL);
}
/* returns a result form url */
function curl_get_result($url) {
$ch = curl_init();
$timeout = 5;
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
#########################
# Bit.ly Bitly End
###################################################
/***
* FB_CURL
*/
function curl_json ($url="",$post,$params,$json=0){
$host = "dev.rio.matraex.com";
if (!$url)
$url=$host;
$ch = curl_init();
if ($post){
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_POSTFIELDS => $params,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_VERBOSE => true
));
}else{
// GET
if ($json)
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));
curl_setopt($ch, CURLOPT_POSTFIELDS, null);
curl_setopt($ch, CURLOPT_POST, FALSE);
curl_setopt($ch, CURLOPT_HTTPGET, TRUE);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, true);
}
$result = curl_exec($ch);
if ($json)
$r = json_decode($result,true);
if (!r && $result){
$str = substr(substr($result,0,-1),1);
$r = json_decode($str,true);
if ($r)
$result = $r;
}
d(curlresult,$result);
return $result;
}
function freosalesforceapi_error($property, $apn,$error, $data='', $client=false,$additionalmessage="")
{
global $soapwsdl;
$property = trim($property);
$apn = trim($apn);
$error = trim($error);
d(apn,$apn);
d(error,$error);
d(property,$property);
dlog('freosalesforceapi',"freosalesforceapi_error($apn) - $property - $error) ".print_r($data, true));
$to="freoemailaddress";
$to='michael@matraex.com';
$to='no-reply@riogenesis.com';
$to='helpdesk-support@matraex.com,ekim@pretiumpartnersllc.com';
$from=FREODOCUMENTBOXEMAIL_FROM;
$subject ="RIO -> FREOSALESFORCE API Error";
$dataout = $data;
if(is_array($data) && $data)
{
$dataout = "data = ";
foreach($data as $k=>$v)
$dataout.=" $k=>'$v',";
}
$body="An error has been detected in the RIO -> FREOSALESFORCE API
" . $additionalmessage . "
| Time: | ".dttime_format(time())." |
| Property: | $property |
| RIO User: | ".get_login_info(loginid())." |
";
if($dataout)
$body.=" | Parameters: | $dataout |
";
if($client)
{
$lastrequest = $client->__getLastRequest();
if($lastrequest)
{
$lastrequest=htmlentities($lastrequest);
$body.="| Last Request: | $lastrequest |
";
}
}
$body.="
| APN: | $apn |
| APN: | $apn |
| Error: | $error |
| WSDL: | $soapwsdl |
| HTTP_HOST: | $_SERVER[HTTP_HOST] |
| REMOTE_ADDR: | $_SERVER[REMOTE_ADDR] |
";
html_mail($to,$from,$subject,$body,$attachmentdocumentid=0,$headerarr="");
}
function freosalesforceapi_statusupdate($offerid,$statustext,$propertyid=0)
{
return false; // Temporary disabled per client request MTX 21378
global $soapwsdl;
dlog('freosalesforceapi',"$property[propertyid] | $offerID - $propertyid | $apn | SOAPCLIENT ($soapwsdl) Status $statustext");
$soapwsdl = "http://riomsgprocessor.cloudapp.net/riomsgprocessor.svc?wsdl";
if(app_get('setting_freoapi_sandbox')|| developer_variable('SOAP_SandBOX'))
$soapwsdl = "http://4e598a44cdd3446288a316353ab9199a.cloudapp.net/riomsgprocessor.svc?wsdl"; // sandbox testing instance - use test apn: 54855
if ($offerid)
{
$sql = "select * from tbloffer join tblavailablepropertyentry using (offerid) where clientcompanyid = 92 and offerid = ".db_number($offerid);
$offer = db_first($sql);
if(!$offer)
return "Invalid Offer for FREO Update ID: $offerid";
$property = get_property($offer[propertyid]);
}
if (db_number($propertyid) && !$property)
$property = get_property($propertyid);
if(!$property)
return "Invalid Property: $propertyid";
$propdesc = "$property[propertyaddress] $property[propertycity] $property[propertystate] $property[propertyzip]";
$apn = get_propertyextensionentry($property[propertyid],propertyextensionuniqueid);
if(!$apn)
$apn = get_propertyextensionentry($property[propertyid],propertyextensionparcelapn);
if(!$apn)
return "No Unique ID(APN) Set on property for FREO Update: $property[propertyaddress]";
$arr[apn] = $apn;
$arr[value] = $statustext;
try
{
dlog('freosalesforceapi',"$property[propertyid] | $offer[offerid] | $apn | SOAPCLIENT ($soapwsdl) Status $statustext");
ini_set("default_socket_timeout", 100); // this will extend SOAP socket to 100 sec
$client = new SoapClient($soapwsdl,array("trace"=>1, "connection_timeout"=>100) );
$ret = $client->PropertyUpdate_Stage($arr);
//d(ret,$ret,0,0,"", " | ");
//$response = $client->SomeSoapRequest();
}
catch(Exception $ex)
{
//d(ex,$ex);
$error = "RIO -> FREO Connectivity Error - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected response recived from FREO Servers while attempting to connect.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($propdesc, $apn,$error,$arr, $client,$additionalmessage);
return "$error" . $additionalmessage . "We applogize for inconviniece. Please try your request latter.";
}
$outarr = (array)$ret->PropertyUpdate_StageResult;
if ($outarr[ErrorMsg])
{
dlog('freosalesforceapi',"$property[propertyid] | $offer[offerid] | $apn | Error: $outarr[ErrorMsg] ");
return $outarr[ErrorMsg];
}
else{
$billingtribecaid = get_propertyextensionentry($property[propertyid],propertyextensionbillingtribecaid);
dlog('freosalesforceapi',"$property[propertyid] | $offer[offerid] | $apn | SOAPCLIENT ($soapwsdl) Status :".print_r($outarr,true));
if(!$billingtribecaid && $outarr[TribecaID] )
property_ext_save($property[propertyid],propertyextensionbillingtribecaid, $outarr[TribecaID]);
// We dont have an error message time to update db.
$sql = "insert into tblofferstage (offerid, offerstagecreatedby, offerstagestatus)
VALUES (" . db_number($offerid) . "," . db_number(loginid()) . "," . db_tick($statustext) . ")";
db_exec($sql);
}
return false; // On Success return false
}
function freosalesforceapi_property($offerid, $section)
{
if(!db_number($offerid))
return;
return true; // Temporary disabled on CLient request MTX 21378
$clientcompanyid = 92; //freo clientcompanyid
$uniquepe = 'propertyextensionuniqueid'; //use this value as the primary uniqueid
$uniquepe2 = 'propertyextensionparcelapn'; //if we dont' have a value, use this.
$uniquesf = 'apn';
$extens = get_propertyextensions_byconfigtypematch("freosalesforceapifunction",'',$clientcompanyid, false );
$sql = "select * from tbloffer join tblproperty using(propertyid) where offerid = ".db_number($offerid);
$offer = db_first($sql);
if(!$offer)
ddie("Invalid offer");
$propertyid = $offer[propertyid];
d(extens,$extens);
$extensmap = array_column($extens, propertyextensionconfigvalue, propertyextensionkey);
d(extensmap,$extensmap);
$getkeys = $extensmap;
$getkeys[$uniquepe] = $uniquepe;
$getkeys[$uniquepe2] = $uniquepe2;
$sql = "select * from tblpropertyextensionentry
where propertyid = ".db_number($propertyid)."
and coalesce(propertyextensionentryvalue,'') <> ''
";
$values = db_query($sql);
$values = array_column($values, propertyextensionentryvalue, propertyextensionkey);
d(values, $values);
$apn = $values[$uniquepe];
if(!$apn)
{
$uniquepe=$uniquepe2;
$apn = $values[$uniquepe];
}
foreach($values as $k=>$v)
{
unset($values[$k]);
$k = str_replace("_offer$offerid","",$k);
$values[$k] = $v;
}
$hoaname = $values[propertyextensionhoaname1];
//keep this set so that as the WSDL changes
global $soapwsdl;
$soapwsdl = "http://riomsgprocessor.cloudapp.net/riomsgprocessor.svc?wsdl"; //live site testing instance apn: 108xxx?
d(sandbox,app_get('setting_freoapi_sandbox'));
if(app_get('setting_freoapi_sandbox'))
$soapwsdl = "http://4e598a44cdd3446288a316353ab9199a.cloudapp.net/riomsgprocessor.svc?wsdl"; // sandbox testing instance - use test apn: 54855
$property = get_property($propertyid);
$propdesc = "$property[propertyaddress] $property[propertycity] $property[propertystate] $property[propertyzip]";
try
{
dlog('freosalesforceapi',"$offer[propertyid] $offer[offerid] SOAPCLIENT ($soapwsdl)");
ini_set("default_socket_timeout", 100); // this will extend SOAP socket to 100 sec
$client = new SoapClient($soapwsdl, array('trace'=>1, "connection_timeout"=>100 ) );
//$response = $client->SomeSoapRequest();
}
catch(Exception $ex)
{
d(ex,$ex);
$error = "RIO -> FREO Connectivity Error - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected Network Communication received from FREO Servers while attempting to connect.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($propdesc, $values[$uniquepe],$error, $client, $additionalmessage);
return "$error" . $additionalmessage . "We applogize for inconviniece. Please try your request latter.";
//freosalesforceapi_error("Connectivity error )
}
$fs = $client->__getFunctions();
$types =$client->__getTypes() ;
d(freo_functions, $fs);
d(freo_types, $types);
d(property,$property);
d(values,$values);
if($hoaname == 'N/A')
$skiphoafields = 1;
d("extensmap",$extensmap);
arsort($extensmap ); //put the property updates before the HOA updates
d("extensmap",$extensmap);
foreach($extensmap as $fld => $func)
{
//d($fld,array_keys($exclusionmap));
if(!$func)
{
d("invalid configuration field $fld is somehow turned on but not with a value");
continue;
}
$arr = array();
$arr[$uniquesf] = $values[$uniquepe];
$value = $values[$fld];
if(!strlen($value))
continue; // skip any empty columns
$cftype = $extens[$fld][customfieldtypename];
if($cftype == 'money')
$value = str_replace("$",'',$value) ;
if($cftype == 'money')
$value = str_replace(",",'',$value) ;
if($cftype == 'timedatepicker')
{
$value = date("c",strtotime($value)) ; // put this in ISO8601 formatted timestamp
}
$arr[value] = trim($value); // trim extra spaces
//
if(strstr($func,HoaUpdate ) )
{
$foundaddnew = false;
d($_POST[addnew],$hoaname);
if($_POST[addnew] )
$foundaddnew = array_search($hoaname,$_POST[addnew]);
if(strlen($foundaddnew)) // if we have problems with creating HOA please look in MTX 19249 for pseudo code for solution
{
$createarr=array();
unset($_POST[addnew][$foundaddnew]);
$createarr[value] = trim($hoaname);
$createarr[apn] = $apn;
try
{
dlog('freosalesforceapi',"Hoa_Create $ofr[propertyid] $ofr[offerid] $createarr[apn] '$createarr[value]'");
$ret = $client->Hoa_Create($createarr);
d(createarr,$createarr);
d(create_ret,$ret);
}
catch(SoapFault $ex)
{
if($ex->faultcode == "HTTP")
{
$error = "RIO -> FREO API Error $ret = $client->Hoa_Create($arr); operation: $func - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected Network Communication received from FREO Servers while attempting to connect.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($propdesc, $values[$uniquepe],$error,$createarr, $client,$additonalmessage);
//if we run into a connectivity issue, lets stop attempting to connect - return
return $error;
}
$error = "RIO -> FREO API Error field:$fld operation: $func - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected Response received from FREO Servers.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($propdesc, $values[$uniquepe],$error,$createarr, $client,$additionalmessage);
$skiphoafields =1; // Skip all hoa fields HOA is broken
continue;
}
dlog('freosalesforceapi'," $createarr[apn] '$createarr[value]' HOA Create result :" . print_r($ret->Hoa_CreateResult,true) );
if($ret->Hoa_CreateResult->ErrorMsg)
{
$skiphoafields =1; // Skip all hoa fields HOA is broken
$error = "RIO -> FREO API Error Hoa_Create(".print_r($createarr,true)."); Error: ".$ret->Hoa_CreateResult->ErrorMsg;
if (!strstr($error,"Could not find HOAs for") ) // Dont send email if error type contains this string.
if (!strstr($error,"already exists")){ // Dont send email if HOA already exists just notify user
$additionalmessage = "
Unexpected Response received from FREO Servers.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($propdesc, $values[$uniquepe],$error,$createarr, $client,$additionalmessage);
}
//if we run into a connectivity issue, lets stop attempting to connect - return
return "HOA Did not save -> ".$ret->Hoa_CreateResult->ErrorMsg ;
}
//ddie("dont continue");
}
if($skiphoafields)
{
d("skipping update of the HOA fields since it is marked as 'N/A'");
continue;
}
$arr[hoaName] = $hoaname;
}
d($fld." | ".$func,$arr);
if(!$func)
{
d("invalid configuration field $fld is somehow turned on but not with a value");
continue;
}
try
{
$ret = $client->$func($arr);
d(ret,$ret);
}
catch(SoapFault $ex)
{
if($ex->faultcode == "HTTP")
{
$error = "RIO -> FREO API Error field:$fld operation: $func - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected Network Communication received from FREO Servers while attempting to connect.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($propdesc, $values[$uniquepe],$error,$arr, $client,$additionalmessage);
//if we run into a connectivity issue, lets stop attempting to connect - return
return $error;
}
$error = "RIO -> FREO API Error field:$fld operation: $func - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected Response received from FREO Servers.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($propdesc, $values[$uniquepe],$error,$arr, $client,$additionalmessage);
continue;
}
//$ret has the full response
foreach($ret as $response)
{
$ret = $response;
break;
}
//d(ret,$ret);
dlog('freosalesforceapi',"$offer[propertyid] $offer[offerid] SOAPFUNC->$func(apn=>$apn,value=>'$arr[value]',hoaName=>'$arr[hoaName]') == (error=>'$ret->ErrorMsg', Succeeded=>'$ret->Succeeded' $property[propertyaddress])");
//d(ret,$ret);
//need to verify whether their is an APN error or not
if(strstr($ret->ErrorMsg , 'APNERROR'))
return $ret->ErrorMsg;
//need to verify whether their is an APN error or not
if(strstr($ret->ErrorMsg , 'HOAERROR'))
return $ret->ErrorMsg;
if($ret->ErrorMsg )
{
$error = "RIO -> FREO API Error field:$fld operation:$func - API Returned Error:" .$ret->ErrorMsg;
$additionalmessage = "
Unexpected Response received from FREO Servers.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($propdesc, $values[$uniquepe],$error,$arr,$client,$additionalmessage);
//this type of message is non fatal
//continue;
if(strstr($func,HoaUpdate ) )
{
$skiphoafields =1; // Hoa Update has failed do not update HOA fields.
}
}
if(!$processed_documents )
{ //upload all documents at the bottom of the extension loop if at least one extension was uploaded without a problem
$processed_documents++;
$docextens = gettab_extensions($section, '','','1',$clientcompanyid);
foreach($docextens as $fld =>$docexten)
{
$ret = '';
if($docexten[customfieldtypename] == 'documentupload' && $values[$docexten[propertyextensionkey]] > 1){
$docid = $values[$docexten[propertyextensionkey]];
if (db_number($docid) && $apn)
$ret = freosalesforceapi_sendfile($apn,$docid);
if ( strlen($ret)>2 )
set_message($ret,fileerror);
}
}
}
continue;
}
d(offer,$offer);
d(section,$section);
return true; // this must return true or the Agent gets an error on their page.
}
/**
* @name freosalesforceapi_sendfile
* @param string $apn APN
* @param integer $documentid tbldocument.documentid.
*/
function freosalesforceapi_sendfile($apn,$documentid){
return false; // Temporary disabled per Client Request MTX 21378
if (!$apn)
return "Error: Missing APN";
if (!db_number($documentid) )
return "Error: Missinf DocumentID";
// init SOAP
global $soapwsdl;
if(app_get('setting_freoapi_sandbox') || $_SESSION[developer][SOAP_SandBOX])
$soapwsdl = "http://4e598a44cdd3446288a316353ab9199a.cloudapp.net/riomsgprocessor.svc?wsdl"; // sandbox testing instance - use test apn: 54855
else
$soapwsdl = "http://riomsgprocessor.cloudapp.net/riomsgprocessor.svc?wsdl"; //live site testing instance apn: 108xxx?
// Make Soap call
/****
* Soap said:
Property_FileUpload {
string apn;
string fileName;
base64Binary buffer;
*/
try
{
dlog('freosalesforceapi',"$apn $sendfile SOAPCLIENT ($soapwsdl)");
ini_set("default_socket_timeout", 100); // this will extend SOAP socket to 100 sec
$client = new SoapClient($soapwsdl, array('trace'=>1, "connection_timeout"=>100 ) );
}
catch(Exception $ex)
{
d(ex,$ex);
$error = "RIO -> FREO Connectivity Error - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected Network Communication received from FREO Servers while attempting to connect.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($apn, $sendfile,$error, $client,$additionalmessage);
return "$error";
}
if (1==2)
{
$fs = $client->__getFunctions();
$types =$client->__getTypes() ;
d(freo_functions, $fs);
d(freo_types, $types);
d(property,$property);
d(values,$values);
}
if ($documentid)
{
$sql = "select documentid, documentname from tbldocument where documentid = " . db_number($documentid) . " Limit 1";
$docarr = array_shift ( db_query ($sql) );
$path = $_SERVER[DOCUMENT_ROOT]."/document/".getrelativedocumentdir($docarr[documentid]).$docarr[documentname];
$sendfile = $docarr[documentid] . "_" .$docarr[documentname];
if (file_exists($path) )
{
$fh = fopen($path, "r");
$bytearray = fread($fh, filesize($path));
fclose($fh);
}
else
return "File not found : " . (is_developer() ? $path : str_replace ($_SERVER['DOCUMENT_ROOT'],"",$path));
}
try
{
dlog('freosalesforceapi',"$offer[propertyid] $offer[offerid] SOAPFUNC->Property_FileUpload(apn=>$apn,fileName=>$sendfile)");
$ret = (array) $client ->Property_FileUpload(array('apn'=>$apn,'fileName'=>$sendfile,'buffer'=>$bytearray));
}
catch(SoapFault $ex)
{
if($ex->faultcode == "HTTP")
{
$error = "RIO -> FREO API Error field:$fld operation: $func - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected Network Communication received from FREO Servers while attempting to connect.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($apn, $sendfile,strlen($filedata) ,$error, $client,$additionalmessage);
//if we run into a connectivity issue, lets stop attempting to connect - return
return $error;
}
return $ex;
}
$ret = array_shift($ret);
dlog('freosalesforceapi',"$offer[propertyid] $offer[offerid] SOAPFUNC->Property_FileUpload(apn=>$apn,fileName=>$sendfile) (error=>'$ret->ErrorMsg', Succeeded=>'$ret->Succeeded' $property[propertyaddress])");
if(stristr($ret->ErrorMsg,'Property already has a file named')) //this means that the uload has already been done and we can ignore.
return false;
$r = (array)$ret;
if ($r['ErrorMsg'] && strstr($r['ErrorMsg'],'DOCERROR:') )
{
$additionalmessage = "
File Transfer Error received from FREO Servers while attempting to upload file: " . $sendfile . "
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($apn, $sendfile,strlen($filedata) ,$r['ErrorMsg'], $client,$additionalmessage);
return str_replace('DOCERROR:', '',$r['ErrorMsg']); // Return error
}
return false;
}
function freosalesforceapi_updatehoa($apn,$old,$newhoa){
return false; // Salesforce API disabled on Client Request MTX 21378
if (!$apn)
return "Error: Missing APN";
// init SOAP
global $soapwsdl;
global $application_variables_set;
d(glob,$application_variables_set);
if(app_get('setting_freoapi_sandbox') || $_SESSION[developer][SOAP_SandBOX])
$soapwsdl = "http://4e598a44cdd3446288a316353ab9199a.cloudapp.net/riomsgprocessor.svc?wsdl"; // sandbox testing instance - use test apn: 54855
else
$soapwsdl = "http://riomsgprocessor.cloudapp.net/riomsgprocessor.svc?wsdl"; //live site testing instance apn: 108xxx?
d(wsdl,$soapwsdl);
try
{
dlog('freosalesforceapi',"$apn $ SOAPCLIENT ($soapwsdl)");
ini_set("default_socket_timeout", 100); // this will extend SOAP socket to 100 sec
$client = new SoapClient($soapwsdl, array('trace'=>1, "connection_timeout"=>100) );
}
catch(Exception $ex)
{
d(ex,$ex);
$error = "RIO -> FREO Connectivity Error - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected Network Communication received from FREO Servers while attempting to connect.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($apn, 'oldhoa:'.$old.'new:'.$newhoa ,$error, $client,$additionalmessage);
return "$error";
}
if (1==2)
{
$fs = $client->__getFunctions();
$types =$client->__getTypes() ;
d(freo_functions, $fs);
d(freo_types, $types);
d(property,$property);
d(values,$values);
}
if (trim($old) !='' && $old !='N/A')
{
if (trim($newhoa) == 'N/A')
$newhoa = '';
try
{
dlog('freosalesforceapi',"$apn SOAPFUNC->HoaUpdate_HoaName(apn=>$apn,value=>$newhoa,hoaName=>$old)");
$ret = (array) $client ->HoaUpdate_HoaName(array('apn'=>$apn,'value'=>$newhoa,'hoaName'=>$old));
}
catch(SoapFault $ex)
{
if($ex->faultcode == "HTTP")
{
$error = "RIO -> FREO API Error HOA:$old operation: HOAUpdate - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
$additionalmessage = "
Unexpected Network Communication received from FREO Servers while attempting to connect.
RIO and FREO Tech Support have been notified.
";
freosalesforceapi_error($apn, $old,$newhoa ,$error, $client,$additionalmessage);
//if we run into a connectivity issue, lets stop attempting to connect - return
return $error;
}
return $ex;
}
}else if (trim($newhoa) !='N/A' && trim($newhoa) !=''){
// Per MB we are removing create code from this subroutine. Only update possible to prevent from creating duplicates on their end.
// $createarr=array();
// $createarr[value] = $newhoa;
// $createarr[apn] = $apn;
// try
// {
// dlog('freosalesforceapi',"Hoa_Create $createarr[apn] '$createarr[value]'");
// $ret = $client->Hoa_Create($createarr);
// d(createarr,$createarr);
// d(ret,$ret);
// }
// catch(SoapFault $ex)
// {
// if($ex->faultcode == "HTTP")
// {
// $error = "RIO -> FREO API Error $ret = $client->Hoa_Create($createarr); operation: hoaCREATE - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
// freosalesforceapi_error($propdesc, $values[$uniquepe],$error,$createarr, $client);
// //if we run into a connectivity issue, lets stop attempting to connect - return
// return $error;
// }
// $error = "RIO -> FREO API Error field:$fld operation: $func - faultcode: ".$ex->faultcode." faultstring: ".$ex->faultstring;
// freosalesforceapi_error($propdesc, $apn,$error,$createarr, $client);
// continue;
// }
// if($ret->Hoa_CreateResult->ErrorMsg)
// {
// $error = "RIO -> FREO API Error Hoa_Create(".print_r($createarr,true)."); Error: ".$ret->Hoa_CreateResult->ErrorMsg;
// freosalesforceapi_error($propdesc, $values[$uniquepe],$error,$createarr, $client);
// //if we run into a connectivity issue, lets stop attempting to connect - return
// return "HOA Did not save -> ".$ret->Hoa_CreateResult->ErrorMsg ;
// }
// Dont save new HOA
return flase;
}
if (is_array($ret))
$ret = array_shift($ret);
dlog('freosalesforceapi',"$apn SOAPFUNC->SOAPFUNC->HoaUpdate_HoaName(apn=>$apn,value=>$newhoa,hoaName=>$old) (error=>'$ret->ErrorMsg', Succeeded=>'$ret->Succeeded' )");
if(stristr($ret->ErrorMsg,'HOA'))
return false;
$r = (array)$ret;
if ($r[ErrorMsg] && strstr($r[ErrorMsg],'HOA:') )
return str_replace('HOA:', '',$r[ErrorMsg]); // Return error
return false;
}