Urbanesia - Open Source & Microsoft
Today I was a speaker at Microsoft’s SQL on PHP event and I’m displaying the slides for the presentation below. It was a fun moment of sharing experiences, laughters and geekdom.
Jajan for Android Open Sourced at Github
OAUTHnesia for PHP
It’s 2012 now and Urbanesia is publishing a new OAUTHnesia client for Urbanesia’s API. This time it’s for PHP. Why it took so long to actually finish a PHP version is because we gave up on a third party library that is too complicated to do simple things. So without further ado, the codes are available below.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); | |
/** | |
* OAUTHnesia for PHP Class | |
* | |
* @package OAUTHnesia | |
* @subpackage PHP | |
* @category OAUTH Client | |
* @author Batista R. Harahap <tista@urbanesia.com> | |
* @link http://www.bango29.com | |
* @license MIT License - http://www.opensource.org/licenses/mit-license.php | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a | |
* copy of this software and associated documentation files (the "Software"), | |
* to deal in the Software without restriction, including without limitation | |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
* and/or sell copies of the Software, and to permit persons to whom the | |
* Software is furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
* IN THE SOFTWARE. | |
*/ | |
class Oauthnesia { | |
var $cons_key = ""; | |
var $cons_sec = ""; | |
var $user_key = ""; | |
var $user_sec = ""; | |
var $API_URL = "http://api1.urbanesia.com/"; | |
var $api_uri = ""; | |
function __construct($conf) { | |
if(empty($conf)) | |
throw new Oauthnesia_Exception("Empty configuration array"); | |
if(empty($conf['consumer_key'])) | |
throw new Oauthnesia_Exception("Please initialize with Consumer Key"); | |
if(empty($conf['consumer_secret'])) | |
throw new Oauthnesia_Exception("Please initialize with Consumer Secret"); | |
if( (empty($conf['user_key']) && !empty($conf['user_secret'])) || (!empty($user_key) && !empty($user_sec)) ) | |
throw new Oauthnesia_Exception("Both User Tokens must be initialized"); | |
$this->API_URL = !empty($conf['api_base_url']) ? $conf['api_base_url'] : $this->API_URL; | |
$this->cons_key = $conf['consumer_key']; | |
$this->cons_sec = $conf['consumer_secret']; | |
$this->user_key = !empty($conf['user_key']) ? $conf['user_key'] : ''; | |
$this->user_sec = !empty($conf['user_secret']) ? $conf['user_secret'] : ''; | |
} | |
function request($uri = "", $post = "", $get = "", $with_user_key = false) { | |
if(empty($uri)) | |
throw new Oauthnesia_Exception("API URI must be initialized"); | |
if(!is_string($uri)) | |
throw new Oauthnesia_Exception("API URI must be a String object"); | |
if(!is_string($post)) | |
throw new Oauthnesia_Exception("API POST Requests must be a String object"); | |
if(!is_string($get)) | |
throw new Oauthnesia_Exception("API GET Requests must be a String object"); | |
if(!is_bool($with_user_key)) | |
throw new Oauthnesia_Exception("User Key Signing flag must be boolean"); | |
$this->api_uri = $uri; | |
// Add default POST requirements for Urbanesia | |
$def_post = $this->get_default_post($with_user_key); | |
// Merge POST with default POST | |
if(empty($post)) | |
$post = $def_post; | |
else | |
$post .= "&" . $def_post; | |
// Encode POST and GET for OAUTH | |
$post = $this->encode_for_oauth($post); | |
$get = $this->encode_for_oauth($get); | |
// Encode the whole GET + POST | |
$requestify = $this->sortify($post ."&". $get); | |
// Base Signature | |
$base_sig = $this->get_base_sig($requestify); | |
// Sign the request with Consumer/User Secret | |
$oauth_sig = hash_hmac("SHA1", $base_sig, $this->cons_sec . "&" . $this->user_sec, TRUE); | |
$oauth_sig = base64_encode($oauth_sig); | |
$oauth_sig = str_replace("=", "%3D", $oauth_sig); | |
$oauth_sig = str_replace("+", "%2B", $oauth_sig); | |
$oauth_sig = "?oauth_signature=" . $oauth_sig; | |
$url = $this->API_URL . $this->api_uri . $oauth_sig . "&" . $get; | |
return $this->send_request($url, $post); | |
} | |
function xauth($username, $password) { | |
if(empty($username)) | |
throw new Oauthnesia_Exception("No username specified for xAuth"); | |
if(empty($password)) | |
throw new Oauthnesia_Exception("No password specified for xAuth"); | |
$this->api_uri = "oauth/access_token"; | |
// Add default POST requirements for Urbanesia | |
$def_post = $this->get_default_post(FALSE); | |
// Xauth Default POST | |
$xpost = "&x_auth_username={$username}&x_auth_password={$password}&x_auth_mode=client_auth"; | |
// Merge POST with Xauth | |
$post = $this->encode_for_oauth($def_post . $xpost); | |
// Base Signature | |
$base_sig = $this->get_base_sig($post); | |
// Sign the request with Consumer/User Secret | |
$oauth_sig = hash_hmac("SHA1", $base_sig, $this->cons_sec . "&" . $this->user_sec, TRUE); | |
$oauth_sig = base64_encode($oauth_sig); | |
$oauth_sig = str_replace("=", "%3D", $oauth_sig); | |
$oauth_sig = str_replace("+", "%2B", $oauth_sig); | |
$oauth_sig = "?oauth_signature=" . $oauth_sig; | |
$url = $this->API_URL . $this->api_uri . $oauth_sig; | |
$result = $this->send_request($url, $post); | |
$r =& $result['response']; | |
if( | |
!empty($r->result) && | |
!empty($r->result->oauth_token_key) && | |
!empty($r->result->oauth_token_secret) && | |
!empty($r->result->first_name) && | |
!empty($r->result->last_name) && | |
!empty($r->result->account_id) | |
) { | |
return $r->result; | |
} else { | |
return FALSE; | |
} | |
} | |
function send_request($url, $post) { | |
if(empty($url) || empty($post)) | |
throw new Oauthnesia_Exception("Empty URL/POST request for CURL"); | |
$c = curl_init(); | |
curl_setopt($c, CURLOPT_USERAGENT, "OAUTHnesia for PHP v1.0"); | |
curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 1); | |
curl_setopt($c, CURLOPT_TIMEOUT, 5); | |
curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE); | |
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE); | |
curl_setopt($c, CURLOPT_FOLLOWLOCATION, TRUE); | |
curl_setopt($c, CURLOPT_URL, $url); | |
curl_setopt($c, CURLOPT_POST, TRUE); | |
curl_setopt($c, CURLOPT_POSTFIELDS, $post); | |
$response = curl_exec($c); | |
$code = curl_getinfo($c, CURLINFO_HTTP_CODE); | |
$info = curl_getinfo($c); | |
$mem = memory_get_usage(TRUE); | |
$return = array( | |
'response' => json_decode($response), | |
'code' => $code, | |
'info' => $info, | |
'memory' => round($mem/1024/1024, 2) . " MB" | |
); | |
return $return; | |
} | |
function get_base_sig($req) { | |
return "POST&" . rawurlencode($this->API_URL . $this->api_uri) . "&" | |
. rawurlencode($req); | |
} | |
function sortify($body) { | |
$arr = explode("&", $body); | |
$arr = array_filter($arr); | |
array_multisort($arr); | |
return implode("&", $arr); | |
} | |
function encode_for_oauth($var) { | |
$vars = explode("&", $var); | |
$vars = array_filter($vars); | |
array_multisort($vars); | |
$return = ""; | |
for($i=0, $j=0, $max=count($vars); $i<$max; $i++) { | |
if($j === 1) | |
$return .= "&"; | |
$tmp = explode("=", $vars[$i]); | |
$return .= rawurlencode($tmp[0]) . "=" . rawurlencode($tmp[1]); | |
$j = 1; | |
} | |
return $return; | |
} | |
function get_default_post($with_user_key = false) { | |
if($with_user_key === TRUE && empty($this->user_key)) | |
throw new Oauthnesia_Exception("Trying to make a request signed with User Secret without initializing with User Secret"); | |
$post = "oauth_consumer_key=" . $this->cons_key | |
. "&oauth_nonce=" . $this->get_nonce() | |
. "&oauth_signature_method=HMAC-SHA1" | |
. "&oauth_timestamp=" . mktime() | |
. "&oauth_version=1.0" | |
. "&safe_encode=1"; | |
if($with_user_key) | |
return $post . "&oauth_token=" . $this->user_key; | |
else | |
return $post; | |
} | |
function get_nonce() { | |
return md5(microtime(TRUE)); | |
} | |
function safe_encode($data) { | |
if (is_array($data)) { | |
return array_map(array($this, 'safe_encode'), $data); | |
} else if (is_scalar($data)) { | |
return str_ireplace( | |
array('+', '%7E'), | |
array(' ', '~'), | |
rawurlencode($data) | |
); | |
} else { | |
return ''; | |
} | |
} | |
} | |
class Oauthnesia_Exception extends Exception {} |
@Urbanesia API #Android Class
It’s been quite a day today. Did some code reworking with an app I showed you guys in my last posts. I decided to publish the Urbanesia class to Google Code and make it GPL v2.
I encourage everyone to contribute and make more modifications. I’m not as experienced as others in Java, would love to learn more. The Google Code URL is:
http://code.google.com/p/urbanesia-api-android/
Enjoy and empower yourselves developers!