2010-04-14 14:58:52 +00:00
< ? php
/**
* ownCloud
*
2010-05-16 21:13:42 +00:00
* @ author Frank Karlitschek
2012-07-23 16:34:21 +00:00
* @ author Michael Gapczynski
2012-05-26 17:14:24 +00:00
* @ copyright 2012 Frank Karlitschek frank @ owncloud . org
2012-07-23 16:34:21 +00:00
* @ copyright 2012 Michael Gapczynski mtgap @ owncloud . com
2010-05-16 21:13:42 +00:00
*
2010-04-14 14:58:52 +00:00
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
2010-05-16 21:13:42 +00:00
* License as published by the Free Software Foundation ; either
2010-04-14 14:58:52 +00:00
* version 3 of the License , or any later version .
2010-05-16 21:13:42 +00:00
*
2010-04-14 14:58:52 +00:00
* 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 .
2010-05-16 21:13:42 +00:00
*
2011-02-09 14:50:27 +00:00
* You should have received a copy of the GNU Affero General Public
2010-04-14 14:58:52 +00:00
* License along with this library . If not , see < http :// www . gnu . org / licenses />.
2010-05-16 21:13:42 +00:00
*
2010-04-14 14:58:52 +00:00
*/
/**
* Class to handle open collaboration services API requests
*
*/
class OC_OCS {
2012-07-23 16:34:21 +00:00
/**
* reads input date from get / post / cookies and converts the date to a special data - type
*
* @ param string HTTP method to read the key from
* @ param string Parameter to read
* @ param string Variable type to format data
* @ param mixed Default value to return if the key is not found
* @ return mixed Data or if the key is not found and no default is set it will exit with a 400 Bad request
*/
public static function readData ( $method , $key , $type = 'raw' , $default = null ) {
if ( $method == 'get' ) {
if ( isset ( $_GET [ $key ])) {
$data = $_GET [ $key ];
} else if ( isset ( $default )) {
return $default ;
} else {
$data = false ;
}
} else if ( $method == 'post' ) {
if ( isset ( $_POST [ $key ])) {
$data = $_POST [ $key ];
} else if ( isset ( $default )) {
return $default ;
} else {
$data = false ;
}
}
if ( $data === false ) {
echo self :: generateXml ( '' , 'fail' , 400 , 'Bad request. Please provide a valid ' . $key );
exit ();
} else {
// NOTE: Is the raw type necessary? It might be a little risky without sanitization
if ( $type == 'raw' ) return $data ;
elseif ( $type == 'text' ) return OC_Util :: sanitizeHTML ( $data );
elseif ( $type == 'int' ) return ( int ) $data ;
elseif ( $type == 'float' ) return ( float ) $data ;
elseif ( $type == 'array' ) return OC_Util :: sanitizeHTML ( $data );
else return OC_Util :: sanitizeHTML ( $data );
}
}
/**
main function to handle the REST request
**/
public static function handle () {
// overwrite the 404 error page returncode
header ( " HTTP/1.0 200 OK " );
if ( $_SERVER [ 'REQUEST_METHOD' ] == 'GET' ) {
$method = 'get' ;
} elseif ( $_SERVER [ 'REQUEST_METHOD' ] == 'PUT' ) {
$method = 'put' ;
parse_str ( file_get_contents ( " php://input " ), $put_vars );
} elseif ( $_SERVER [ 'REQUEST_METHOD' ] == 'POST' ) {
$method = 'post' ;
} else {
echo ( 'internal server error: method not supported' );
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
// CONFIG
// apiconfig - GET - CONFIG
if (( $method == 'get' ) and ( $ex [ $paracount - 3 ] == 'v1.php' ) and ( $ex [ $paracount - 2 ] == 'config' )){
OC_OCS :: apiconfig ( $format );
// 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 );
// 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 );
// 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 );
// 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 );
2012-07-23 22:39:59 +00:00
} elseif (( $method == 'get' ) and ( $ex [ $paracount - 6 ] == 'v1.php' ) and ( $ex [ $paracount - 4 ] == 'getattribute' )){
2012-07-23 16:34:21 +00:00
$key = $ex [ $paracount - 2 ];
$app = $ex [ $paracount - 3 ];
OC_OCS :: privateDataGet ( $format , $app , $key );
// 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 );
// 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 );
// CLOUD
2012-07-23 17:43:28 +00:00
// 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 );
// 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 );
2012-07-23 16:34:21 +00:00
// add more calls here
// please document all the call in the draft spec
// http://www.freedesktop.org/wiki/Specifications/open-collaboration-services-1.7#CLOUD
2012-07-23 17:43:28 +00:00
// TODO:
// users
// groups
// bookmarks
// sharing
// versioning
// news (rss)
2012-07-23 16:34:21 +00:00
} else {
$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 ));
}
exit ();
}
/**
* generated some debug information to make it easier to find faild API calls
* @ return debug data string
*/
private static function getDebugOutput () {
$txt = '' ;
$txt .= " debug output: \n " ;
if ( isset ( $_SERVER [ 'REQUEST_METHOD' ])) $txt .= 'http request method: ' . $_SERVER [ 'REQUEST_METHOD' ] . " \n " ;
if ( isset ( $_SERVER [ 'REQUEST_URI' ])) $txt .= 'http request uri: ' . $_SERVER [ 'REQUEST_URI' ] . " \n " ;
if ( isset ( $_GET )) foreach ( $_GET as $key => $value ) $txt .= 'get parameter: ' . $key . '->' . $value . " \n " ;
if ( isset ( $_POST )) foreach ( $_POST as $key => $value ) $txt .= 'post parameter: ' . $key . '->' . $value . " \n " ;
return ( $txt );
}
/**
* checks if the user is authenticated
* checks the IP whitlist , apikeys and login / password combination
* if $forceuser is true and the authentication failed it returns an 401 http response .
* if $forceuser is false and authentification fails it returns an empty username string
* @ param bool $forceuser
* @ return username string
*/
private static function checkPassword ( $forceuser = true ) {
//valid user account ?
if ( isset ( $_SERVER [ 'PHP_AUTH_USER' ])) $authuser = $_SERVER [ 'PHP_AUTH_USER' ]; else $authuser = '' ;
if ( isset ( $_SERVER [ 'PHP_AUTH_PW' ])) $authpw = $_SERVER [ 'PHP_AUTH_PW' ]; else $authpw = '' ;
if ( empty ( $authuser )) {
if ( $forceuser ){
header ( 'WWW-Authenticate: Basic realm="your valid user account or api key"' );
header ( 'HTTP/1.0 401 Unauthorized' );
exit ;
} else {
$identifieduser = '' ;
}
} else {
if ( ! OC_User :: login ( $authuser , $authpw )){
if ( $forceuser ){
header ( 'WWW-Authenticate: Basic realm="your valid user account or api key"' );
header ( 'HTTP/1.0 401 Unauthorized' );
exit ;
} else {
$identifieduser = '' ;
}
} else {
$identifieduser = $authuser ;
}
}
return ( $identifieduser );
}
/**
* generates the xml or json response for the API call from an multidimenional data array .
* @ param string $format
* @ param string $status
* @ param string $statuscode
* @ param string $message
* @ param array $data
* @ param string $tag
* @ param string $tagattribute
* @ param int $dimension
* @ param int $itemscount
* @ param int $itemsperpage
* @ return string xml / json
*/
private static function generateXml ( $format , $status , $statuscode , $message , $data = array (), $tag = '' , $tagattribute = '' , $dimension =- 1 , $itemscount = '' , $itemsperpage = '' ) {
if ( $format == 'json' ) {
$json = array ();
$json [ 'status' ] = $status ;
$json [ 'statuscode' ] = $statuscode ;
$json [ 'message' ] = $message ;
$json [ 'totalitems' ] = $itemscount ;
$json [ 'itemsperpage' ] = $itemsperpage ;
$json [ 'data' ] = $data ;
return ( json_encode ( $json ));
} else {
$txt = '' ;
$writer = xmlwriter_open_memory ();
xmlwriter_set_indent ( $writer , 2 );
xmlwriter_start_document ( $writer );
xmlwriter_start_element ( $writer , 'ocs' );
xmlwriter_start_element ( $writer , 'meta' );
xmlwriter_write_element ( $writer , 'status' , $status );
xmlwriter_write_element ( $writer , 'statuscode' , $statuscode );
xmlwriter_write_element ( $writer , 'message' , $message );
if ( $itemscount <> '' ) xmlwriter_write_element ( $writer , 'totalitems' , $itemscount );
if ( ! empty ( $itemsperpage )) xmlwriter_write_element ( $writer , 'itemsperpage' , $itemsperpage );
xmlwriter_end_element ( $writer );
if ( $dimension == '0' ) {
// 0 dimensions
xmlwriter_write_element ( $writer , 'data' , $data );
} elseif ( $dimension == '1' ) {
xmlwriter_start_element ( $writer , 'data' );
foreach ( $data as $key => $entry ) {
xmlwriter_write_element ( $writer , $key , $entry );
}
xmlwriter_end_element ( $writer );
} elseif ( $dimension == '2' ) {
xmlwriter_start_element ( $writer , 'data' );
foreach ( $data as $entry ) {
xmlwriter_start_element ( $writer , $tag );
if ( ! empty ( $tagattribute )) {
xmlwriter_write_attribute ( $writer , 'details' , $tagattribute );
}
foreach ( $entry as $key => $value ) {
if ( is_array ( $value )){
foreach ( $value as $k => $v ) {
xmlwriter_write_element ( $writer , $k , $v );
}
} else {
xmlwriter_write_element ( $writer , $key , $value );
}
}
xmlwriter_end_element ( $writer );
}
xmlwriter_end_element ( $writer );
} elseif ( $dimension == '3' ) {
xmlwriter_start_element ( $writer , 'data' );
foreach ( $data as $entrykey => $entry ) {
xmlwriter_start_element ( $writer , $tag );
if ( ! empty ( $tagattribute )) {
xmlwriter_write_attribute ( $writer , 'details' , $tagattribute );
}
foreach ( $entry as $key => $value ) {
if ( is_array ( $value )){
xmlwriter_start_element ( $writer , $entrykey );
foreach ( $value as $k => $v ) {
xmlwriter_write_element ( $writer , $k , $v );
}
xmlwriter_end_element ( $writer );
} else {
xmlwriter_write_element ( $writer , $key , $value );
}
}
xmlwriter_end_element ( $writer );
}
xmlwriter_end_element ( $writer );
} elseif ( $dimension == 'dynamic' ) {
xmlwriter_start_element ( $writer , 'data' );
OC_OCS :: toxml ( $writer , $data , 'comment' );
xmlwriter_end_element ( $writer );
}
xmlwriter_end_element ( $writer );
xmlwriter_end_document ( $writer );
$txt .= xmlwriter_output_memory ( $writer );
unset ( $writer );
return ( $txt );
}
}
public static function toXml ( $writer , $data , $node ) {
foreach ( $data as $key => $value ) {
if ( is_numeric ( $key )) {
$key = $node ;
}
if ( is_array ( $value )){
xmlwriter_start_element ( $writer , $key );
OC_OCS :: toxml ( $writer , $value , $node );
xmlwriter_end_element ( $writer );
} else {
xmlwriter_write_element ( $writer , $key , $value );
}
}
}
/**
* return the config data of this server
* @ param string $format
* @ return string xml / json
*/
private static function apiConfig ( $format ) {
$user = OC_OCS :: checkpassword ( false );
$url = substr ( OCP\Util :: getServerHost () . $_SERVER [ 'SCRIPT_NAME' ], 0 , - 11 ) . '' ;
$xml [ 'version' ] = '1.7' ;
$xml [ 'website' ] = 'ownCloud' ;
$xml [ 'host' ] = OCP\Util :: getServerHost ();
$xml [ 'contact' ] = '' ;
$xml [ 'ssl' ] = 'false' ;
echo ( OC_OCS :: generatexml ( $format , 'ok' , 100 , '' , $xml , 'config' , '' , 1 ));
}
/**
* check if the provided login / apikey / password is valid
* @ param string $format
* @ param string $login
* @ param string $passwd
* @ return string xml / json
*/
private static function personCheck ( $format , $login , $passwd ) {
if ( $login <> '' ){
if ( OC_User :: login ( $login , $passwd )){
$xml [ 'person' ][ 'personid' ] = $login ;
echo ( OC_OCS :: generatexml ( $format , 'ok' , 100 , '' , $xml , 'person' , 'check' , 2 ));
} else {
echo ( OC_OCS :: generatexml ( $format , 'failed' , 102 , 'login not valid' ));
}
} else {
echo ( OC_OCS :: generatexml ( $format , 'failed' , 101 , 'please specify all mandatory fields' ));
}
}
// ACTIVITY API #############################################
/**
* get my activities
* @ param string $format
* @ param string $page
* @ param string $pagesize
* @ return string xml / json
*/
private static function activityGet ( $format , $page , $pagesize ) {
$user = OC_OCS :: checkpassword ();
//TODO
$txt = OC_OCS :: generatexml ( $format , 'ok' , 100 , '' , $xml , 'activity' , 'full' , 2 , $totalcount , $pagesize );
echo ( $txt );
}
/**
* submit a activity
* @ param string $format
* @ param string $message
* @ return string xml / json
*/
private static function activityPut ( $format , $message ) {
// not implemented in ownCloud
$user = OC_OCS :: checkpassword ();
echo ( OC_OCS :: generatexml ( $format , 'ok' , 100 , '' ));
}
// PRIVATEDATA API #############################################
/**
* get private data and create the xml for ocs
* @ param string $format
* @ param string $app
* @ param string $key
* @ return string xml / json
*/
private static function privateDataGet ( $format , $app = " " , $key = " " ) {
$user = OC_OCS :: checkpassword ();
$result = OC_OCS :: getData ( $user , $app , $key );
$xml = array ();
foreach ( $result as $i => $log ) {
$xml [ $i ][ 'key' ] = $log [ 'key' ];
$xml [ $i ][ 'app' ] = $log [ 'app' ];
$xml [ $i ][ 'value' ] = $log [ 'value' ];
}
$txt = OC_OCS :: generatexml ( $format , 'ok' , 100 , '' , $xml , 'privatedata' , 'full' , 2 , count ( $xml ), 0 ); //TODO: replace 'privatedata' with 'attribute' once a new libattice has been released that works with it
echo ( $txt );
}
/**
* set private data referenced by $key to $value and generate the xml for ocs
* @ param string $format
* @ param string $app
* @ param string $key
* @ param string $value
* @ return string xml / json
*/
2011-01-23 02:23:03 +00:00
private static function privateDataSet ( $format , $app , $key , $value ) {
2011-02-06 00:22:48 +00:00
$user = OC_OCS :: checkpassword ();
if ( OC_OCS :: setData ( $user , $app , $key , $value )){
echo ( OC_OCS :: generatexml ( $format , 'ok' , 100 , '' ));
}
}
/**
* delete private data referenced by $key and generate the xml for ocs
* @ param string $format
* @ param string $app
* @ param string $key
* @ return string xml / json
*/
private static function privateDataDelete ( $format , $app , $key ) {
if ( $key == " " or $app == " " ){
return ; //key and app are NOT optional here
}
$user = OC_OCS :: checkpassword ();
if ( OC_OCS :: deleteData ( $user , $app , $key )){
echo ( OC_OCS :: generatexml ( $format , 'ok' , 100 , '' ));
}
}
/**
* get private data
* @ param string $user
* @ param string $app
* @ param string $key
2011-03-16 17:18:45 +00:00
* @ param bool $like use LIKE instead of = when comparing keys
2011-02-06 00:22:48 +00:00
* @ return array
*/
2011-07-28 18:23:58 +00:00
public static function getData ( $user , $app = " " , $key = " " ) {
2011-02-06 00:22:48 +00:00
if ( $app ){
2011-07-28 18:23:58 +00:00
$apps = array ( $app );
} else {
2011-07-29 19:36:03 +00:00
$apps = OC_Preferences :: getApps ( $user );
2011-07-28 18:23:58 +00:00
}
if ( $key ){
$keys = array ( $key );
2011-02-06 00:22:48 +00:00
} else {
2011-07-28 18:23:58 +00:00
foreach ( $apps as $app ){
2011-07-29 19:36:03 +00:00
$keys = OC_Preferences :: getKeys ( $user , $app );
2011-07-28 18:23:58 +00:00
}
}
$result = array ();
foreach ( $apps as $app ){
foreach ( $keys as $key ){
2011-07-29 19:36:03 +00:00
$value = OC_Preferences :: getValue ( $user , $app , $key );
2011-07-28 18:23:58 +00:00
$result [] = array ( 'app' => $app , 'key' => $key , 'value' => $value );
2011-02-06 00:22:48 +00:00
}
}
return $result ;
}
/**
* set private data referenced by $key to $value
* @ param string $user
* @ param string $app
* @ param string $key
* @ param string $value
* @ return bool
*/
public static function setData ( $user , $app , $key , $value ) {
2011-07-29 19:36:03 +00:00
return OC_Preferences :: setValue ( $user , $app , $key , $value );
2011-01-23 02:23:03 +00:00
}
2010-04-14 14:58:52 +00:00
2011-02-06 00:22:48 +00:00
/**
* delete private data referenced by $key
* @ param string $user
* @ param string $app
* @ param string $key
* @ return string xml / json
*/
public static function deleteData ( $user , $app , $key ) {
2011-07-29 19:36:03 +00:00
return OC_Preferences :: deleteKey ( $user , $app , $key );
2011-03-16 17:18:45 +00:00
}
2012-07-23 16:34:21 +00:00
// CLOUD API #############################################
/**
2012-07-23 17:43:28 +00:00
* get the quota of a user
2012-07-23 16:34:21 +00:00
* @ param string $format
2012-07-23 17:43:28 +00:00
* @ param string $user
2012-07-23 16:34:21 +00:00
* @ return string xml / json
*/
2012-07-23 17:43:28 +00:00
private static function quotaGet ( $format , $user ) {
$login = OC_OCS :: checkpassword ();
if ( OC_Group :: inGroup ( $login , 'admin' ) or ( $login == $user )) {
if ( OC_User :: userExists ( $user )){
// calculate the disc space
$user_dir = '/' . $user . '/files' ;
OC_Filesystem :: init ( $user_dir );
$rootInfo = OC_FileCache :: get ( '' );
$sharedInfo = OC_FileCache :: get ( '/Shared' );
$used = $rootInfo [ 'size' ] - $sharedInfo [ 'size' ];
$free = OC_Filesystem :: free_space ();
$total = $free + $used ;
if ( $total == 0 ) $total = 1 ; // prevent division by zero
$relative = round (( $used / $total ) * 10000 ) / 100 ;
$xml = array ();
$xml [ 'quota' ] = $total ;
$xml [ 'free' ] = $free ;
$xml [ 'used' ] = $used ;
$xml [ 'relative' ] = $relative ;
$txt = OC_OCS :: generatexml ( $format , 'ok' , 100 , '' , $xml , 'cloud' , 'full' , 1 , count ( $xml ), 0 );
echo ( $txt );
} else {
echo self :: generateXml ( '' , 'fail' , 300 , 'User does not exist' );
}
} else {
echo self :: generateXml ( '' , 'fail' , 300 , 'You don´ t have permission to access this ressource.' );
}
2012-07-23 16:34:21 +00:00
}
2012-07-23 17:43:28 +00:00
/**
* set the quota of a user
* @ param string $format
* @ param string $user
* @ param string $quota
* @ return string xml / json
*/
private static function quotaSet ( $format , $user , $quota ) {
$login = OC_OCS :: checkpassword ();
if ( OC_Group :: inGroup ( $login , 'admin' )) {
// todo
// not yet implemented
// edit logic here
error_log ( 'OCS call: user:' . $user . ' quota:' . $quota );
$xml = array ();
$txt = OC_OCS :: generatexml ( $format , 'ok' , 100 , '' , $xml , 'cloud' , 'full' , 1 , count ( $xml ), 0 );
echo ( $txt );
} else {
echo self :: generateXml ( '' , 'fail' , 300 , 'You don´ t have permission to access this ressource.' );
}
}
2012-07-23 16:34:21 +00:00
2011-02-06 00:22:48 +00:00
}