ocs.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Frank Karlitschek
  6. * @copyright 2012 Frank Karlitschek frank@owncloud.org
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. /**
  23. * Class to handle open collaboration services API requests
  24. *
  25. */
  26. class OC_OCS {
  27. /**
  28. * reads input date from get/post/cookies and converts the date to a special data-type
  29. *
  30. * @param variable $key
  31. * @param variable-type $type
  32. * @param priority $getpriority
  33. * @param default $default
  34. * @return data
  35. */
  36. public static function readData($key,$type='raw',$getpriority=false,$default='') {
  37. if($getpriority) {
  38. if(isset($_GET[$key])) {
  39. $data=$_GET[$key];
  40. } elseif(isset($_POST[$key])) {
  41. $data=$_POST[$key];
  42. } else {
  43. if($default=='') {
  44. if(($type=='int') or ($type=='float')) $data=0; else $data='';
  45. } else {
  46. $data=$default;
  47. }
  48. }
  49. } else {
  50. if(isset($_POST[$key])) {
  51. $data=$_POST[$key];
  52. } elseif(isset($_GET[$key])) {
  53. $data=$_GET[$key];
  54. } elseif(isset($_COOKIE[$key])) {
  55. $data=$_COOKIE[$key];
  56. } else {
  57. if($default=='') {
  58. if(($type=='int') or ($type=='float')) $data=0; else $data='';
  59. } else {
  60. $data=$default;
  61. }
  62. }
  63. }
  64. if($type=='raw') return($data);
  65. elseif($type=='text') return(addslashes(strip_tags($data)));
  66. elseif($type=='int') { $data = (int) $data; return($data); }
  67. elseif($type=='float') { $data = (float) $data; return($data); }
  68. elseif($type=='array') { $data = $data; return($data); }
  69. }
  70. /**
  71. main function to handle the REST request
  72. **/
  73. public static function handle() {
  74. // overwrite the 404 error page returncode
  75. header("HTTP/1.0 200 OK");
  76. if($_SERVER['REQUEST_METHOD'] == 'GET') {
  77. $method='get';
  78. }elseif($_SERVER['REQUEST_METHOD'] == 'PUT') {
  79. $method='put';
  80. parse_str(file_get_contents("php://input"),$put_vars);
  81. }elseif($_SERVER['REQUEST_METHOD'] == 'POST') {
  82. $method='post';
  83. }else{
  84. echo('internal server error: method not supported');
  85. exit();
  86. }
  87. // preprocess url
  88. $url=$_SERVER['REQUEST_URI'];
  89. if(substr($url,(strlen($url)-1))<>'/') $url.='/';
  90. $ex=explode('/',$url);
  91. $paracount=count($ex);
  92. // eventhandler
  93. // CONFIG
  94. // apiconfig - GET - CONFIG
  95. if(($method=='get') and (strtolower($ex[$paracount-3])=='v1.php') and (strtolower($ex[$paracount-2])=='config')){
  96. $format=OC_OCS::readdata('format','text');
  97. OC_OCS::apiconfig($format);
  98. // PERSON
  99. // personcheck - POST - PERSON/CHECK
  100. }elseif(($method=='post') and (strtolower($ex[$paracount-4])=='v1.php') and (strtolower($ex[$paracount-3])=='person') and (strtolower($ex[$paracount-2])=='check')){
  101. $format=OC_OCS::readdata('format','text');
  102. $login=OC_OCS::readdata('login','text');
  103. $passwd=OC_OCS::readdata('password','text');
  104. OC_OCS::personcheck($format,$login,$passwd);
  105. // ACTIVITY
  106. // activityget - GET ACTIVITY page,pagesize als urlparameter
  107. }elseif(($method=='get') and (strtolower($ex[$paracount-3])=='v1.php')and (strtolower($ex[$paracount-2])=='activity')){
  108. $format=OC_OCS::readdata('format','text');
  109. $page=OC_OCS::readdata('page','int');
  110. $pagesize=OC_OCS::readdata('pagesize','int');
  111. if($pagesize<1 or $pagesize>100) $pagesize=10;
  112. OC_OCS::activityget($format,$page,$pagesize);
  113. // activityput - POST ACTIVITY
  114. }elseif(($method=='post') and (strtolower($ex[$paracount-3])=='v1.php')and (strtolower($ex[$paracount-2])=='activity')){
  115. $format=OC_OCS::readdata('format','text');
  116. $message=OC_OCS::readdata('message','text');
  117. OC_OCS::activityput($format,$message);
  118. // PRIVATEDATA
  119. // get - GET DATA
  120. }elseif(($method=='get') and (strtolower($ex[$paracount-4])=='v1.php')and (strtolower($ex[$paracount-2])=='getattribute')){
  121. $format=OC_OCS::readdata('format','text');
  122. OC_OCS::privateDataGet($format);
  123. }elseif(($method=='get') and (strtolower($ex[$paracount-5])=='v1.php')and (strtolower($ex[$paracount-3])=='getattribute')){
  124. $format=OC_OCS::readdata('format','text');
  125. $app=$ex[$paracount-2];
  126. OC_OCS::privateDataGet($format, $app);
  127. }elseif(($method=='get') and (strtolower($ex[$paracount-6])=='v1.php')and (strtolower($ex[$paracount-4])=='getattribute')){
  128. $format=OC_OCS::readdata('format','text');
  129. $key=$ex[$paracount-2];
  130. $app=$ex[$paracount-3];
  131. OC_OCS::privateDataGet($format, $app,$key);
  132. // set - POST DATA
  133. }elseif(($method=='post') and (strtolower($ex[$paracount-6])=='v1.php')and (strtolower($ex[$paracount-4])=='setattribute')){
  134. $format=OC_OCS::readdata('format','text');
  135. $key=$ex[$paracount-2];
  136. $app=$ex[$paracount-3];
  137. $value=OC_OCS::readdata('value','text');
  138. OC_OCS::privatedataset($format, $app, $key, $value);
  139. // delete - POST DATA
  140. }elseif(($method=='post') and (strtolower($ex[$paracount-6])=='v1.php')and (strtolower($ex[$paracount-4])=='deleteattribute')){
  141. $format=OC_OCS::readdata('format','text');
  142. $key=$ex[$paracount-2];
  143. $app=$ex[$paracount-3];
  144. OC_OCS::privatedatadelete($format, $app, $key);
  145. }else{
  146. $format=OC_OCS::readdata('format','text');
  147. $txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
  148. $txt.=OC_OCS::getdebugoutput();
  149. echo(OC_OCS::generatexml($format,'failed',999,$txt));
  150. }
  151. exit();
  152. }
  153. /**
  154. * generated some debug information to make it easier to find faild API calls
  155. * @return debug data string
  156. */
  157. private static function getDebugOutput() {
  158. $txt='';
  159. $txt.="debug output:\n";
  160. if(isset($_SERVER['REQUEST_METHOD'])) $txt.='http request method: '.$_SERVER['REQUEST_METHOD']."\n";
  161. if(isset($_SERVER['REQUEST_URI'])) $txt.='http request uri: '.$_SERVER['REQUEST_URI']."\n";
  162. if(isset($_GET)) foreach($_GET as $key=>$value) $txt.='get parameter: '.$key.'->'.$value."\n";
  163. if(isset($_POST)) foreach($_POST as $key=>$value) $txt.='post parameter: '.$key.'->'.$value."\n";
  164. return($txt);
  165. }
  166. /**
  167. * checks if the user is authenticated
  168. * checks the IP whitlist, apikeys and login/password combination
  169. * if $forceuser is true and the authentication failed it returns an 401 http response.
  170. * if $forceuser is false and authentification fails it returns an empty username string
  171. * @param bool $forceuser
  172. * @return username string
  173. */
  174. private static function checkPassword($forceuser=true) {
  175. //valid user account ?
  176. if(isset($_SERVER['PHP_AUTH_USER'])) $authuser=$_SERVER['PHP_AUTH_USER']; else $authuser='';
  177. if(isset($_SERVER['PHP_AUTH_PW'])) $authpw=$_SERVER['PHP_AUTH_PW']; else $authpw='';
  178. if(empty($authuser)) {
  179. if($forceuser){
  180. header('WWW-Authenticate: Basic realm="your valid user account or api key"');
  181. header('HTTP/1.0 401 Unauthorized');
  182. exit;
  183. }else{
  184. $identifieduser='';
  185. }
  186. }else{
  187. if(!OC_User::login($authuser,$authpw)){
  188. if($forceuser){
  189. header('WWW-Authenticate: Basic realm="your valid user account or api key"');
  190. header('HTTP/1.0 401 Unauthorized');
  191. exit;
  192. }else{
  193. $identifieduser='';
  194. }
  195. }else{
  196. $identifieduser=$authuser;
  197. }
  198. }
  199. return($identifieduser);
  200. }
  201. /**
  202. * generates the xml or json response for the API call from an multidimenional data array.
  203. * @param string $format
  204. * @param string $status
  205. * @param string $statuscode
  206. * @param string $message
  207. * @param array $data
  208. * @param string $tag
  209. * @param string $tagattribute
  210. * @param int $dimension
  211. * @param int $itemscount
  212. * @param int $itemsperpage
  213. * @return string xml/json
  214. */
  215. private static function generateXml($format,$status,$statuscode,$message,$data=array(),$tag='',$tagattribute='',$dimension=-1,$itemscount='',$itemsperpage='') {
  216. if($format=='json') {
  217. $json=array();
  218. $json['status']=$status;
  219. $json['statuscode']=$statuscode;
  220. $json['message']=$message;
  221. $json['totalitems']=$itemscount;
  222. $json['itemsperpage']=$itemsperpage;
  223. $json['data']=$data;
  224. return(json_encode($json));
  225. }else{
  226. $txt='';
  227. $writer = xmlwriter_open_memory();
  228. xmlwriter_set_indent( $writer, 2 );
  229. xmlwriter_start_document($writer );
  230. xmlwriter_start_element($writer,'ocs');
  231. xmlwriter_start_element($writer,'meta');
  232. xmlwriter_write_element($writer,'status',$status);
  233. xmlwriter_write_element($writer,'statuscode',$statuscode);
  234. xmlwriter_write_element($writer,'message',$message);
  235. if($itemscount<>'') xmlwriter_write_element($writer,'totalitems',$itemscount);
  236. if(!empty($itemsperpage)) xmlwriter_write_element($writer,'itemsperpage',$itemsperpage);
  237. xmlwriter_end_element($writer);
  238. if($dimension=='0') {
  239. // 0 dimensions
  240. xmlwriter_write_element($writer,'data',$data);
  241. }elseif($dimension=='1') {
  242. xmlwriter_start_element($writer,'data');
  243. foreach($data as $key=>$entry) {
  244. xmlwriter_write_element($writer,$key,$entry);
  245. }
  246. xmlwriter_end_element($writer);
  247. }elseif($dimension=='2') {
  248. xmlwriter_start_element($writer,'data');
  249. foreach($data as $entry) {
  250. xmlwriter_start_element($writer,$tag);
  251. if(!empty($tagattribute)) {
  252. xmlwriter_write_attribute($writer,'details',$tagattribute);
  253. }
  254. foreach($entry as $key=>$value) {
  255. if(is_array($value)){
  256. foreach($value as $k=>$v) {
  257. xmlwriter_write_element($writer,$k,$v);
  258. }
  259. } else {
  260. xmlwriter_write_element($writer,$key,$value);
  261. }
  262. }
  263. xmlwriter_end_element($writer);
  264. }
  265. xmlwriter_end_element($writer);
  266. }elseif($dimension=='3') {
  267. xmlwriter_start_element($writer,'data');
  268. foreach($data as $entrykey=>$entry) {
  269. xmlwriter_start_element($writer,$tag);
  270. if(!empty($tagattribute)) {
  271. xmlwriter_write_attribute($writer,'details',$tagattribute);
  272. }
  273. foreach($entry as $key=>$value) {
  274. if(is_array($value)){
  275. xmlwriter_start_element($writer,$entrykey);
  276. foreach($value as $k=>$v) {
  277. xmlwriter_write_element($writer,$k,$v);
  278. }
  279. xmlwriter_end_element($writer);
  280. } else {
  281. xmlwriter_write_element($writer,$key,$value);
  282. }
  283. }
  284. xmlwriter_end_element($writer);
  285. }
  286. xmlwriter_end_element($writer);
  287. }elseif($dimension=='dynamic') {
  288. xmlwriter_start_element($writer,'data');
  289. OC_OCS::toxml($writer,$data,'comment');
  290. xmlwriter_end_element($writer);
  291. }
  292. xmlwriter_end_element($writer);
  293. xmlwriter_end_document( $writer );
  294. $txt.=xmlwriter_output_memory( $writer );
  295. unset($writer);
  296. return($txt);
  297. }
  298. }
  299. public static function toXml($writer,$data,$node) {
  300. foreach($data as $key => $value) {
  301. if (is_numeric($key)) {
  302. $key = $node;
  303. }
  304. if (is_array($value)){
  305. xmlwriter_start_element($writer,$key);
  306. OC_OCS::toxml($writer,$value,$node);
  307. xmlwriter_end_element($writer);
  308. }else{
  309. xmlwriter_write_element($writer,$key,$value);
  310. }
  311. }
  312. }
  313. /**
  314. * return the config data of this server
  315. * @param string $format
  316. * @return string xml/json
  317. */
  318. private static function apiConfig($format) {
  319. $user=OC_OCS::checkpassword(false);
  320. $url=substr(OCP\Util::getServerHost().$_SERVER['SCRIPT_NAME'],0,-11).'';
  321. $xml['version']='1.5';
  322. $xml['website']='ownCloud';
  323. $xml['host']=OCP\Util::getServerHost();
  324. $xml['contact']='';
  325. $xml['ssl']='false';
  326. echo(OC_OCS::generatexml($format,'ok',100,'',$xml,'config','',1));
  327. }
  328. /**
  329. * check if the provided login/apikey/password is valid
  330. * @param string $format
  331. * @param string $login
  332. * @param string $passwd
  333. * @return string xml/json
  334. */
  335. private static function personCheck($format,$login,$passwd) {
  336. if($login<>''){
  337. if(OC_User::login($login,$passwd)){
  338. $xml['person']['personid']=$login;
  339. echo(OC_OCS::generatexml($format,'ok',100,'',$xml,'person','check',2));
  340. }else{
  341. echo(OC_OCS::generatexml($format,'failed',102,'login not valid'));
  342. }
  343. }else{
  344. echo(OC_OCS::generatexml($format,'failed',101,'please specify all mandatory fields'));
  345. }
  346. }
  347. // ACTIVITY API #############################################
  348. /**
  349. * get my activities
  350. * @param string $format
  351. * @param string $page
  352. * @param string $pagesize
  353. * @return string xml/json
  354. */
  355. private static function activityGet($format,$page,$pagesize) {
  356. $user=OC_OCS::checkpassword();
  357. //TODO
  358. $txt=OC_OCS::generatexml($format,'ok',100,'',$xml,'activity','full',2,$totalcount,$pagesize);
  359. echo($txt);
  360. }
  361. /**
  362. * submit a activity
  363. * @param string $format
  364. * @param string $message
  365. * @return string xml/json
  366. */
  367. private static function activityPut($format,$message) {
  368. // not implemented in ownCloud
  369. $user=OC_OCS::checkpassword();
  370. echo(OC_OCS::generatexml($format,'ok',100,''));
  371. }
  372. // PRIVATEDATA API #############################################
  373. /**
  374. * get private data and create the xml for ocs
  375. * @param string $format
  376. * @param string $app
  377. * @param string $key
  378. * @return string xml/json
  379. */
  380. private static function privateDataGet($format,$app="",$key="") {
  381. $user=OC_OCS::checkpassword();
  382. $result=OC_OCS::getData($user,$app,$key);
  383. $xml=array();
  384. foreach($result as $i=>$log) {
  385. $xml[$i]['key']=$log['key'];
  386. $xml[$i]['app']=$log['app'];
  387. $xml[$i]['value']=$log['value'];
  388. }
  389. $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
  390. echo($txt);
  391. }
  392. /**
  393. * set private data referenced by $key to $value and generate the xml for ocs
  394. * @param string $format
  395. * @param string $app
  396. * @param string $key
  397. * @param string $value
  398. * @return string xml/json
  399. */
  400. private static function privateDataSet($format, $app, $key, $value) {
  401. $user=OC_OCS::checkpassword();
  402. if(OC_OCS::setData($user,$app,$key,$value)){
  403. echo(OC_OCS::generatexml($format,'ok',100,''));
  404. }
  405. }
  406. /**
  407. * delete private data referenced by $key and generate the xml for ocs
  408. * @param string $format
  409. * @param string $app
  410. * @param string $key
  411. * @return string xml/json
  412. */
  413. private static function privateDataDelete($format, $app, $key) {
  414. if($key=="" or $app==""){
  415. return; //key and app are NOT optional here
  416. }
  417. $user=OC_OCS::checkpassword();
  418. if(OC_OCS::deleteData($user,$app,$key)){
  419. echo(OC_OCS::generatexml($format,'ok',100,''));
  420. }
  421. }
  422. /**
  423. * get private data
  424. * @param string $user
  425. * @param string $app
  426. * @param string $key
  427. * @param bool $like use LIKE instead of = when comparing keys
  428. * @return array
  429. */
  430. public static function getData($user,$app="",$key="") {
  431. if($app){
  432. $apps=array($app);
  433. }else{
  434. $apps=OC_Preferences::getApps($user);
  435. }
  436. if($key){
  437. $keys=array($key);
  438. }else{
  439. foreach($apps as $app){
  440. $keys=OC_Preferences::getKeys($user,$app);
  441. }
  442. }
  443. $result=array();
  444. foreach($apps as $app){
  445. foreach($keys as $key){
  446. $value=OC_Preferences::getValue($user,$app,$key);
  447. $result[]=array('app'=>$app,'key'=>$key,'value'=>$value);
  448. }
  449. }
  450. return $result;
  451. }
  452. /**
  453. * set private data referenced by $key to $value
  454. * @param string $user
  455. * @param string $app
  456. * @param string $key
  457. * @param string $value
  458. * @return bool
  459. */
  460. public static function setData($user, $app, $key, $value) {
  461. return OC_Preferences::setValue($user,$app,$key,$value);
  462. }
  463. /**
  464. * delete private data referenced by $key
  465. * @param string $user
  466. * @param string $app
  467. * @param string $key
  468. * @return string xml/json
  469. */
  470. public static function deleteData($user, $app, $key) {
  471. return OC_Preferences::deleteKey($user,$app,$key);
  472. }
  473. }