diff options
-rw-r--r-- | .gitmodules | 3 | ||||
m--------- | 3rdparty/Symfony/Component/Routing | 0 | ||||
-rw-r--r-- | core/js/js.js | 4 | ||||
-rw-r--r-- | core/routes.php | 19 | ||||
-rw-r--r-- | lib/base.php | 53 | ||||
-rw-r--r-- | lib/helper.php | 4 | ||||
-rw-r--r-- | lib/ocs.php | 190 | ||||
-rw-r--r-- | lib/route.php | 67 | ||||
-rw-r--r-- | lib/router.php | 80 |
9 files changed, 337 insertions, 83 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000000..0f4ad588071 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "3rdparty/Symfony/Component/Routing"] + path = 3rdparty/Symfony/Component/Routing + url = git://github.com/symfony/Routing.git diff --git a/3rdparty/Symfony/Component/Routing b/3rdparty/Symfony/Component/Routing new file mode 160000 +Subproject d72483890880a987afa679503af096d2aaf7d2e diff --git a/core/js/js.js b/core/js/js.js index 92a2660fd9c..7a50b2e7b9d 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -54,9 +54,9 @@ OC={ var isCore=OC.coreApps.indexOf(app)!=-1; var link=OC.webroot; if((file.substring(file.length-3) == 'php' || file.substring(file.length-3) == 'css') && !isCore){ - link+='/?app=' + app; + link+='/index.php/apps/' + app; if (file != 'index.php') { - link+='&getfile='; + link+='/'; if(type){ link+=encodeURI(type + '/'); } diff --git a/core/routes.php b/core/routes.php new file mode 100644 index 00000000000..04b42d20598 --- /dev/null +++ b/core/routes.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +$this->create('app_css', '/apps/{app}/{file}') + ->requirements(array('file' => '.*.css')) + ->action('OC', 'loadCSSFile'); +$this->create('app_index_script', '/apps/{app}/') + ->defaults(array('file' => 'index.php')) + //->requirements(array('file' => '.*.php')) + ->action('OC', 'loadAppScriptFile'); +$this->create('app_script', '/apps/{app}/{file}') + ->defaults(array('file' => 'index.php')) + ->requirements(array('file' => '.*.php')) + ->action('OC', 'loadAppScriptFile'); diff --git a/lib/base.php b/lib/base.php index b4f3e667133..fb49e9e6706 100644 --- a/lib/base.php +++ b/lib/base.php @@ -66,6 +66,10 @@ class OC{ * check if owncloud runs in cli mode */ public static $CLI = false; + /* + * OC router + */ + protected static $router = null; /** * SPL autoload */ @@ -89,6 +93,9 @@ class OC{ elseif(strpos($className,'Sabre_')===0) { require_once str_replace('_','/',$className) . '.php'; } + elseif(strpos($className,'Symfony\\')===0){ + require_once str_replace('\\','/',$className) . '.php'; + } elseif(strpos($className,'Test_')===0){ require_once 'tests/lib/'.strtolower(str_replace('_','/',substr($className,5)) . '.php'); } @@ -251,6 +258,15 @@ class OC{ session_start(); } + public static function getRouter() { + if (!isset(OC::$router)) { + OC::$router = new OC_Router(); + OC::$router->loadRoutes(); + } + + return OC::$router; + } + public static function init(){ // register autoloader spl_autoload_register(array('OC','autoload')); @@ -406,26 +422,36 @@ class OC{ header('location: '.OC_Helper::linkToRemote('webdav')); return; } + try { + OC::getRouter()->match(OC_Request::getPathInfo()); + return; + } catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) { + //header('HTTP/1.0 404 Not Found'); + } catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) { + OC_Response::setStatus(405); + return; + } + $app = OC::$REQUESTEDAPP; + $file = OC::$REQUESTEDFILE; + $param = array('app' => $app, 'file' => $file); // Handle app css files - if(substr(OC::$REQUESTEDFILE,-3) == 'css') { - self::loadCSSFile(); + if(substr($file,-3) == 'css') { + self::loadCSSFile($param); return; } // Someone is logged in : if(OC_User::isLoggedIn()) { - OC_App::loadApps(); if(isset($_GET["logout"]) and ($_GET["logout"])) { + OC_App::loadApps(); OC_User::logout(); header("Location: ".OC::$WEBROOT.'/'); }else{ - $app = OC::$REQUESTEDAPP; - $file = OC::$REQUESTEDFILE; if(is_null($file)) { - $file = 'index.php'; + $param['file'] = 'index.php'; } - $file_ext = substr($file, -3); + $file_ext = substr($param['file'], -3); if ($file_ext != 'php' - || !self::loadAppScriptFile($app, $file)) { + || !self::loadAppScriptFile($param)) { header('HTTP/1.0 404 Not Found'); } } @@ -435,7 +461,10 @@ class OC{ self::handleLogin(); } - protected static function loadAppScriptFile($app, $file) { + public static function loadAppScriptFile($param) { + OC_App::loadApps(); + $app = $param['app']; + $file = $param['file']; $app_path = OC_App::getAppPath($app); $file = $app_path . '/' . $file; unset($app, $app_path); @@ -446,9 +475,9 @@ class OC{ return false; } - protected static function loadCSSFile() { - $app = OC::$REQUESTEDAPP; - $file = OC::$REQUESTEDFILE; + public static function loadCSSFile($param) { + $app = $param['app']; + $file = $param['file']; $app_path = OC_App::getAppPath($app); if (file_exists($app_path . '/' . $file)) { $app_web_path = OC_App::getAppWebPath($app); diff --git a/lib/helper.php b/lib/helper.php index 8c362747a27..3cdb3e53c22 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -42,8 +42,8 @@ class OC_Helper { // Check if the app is in the app folder if( $app_path && file_exists( $app_path.'/'.$file )){ if(substr($file, -3) == 'php' || substr($file, -3) == 'css'){ - $urlLinkTo = OC::$WEBROOT . '/?app=' . $app; - $urlLinkTo .= ($file!='index.php')?'&getfile=' . urlencode($file):''; + $urlLinkTo = OC::$WEBROOT . '/index.php/apps/' . $app; + $urlLinkTo .= ($file!='index.php') ? '/' . $file : ''; }else{ $urlLinkTo = OC_App::getAppWebPath($app) . '/' . $file; } diff --git a/lib/ocs.php b/lib/ocs.php index 3157aae99e6..1df08df9fa1 100644 --- a/lib/ocs.php +++ b/lib/ocs.php @@ -23,7 +23,8 @@ * */ - +use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Routing\Exception\MethodNotAllowedException; /** * Class to handle open collaboration services API requests @@ -92,91 +93,144 @@ class OC_OCS { exit(); } - // preprocess url - $url = strtolower($_SERVER['REQUEST_URI']); - if(substr($url,(strlen($url)-1))<>'/') $url.='/'; - $ex=explode('/',$url); - $paracount=count($ex); $format = self::readData($method, 'format', 'text', ''); - // eventhandler + $router = new OC_Router(); + $router->useCollection('root'); // CONFIG - // apiconfig - GET - CONFIG - if(($method=='get') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'config')){ - OC_OCS::apiconfig($format); + $router->create('config', '/config.{format}') + ->defaults(array('format' => $format)) + ->action('OC_OCS', 'apiConfig') + ->requirements(array('format'=>'xml|json')); // PERSON - // personcheck - POST - PERSON/CHECK - }elseif(($method=='post') and ($ex[$paracount-4] == 'v1.php') and ($ex[$paracount-3]=='person') and ($ex[$paracount-2] == 'check')){ - $login = self::readData($method, 'login', 'text'); - $passwd = self::readData($method, 'password', 'text'); - OC_OCS::personcheck($format,$login,$passwd); + $router->create('person_check', '/person/check.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $login = OC_OCS::readData('post', 'login', 'text'); + $passwd = OC_OCS::readData('post', 'password', 'text'); + OC_OCS::personCheck($format,$login,$passwd); + }) + ->requirements(array('format'=>'xml|json')); // ACTIVITY // activityget - GET ACTIVITY page,pagesize als urlparameter - }elseif(($method=='get') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'activity')){ - $page = self::readData($method, 'page', 'int', 0); - $pagesize = self::readData($method, 'pagesize','int', 10); - if($pagesize<1 or $pagesize>100) $pagesize=10; - OC_OCS::activityget($format,$page,$pagesize); - + $router->create('activity_get', '/activity.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $page = OC_OCS::readData('get', 'page', 'int', 0); + $pagesize = OC_OCS::readData('get', 'pagesize', 'int', 10); + if($pagesize<1 or $pagesize>100) $pagesize=10; + OC_OCS::activityGet($format, $page, $pagesize); + }) + ->requirements(array('format'=>'xml|json')); // activityput - POST ACTIVITY - }elseif(($method=='post') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'activity')){ - $message = self::readData($method, 'message', 'text'); - OC_OCS::activityput($format,$message); - + $router->create('activity_put', '/activity.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $message = OC_OCS::readData('post', 'message', 'text'); + OC_OCS::activityPut($format,$message); + }) + ->requirements(array('format'=>'xml|json')); // PRIVATEDATA // get - GET DATA - }elseif(($method=='get') and ($ex[$paracount-4] == 'v1.php') and ($ex[$paracount-2] == 'getattribute')){ - OC_OCS::privateDataGet($format); - - }elseif(($method=='get') and ($ex[$paracount-5] == 'v1.php') and ($ex[$paracount-3] == 'getattribute')){ - $app=$ex[$paracount-2]; - OC_OCS::privateDataGet($format, $app); - }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-4] == 'getattribute')){ - - $key=$ex[$paracount-2]; - $app=$ex[$paracount-3]; - OC_OCS::privateDataGet($format, $app,$key); - + $router->create('privatedata_get', + '/privatedata/getattribute/{app}/{key}.{format}') + ->defaults(array('app' => '', 'key' => '', 'format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $app = addslashes(strip_tags($parameters['app'])); + $key = addslashes(strip_tags($parameters['key'])); + OC_OCS::privateDataGet($format, $app, $key); + }) + ->requirements(array('format'=>'xml|json')); // set - POST DATA - }elseif(($method=='post') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-4] == 'setattribute')){ - $key=$ex[$paracount-2]; - $app=$ex[$paracount-3]; - $value = self::readData($method, 'value', 'text'); - OC_OCS::privatedataset($format, $app, $key, $value); + $router->create('privatedata_set', + '/privatedata/setattribute/{app}/{key}.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $app = addslashes(strip_tags($parameters['app'])); + $key = addslashes(strip_tags($parameters['key'])); + $value=OC_OCS::readData('post', 'value', 'text'); + OC_OCS::privateDataSet($format, $app, $key, $value); + }) + ->requirements(array('format'=>'xml|json')); // delete - POST DATA - }elseif(($method=='post') and ($ex[$paracount-6] =='v1.php') and ($ex[$paracount-4] == 'deleteattribute')){ - $key=$ex[$paracount-2]; - $app=$ex[$paracount-3]; - OC_OCS::privatedatadelete($format, $app, $key); + $router->create('privatedata_delete', + '/privatedata/deleteattribute/{app}/{key}.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $app = addslashes(strip_tags($parameters['app'])); + $key = addslashes(strip_tags($parameters['key'])); + OC_OCS::privateDataDelete($format, $app, $key); + }) + ->requirements(array('format'=>'xml|json')); // CLOUD // systemWebApps - }elseif(($method=='get') and ($ex[$paracount-5] == 'v1.php') and ($ex[$paracount-4]=='cloud') and ($ex[$paracount-3] == 'system') and ($ex[$paracount-2] == 'webapps')){ - OC_OCS::systemwebapps($format); + $router->create('system_webapps', + '/cloud/system/webapps.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + OC_OCS::systemwebapps($format); + }) + ->requirements(array('format'=>'xml|json')); // quotaget - }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'quota')){ - $user=$ex[$paracount-3]; - OC_OCS::quotaget($format,$user); - + $router->create('quota_get', + '/cloud/user/{user}.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $user = $parameters['user']; + OC_OCS::quotaGet($format, $user); + }) + ->requirements(array('format'=>'xml|json')); // quotaset - }elseif(($method=='post') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'quota')){ - $user=$ex[$paracount-3]; - $quota = self::readData('post', 'quota', 'int'); - OC_OCS::quotaset($format,$user,$quota); + $router->create('quota_set', + '/cloud/user/{user}.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $user = $parameters['user']; + $quota = self::readData('post', 'quota', 'int'); + OC_OCS::quotaSet($format, $user, $quota); + }) + ->requirements(array('format'=>'xml|json')); // keygetpublic - }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'publickey')){ - $user=$ex[$paracount-3]; - OC_OCS::publicKeyGet($format,$user); + $router->create('keygetpublic', + '/cloud/user/{user}/publickey.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $user = $parameters['user']; + OC_OCS::publicKeyGet($format,$user); + }) + ->requirements(array('format'=>'xml|json')); // keygetprivate - }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'privatekey')){ - $user=$ex[$paracount-3]; - OC_OCS::privateKeyGet($format,$user); + $router->create('keygetpublic', + '/cloud/user/{user}/privatekey.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $user = $parameters['user']; + OC_OCS::privateKeyGet($format,$user); + }) + ->requirements(array('format'=>'xml|json')); // add more calls here @@ -190,13 +244,14 @@ class OC_OCS { // sharing // versioning // news (rss) - - - - }else{ + try { + $router->match($_SERVER['PATH_INFO']); + } catch (ResourceNotFoundException $e) { $txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n"; $txt.=OC_OCS::getdebugoutput(); echo(OC_OCS::generatexml($format,'failed',999,$txt)); + } catch (MethodNotAllowedException $e) { + OC_Response::setStatus(405); } exit(); } @@ -381,7 +436,8 @@ class OC_OCS { * @param string $format * @return string xml/json */ - private static function apiConfig($format) { + public static function apiConfig($parameters) { + $format = $parameters['format']; $user=OC_OCS::checkpassword(false); $url=substr(OCP\Util::getServerHost().$_SERVER['SCRIPT_NAME'],0,-11).''; diff --git a/lib/route.php b/lib/route.php new file mode 100644 index 00000000000..772446e5615 --- /dev/null +++ b/lib/route.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +use Symfony\Component\Routing\Route; + +class OC_Route extends Route { + public function method($method) { + $this->setRequirement('_method', strtoupper($method)); + return $this; + } + + public function post() { + $this->method('POST'); + return $this; + } + + public function get() { + $this->method('GET'); + return $this; + } + + public function put() { + $this->method('PUT'); + return $this; + } + + public function delete() { + $this->method('DELETE'); + return $this; + } + + public function defaults($defaults) { + $action = $this->getDefault('action'); + $this->setDefaults($defaults); + if (isset($defaults['action'])) { + $action = $defaults['action']; + } + $this->action($action); + return $this; + } + + public function requirements($requirements) { + $method = $this->getRequirement('_method'); + $this->setRequirements($requirements); + if (isset($requirements['_method'])) { + $method = $requirements['_method']; + } + if ($method) { + $this->method($method); + } + return $this; + } + + public function action($class, $function = null) { + $action = array($class, $function); + if (is_null($function)) { + $action = $class; + } + $this->setDefault('action', $action); + return $this; + } +} diff --git a/lib/router.php b/lib/router.php new file mode 100644 index 00000000000..65fc51aff2c --- /dev/null +++ b/lib/router.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +use Symfony\Component\Routing\Matcher\UrlMatcher; +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\RouteCollection; +//use Symfony\Component\Routing\Route; + +class OC_Router { + protected $collections = array(); + protected $collection = null; + protected $root = null; + + public function __construct() { + // TODO cache + $this->root = $this->getCollection('root'); + } + + /** + * loads the api routes + */ + public function loadRoutes() { + foreach(OC_APP::getEnabledApps() as $app){ + $file = OC_App::getAppPath($app).'/appinfo/routes.php'; + if(file_exists($file)){ + $this->useCollection($app); + require_once($file); + $collection = $this->getCollection($app); + $this->root->addCollection($collection, '/apps/'.$app); + } + } + $this->useCollection('root'); + require_once('core/routes.php'); + } + + protected function getCollection($name) { + if (!isset($this->collections[$name])) { + $this->collections[$name] = new RouteCollection(); + } + return $this->collections[$name]; + } + + public function useCollection($name) { + $this->collection = $this->getCollection($name); + } + + public function create($name, $pattern, array $defaults = array(), array $requirements = array()) { + $route = new OC_Route($pattern, $defaults, $requirements); + $this->collection->add($name, $route); + return $route; + } + + public function match($url) { + $baseUrl = OC_Helper::linkTo('', 'index.php'); + $method = $_SERVER['REQUEST_METHOD']; + $host = OC_Request::serverHost(); + $schema = OC_Request::serverProtocol(); + $context = new RequestContext($baseUrl, $method, $host, $schema); + $matcher = new UrlMatcher($this->root, $context); + $parameters = $matcher->match($url); + if (isset($parameters['action'])) { + $action = $parameters['action']; + if (!is_callable($action)) { + var_dump($action); + throw new Exception('not a callable action'); + } + unset($parameters['action']); + call_user_func($action, $parameters); + } elseif (isset($parameters['file'])) { + include ($parameters['file']); + } else { + throw new Exception('no action available'); + } + } +} |