-
-
Save keyosk/9c86b981948a3cf7f378 to your computer and use it in GitHub Desktop.
Pubnub PHP SDK 3.4 Altered with PAM hotfix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require_once('PubnubAES.php'); | |
/** | |
* PubNub 3.4 Real-time Push Cloud API | |
* @package Pubnub | |
*/ | |
class Pubnub { | |
private $ORIGIN = 'pubsub.pubnub.com'; | |
private $PUBLISH_KEY = 'demo'; | |
private $SUBSCRIBE_KEY = 'demo'; | |
private $SECRET_KEY = false; | |
private $AUTH_TOKEN = false; | |
private $CIPHER_KEY = ''; | |
private $SSL = false; | |
private $SESSION_UUID = ''; | |
private $PROXY = false; | |
// New style response contains channel after timetoken | |
// Old style response does not | |
private $NEW_STYLE_RESPONSE = true; | |
private $PEM_PATH = __DIR__; | |
/** | |
* Pubnub | |
* | |
* Init the Pubnub Client API | |
* | |
* @param string $publish_key required key to send messages. | |
* @param string $subscribe_key required key to receive messages. | |
* @param string $secret_key optional key to sign messages. | |
* @param string $origin optional setting for cloud origin. | |
* @param boolean $ssl required for 2048 bit encrypted messages. | |
*/ | |
function Pubnub( | |
$args = array(), | |
$subscribe_key = 'demo', | |
$secret_key = false, | |
$cipher_key = false, | |
$ssl = false, | |
$origin = false, | |
$pem_path = false, | |
$proxy = false | |
) { | |
$publish_key = 'demo'; | |
$auth_token = false; | |
if (is_array($args)) { | |
$publish_key = isset($args['publish_key']) ? $args['publish_key'] : $publish_key; | |
$subscribe_key = isset($args['subscribe_key']) ? $args['subscribe_key'] : $subscribe_key; | |
$secret_key = isset($args['secret_key']) ? $args['secret_key'] : $secret_key; | |
$auth_token = isset($args['auth_token']) ? $args['auth_token'] : $auth_token; | |
$cipher_key = isset($args['cipher_key']) ? $args['cipher_key'] : $cipher_key; | |
$ssl = isset($args['ssl']) ? $args['ssl'] : $ssl; | |
$origin = isset($args['origin']) ? $args['origin'] : $origin; | |
$pem_path = isset($args['pem_path']) ? $args['pem_path'] : $pem_path; | |
$proxy = isset($args['proxy']) ? $args['proxy'] : $proxy; | |
} else { | |
$publish_key = $args; | |
} | |
$this->SESSION_UUID = $this->uuid(); | |
$this->PUBLISH_KEY = $publish_key; | |
$this->SUBSCRIBE_KEY = $subscribe_key; | |
$this->AUTH_TOKEN = $auth_token; | |
$this->SECRET_KEY = $secret_key; | |
$this->PROXY = $proxy; | |
if (!isBlank($cipher_key)) { | |
$this->CIPHER_KEY = $cipher_key; | |
} | |
$this->SSL = $ssl; | |
if ($pem_path != false) $this->PEM_PATH = $pem_path; | |
if ($origin) $this->ORIGIN = $origin; | |
if ($ssl) $this->ORIGIN = 'https://' . $this->ORIGIN; | |
else $this->ORIGIN = 'http://' . $this->ORIGIN; | |
} | |
/** | |
* Publish | |
* | |
* Send a message to a channel. | |
* | |
* @param array $args with channel and message. | |
* @return array success information. | |
*/ | |
function publish($args) | |
{ | |
## Fail if bad input. | |
if (!(isset($args['channel']) && isset($args['message']))) { | |
echo('Missing Channel or Message'); | |
return false; | |
} | |
## Capture User Input | |
$channel = $args['channel']; | |
$message_org = $args['message']; | |
$message = $this->sendMessage($message_org); | |
## Sign Message | |
$signature = "0"; | |
/* | |
if ($this->AUTH_TOKEN) { | |
## Generate String to Sign | |
$string_to_sign = implode('/', array( | |
$this->PUBLISH_KEY, | |
$this->SUBSCRIBE_KEY, | |
$this->AUTH_TOKEN, | |
$channel, | |
$message | |
)); | |
$signature = md5($string_to_sign); | |
} | |
*/ | |
## Send Message | |
$publishResponse = $this->_request(array( | |
'publish', | |
$this->PUBLISH_KEY, | |
$this->SUBSCRIBE_KEY, | |
$signature, | |
$channel, | |
'0', | |
$message | |
)); | |
if ($publishResponse == null) | |
return array(0, "Error during publish."); | |
else | |
return $publishResponse; | |
} | |
public function sendMessage($message_org) | |
{ | |
if ($this->CIPHER_KEY != false) { | |
$message = json_encode(encrypt(json_encode($message_org), $this->CIPHER_KEY)); | |
} else { | |
$message = json_encode($message_org); | |
} | |
return $message; | |
} | |
function here_now($args) | |
{ | |
if (!($args['channel'])) { | |
echo('Missing Channel'); | |
return false; | |
} | |
## Capture User Input | |
$channel = $args['channel']; | |
return $this->_request(array( | |
'v2', | |
'presence', | |
'sub_key', | |
$this->SUBSCRIBE_KEY, | |
'channel', | |
$channel | |
)); | |
} | |
/** | |
* Subscribe | |
* | |
* This is BLOCKING. | |
* Listen for a message on a channel. | |
* | |
* @param array $args with channel and message. | |
* @return mixed false on fail, array on success. | |
*/ | |
function subscribe($args, $presence = false) | |
{ | |
## Capture User Input | |
$channel = $args['channel']; | |
$callback = $args['callback']; | |
$timetoken = isset($args['timetoken']) ? $args['timetoken'] : '0'; | |
## Fail if missing channel | |
if (!$channel) { | |
echo("Missing Channel.\n"); | |
return false; | |
} | |
## Fail if missing callback | |
if (!$callback) { | |
echo("Missing Callback.\n"); | |
return false; | |
} | |
if ($presence == true) { | |
$mode = "presence"; | |
} else | |
$mode = "default"; | |
while (1) { | |
try { | |
## Wait for Message | |
$response = $this->_request(array( | |
'subscribe', | |
$this->SUBSCRIBE_KEY, | |
$channel, | |
'0', | |
$timetoken | |
)); | |
if ($response == "_PUBNUB_TIMEOUT") { | |
continue; | |
} elseif ($response == "_PUBNUB_MESSAGE_TOO_LARGE") { | |
$timetoken = $this->throwAndResetTimetoken($callback, "Message Too Large"); | |
continue; | |
} elseif ($response == null || $timetoken == null) { | |
$timetoken = $this->throwAndResetTimetoken($callback, "Bad server response."); | |
continue; | |
} | |
$messages = $response[0]; | |
$timetoken = $response[1]; | |
// determine the channel | |
if ((count($response) == 3)) { | |
$derivedChannel = explode(",", $response[2]); | |
} else { | |
$channel_array = array(); | |
for ($a = 0; $a < sizeof($messages); $a++) { | |
array_push($channel_array, $channel); | |
} | |
$derivedChannel = $channel_array; | |
} | |
if (!count($messages)) { | |
continue; | |
} | |
$receivedMessages = $this->decodeAndDecrypt($messages, $mode); | |
$returnArray = $this->NEW_STYLE_RESPONSE ? array($receivedMessages, $derivedChannel, $timetoken) : array($receivedMessages, $timetoken); | |
# Call once for each message for each channel | |
$exit_now = false; | |
for ($i = 0; $i < sizeof($receivedMessages); $i++) { | |
$cbReturn = $callback(array("message" => $returnArray[0][$i], "channel" => $returnArray[1][$i], "timetoken" => $returnArray[2])); | |
if ($cbReturn == false) { | |
$exit_now = true; | |
} | |
} | |
if ($exit_now) { | |
return; | |
} | |
} catch (Exception $error) { | |
$this->handleError($error, $args); | |
$timetoken = $this->throwAndResetTimetoken($callback, "Unknown error."); | |
continue; | |
} | |
} | |
} | |
public function throwAndResetTimetoken($callback, $errorMessage) | |
{ | |
$callback(array(0, $errorMessage)); | |
$timetoken = "0"; | |
return $timetoken; | |
} | |
public function decodeAndDecrypt($messages, $mode = "default") | |
{ | |
$receivedMessages = array(); | |
if ($mode == "presence") { | |
return $messages; | |
} elseif ($mode == "default") { | |
$messageArray = $messages; | |
$receivedMessages = $this->decodeDecryptLoop($messageArray); | |
} elseif ($mode == "detailedHistory") { | |
$decodedMessages = $this->decodeDecryptLoop($messages); | |
$receivedMessages = array($decodedMessages[0], $messages[1], $messages[2] ); | |
} | |
return $receivedMessages; | |
} | |
public function decodeDecryptLoop($messageArray) | |
{ | |
$receivedMessages = array(); | |
foreach ($messageArray as $message) { | |
if ($this->CIPHER_KEY) { | |
$decryptedMessage = decrypt($message, $this->CIPHER_KEY); | |
$message = json_decode($decryptedMessage, true); | |
} | |
array_push($receivedMessages, $message); | |
} | |
return $receivedMessages; | |
} | |
public function handleError($error, $args) | |
{ | |
$errorMsg = 'Error on line ' . $error->getLine() . ' in ' . $error->getFile() . $error->getMessage(); | |
trigger_error($errorMsg, E_COMPILE_WARNING); | |
sleep(1); | |
} | |
/** | |
* Presence | |
* | |
* This is BLOCKING. | |
* Listen for a message on a channel. | |
* | |
* @param array $args with channel and message. | |
* @return mixed false on fail, array on success. | |
*/ | |
function presence($args) | |
{ | |
## Capture User Input | |
$args['channel'] = ($args['channel'] . "-pnpres"); | |
$this->subscribe($args, true); | |
} | |
/** | |
* Detailed History | |
* | |
* Load history from a channel. | |
* | |
* @param array $args with 'channel' and 'limit'. | |
* @return mixed false on fail, array on success. | |
*/ | |
function detailedHistory($args) | |
{ | |
## Capture User Input | |
## Fail if bad input. | |
if (!$args['channel']) { | |
echo('Missing Channel'); | |
return false; | |
} | |
$channel = $args['channel']; | |
$urlParams = ""; | |
if ($args['count'] || $args['start'] || $args['end'] || $args['reverse']) { | |
$urlParamSep = "?"; | |
if (isset($args['count'])) { | |
$urlParams .= $urlParamSep . "count=" . $args['count']; | |
$urlParamSep = "&"; | |
} | |
if (isset($args['start'])) { | |
$urlParams .= $urlParamSep . "start=" . $args['start']; | |
$urlParamSep = "&"; | |
} | |
if (isset($args['end'])) { | |
$urlParams .= $urlParamSep . "end=" . $args['end']; | |
$urlParamSep = "&"; | |
} | |
if (isset($args['reverse'])) { | |
$urlParams .= $urlParamSep . "reverse=" . $args['reverse']; | |
} | |
} | |
$response = $this->_request(array( | |
'v2', | |
'history', | |
"sub-key", | |
$this->SUBSCRIBE_KEY, | |
"channel", | |
$channel | |
), $urlParams); | |
; | |
$receivedMessages = $this->decodeAndDecrypt($response, "detailedHistory"); | |
return $receivedMessages; | |
} | |
/** | |
* History | |
* | |
* Load history from a channel. | |
* | |
* @param array $args with 'channel' and 'limit'. | |
* @return mixed false on fail, array on success. | |
*/ | |
function history($args) | |
{ | |
## Capture User Input | |
$limit = +$args['limit'] ? +$args['limit'] : 10; | |
$channel = $args['channel']; | |
## Fail if bad input. | |
if (!$channel) { | |
echo('Missing Channel'); | |
return false; | |
} | |
## Get History | |
$response = $this->_request(array( | |
'history', | |
$this->SUBSCRIBE_KEY, | |
$channel, | |
'0', | |
$limit | |
)); | |
; | |
$receivedMessages = $this->decodeAndDecrypt($response); | |
return $receivedMessages; | |
} | |
/** | |
* Time | |
* | |
* Timestamp from PubNub Cloud. | |
* | |
* @return int timestamp. | |
*/ | |
function time() | |
{ | |
## Get History | |
$response = $this->_request(array( | |
'time', | |
'0' | |
)); | |
return $response[0]; | |
} | |
/** | |
* UUID | |
* | |
* UUID generator | |
* | |
* @return UUID | |
*/ | |
function uuid() | |
{ | |
if (function_exists('com_create_guid') === true) { | |
return trim(com_create_guid(), '{}'); | |
} | |
return sprintf('%04X%04X-%04X-%04X-%04X-%04X%04X%04X', mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(16384, 20479), mt_rand(32768, 49151), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535)); | |
} | |
/** | |
* Request URL | |
* | |
* @param array $request of url directories. | |
* @return array from JSON response. | |
*/ | |
private function _request($request, $urlParams = false) | |
{ | |
$request = array_map('Pubnub::_encode', $request); | |
array_unshift($request, $this->ORIGIN); | |
$qs_not_and = false;; | |
$urlString = implode('/', $request); | |
if ($urlParams) { | |
$urlString .= $urlParams; | |
} | |
if (($request[1] === 'presence') || ($request[1] === 'subscribe')) { | |
$urlString .= '?uuid=' . $this->SESSION_UUID; | |
$qs_not_and = true; | |
} | |
if ($this->AUTH_TOKEN) { | |
$urlString .= ($qs_not_and ? '&' : '?') . 'auth=' . $this->AUTH_TOKEN; | |
} | |
$ch = curl_init(); | |
$pubnubHeaders = array("V: 3.4", "Accept: */*"); // GZIP Support | |
curl_setopt($ch, CURLOPT_HTTPHEADER, $pubnubHeaders); | |
curl_setopt($ch, CURLOPT_USERAGENT, "PHP"); | |
//curl_setopt($ch, CURLOPT_PIPELINING, 1); // optimal TCP packet usage. | |
//curl_setopt($ch, CURLOPT_MAXCONNECTS, 100); // concurrent sockets pipes. | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |
curl_setopt($ch, CURLOPT_TIMEOUT, 310); | |
if($this->PROXY) { | |
curl_setopt($ch, CURLOPT_PROXY, $this->PROXY); | |
} | |
curl_setopt($ch, CURLOPT_URL, $urlString); | |
if ($this->SSL) { | |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); | |
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); | |
$pemPathAndFilename = $this->PEM_PATH . "/pubnub.com.pem"; | |
if (file_exists($pemPathAndFilename)) | |
curl_setopt($ch, CURLOPT_CAINFO, $pemPathAndFilename); | |
else { | |
trigger_error("Can't find PEM file. Please set pem_path in initializer."); | |
exit; | |
} | |
} | |
$output = curl_exec($ch); | |
$curlError = curl_errno($ch); | |
$curlResponseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
curl_close($ch); | |
$JSONdecodedResponse = json_decode($output, true); | |
if ($JSONdecodedResponse != null) | |
return $JSONdecodedResponse; | |
elseif ($curlError == 28) | |
return "_PUBNUB_TIMEOUT"; | |
elseif ($curlResponseCode == 400 || $curlResponseCode == 404) | |
return "_PUBNUB_MESSAGE_TOO_LARGE"; | |
} | |
private function setProxy($proxy) { | |
$this->PROXY = $proxy; | |
} | |
/** | |
* Encode | |
* | |
* @param string $part of url directories. | |
* @return string encoded string. | |
*/ | |
private static function _encode($part) | |
{ | |
$pieces = array_map('Pubnub::_encode_char', str_split($part)); | |
return implode('', $pieces); | |
} | |
/** | |
* Encode Char | |
* | |
* @param string $char val. | |
* @return string encoded char. | |
*/ | |
private static function _encode_char($char) | |
{ | |
if (strpos(' ~`!@#$%^&*()+=[]\\{}|;\':",./<>?', $char) === false) | |
return $char; | |
else | |
return rawurlencode($char); | |
} | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
#$plaintext = "this is my plaintext."; | |
$cipher_key = "enigma"; | |
#printf("\ncipher key is %s\n", $cipher_key); | |
#$cipher_text = "q/xJqqN6qbiZMXYmiQC1Fw=="; | |
#$decrypt = "RVOElAJIHskATgCCP+KlaQ=="; | |
#$key = "67a4f45f0d1d9bc606486fc42dc49416"; | |
#$iv = "0123456789012345"; | |
## Manual Run | |
#$cipher_text = encrypt("hellohellohello!", $cipher_key, $iv); | |
#$p_text = decrypt($cipher_text, $cipher_key, $iv); | |
## | |
function decrypt($cipher_text, $cipher_key) { | |
$iv = "0123456789012345"; | |
if (gettype($cipher_text) != "string") | |
return "DECRYPTION_ERROR"; | |
$decoded = base64_decode($cipher_text); | |
$sha_cipher_key = hash("sha256", $cipher_key); | |
$padded_cipher_key = substr($sha_cipher_key, 0, 32); | |
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); | |
mcrypt_generic_init($td, $padded_cipher_key, $iv); | |
$decrypted = mdecrypt_generic($td, $decoded); // TODO: handle non-encrypted unicode corner-case | |
mcrypt_generic_deinit($td); | |
mcrypt_module_close($td); | |
$unpadded = unpadPKCS7($decrypted, 16); | |
#printf("\ndecoded: %s", $unpadded); | |
return $unpadded; | |
} | |
function encrypt($plain_text, $cipher_key) { | |
$iv = "0123456789012345"; | |
$sha_cipher_key = hash("sha256", $cipher_key); | |
$padded_cipher_key = substr($sha_cipher_key, 0, 32); | |
$padded_plain_text = pkcs5_pad($plain_text, 16); | |
// printf("sha256 key is %s\n", $sha_cipher_key); | |
// printf("padded cipher key is %s\n\n", $padded_cipher_key); | |
// printf("padded plain_text is %s\n\n", $padded_plain_text); | |
# This is the way to do AES-256 using mcrypt PHP - its not AES-128 or anything other than that! | |
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); | |
mcrypt_generic_init($td, $padded_cipher_key, $iv); | |
$encrypted = mcrypt_generic($td, $padded_plain_text); | |
$encode = base64_encode($encrypted); | |
mcrypt_generic_deinit($td); | |
mcrypt_module_close($td); | |
#printf("\nencoded: %s", $encode); | |
return $encode; | |
} | |
function pkcs5_pad ($text, $blocksize) | |
{ | |
$pad = $blocksize - (strlen($text) % $blocksize); | |
return $text . str_repeat(chr($pad), $pad); | |
} | |
function unpadPKCS7($data, $blockSize) | |
{ | |
$length = strlen($data); | |
if ($length > 0) { | |
$first = substr($data, -1); | |
if (ord($first) <= $blockSize) { | |
for ($i = $length - 2; $i > 0; $i--) | |
if (ord($data [$i] != $first)) | |
break; | |
return substr($data, 0, $i+1); | |
} | |
} | |
return $data; | |
} | |
function isBlank($word) | |
{ | |
if (($word == null) || ($word == false)) | |
return true; | |
else | |
return false; | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment