app.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Frank Karlitschek
  6. * @author Jakob Sack
  7. * @copyright 2010 Frank Karlitschek karlitschek@kde.org
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  11. * License as published by the Free Software Foundation; either
  12. * version 3 of the License, or any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public
  20. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. /**
  24. * This class manages the apps. It allows them to register and integrate in the
  25. * owncloud ecosystem. Furthermore, this class is responsible for installing,
  26. * upgrading and removing apps.
  27. */
  28. class OC_App{
  29. static private $init = false;
  30. static private $apps = array();
  31. static private $activeapp = '';
  32. static private $navigation = array();
  33. static private $settingsForms = array();
  34. static private $adminForms = array();
  35. static private $personalForms = array();
  36. /**
  37. * @brief loads all apps
  38. * @returns true/false
  39. *
  40. * This function walks through the owncloud directory and loads all apps
  41. * it can find. A directory contains an app if the file /appinfo/app.php
  42. * exists.
  43. */
  44. public static function loadApps(){
  45. // Did we allready load everything?
  46. if( self::$init ){
  47. return true;
  48. }
  49. // Our very own core apps are hardcoded
  50. foreach( array('files', 'settings') as $app ){
  51. require( $app.'/appinfo/app.php' );
  52. }
  53. // The rest comes here
  54. $apps = OC_Appconfig::getApps();
  55. foreach( $apps as $app ){
  56. if( self::isEnabled( $app )){
  57. if(is_file(OC::$SERVERROOT.'/apps/'.$app.'/appinfo/app.php')){
  58. require( 'apps/'.$app.'/appinfo/app.php' );
  59. }
  60. }
  61. }
  62. self::$init = true;
  63. // return
  64. return true;
  65. }
  66. /**
  67. * @brief checks whether or not an app is enabled
  68. * @param $app app
  69. * @returns true/false
  70. *
  71. * This function checks whether or not an app is enabled.
  72. */
  73. public static function isEnabled( $app ){
  74. if( 'yes' == OC_Appconfig::getValue( $app, 'enabled' )){
  75. return true;
  76. }
  77. return false;
  78. }
  79. /**
  80. * @brief enables an app
  81. * @param $app app
  82. * @returns true/false
  83. *
  84. * This function set an app as enabled in appconfig.
  85. */
  86. public static function enable( $app ){
  87. if(!OC_Installer::isInstalled($app)){
  88. // check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string
  89. if(!is_numeric($app)){
  90. OC_Installer::installShippedApp($app);
  91. }else{
  92. $download=OC_OCSClient::getApplicationDownload($app,1);
  93. if(isset($download['downloadlink']) and $download['downloadlink']<>'') {
  94. $app=OC_Installer::installApp(array('source'=>'http','href'=>$download['downloadlink']));
  95. }
  96. }
  97. }
  98. OC_Appconfig::setValue( $app, 'enabled', 'yes' );
  99. }
  100. /**
  101. * @brief disables an app
  102. * @param $app app
  103. * @returns true/false
  104. *
  105. * This function set an app as disabled in appconfig.
  106. */
  107. public static function disable( $app ){
  108. // check if app is a shiped app or not. if not delete
  109. OC_Appconfig::setValue( $app, 'enabled', 'no' );
  110. }
  111. /**
  112. * @brief makes owncloud aware of this app
  113. * @param $data array with all information
  114. * @returns true/false
  115. *
  116. * This function registers the application. $data is an associative array.
  117. * The following keys are required:
  118. * - id: id of the application, has to be unique ('addressbook')
  119. * - name: Human readable name ('Addressbook')
  120. * - version: array with Version (major, minor, bugfix) ( array(1, 0, 2))
  121. *
  122. * The following keys are optional:
  123. * - order: integer, that influences the position of your application in
  124. * a list of applications. Lower values come first.
  125. *
  126. */
  127. public static function register( $data ){
  128. OC_App::$apps[] = $data;
  129. }
  130. /**
  131. * @brief returns information of all apps
  132. * @return array with all information
  133. *
  134. * This function returns all data it got via register().
  135. */
  136. public static function get(){
  137. return OC_App::$apps;
  138. }
  139. /**
  140. * @brief adds an entry to the navigation
  141. * @param $data array containing the data
  142. * @returns true/false
  143. *
  144. * This function adds a new entry to the navigation visible to users. $data
  145. * is an associative array.
  146. * The following keys are required:
  147. * - id: unique id for this entry ('addressbook_index')
  148. * - href: link to the page
  149. * - name: Human readable name ('Addressbook')
  150. *
  151. * The following keys are optional:
  152. * - icon: path to the icon of the app
  153. * - order: integer, that influences the position of your application in
  154. * the navigation. Lower values come first.
  155. */
  156. public static function addNavigationEntry( $data ){
  157. $data['active']=false;
  158. if(!isset($data['icon'])){
  159. $data['icon']='';
  160. }
  161. OC_App::$navigation[] = $data;
  162. return true;
  163. }
  164. /**
  165. * @brief marks a navigation entry as active
  166. * @param $id id of the entry
  167. * @returns true/false
  168. *
  169. * This function sets a navigation entry as active and removes the 'active'
  170. * property from all other entries. The templates can use this for
  171. * highlighting the current position of the user.
  172. */
  173. public static function setActiveNavigationEntry( $id ){
  174. self::$activeapp = $id;
  175. return true;
  176. }
  177. /**
  178. * @brief gets the active Menu entry
  179. * @returns id or empty string
  180. *
  181. * This function returns the id of the active navigation entry (set by
  182. * setActiveNavigationEntry
  183. */
  184. public static function getActiveNavigationEntry(){
  185. return self::$activeapp;
  186. }
  187. /**
  188. * @brief Returns the Settings Navigation
  189. * @returns associative array
  190. *
  191. * This function returns an array containing all settings pages added. The
  192. * entries are sorted by the key 'order' ascending.
  193. */
  194. public static function getSettingsNavigation(){
  195. $l=new OC_L10N('core');
  196. // by default, settings only contain the help menu
  197. $settings = array(
  198. array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "help.php" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" ))
  199. );
  200. // if the user is logged-in
  201. if (OC_User::isLoggedIn()) {
  202. // personal menu
  203. $settings[] = array( "id" => "personal", "order" => 1, "href" => OC_Helper::linkTo( "settings", "personal.php" ), "name" => $l->t("Personal"), "icon" => OC_Helper::imagePath( "settings", "personal.svg" ));
  204. // if there're some settings forms
  205. if(!empty(self::$settingsForms))
  206. // settings menu
  207. $settings[]=array( "id" => "settings", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "settings.php" ), "name" => $l->t("Settings"), "icon" => OC_Helper::imagePath( "settings", "settings.svg" ));
  208. // if the user is an admin
  209. if(OC_Group::inGroup( $_SESSION["user_id"], "admin" )) {
  210. // admin users menu
  211. $settings[] = array( "id" => "core_users", "order" => 2, "href" => OC_Helper::linkTo( "settings", "users.php" ), "name" => $l->t("Users"), "icon" => OC_Helper::imagePath( "settings", "users.svg" ));
  212. // admin apps menu
  213. $settings[] = array( "id" => "core_apps", "order" => 3, "href" => OC_Helper::linkTo( "settings", "apps.php?installed" ), "name" => $l->t("Apps"), "icon" => OC_Helper::imagePath( "settings", "apps.svg" ));
  214. // admin log menu
  215. $settings[] = array( "id" => "core_log", "order" => 4, "href" => OC_Helper::linkTo( "settings", "log.php" ), "name" => $l->t("Log"), "icon" => OC_Helper::imagePath( "settings", "log.svg" ));
  216. $settings[]=array( "id" => "admin", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "admin.php" ), "name" => $l->t("Admin"), "icon" => OC_Helper::imagePath( "settings", "admin.svg" ));
  217. }
  218. }
  219. $navigation = self::proceedNavigation($settings);
  220. return $navigation;
  221. }
  222. /// This is private as well. It simply works, so don't ask for more details
  223. private static function proceedNavigation( $list ){
  224. foreach( $list as &$naventry ){
  225. $naventry['subnavigation'] = array();
  226. if( $naventry['id'] == self::$activeapp ){
  227. $naventry['active'] = true;
  228. }
  229. else{
  230. $naventry['active'] = false;
  231. }
  232. } unset( $naventry );
  233. usort( $list, create_function( '$a, $b', 'if( $a["order"] == $b["order"] ){return 0;}elseif( $a["order"] < $b["order"] ){return -1;}else{return 1;}' ));
  234. return $list;
  235. }
  236. /**
  237. * @brief Read app metadata from the info.xml file
  238. * @param string $appid id of the app or the path of the info.xml file
  239. * @returns array
  240. */
  241. public static function getAppInfo($appid){
  242. if(is_file($appid)){
  243. $file=$appid;
  244. }else{
  245. $file=OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/info.xml';
  246. if(!is_file($file)){
  247. return array();
  248. }
  249. }
  250. $data=array();
  251. $content=file_get_contents($file);
  252. $xml = new SimpleXMLElement($content);
  253. $data['info']=array();
  254. foreach($xml->children() as $child){
  255. $data[$child->getName()]=(string)$child;
  256. }
  257. return $data;
  258. }
  259. /**
  260. * @brief Returns the navigation
  261. * @returns associative array
  262. *
  263. * This function returns an array containing all entries added. The
  264. * entries are sorted by the key 'order' ascending. Additional to the keys
  265. * given for each app the following keys exist:
  266. * - active: boolean, signals if the user is on this navigation entry
  267. * - children: array that is empty if the key 'active' is false or
  268. * contains the subentries if the key 'active' is true
  269. */
  270. public static function getNavigation(){
  271. $navigation = self::proceedNavigation( self::$navigation );
  272. return $navigation;
  273. }
  274. /**
  275. * get the id of loaded app
  276. * @return string
  277. */
  278. public static function getCurrentApp(){
  279. $script=substr($_SERVER["SCRIPT_NAME"],strlen(OC::$WEBROOT)+1);
  280. $topFolder=substr($script,0,strpos($script,'/'));
  281. if($topFolder=='apps'){
  282. $length=strlen($topFolder);
  283. return substr($script,$length+1,strpos($script,'/',$length+1)-$length-1);
  284. }else{
  285. return $topFolder;
  286. }
  287. }
  288. /**
  289. * get the forms for either settings, admin or personal
  290. */
  291. public static function getForms($type){
  292. $forms=array();
  293. switch($type){
  294. case 'settings':
  295. $source=self::$settingsForms;
  296. break;
  297. case 'admin':
  298. $source=self::$adminForms;
  299. break;
  300. case 'personal':
  301. $source=self::$personalForms;
  302. break;
  303. }
  304. foreach($source as $form){
  305. $forms[]=include $form;
  306. }
  307. return $forms;
  308. }
  309. /**
  310. * register a settings form to be shown
  311. */
  312. public static function registerSettings($app,$page){
  313. self::$settingsForms[]='apps/'.$app.'/'.$page.'.php';
  314. }
  315. /**
  316. * register an admin form to be shown
  317. */
  318. public static function registerAdmin($app,$page){
  319. self::$adminForms[]='apps/'.$app.'/'.$page.'.php';
  320. }
  321. /**
  322. * register a personal form to be shown
  323. */
  324. public static function registerPersonal($app,$page){
  325. self::$personalForms[]='apps/'.$app.'/'.$page.'.php';
  326. }
  327. /**
  328. * get a list of all apps in the apps folder
  329. */
  330. public static function getAllApps(){
  331. $apps=array();
  332. $dh=opendir(OC::$SERVERROOT.'/apps');
  333. while($file=readdir($dh)){
  334. if(is_file(OC::$SERVERROOT.'/apps/'.$file.'/appinfo/app.php')){
  335. $apps[]=$file;
  336. }
  337. }
  338. return $apps;
  339. }
  340. /**
  341. * check if any apps need updating and update those
  342. */
  343. public static function updateApps(){
  344. // The rest comes here
  345. $apps = OC_Appconfig::getApps();
  346. foreach( $apps as $app ){
  347. $installedVersion=OC_Appconfig::getValue($app,'installed_version');
  348. $appInfo=OC_App::getAppInfo($app);
  349. if (isset($appInfo['version'])) {
  350. $currentVersion=$appInfo['version'];
  351. if (version_compare($currentVersion, $installedVersion, '>')) {
  352. OC_App::updateApp($app);
  353. OC_Appconfig::setValue($app,'installed_version',$appInfo['version']);
  354. }
  355. }
  356. }
  357. }
  358. /**
  359. * update the database for the app and call the update script
  360. * @param string appid
  361. */
  362. public static function updateApp($appid){
  363. if(file_exists(OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/database.xml')){
  364. OC_DB::updateDbFromStructure(OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/database.xml');
  365. }
  366. if(file_exists(OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/update.php')){
  367. include OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/update.php';
  368. }
  369. }
  370. /**
  371. * @param string appid
  372. * @return OC_FilesystemView
  373. */
  374. public static function getStorage($appid){
  375. if(OC_App::isEnabled($appid)){//sanity check
  376. if(OC_User::isLoggedIn()){
  377. return new OC_FilesystemView('/'.OC_User::getUser().'/'.$appid);
  378. }else{
  379. OC_Log::write('core','Can\'t get app storage, app, user not logged in',OC_Log::ERROR);
  380. return false;
  381. }
  382. }else{
  383. OC_Log::write('core','Can\'t get app storage, app '.$appid.' not enabled',OC_Log::ERROR);
  384. false;
  385. }
  386. }
  387. }