diff options
Diffstat (limited to 'apps/shorty/lib')
-rw-r--r-- | apps/shorty/lib/backend.php | 286 | ||||
-rw-r--r-- | apps/shorty/lib/exception.php | 162 | ||||
-rw-r--r-- | apps/shorty/lib/hooks.php | 64 | ||||
-rw-r--r-- | apps/shorty/lib/l10n.php | 93 | ||||
-rw-r--r-- | apps/shorty/lib/meta.php | 213 | ||||
-rw-r--r-- | apps/shorty/lib/query.php | 57 | ||||
-rw-r--r-- | apps/shorty/lib/tools.php | 235 | ||||
-rw-r--r-- | apps/shorty/lib/type.php | 291 |
8 files changed, 1401 insertions, 0 deletions
diff --git a/apps/shorty/lib/backend.php b/apps/shorty/lib/backend.php new file mode 100644 index 00000000000..aa6c58b4490 --- /dev/null +++ b/apps/shorty/lib/backend.php @@ -0,0 +1,286 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/backend.php + * Routines to use remote (online) shortening services as backends in a local workflow + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Backend + * @brief Library to register urls using backends, typically remote (online) url shortening services + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Backend +{ + /** + * @method OC_Shorty_Backend::registerUrl + * @brief Wrapper function around the specific backend routines + * @param id (string) Internal shorty id used to reference a shorty upon usage. + * @returns (string) The shortened url as generated by a specific backend. + * @throws OC_Shorty_Exception taking over the explaining of the failure from the specific backend + * @access public + * @author Christian Reiner + */ + static function registerUrl ( $id ) + { + try + { + // construct the $relay, the url to be called to reach THIS service (ownclouds shorty plugin) + $relay = OC_Shorty_Tools::relayUrl ( $id ); + // call backend specific work horse + switch ( $type=OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-type','none') ) + { + default: return OC_Shorty_Backend::registerUrl_default ( $id, $relay ); + case 'static': return OC_Shorty_Backend::registerUrl_static ( $id, $relay ); + case 'bitly': return OC_Shorty_Backend::registerUrl_bitly ( $id, $relay ); + case 'cligs': return OC_Shorty_Backend::registerUrl_cligs ( $id, $relay ); + case 'google': return OC_Shorty_Backend::registerUrl_google ( $id, $relay ); + case 'isgd': return OC_Shorty_Backend::registerUrl_isgd ( $id, $relay ); + case 'tinyurl': return OC_Shorty_Backend::registerUrl_tinyurl ( $id, $relay ); + case 'tinycc': return OC_Shorty_Backend::registerUrl_tinycc ( $id, $relay ); + } // switch + } // try + catch (OC_Shorty_Exception $e) + { + throw $e; + } // catch + catch (Exception $e) + { + throw new OC_Shorty_Exception ( "Failed to register url '%s' at '%s' backend", array($relay,$type) ); + } // catch + } // OC_Shorty_Backend::registerUrl + + /** + * @method OC_Shorty_Backend::registerUrl_default + * @brief Pseudo-registers a given local relay url + * @param id (string) + * @param relay (url) + * @returns validated and pseudo-registered relay + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_default ( $id, $relay ) + { + return OC_Shorty_Type::validate ( $relay, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_default + + /** + * @method OC_Shorty_Backend::registerUrl_static + * @brief Registers a given local relay url as local static shorty + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_static ( $id, $relay ) + { + if ( (FALSE===($base=trim ( OCP\Config::getAppValue('shorty','backend-static-base',FALSE)))) + ||(empty($base)) ) + throw new OC_Shorty_Exception ( 'No base url defined for the static backend' ); + return OC_Shorty_Type::validate ( $base.$id, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_static + + /** + * @method OC_Shorty_Backend::registerUrl_bitly + * @brief Registers a given local relay url at the bit.ly shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_bitly ( $id, $relay ) + { + $bitly_api_user = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-bitly-user',''); + $bitly_api_key = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-bitly-key', ''); + if ( ! $bitly_api_key || ! $bitly_api_user ) + throw new OC_Shorty_Exception ( 'No API user or key configured' ); + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, 'https://api-ssl.bit.ly/shorten' ); + curl_setopt ( $curl, CURLOPT_SSL_VERIFYHOST, TRUE ); + curl_setopt ( $curl, CURLOPT_POST, TRUE ); + curl_setopt ( $curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json') ); + curl_setopt ( $curl, CURLOPT_POSTFIELDS, json_encode(array('version'=>'2.0.1', + 'longUrl'=>$relay, + 'format'=>'json', + 'login'=>$bitly_api_user, + 'apiKey'=>$bitly_api_key) ) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||(NULL===($payload=json_decode($reply))) + ||(!is_object($payload)) + ||(!property_exists($payload,'id')) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'static'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $payload->id, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_bitly + + /** + * @method OC_Shorty_Backend::registerUrl_cligs + * @brief Registers a given local relay url at the cli.gs shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_cligs ( $id, $relay ) + { + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, sprintf('http://cli.gs/api/v2/cligs/create?url=%s&appid=owncloud_shorty&test=1', urlencode(trim($relay))) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||( ! preg_match( '/^(.+)$/', $reply, $match )) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'cli.gs'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $match[1], OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_cligs + + /** + * @method OC_Shorty_Backend::registerUrl_isgd + * @brief Registers a given local relay url at the is.gd shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_isgd ( $id, $relay ) + { + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, sprintf('http://is.gd/create.php?format=simple&url=%s', urlencode(trim($relay))) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||( ! preg_match( '/^(.+)$/', $reply, $match )) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'is.gd'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $match[1], OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_isgd + + /** + * @method OC_Shorty_Backend::registerUrl_google + * @brief Registers a given local relay url at the google shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_google ( $id, $relay ) + { + $api_key = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-google-key',''); + if ( ! $api_key ) + throw new OC_Shorty_Exception ( 'No goo.gl API key configured' ); + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, 'https://www.googleapis.com/urlshortener/v1/url' ); + curl_setopt ( $curl, CURLOPT_SSL_VERIFYHOST, TRUE ); + curl_setopt ( $curl, CURLOPT_POST, TRUE ); + curl_setopt ( $curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json') ); + curl_setopt ( $curl, CURLOPT_POSTFIELDS, json_encode(array('longUrl'=>$relay, + 'key'=>$api_key) ) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||(NULL===($payload=json_decode($reply))) + ||(!is_object($payload)) + ||(!property_exists($payload,'id')) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'goo.gl'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $payload->id, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_google + + /** + * @method OC_Shorty_Backend::registerUrl_tinycc + * @brief Registers a given local relay url at the tiny.cc shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_tinycc ( $id, $relay ) + { + $api_user = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-tinycc-user',''); + $api_key = OCP\Config::getUserValue(OCP\User::getUser(),'shorty','backend-tinycc-key',''); + if ( ! $api_key || ! $api_user ) + throw new OC_Shorty_Exception ( 'No goo.gl API key configured' ); + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, 'http://tiny.cc/?c=shorten' ); + curl_setopt ( $curl, CURLOPT_SSL_VERIFYHOST, TRUE ); + curl_setopt ( $curl, CURLOPT_POST, TRUE ); + curl_setopt ( $curl, CURLOPT_HEADER, TRUE ); + curl_setopt ( $curl, CURLOPT_POSTFIELDS, array('longUrl'=>$relay, + 'version'=>'2.0.3', + 'format'=>'json', + 'login'=>$api_user, + 'apiKey'=>$api_key) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||(NULL===($payload=json_decode($reply))) + ||(!is_object($payload)) + ||(!property_exists($payload,'id')) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'tiny.cc'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $payload->id, OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_google + + /** + * @method OC_Shorty_Backend::registerUrl_tinyurl + * @brief Registers a given local relay url at the tinyURL shortening service + * @param id (string) + * @param relay (url) + * @returns registered and validated relay url + * @access public + * @author Chrisian Reiner + */ + static function registerUrl_tinyurl ( $id, $relay ) + { + $curl = curl_init ( ); + curl_setopt ( $curl, CURLOPT_URL, sprintf('http://tinyurl.com/api-create.php?url=%s', urlencode(trim($relay))) ); + curl_setopt ( $curl, CURLOPT_RETURNTRANSFER, TRUE ); + if ( (FALSE===($reply=curl_exec($curl))) + ||( ! preg_match( '/^(.+)$/', $reply, $match )) ) + { + throw new OC_Shorty_Exception ( "Failed to register url at backend 'tinyUrl'" ); + } + curl_close ( $curl ); + return OC_Shorty_Type::validate ( $match[1], OC_Shorty_Type::URL ); + } // OC_Shorty_Backend::registerUrl_tinyurl + +} // class OC_Shorty_Backend diff --git a/apps/shorty/lib/exception.php b/apps/shorty/lib/exception.php new file mode 100644 index 00000000000..daeb9d10a9c --- /dev/null +++ b/apps/shorty/lib/exception.php @@ -0,0 +1,162 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/exception.php + * Application specific exception class + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Exception + * @brief Application specific exception class + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Exception extends Exception +{ + protected $phrase = ''; + protected $param = array ( ); + + /** + * @method OC_Shorty_Exception::__construct + * @brief: Constructs an exception based on a phrase and a set of parameters + * @param phrase (string) Human readable message that should be translatable + * @param param (array) Set of parameters to be used as sprintf arguments to fill the phrase + * @access public + * @author Christian Reiner + */ + public function __construct ( $phrase, $param=array() ) + { + if ( is_array($param) ) + $this->param = $param; + else $this->param = array($param); + $this->phrase = $phrase; +// $this->message = vsprintf ( $phrase, $this->params ); + Exception::__construct ( vsprintf($phrase,$this->param), 1 ); + } + + /** + * @method OC_Shorty_Exception::getTranslation + * @brief: Returns the translated message of the exception + * @returns (string) Translated message including the filled in set of arguments + * @access public + * @author Christian Reiner + */ + public function getTranslation ( ) + { + return OC_Shorty_L10n::t ( $this->phrase, $this->param ); + } + + /** + * @method OC_Shorty_Exception::JSONerror + * @brief Calls OCP\JSON::error with a pretty formated version of an exception + * @param e (exception) an exception object holding information + * @returns (json) OCP\JSON::error + * @access public + * @author Christian Reiner + */ + static function JSONerror ( $e ) + { + $title = OC_Shorty_L10n::t("Exception"); + switch ( get_class($e) ) + { + case 'OC_Shorty_Exception': + $message = $e->getTranslation(); + break; + case 'PDOException': + $message = sprintf ( OC_Shorty_L10n::t( "%s\nMessage(code): %s (%s)\nFile(line): %s (%s)\nInfo: %%s", + OC_Shorty_L10n::t("Exception (%s)", get_class($e)), + htmlspecialchars($e->getMessage()), + htmlspecialchars($e->getCode()), + htmlspecialchars($e->getFile()), + htmlspecialchars($e->getLine()) ), + (method_exists($e,'errorInfo') ? trim($e->errorInfo()) : '-/-') ); + break; + default: + if ( is_a($e,'Exception') ) + $message = OC_Shorty_L10n::t("Unexpected type of exception caught: %s", get_class($e)); + else $message = OC_Shorty_L10n::t("Unknown object of type caught: %s", get_class($e)); + } // switch + // swallow any accidential output generated by php notices and stuff to preserve a clean JSON reply structure + $output = trim ( OC_Shorty_Tools::ob_control(FALSE) ); + if ( $output ) + { + $message = "! Swallowing accidential output from ajax routines ! \n" + ."Please fix this ! Here is the first line: \n" + .substr ( $output, 0, strpos($output,"\n") ); + OCP\Util::writeLog( 'shorty', $message, OC_Log::WARN ); + } // output + // return a clean JSON error + return OCP\JSON::error ( array ( 'title' => $title, + 'message' => sprintf("%s: %s", $title, $message) ) ); + } // function error +} // class OC_Shorty_Exception + +/** + * @class OC_Shorty_HttpException + * @brief Application specific exception class: protocol layer + * @access public + * @author Christian Reiner + */ +class OC_Shorty_HttpException extends OC_Shorty_Exception +{ + + /** + * @method OC_Shorty_HttpException::__construct + * @brief: Constructs an exception based on a phrase and a set of parameters + * @param status (integer) Http status code + * @access public + * @author Christian Reiner + */ + public function __construct ( $status ) + { + if ( is_numeric($status) + && array_key_exists($status,OC_Shorty_Type::$HTTPCODE) ) + { + $status = intval($status); + $phrase = OC_Shorty_Type::$HTTPCODE[$status]; + } + else + { + $status = 400; + $phrase = OC_Shorty_Type::$HTTPCODE[400]; // "Bad Request" + } // switch + + // return http status code to client (browser) + if ( ! headers_sent() ) + { + header ( sprintf("HTTP/1.0 %s %s",$status,$phrase) ); + } + $tmpl = new OCP\Template("shorty", "tmpl_http_status", "guest"); + $tmpl->assign("explanation", OC_Shorty_L10n::t($phrase)); + $tmpl->printPage(); + exit; + } // function __construct + +} // class OC_Shorty_HttpException + +?> diff --git a/apps/shorty/lib/hooks.php b/apps/shorty/lib/hooks.php new file mode 100644 index 00000000000..6ba59eccbda --- /dev/null +++ b/apps/shorty/lib/hooks.php @@ -0,0 +1,64 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/hooks.php + * Static class providing routines to populate hooks called by other parts of ownCloud + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Hooks + * @brief Static 'namespace' class for api hook population + * ownCloud propagates to use static classes as namespaces instead of OOP. + * This 'namespace' defines routines to populate hooks called by other parts of ownCloud + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Hooks +{ + /** + * @brief Deletes all Shortys and preferences of a certain user + * @param paramters (array) parameters from postDeleteUser-Hook + * @return bool + */ + public static function deleteUser ( $parameters ) + { + OCP\Util::writeLog ( 'user post delete','wiping all users Shortys', OCP\Util::INFO ); + $result = TRUE; + $param = array ( 'user' => OCP\User::getUser() ); + // wipe shortys + $query = OCP\DB::prepare ( OC_Shorty_Query::WIPE_SHORTYS ); + if ( FALSE===$query->execute($param) ) + $result = FALSE; + // wipe preferences + $query = OCP\DB::prepare ( OC_Shorty_Query::WIPE_PREFERENCES ); + if ( FALSE===$query->execute($param) ) + $result = FALSE; + // report completion success + return $result; + } +} diff --git a/apps/shorty/lib/l10n.php b/apps/shorty/lib/l10n.php new file mode 100644 index 00000000000..648130645a0 --- /dev/null +++ b/apps/shorty/lib/l10n.php @@ -0,0 +1,93 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/l10n.php + * Translation singleton + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_L10n + * @brief Convenient translation singleton + * @access public + * @author Christian Reiner + */ +class OC_Shorty_L10n +{ + /** + * @var OC_Shorty_L10n::dictionary + * @brief An internal dictionary file filled from the translation files provided. + * @access private + * @author Christian Reiner + */ + private $dictionary; + + /** + * @var OC_Shorty_L10n::instance + * @brief Internal singleton object + * @access private + * @author Christian Reiner + */ + static private $instance=NULL; + + /** + * @method OC_Shorty_L10n::__construct + * @brief + * @access private + * @author Christian Reiner + */ + private function __construct ( ) { $this->dictionary = new OC_L10n('shorty'); } + + /** + * @method OC_Shorty_L10n::t + * @brief Translates a given string into the users session language and fills any placeolders + * @param phrase to be translated + * @param … further arguments used as filling tokens in the tradition of printf strategies + * @returns translated phrase or the original phrase incase no translation could be found + * @access public + * @author Christian Reiner + */ + static public function t ( $phrase ) + { + // create singleton instance, if required + if ( ! self::$instance ) + self::$instance = new OC_Shorty_L10n ( ); + // handle different styles of how arguments can be handed over to this method + switch ( func_num_args() ) + { + case 1: return self::$instance->dictionary->t ( $phrase, array() ); + case 2: $arg = func_get_arg(1); + if ( is_array($arg) ) + return self::$instance->dictionary->t ( $phrase, $arg ); + else return self::$instance->dictionary->t ( $phrase, array($arg) ); + default: $args = func_get_args(); + array_shift ( $args ); + return self::$instance->dictionary->t ( $phrase, $args ); + } + } +} // class OC_Shorty_L10n +?> diff --git a/apps/shorty/lib/meta.php b/apps/shorty/lib/meta.php new file mode 100644 index 00000000000..91937bd3c8a --- /dev/null +++ b/apps/shorty/lib/meta.php @@ -0,0 +1,213 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/meta.php + * Routines to retrieve meta information about a remote url + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Meta + * @brief Static 'namespace' class for url meta information retrieval + * ownCloud propagates to use static classes as namespaces instead of OOP. + * This 'namespace' defines routines for the retrieval of meta information about remote urls. + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Meta +{ + + /** + * @method OC_Shorty_Meta::fetchMetaData + * @brief Retrieves the meta information to a given remote url + * @param url decoded target url for which meta information if requested + * @returns associative array holding the requested meta data + * @access public + * @author Christian Reiner + */ + static function fetchMetaData ( $url ) + { + $url_token = parse_url ( $url ); + // some sane fallback values, in case we cannot get the meta data + $meta = array(); + $meta['target'] = $url; + $meta['title'] = strtolower ( $url_token['host'] ); + $meta['scheme'] = strtolower ( $url_token['scheme'] ); + $meta['mimetype'] = 'application/octet-stream'; + $meta['schemicon'] = self::selectIcon ( 'scheme', strtolower($url_token['scheme']) ); + // we wont bother retrieving data about other protocols than http or ftp + if ( ! in_array(strtolower($url_token['scheme']),array('http','https','ftp','ftps')) ) + return $meta; + // to fetch meta data we rely on curl being installed + if ( ! function_exists('curl_init') ) + return $meta; + // try to retrieve the meta data + $handle = curl_init ( ); + curl_setopt ( $handle, CURLOPT_URL, $url ); + curl_setopt ( $handle, CURLOPT_RETURNTRANSFER, 1 ); + curl_setopt ( $handle, CURLOPT_FOLLOWLOCATION, TRUE ); + curl_setopt ( $handle, CURLOPT_MAXREDIRS, 10 ); + if ( FALSE!==($page=curl_exec($handle)) ) + { + // try to extract title from page + preg_match ( "/<head>.*<title>(.*)<\/title>.*<\/head>/si", $page, $match ); + $meta['title'] = htmlspecialchars_decode ( $match[1] ); + $meta['staticon'] = self::selectIcon ( 'state', TRUE ); + // final url after a possible redirection + $meta['final'] = curl_getinfo ( $handle, CURLINFO_EFFECTIVE_URL ); + // try to extract favicon from page + preg_match ( '/<[^>]*link[^>]*(rel=["\']icon["\']|rel=["\']shortcut icon["\']) .*href=["\']([^>]*)["\'].*>/iU', $page, $match ); + if (1<sizeof($match)) + { + // the specified uri might be an url, an absolute or a relative path + // we have to turn it into an url to be able to display it out of context + $favicon = htmlspecialchars_decode ( $match[2] ); + // test for an url + if (parse_url($favicon,PHP_URL_SCHEME)) + { + $meta['favicon'] = $favicon; + } + // test for an absolute path + elseif ( 0===strpos(parse_url($favicon,PHP_URL_PATH),'/') ) + { + $url_token = parse_url($meta['final']); + $meta['favicon'] = sprintf( '%s://%s/%s', $url_token['scheme'], $url_token['host'], $favicon ); + } + // so it appears to be a relative path + else + { + $url_token = parse_url($meta['final']); + $meta['favicon'] = sprintf( '%s://%s%s%s', $url_token['scheme'], $url_token['host'], dirname($url_token['path']), $favicon ); + } + } + $meta['mimetype'] = preg_replace ( '/^([^;]+);.*/i', '$1', curl_getinfo($handle,CURLINFO_CONTENT_TYPE) ); + $meta['mimicon'] = self::selectIcon ( 'mimetype', $meta['mimetype'] ); + $meta['code'] = curl_getinfo ( $handle, CURLINFO_HTTP_CODE ); + $meta['status'] = OC_Shorty_L10n::t ( self::selectCode('status',$meta['code']) ); + $meta['explanation'] = OC_Shorty_L10n::t ( self::selectCode('explanation',$meta['code']) ); + } + curl_close ( $handle ); + // that's it ! + return $meta; + } // function fetchMetaData + + /** + * @method OC_Shorty_Meta::selectCode + * @brief Some helper utility used to resolve numeric http status codes into human readable strings + * @param aspect a string indicating a section/pool a code is to be resolved in + * @param identifier a string indicating a specific code to be resolved + * @returns a human readable string resolving the specified numeric status code + * @throws OC_Shorty_Exception in case of an undefined code to be resolved + * @access public + * @author Christian Reiner + */ + static function selectCode ( $aspect, $identifier ) + { + // map of official http status codes + $_code_map = array + ( + 'status' => OC_Shorty_Type::$HTTPCODE, + 'explanation' => array + ( + 200 => 'Target url is valid and resolved.', + 201 => 'The request has been fulfilled and created a new ressource.', + 202 => 'The request has been accepted.', + 203 => 'The request yielded in non-authorative information.', + 204 => 'The request has been fulfilled but not produced any content.', + 205 => 'The request has been fulfilled and the view should be reset.', + 206 => 'The request has been fulfilled partially.', + ) + ); + // resolve specified code against map or provide some fallback content + if ( key_exists($aspect,$_code_map) && key_exists($identifier,$_code_map[$aspect]) ) + return $_code_map[$aspect][$identifier]; + else + { + switch ( $aspect ) + { + case 'status': return sprintf("Status %s [unknown]",$identifier); + case 'explanation': return sprintf("[Undefined status code '%s']",$identifier); + default: throw new OC_Shorty_Exception ( "unknown aspect '%s' requested to resolve code '%s'", + array($aspect,$identifier) ); + } // switch + } + } // function selectCode + + /** + * @method OC_Shorty_Meta::selectIcon + * @brief Some helper utility for the easy integrate of icon references into templates and alike + * @param aspect a string indicating a section/pool an icon is to be chosen from + * @param identifier a string indicating a specific icon to be referenced + * @returns a hyper reference to an icon in form of a string + * @access public + * @author Christian Reiner + */ + static function selectIcon ( $aspect, $identifier ) + { + switch ( $aspect ) + { + case 'state': + switch ($identifier) + { + case TRUE: return OCP\Util::imagePath('shorty', 'status/good.png'); + case FALSE: return OCP\Util::imagePath('shorty', 'status/bad.png'); + default: return OCP\Util::imagePath('shorty', 'status/neutral.png'); + } // switch identifier + case 'scheme': + switch ($identifier) + { + case 'http': + case 'https': return OCP\Util::imagePath('shorty', 'scheme/H.png'); + case 'ftp': + case 'ftps': return OCP\Util::imagePath('shorty', 'scheme/F.png'); + case 'sftp': return OCP\Util::imagePath('shorty', 'scheme/S.png'); + case 'mailto': return OCP\Util::imagePath('shorty', 'scheme/M.png'); + case 'gopher': return OCP\Util::imagePath('shorty', 'scheme/G.png'); + case 'webdav': + case 'webdavs': return OCP\Util::imagePath('shorty', 'scheme/W.png'); + default: return OCP\Util::imagePath('shorty', 'blank.png'); + } // switch identifier + case 'mimetype': + $identifier = explode('/',$identifier); + switch ($identifier[0]) + { + case 'audio': return OCP\Util::imagePath('core', 'filetypes/audio.png'); + case 'text': return OCP\Util::imagePath('core', 'filetypes/text.png'); + case 'video': return OCP\Util::imagePath('core', 'filetypes/video.png'); + case 'application': + switch ($identifier[1]) + { + case 'pdf': return OCP\Util::imagePath('core', 'filetypes/application-pdf.png'); + default: return OCP\Util::imagePath('shorty', 'blank.png'); + } // switch identifier[1] + default: return OCP\Util::imagePath('shorty', 'blank.png'); + } // switch identifier[0] + } // switch aspect + } // function selectIcon + +} // class OC_Shorty_Meta +?> diff --git a/apps/shorty/lib/query.php b/apps/shorty/lib/query.php new file mode 100644 index 00000000000..6501a54d927 --- /dev/null +++ b/apps/shorty/lib/query.php @@ -0,0 +1,57 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/query.php + * Static catalog of sql queries + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Query + * @brief Static catalog of sql queries + * These query templates are referenced by a OC_Shorty_Query::URL_... + * They have to be prapared by adding an array of parameters + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Query +{ + const URL_INSERT = "INSERT INTO *PREFIX*shorty (id,status,favicon,title,source,target,user,until,created,notes) VALUES (:id,:status,:favicon,:title,:source,:target,:user,:until,CURRENT_DATE,:notes)"; + const URL_DELETE = "DELETE FROM *PREFIX*shorty WHERE user=:user AND id=:id"; + const URL_REMOVE = "DELETE FROM *PREFIX*shorty WHERE user=:user AND 'deleted'=status"; + const URL_UPDATE = "UPDATE *PREFIX*shorty SET status=:status,title=:title,until=:until,notes=:notes WHERE user=:user AND id=:id"; + const URL_STATUS = "UPDATE *PREFIX*shorty SET status=:status WHERE user=:user AND id=:id"; + const URL_CLICK = "UPDATE *PREFIX*shorty SET accessed=CURRENT_TIMESTAMP, clicks=(clicks+1) WHERE id=:id"; + const URL_FORWARD = "SELECT user,source,target,status,(until IS NOT NULL AND until!='' AND until<CURRENT_TIMESTAMP) AS expired FROM *PREFIX*shorty WHERE id=:id"; + const URL_SOURCE = "SELECT id,source,target,status,(until IS NOT NULL AND until!='' AND until<CURRENT_TIMESTAMP) AS expired FROM *PREFIX*shorty WHERE source=:source"; + const URL_VERIFY = "SELECT id,status,favicon,title,source,target,clicks,created,accessed,until,notes FROM *PREFIX*shorty WHERE user=:user AND id=:id LIMIT 1"; + const URL_LIST = "SELECT id,status,favicon,title,source,target,clicks,created,accessed,until,notes FROM *PREFIX*shorty WHERE user=:user ORDER BY :sort"; + const URL_COUNT = "SELECT count(*) AS sum_shortys,IFNULL(sum(clicks),0) AS sum_clicks FROM *PREFIX*shorty WHERE user=:user"; + const WIPE_SHORTYS = "DELETE FROM *PREFIX*shorty WHERE user=:user"; + const WIPE_PREFERENCES = "DELETE FROM *PREFIX*preferences WHERE user=:user"; +} // class OC_Shorty_Query +?> diff --git a/apps/shorty/lib/tools.php b/apps/shorty/lib/tools.php new file mode 100644 index 00000000000..2b3bac70672 --- /dev/null +++ b/apps/shorty/lib/tools.php @@ -0,0 +1,235 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/tools.php + * A collection of general utility routines + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Tools + * @brief Collection of a few practical routines, a tool box + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Tools +{ + // internal flag indicating if output buffering should be used to prevent accidentially output during ajax requests + static $ob_usage = TRUE; + // internal flag indicating if there is currently an output buffer active + static $ob_active = FALSE; + + /** + * @method OC_Shorty_Tools::ob_control + * @param on (boolean) wether to activate or deactivate the buffer + * @access public + * @author Christian Reiner + */ + static function ob_control ( $on=TRUE ) + { + $output = NULL; + if ( self::$ob_usage ) + { + // attempt to use outpout buffering + if ( $on ) + { + // start buffering if possible and not yet started before + if ( function_exists('ob_start') // output buffers installed at all ? + && ! self::$ob_active ) // don't stack buffers (create buffer only, if not yet started) + { + ob_implicit_flush ( FALSE ); + ob_start ( ); + self::$ob_active = TRUE; + } + } // if $on==TRUE + else + { + // end buffering _if_ it has been started before + if ( self::$ob_active ) + { + $output = ob_get_contents ( ); + ob_end_clean ( ); + self::$ob_active = FALSE; + } + } // if $on==FALSE + } // if ob_usage + return $output; + } // function ob_control + + /** + * @method OC_Shorty_Tools::db_escape + * @brief escape a value for incusion in db statements + * @param value (string) value to be escaped + * @returns (string) escaped string value + * @throws OC_Shorty_Exception in case of an unknown database engine + * @access public + * @author Christian Reiner + * @todo use mdb2::quote() / mdb2:.escape() instead ? + */ + static function db_escape ( $value ) + { + $type = OCP\Config::getSystemValue ( 'dbtype', 'sqlite' ); + switch ( $type ) + { + case 'sqlite': + case 'sqlite3': + return sqlite_escape_string ( $value ); + case 'pgsql': + return pg_escape_string ( $value ); + case 'mysql': + if (get_magic_quotes_gpc()) + return mysql_real_escape_string ( stripslashes($value) ); + else return mysql_real_escape_string ( $value ); + } + throw new OC_Shorty_Exception ( "unknown database backend type '%1'", array($type) ); + } // function db_escape + + /** + * @method OC_Shorty_Tools::db_timestamp + * @brief current timestamp as required by db engine + * @returns (string) current timestamp as required by db engine + * @throws OC_Shorty_Exception in case of an unknown database engine + * @access public + * @author Christian Reiner + * @todo not really required any more, we rely on CURRENT_TIMESTAMP instead + */ + static function db_timestamp ( ) + { + $type = OCP\Config::getSystemValue( "dbtype", "sqlite" ); + switch ( $type ) + { + case 'sqlite': + case 'sqlite3': return "strftime('%s','now')"; + case 'mysql': return 'UNIX_TIMESTAMP()'; + case 'pgsql': return "date_part('epoch',now())::integer"; + } + throw new OC_Shorty_Exception ( "unknown database backend type '%1'", array($type) ); + } // function db_timestamp + + /** + * @method OC_Shorty_Tools::shorty_id + * @brief Creates a unique id to be used for a new shorty entry + * @returns (string) valid and unique id + * @access public + * @author Christian Reiner + */ + static function shorty_id ( ) + { + // each shorty installation uses a (once self generated) 62 char alphabet + $alphabet=OCP\Config::getAppValue('shorty','id-alphabet'); + if ( empty($alphabet) ) + { + $alphabet = self::randomAlphabet(62); + OCP\Config::setAppValue ( 'shorty', 'id-alphabet', $alphabet ); + } + // use alphabet to generate a id being unique over time + return self::convertToAlphabet ( str_replace(array(' ','.'),'',microtime()), $alphabet ); + } // function shorty_id + + /** + * + */ + static function randomAlphabet ($length) + { + if ( ! is_integer($length) ) + return FALSE; + $c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxwz0123456789"; + for($l=0;$l<$length;$l++) $s .= $c{rand(0,strlen($c))}; + return str_shuffle($s); + } // function randomAlphabet + + /** + * @method OC_Shorty_Tools::convertToAlphabet + * @brief Converts a given decimal number into an arbitrary base (alphabet) + * @param number decimal value to be converted + * @returns (string) converted value in string notation + * @access public + * @author Christian Reiner + */ + static function convertToAlphabet ( $number, $alphabet ) + { + $alphabetLen = strlen($alphabet); + $decVal = (int) $number; + $number = FALSE; + $nslen = 0; + $pos = 1; + while ($decVal > 0) + { + $valPerChar = pow($alphabetLen, $pos); + $curChar = floor($decVal / $valPerChar); + if ($curChar >= $alphabetLen) + { + $pos++; + } else { + $decVal -= ($curChar * $valPerChar); + if ($number === FALSE) + { + $number = str_repeat($alphabet{1}, $pos); + $nslen = $pos; + } + $number = substr($number, 0, ($nslen - $pos)) . $alphabet{$curChar} . substr($number, (($nslen - $pos) + 1)); + $pos--; + } + } + if ($number === FALSE) $number = $alphabet{1}; + return $number; + } + + /** + * @method OC_Shorty_Tools::relayUrl + * @brief Generates a relay url for a given id acting as a href target for all backends + * @param id (string) shorty id as shorty identification + * @returns (string) generated absolute relay url + * @access public + * @author Christian Reiner + */ + static function relayUrl ($id) + { + return sprintf ( '%s?service=%s&id=%s', OCP\Util::linkToAbsolute("", "public.php"), 'shorty_relay', $id ); + } // function relayUrl + + /** + * @method OC_Shorty_Tools::countShortys + * @brief Returns the total number of entries and clicks from the database + * @returns (array) two elements sum_shortys & sum_clicks holding an integer each + * @access public + * @author Christian Reiner + */ + static function countShorties () + { + $param = array + ( + ':user' => OCP\User::getUser ( ), + ); + $query = OCP\DB::prepare ( OC_Shorty_Query::URL_COUNT ); + $result = $query->execute($param); + $reply = $result->fetchAll(); + return $reply[0]; + } // function countShorties + +} // class OC_Shorty_Tools +?> diff --git a/apps/shorty/lib/type.php b/apps/shorty/lib/type.php new file mode 100644 index 00000000000..97cbf04ddb4 --- /dev/null +++ b/apps/shorty/lib/type.php @@ -0,0 +1,291 @@ +<?php +/** +* @package shorty an ownCloud url shortener plugin +* @category internet +* @author Christian Reiner +* @copyright 2011-2012 Christian Reiner <foss@christian-reiner.info> +* @license GNU Affero General Public license (AGPL) +* @link information +* @link repository https://svn.christian-reiner.info/svn/app/oc/shorty +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the license, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. +* If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/** + * @file lib/type.php + * Type handling, recognition and verification routines + * @author Christian Reiner + */ + +/** + * @class OC_Shorty_Type + * @brief Static 'namespace' class offering routines and constants used to handle type recognition and value verification + * @access public + * @author Christian Reiner + */ +class OC_Shorty_Type +{ + // the 'types' of values we deal with, actually more something like flavours + const ID = 'id'; + const STATUS = 'status'; + const SORTKEY = 'sortkey'; + const SORTVAL = 'sortval'; + const STRING = 'string'; + const URL = 'url'; + const INTEGER = 'integer'; + const FLOAT = 'float'; + const DATE = 'date'; + const TIMESTAMP = 'timestamp'; + // a list of all valid list sorting codes + static $SORTING = array ( + '' =>'created DESC', // default + 'aa'=>'accessed', 'ad'=>'accessed DESC', + 'ca'=>'created', 'cd'=>'created DESC', + 'da'=>'until', 'dd'=>'until DESC', + 'ha'=>'clicks', 'hd'=>'clicks DESC', + 'ka'=>'id', 'kd'=>'id DESC', + 'sa'=>'status', 'sd'=>'status DESC', + 'ta'=>'title', 'td'=>'title DESC', + 'ua'=>'target', 'ud'=>'target DESC' ); + // a list of all valid user preferences + static $PREFERENCE = array ( + 'backend-type' => OC_Shorty_Type::STRING, + 'backend-static-base' => OC_Shorty_Type::URL, + 'backend-bitly-user' => OC_Shorty_Type::STRING, + 'backend-bitly-key' => OC_Shorty_Type::STRING, + 'backend-google-key' => OC_Shorty_Type::STRING, + 'backend-tinycc-user' => OC_Shorty_Type::STRING, + 'backend-tinycc-key' => OC_Shorty_Type::STRING, + 'sms-control' => OC_Shorty_Type::STRING, + 'list-sort-code' => OC_Shorty_Type::SORTKEY, + ); + // valid status for entries + static $STATUS = array ( + 'blocked', + 'private', + 'shared', + 'public', + 'deleted', + ); + // a list of implemented backends + static $BACKENDS = array ( + 'none' => ' [ none ] ', + 'static' => 'static backend', +// 'bitly' => 'bitly.com service', +// 'cligs' => 'cli.gs service', + 'isgd' => 'is.gd service', + 'google' => 'goo.gl service', +// 'tinycc' => 'tiny.cc service', + 'tinyurl' => 'ti.ny service', + ); + // a list of all valid system settings + static $SETTING = array ( + 'backend-static-base' => OC_Shorty_Type::URL, + ); + static $HTTPCODE = array ( + 200 => 'Ok', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => '(unused)', + 307 => 'Temporary Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + ); + + /** + * @method OC_Shorty_Type::validate + * @brief Validates a given value against a type specific regular expression + * Validates a given value according to the claimed type of the value. + * Validation is done by matching the value against a type specific regular expression. + * @param value the value to be verified according to the specified type + * @param type the type the value is said to belong to, important for verification + * @param strict flag indicating if the verification should be done strict, that is if an exception should be thrown in case of a failure + * @returns the value itself in case of a positive validation, NULL or an exception in case of a failure, depending on the flag indication strict mode + * @throws error indicating a failed validation in case of strict mode + * @access public + * @author Christian Reiner + */ + static function validate ( $value, $type, $strict=FALSE ) + { + switch ( $type ) + { + case self::ID: + if ( preg_match ( '/^[a-z0-9]{2,20}$/i', $value ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::STATUS: + if ( in_array($value,OC_Shorty_Type::$STATUS) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::SORTKEY: + if ( array_key_exists ( trim($value), self::$SORTING ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::SORTVAL: + if ( in_array ( trim($value), self::$SORTING ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::STRING: + if ( preg_match ( '/^.*$/x', str_replace("\n","\\n",$value) ) ) + return str_replace("\n","\\n",$value); + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::URL: +// $pattern = '/^([a-zA-Z][a-zA-Z][a-zA-Z0-9]+)\:\/\/([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(\/($|[a-zA-Z0-9\.\;\:\,\@\?\'\\\+&%\$#\=~_\-]+)?)*$/'; + $pattern = '/^([a-zA-Z][a-zA-Z][a-zA-Z0-9]+)\:\/\/([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(\/($|.+)?)*$/'; + if ( preg_match ( $pattern, $value ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::INTEGER: + if ( preg_match ( '/^[0-9]+$/', $value ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::FLOAT: + if ( preg_match ( '/^[0-9]+(\.[0-9]+)?$/', $value ) ) + return $value; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::TIMESTAMP: + if ( preg_match ( '/^[0-9]{10}$/', $value ) ) + return $value; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + case self::DATE: + if (FALSE!==($time=strtotime($value))) + return $time; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "invalid value '%s' for type '%s'", array( ((24<sizeof($value))?$value:substr($value,0,21).'…'),$type) ); + } // switch $type + throw new OC_Shorty_Exception ( "unknown request argument type '%s'", array($type) ); + } // function is_valid + + /** + * @method OC_Shorty_Type::normalize + * @brief cleanup and formal normalization of a given value according to its type + * Normalizes a given value according to its claimed type. + * This typically means trimming of string values, but sometimes also more specific actions. + * @param value the value to be normalized + * @param type the supposed type of the value + * @param strict boolean flag indicating if the normalization should be done in a strict way + * @returns the normalized value + * @throws error indicating a parameter violation + * @access public + * @author Christian Reiner + */ + static function normalize ( $value, $type, $strict=FALSE ) + { + if (NULL===(self::validate($value,$type,$strict))) + { + if ( ! $strict) + return NULL; + else + throw new OC_Shorty_Exception ( "invalid value '%1\$s' for type '%2\$s'", array($value,$type) ); + } // if + switch ( $type ) + { + case self::ID: return trim ( $value ); + case self::STATUS: return trim ( $value ); + case self::SORTKEY: return trim ( $value ); + case self::SORTVAL: return trim ( $value ); + case self::STRING: return trim ( $value ); + case self::URL: return trim ( $value ); + case self::INTEGER: return sprintf ( '%d', $value ); + case self::FLOAT: return sprintf ( '%f', $value ); + case self::TIMESTAMP: return trim ( $value ); + case self::DATE: return date ( 'Y-m-d', self::validate($value,OC_Shorty_Type::DATE) ); + } // switch $type + throw new OC_Shorty_Exception ( "unknown request argument type '%s'", array($type) ); + } // function normalize + + /** + * @method OC_Shorty_Type::req_argument + * @brief returns checked request argument or throws an error + * @param arg (string) name of the request argument to get_argument + * @param strict (bool) controls if an exception will be thrown upon a missing argument + * @returns (string) checked and prepared value of request argument + * @throws error indicating a parameter violation + * @access public + * @author Christian Reiner + */ + static function req_argument ( $arg, $type, $strict=FALSE ) + { + switch ( $_SERVER['REQUEST_METHOD'] ) + { + case 'POST': + if ( isset($_POST[$arg]) && !empty($_POST[$arg]) ) + return self::normalize ( urldecode($_POST[$arg]), $type ) ; + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "missing mandatory argument '%1s'", array($arg) ); + case 'GET': + if ( isset($_GET[$arg]) && !empty($_GET[$arg]) ) + return self::normalize ( urldecode(trim($_GET[$arg])), $type, $strict ); + elseif ( ! $strict) + return NULL; + throw new OC_Shorty_Exception ( "missing mandatory argument '%1s'", array($arg) ); + default: + throw new OC_Shorty_Exception ( "unexpected http request method '%1s'", array($_SERVER['REQUEST_METHOD']) ); + } + } // function req_argument + +} // class OC_Shorty_Query +?> |