diff options
author | Federico Marani <federico.marani@ymail.com> | 2009-03-16 22:43:51 +0000 |
---|---|---|
committer | Federico Marani <federico.marani@ymail.com> | 2009-03-16 22:43:51 +0000 |
commit | 420c3613049bec1360cdeb1f50283b239adf23d3 (patch) | |
tree | 0ab458b3c45c883232b3ed31addbc2aba1288f6a /extlib | |
parent | bab3e1b8586f42bc1f0a5f96b6990d67c6b74446 (diff) | |
parent | b3a0eea3b66e95becb6c4595ed71c7fe71ed6437 (diff) |
Merge branch '0.8.x' of git://gitorious.org/laconica/dev into 0.8.x
Diffstat (limited to 'extlib')
-rw-r--r-- | extlib/OAuth.php | 135 | ||||
-rw-r--r-- | extlib/PEAR/Exception.php | 397 |
2 files changed, 472 insertions, 60 deletions
diff --git a/extlib/OAuth.php b/extlib/OAuth.php index 6dc6b3f35..029166175 100644 --- a/extlib/OAuth.php +++ b/extlib/OAuth.php @@ -16,6 +16,10 @@ class OAuthConsumer {/*{{{*/ $this->secret = $secret; $this->callback_url = $callback_url; }/*}}}*/ + + function __toString() {/*{{{*/ + return "OAuthConsumer[key=$this->key,secret=$this->secret]"; + }/*}}}*/ }/*}}}*/ class OAuthToken {/*{{{*/ @@ -37,8 +41,8 @@ class OAuthToken {/*{{{*/ * would respond to request_token and access_token calls with */ function to_string() {/*{{{*/ - return "oauth_token=" . OAuthUtil::urlencodeRFC3986($this->key) . - "&oauth_token_secret=" . OAuthUtil::urlencodeRFC3986($this->secret); + return "oauth_token=" . OAuthUtil::urlencode_rfc3986($this->key) . + "&oauth_token_secret=" . OAuthUtil::urlencode_rfc3986($this->secret); }/*}}}*/ function __toString() {/*{{{*/ @@ -67,7 +71,7 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {/*{{{*/ ($token) ? $token->secret : "" ); - $key_parts = array_map(array('OAuthUtil','urlencodeRFC3986'), $key_parts); + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); $key = implode('&', $key_parts); return base64_encode( hash_hmac('sha1', $base_string, $key, true)); @@ -81,11 +85,11 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {/*{{{*/ public function build_signature($request, $consumer, $token) {/*{{{*/ $sig = array( - OAuthUtil::urlencodeRFC3986($consumer->secret) + OAuthUtil::urlencode_rfc3986($consumer->secret) ); if ($token) { - array_push($sig, OAuthUtil::urlencodeRFC3986($token->secret)); + array_push($sig, OAuthUtil::urlencode_rfc3986($token->secret)); } else { array_push($sig, ''); } @@ -94,7 +98,7 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {/*{{{*/ // for debug purposes $request->base_string = $raw; - return OAuthUtil::urlencodeRFC3986($raw); + return OAuthUtil::urlencode_rfc3986($raw); }/*}}}*/ }/*}}}*/ @@ -182,7 +186,7 @@ class OAuthRequest {/*{{{*/ */ 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['REQUEST_URI']; + @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI']; @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; $request_headers = OAuthRequest::get_headers(); @@ -192,27 +196,23 @@ class OAuthRequest {/*{{{*/ // do this if ($parameters) { $req = new OAuthRequest($http_method, $http_url, $parameters); + } else { + // collect request parameters from query string (GET) and post-data (POST) if appropriate (note: POST vars have priority) + $req_parameters = $_GET; + if ($http_method == "POST" && @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") ) { + $req_parameters = array_merge($req_parameters, $_POST); + } + + // next check for the auth header, we need to do some extra stuff + // if that is the case, namely suck in the parameters from GET or POST + // so that we can include them in the signature + if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { + $header_parameters = OAuthRequest::split_header($request_headers['Authorization']); + $parameters = array_merge($req_parameters, $header_parameters); + $req = new OAuthRequest($http_method, $http_url, $parameters); + } else $req = new OAuthRequest($http_method, $http_url, $req_parameters); } - // next check for the auth header, we need to do some extra stuff - // if that is the case, namely suck in the parameters from GET or POST - // so that we can include them in the signature - else if (@substr($request_headers['Authorization'], 0, 5) == "OAuth") { - $header_parameters = OAuthRequest::split_header($request_headers['Authorization']); - if ($http_method == "GET") { - $req_parameters = $_GET; - } - else if ($http_method == "POST") { - $req_parameters = $_POST; - } - $parameters = array_merge($header_parameters, $req_parameters); - $req = new OAuthRequest($http_method, $http_url, $parameters); - } - else if ($http_method == "GET") { - $req = new OAuthRequest($http_method, $http_url, $_GET); - } - else if ($http_method == "POST") { - $req = new OAuthRequest($http_method, $http_url, $_POST); - } + return $req; }/*}}}*/ @@ -238,7 +238,7 @@ class OAuthRequest {/*{{{*/ }/*}}}*/ public function get_parameter($name) {/*{{{*/ - return $this->parameters[$name]; + return isset($this->parameters[$name]) ? $this->parameters[$name] : null; }/*}}}*/ public function get_parameters() {/*{{{*/ @@ -267,12 +267,12 @@ class OAuthRequest {/*{{{*/ } // Urlencode both keys and values - $keys = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_keys($params)); - $values = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_values($params)); + $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); + $values = OAuthUtil::urlencode_rfc3986(array_values($params)); $params = array_combine($keys, $values); // Sort by keys (natsort) - uksort($params, 'strnatcmp'); + uksort($params, 'strcmp'); // Generate key=value pairs $pairs = array(); @@ -307,7 +307,7 @@ class OAuthRequest {/*{{{*/ $this->get_signable_parameters() ); - $parts = array_map(array('OAuthUtil', 'urlencodeRFC3986'), $parts); + $parts = OAuthUtil::urlencode_rfc3986($parts); return implode('&', $parts); }/*}}}*/ @@ -351,11 +351,21 @@ class OAuthRequest {/*{{{*/ /** * builds the data one would send in a POST request + * + * TODO(morten.fangel): + * this function might be easily replaced with http_build_query() + * and corrections for rfc3986 compatibility.. but not sure */ public function to_postdata() {/*{{{*/ $total = array(); foreach ($this->parameters as $k => $v) { - $total[] = OAuthUtil::urlencodeRFC3986($k) . "=" . OAuthUtil::urlencodeRFC3986($v); + if (is_array($v)) { + foreach ($v as $va) { + $total[] = OAuthUtil::urlencode_rfc3986($k) . "[]=" . OAuthUtil::urlencode_rfc3986($va); + } + } else { + $total[] = OAuthUtil::urlencode_rfc3986($k) . "=" . OAuthUtil::urlencode_rfc3986($v); + } } $out = implode("&", $total); return $out; @@ -364,12 +374,13 @@ class OAuthRequest {/*{{{*/ /** * builds the Authorization: header */ - public function to_header($realm="") {/*{{{*/ - $out ='"Authorization: OAuth realm="' . $realm . '",'; + public function to_header() {/*{{{*/ + $out ='Authorization: OAuth realm=""'; $total = array(); foreach ($this->parameters as $k => $v) { if (substr($k, 0, 5) != "oauth") continue; - $out .= ',' . OAuthUtil::urlencodeRFC3986($k) . '="' . OAuthUtil::urlencodeRFC3986($v) . '"'; + if (is_array($v)) throw new OAuthException('Arrays not supported in headers'); + $out .= ',' . OAuthUtil::urlencode_rfc3986($k) . '="' . OAuthUtil::urlencode_rfc3986($v) . '"'; } return $out; }/*}}}*/ @@ -412,24 +423,22 @@ class OAuthRequest {/*{{{*/ * parameters, has to do some unescaping */ private static function split_header($header) {/*{{{*/ - // remove 'OAuth ' at the start of a header - $header = substr($header, 6); - - // error cases: commas in parameter values? - $parts = explode(",", $header); - $out = array(); - foreach ($parts as $param) { - $param = ltrim($param); - // skip the "realm" param, nobody ever uses it anyway - if (substr($param, 0, 5) != "oauth") continue; - - $param_parts = explode("=", $param); - - // rawurldecode() used because urldecode() will turn a "+" in the - // value into a space - $out[$param_parts[0]] = rawurldecode(substr($param_parts[1], 1, -1)); + $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]; + $params[$header_name] = OAuthUtil::urldecode_rfc3986( $header_content ); + $offset = $match[1] + strlen($match[0]); } - return $out; + + if (isset($params['realm'])) { + unset($params['realm']); + } + + return $params; }/*}}}*/ /** @@ -506,6 +515,7 @@ class OAuthServer {/*{{{*/ // requires authorized request token $token = $this->get_token($request, $consumer, "request"); + $this->check_signature($request, $consumer, $token); $new_token = $this->data_store->new_access_token($token, $consumer); @@ -654,11 +664,11 @@ class OAuthDataStore {/*{{{*/ // implement me }/*}}}*/ - function fetch_request_token($consumer) {/*{{{*/ + function new_request_token($consumer) {/*{{{*/ // return a new token attached to this consumer }/*}}}*/ - function fetch_access_token($token, $consumer) {/*{{{*/ + function new_access_token($token, $consumer) {/*{{{*/ // return a new access token attached to this consumer // for the user associated with this token if the request token // is authorized @@ -737,17 +747,22 @@ class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/ }/*}}}*/ class OAuthUtil {/*{{{*/ - public static function urlencodeRFC3986($string) {/*{{{*/ - return str_replace('+', ' ', - str_replace('%7E', '~', rawurlencode($string))); - + 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 urldecodeRFC3986($string) {/*{{{*/ + public static function urldecode_rfc3986($string) {/*{{{*/ return rawurldecode($string); }/*}}}*/ }/*}}}*/ diff --git a/extlib/PEAR/Exception.php b/extlib/PEAR/Exception.php new file mode 100644 index 000000000..b3d75b20c --- /dev/null +++ b/extlib/PEAR/Exception.php @@ -0,0 +1,397 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */ +/** + * PEAR_Exception + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt. If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category pear + * @package PEAR + * @author Tomas V. V. Cox <cox@idecnet.com> + * @author Hans Lellelid <hans@velum.net> + * @author Bertrand Mansion <bmansion@mamasam.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: Exception.php,v 1.29 2008/01/03 20:26:35 cellog Exp $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.3 + */ + + +/** + * Base PEAR_Exception Class + * + * 1) Features: + * + * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) + * - Definable triggers, shot when exceptions occur + * - Pretty and informative error messages + * - Added more context info available (like class, method or cause) + * - cause can be a PEAR_Exception or an array of mixed + * PEAR_Exceptions/PEAR_ErrorStack warnings + * - callbacks for specific exception classes and their children + * + * 2) Ideas: + * + * - Maybe a way to define a 'template' for the output + * + * 3) Inherited properties from PHP Exception Class: + * + * protected $message + * protected $code + * protected $line + * protected $file + * private $trace + * + * 4) Inherited methods from PHP Exception Class: + * + * __clone + * __construct + * getMessage + * getCode + * getFile + * getLine + * getTraceSafe + * getTraceSafeAsString + * __toString + * + * 5) Usage example + * + * <code> + * require_once 'PEAR/Exception.php'; + * + * class Test { + * function foo() { + * throw new PEAR_Exception('Error Message', ERROR_CODE); + * } + * } + * + * function myLogger($pear_exception) { + * echo $pear_exception->getMessage(); + * } + * // each time a exception is thrown the 'myLogger' will be called + * // (its use is completely optional) + * PEAR_Exception::addObserver('myLogger'); + * $test = new Test; + * try { + * $test->foo(); + * } catch (PEAR_Exception $e) { + * print $e; + * } + * </code> + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox <cox@idecnet.com> + * @author Hans Lellelid <hans@velum.net> + * @author Bertrand Mansion <bmansion@mamasam.com> + * @author Greg Beaver <cellog@php.net> + * @copyright 1997-2008 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version Release: 1.7.2 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.3 + * + */ +class PEAR_Exception extends Exception +{ + const OBSERVER_PRINT = -2; + const OBSERVER_TRIGGER = -4; + const OBSERVER_DIE = -8; + protected $cause; + private static $_observers = array(); + private static $_uniqueid = 0; + private $_trace; + + /** + * Supported signatures: + * - PEAR_Exception(string $message); + * - PEAR_Exception(string $message, int $code); + * - PEAR_Exception(string $message, Exception $cause); + * - PEAR_Exception(string $message, Exception $cause, int $code); + * - PEAR_Exception(string $message, PEAR_Error $cause); + * - PEAR_Exception(string $message, PEAR_Error $cause, int $code); + * - PEAR_Exception(string $message, array $causes); + * - PEAR_Exception(string $message, array $causes, int $code); + * @param string exception message + * @param int|Exception|PEAR_Error|array|null exception cause + * @param int|null exception code or null + */ + public function __construct($message, $p2 = null, $p3 = null) + { + if (is_int($p2)) { + $code = $p2; + $this->cause = null; + } elseif (is_object($p2) || is_array($p2)) { + // using is_object allows both Exception and PEAR_Error + if (is_object($p2) && !($p2 instanceof Exception)) { + if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) { + throw new PEAR_Exception('exception cause must be Exception, ' . + 'array, or PEAR_Error'); + } + } + $code = $p3; + if (is_array($p2) && isset($p2['message'])) { + // fix potential problem of passing in a single warning + $p2 = array($p2); + } + $this->cause = $p2; + } else { + $code = null; + $this->cause = null; + } + parent::__construct($message, $code); + $this->signal(); + } + + /** + * @param mixed $callback - A valid php callback, see php func is_callable() + * - A PEAR_Exception::OBSERVER_* constant + * - An array(const PEAR_Exception::OBSERVER_*, + * mixed $options) + * @param string $label The name of the observer. Use this if you want + * to remove it later with removeObserver() + */ + public static function addObserver($callback, $label = 'default') + { + self::$_observers[$label] = $callback; + } + + public static function removeObserver($label = 'default') + { + unset(self::$_observers[$label]); + } + + /** + * @return int unique identifier for an observer + */ + public static function getUniqueId() + { + return self::$_uniqueid++; + } + + private function signal() + { + foreach (self::$_observers as $func) { + if (is_callable($func)) { + call_user_func($func, $this); + continue; + } + settype($func, 'array'); + switch ($func[0]) { + case self::OBSERVER_PRINT : + $f = (isset($func[1])) ? $func[1] : '%s'; + printf($f, $this->getMessage()); + break; + case self::OBSERVER_TRIGGER : + $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; + trigger_error($this->getMessage(), $f); + break; + case self::OBSERVER_DIE : + $f = (isset($func[1])) ? $func[1] : '%s'; + die(printf($f, $this->getMessage())); + break; + default: + trigger_error('invalid observer type', E_USER_WARNING); + } + } + } + + /** + * Return specific error information that can be used for more detailed + * error messages or translation. + * + * This method may be overridden in child exception classes in order + * to add functionality not present in PEAR_Exception and is a placeholder + * to define API + * + * The returned array must be an associative array of parameter => value like so: + * <pre> + * array('name' => $name, 'context' => array(...)) + * </pre> + * @return array + */ + public function getErrorData() + { + return array(); + } + + /** + * Returns the exception that caused this exception to be thrown + * @access public + * @return Exception|array The context of the exception + */ + public function getCause() + { + return $this->cause; + } + + /** + * Function must be public to call on caused exceptions + * @param array + */ + public function getCauseMessage(&$causes) + { + $trace = $this->getTraceSafe(); + $cause = array('class' => get_class($this), + 'message' => $this->message, + 'file' => 'unknown', + 'line' => 'unknown'); + if (isset($trace[0])) { + if (isset($trace[0]['file'])) { + $cause['file'] = $trace[0]['file']; + $cause['line'] = $trace[0]['line']; + } + } + $causes[] = $cause; + if ($this->cause instanceof PEAR_Exception) { + $this->cause->getCauseMessage($causes); + } elseif ($this->cause instanceof Exception) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => $this->cause->getFile(), + 'line' => $this->cause->getLine()); + } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($this->cause)) { + foreach ($this->cause as $cause) { + if ($cause instanceof PEAR_Exception) { + $cause->getCauseMessage($causes); + } elseif ($cause instanceof Exception) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => $cause->getFile(), + 'line' => $cause->getLine()); + } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($cause) && isset($cause['message'])) { + // PEAR_ErrorStack warning + $causes[] = array( + 'class' => $cause['package'], + 'message' => $cause['message'], + 'file' => isset($cause['context']['file']) ? + $cause['context']['file'] : + 'unknown', + 'line' => isset($cause['context']['line']) ? + $cause['context']['line'] : + 'unknown', + ); + } + } + } + } + + public function getTraceSafe() + { + if (!isset($this->_trace)) { + $this->_trace = $this->getTrace(); + if (empty($this->_trace)) { + $backtrace = debug_backtrace(); + $this->_trace = array($backtrace[count($backtrace)-1]); + } + } + return $this->_trace; + } + + public function getErrorClass() + { + $trace = $this->getTraceSafe(); + return $trace[0]['class']; + } + + public function getErrorMethod() + { + $trace = $this->getTraceSafe(); + return $trace[0]['function']; + } + + public function __toString() + { + if (isset($_SERVER['REQUEST_URI'])) { + return $this->toHtml(); + } + return $this->toText(); + } + + public function toHtml() + { + $trace = $this->getTraceSafe(); + $causes = array(); + $this->getCauseMessage($causes); + $html = '<table border="1" cellspacing="0">' . "\n"; + foreach ($causes as $i => $cause) { + $html .= '<tr><td colspan="3" bgcolor="#ff9999">' + . str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: ' + . htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> ' + . 'on line <b>' . $cause['line'] . '</b>' + . "</td></tr>\n"; + } + $html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</b></td></tr>' . "\n" + . '<tr><td align="center" bgcolor="#cccccc" width="20"><b>#</b></td>' + . '<td align="center" bgcolor="#cccccc"><b>Function</b></td>' + . '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n"; + + foreach ($trace as $k => $v) { + $html .= '<tr><td align="center">' . $k . '</td>' + . '<td>'; + if (!empty($v['class'])) { + $html .= $v['class'] . $v['type']; + } + $html .= $v['function']; + $args = array(); + if (!empty($v['args'])) { + foreach ($v['args'] as $arg) { + if (is_null($arg)) $args[] = 'null'; + elseif (is_array($arg)) $args[] = 'Array'; + elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')'; + elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false'; + elseif (is_int($arg) || is_double($arg)) $args[] = $arg; + else { + $arg = (string)$arg; + $str = htmlspecialchars(substr($arg, 0, 16)); + if (strlen($arg) > 16) $str .= '…'; + $args[] = "'" . $str . "'"; + } + } + } + $html .= '(' . implode(', ',$args) . ')' + . '</td>' + . '<td>' . (isset($v['file']) ? $v['file'] : 'unknown') + . ':' . (isset($v['line']) ? $v['line'] : 'unknown') + . '</td></tr>' . "\n"; + } + $html .= '<tr><td align="center">' . ($k+1) . '</td>' + . '<td>{main}</td>' + . '<td> </td></tr>' . "\n" + . '</table>'; + return $html; + } + + public function toText() + { + $causes = array(); + $this->getCauseMessage($causes); + $causeMsg = ''; + foreach ($causes as $i => $cause) { + $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' + . $cause['message'] . ' in ' . $cause['file'] + . ' on line ' . $cause['line'] . "\n"; + } + return $causeMsg . $this->getTraceAsString(); + } +} + +?>
\ No newline at end of file |