util.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. <?php
  2. /**
  3. * Class for utility functions
  4. *
  5. */
  6. class OC_Util {
  7. public static $scripts=array();
  8. public static $styles=array();
  9. public static $headers=array();
  10. private static $rootMounted=false;
  11. private static $fsSetup=false;
  12. public static $core_styles=array();
  13. public static $core_scripts=array();
  14. // Can be set up
  15. public static function setupFS( $user = '' ) {// configure the initial filesystem based on the configuration
  16. if(self::$fsSetup) {//setting up the filesystem twice can only lead to trouble
  17. return false;
  18. }
  19. // If we are not forced to load a specific user we load the one that is logged in
  20. if( $user == "" && OC_User::isLoggedIn()) {
  21. $user = OC_User::getUser();
  22. }
  23. // the filesystem will finish when $user is not empty,
  24. // mark fs setup here to avoid doing the setup from loading
  25. // OC_Filesystem
  26. if ($user != '') {
  27. self::$fsSetup=true;
  28. }
  29. $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
  30. //first set up the local "root" storage
  31. if(!self::$rootMounted) {
  32. OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY),'/');
  33. self::$rootMounted=true;
  34. }
  35. if( $user != "" ) { //if we aren't logged in, there is no use to set up the filesystem
  36. $user_dir = '/'.$user.'/files';
  37. $user_root = OC_User::getHome($user);
  38. $userdirectory = $user_root . '/files';
  39. if( !is_dir( $userdirectory )) {
  40. mkdir( $userdirectory, 0755, true );
  41. }
  42. //jail the user into his "home" directory
  43. OC_Filesystem::mount('OC_Filestorage_Local', array('datadir' => $user_root), $user);
  44. OC_Filesystem::init($user_dir);
  45. $quotaProxy=new OC_FileProxy_Quota();
  46. OC_FileProxy::register($quotaProxy);
  47. // Load personal mount config
  48. if (is_file($user_root.'/mount.php')) {
  49. $mountConfig = include($user_root.'/mount.php');
  50. if (isset($mountConfig['user'][$user])) {
  51. foreach ($mountConfig['user'][$user] as $mountPoint => $options) {
  52. OC_Filesystem::mount($options['class'], $options['options'], $mountPoint);
  53. }
  54. }
  55. $mtime=filemtime($user_root.'/mount.php');
  56. $previousMTime=OC_Preferences::getValue($user,'files','mountconfigmtime',0);
  57. if($mtime>$previousMTime) {//mount config has changed, filecache needs to be updated
  58. OC_FileCache::clear($user);
  59. OC_Preferences::setValue($user,'files','mountconfigmtime',$mtime);
  60. }
  61. }
  62. OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $user_dir));
  63. }
  64. }
  65. public static function tearDownFS() {
  66. OC_Filesystem::tearDown();
  67. self::$fsSetup=false;
  68. }
  69. /**
  70. * get the current installed version of ownCloud
  71. * @return array
  72. */
  73. public static function getVersion() {
  74. // hint: We only can count up. So the internal version number of ownCloud 4.5 will be 4,9,0. This is not visible to the user
  75. return array(4,85,11);
  76. }
  77. /**
  78. * get the current installed version string of ownCloud
  79. * @return string
  80. */
  81. public static function getVersionString() {
  82. return '4.5 RC 1';
  83. }
  84. /**
  85. * get the current installed edition of ownCloud. There is the community edition that just returns an empty string and the enterprise edition that returns "Enterprise".
  86. * @return string
  87. */
  88. public static function getEditionString() {
  89. return '';
  90. }
  91. /**
  92. * add a javascript file
  93. *
  94. * @param appid $application
  95. * @param filename $file
  96. */
  97. public static function addScript( $application, $file = null ) {
  98. if( is_null( $file )) {
  99. $file = $application;
  100. $application = "";
  101. }
  102. if( !empty( $application )) {
  103. self::$scripts[] = "$application/js/$file";
  104. }else{
  105. self::$scripts[] = "js/$file";
  106. }
  107. }
  108. /**
  109. * add a css file
  110. *
  111. * @param appid $application
  112. * @param filename $file
  113. */
  114. public static function addStyle( $application, $file = null ) {
  115. if( is_null( $file )) {
  116. $file = $application;
  117. $application = "";
  118. }
  119. if( !empty( $application )) {
  120. self::$styles[] = "$application/css/$file";
  121. }else{
  122. self::$styles[] = "css/$file";
  123. }
  124. }
  125. /**
  126. * @brief Add a custom element to the header
  127. * @param string tag tag name of the element
  128. * @param array $attributes array of attributes for the element
  129. * @param string $text the text content for the element
  130. */
  131. public static function addHeader( $tag, $attributes, $text='') {
  132. self::$headers[]=array('tag'=>$tag,'attributes'=>$attributes,'text'=>$text);
  133. }
  134. /**
  135. * formats a timestamp in the "right" way
  136. *
  137. * @param int timestamp $timestamp
  138. * @param bool dateOnly option to ommit time from the result
  139. */
  140. public static function formatDate( $timestamp,$dateOnly=false) {
  141. if(isset($_SESSION['timezone'])) {//adjust to clients timezone if we know it
  142. $systemTimeZone = intval(date('O'));
  143. $systemTimeZone=(round($systemTimeZone/100,0)*60)+($systemTimeZone%100);
  144. $clientTimeZone=$_SESSION['timezone']*60;
  145. $offset=$clientTimeZone-$systemTimeZone;
  146. $timestamp=$timestamp+$offset*60;
  147. }
  148. $timeformat=$dateOnly?'F j, Y':'F j, Y, H:i';
  149. return date($timeformat,$timestamp);
  150. }
  151. /**
  152. * Shows a pagenavi widget where you can jump to different pages.
  153. *
  154. * @param int $pagecount
  155. * @param int $page
  156. * @param string $url
  157. * @return OC_Template
  158. */
  159. public static function getPageNavi($pagecount,$page,$url) {
  160. $pagelinkcount=8;
  161. if ($pagecount>1) {
  162. $pagestart=$page-$pagelinkcount;
  163. if($pagestart<0) $pagestart=0;
  164. $pagestop=$page+$pagelinkcount;
  165. if($pagestop>$pagecount) $pagestop=$pagecount;
  166. $tmpl = new OC_Template( '', 'part.pagenavi', '' );
  167. $tmpl->assign('page',$page);
  168. $tmpl->assign('pagecount',$pagecount);
  169. $tmpl->assign('pagestart',$pagestart);
  170. $tmpl->assign('pagestop',$pagestop);
  171. $tmpl->assign('url',$url);
  172. return $tmpl;
  173. }
  174. }
  175. /**
  176. * check if the current server configuration is suitable for ownCloud
  177. * @return array arrays with error messages and hints
  178. */
  179. public static function checkServer() {
  180. $errors=array();
  181. $web_server_restart= false;
  182. //check for database drivers
  183. if(!(is_callable('sqlite_open') or class_exists('SQLite3')) and !is_callable('mysql_connect') and !is_callable('pg_connect')) {
  184. $errors[]=array('error'=>'No database drivers (sqlite, mysql, or postgresql) installed.<br/>','hint'=>'');//TODO: sane hint
  185. $web_server_restart= true;
  186. }
  187. //common hint for all file permissons error messages
  188. $permissionsHint="Permissions can usually be fixed by giving the webserver write access to the ownCloud directory";
  189. // Check if config folder is writable.
  190. if(!is_writable(OC::$SERVERROOT."/config/") or !is_readable(OC::$SERVERROOT."/config/")) {
  191. $errors[]=array('error'=>"Can't write into config directory 'config'",'hint'=>"You can usually fix this by giving the webserver user write access to the config directory in owncloud");
  192. }
  193. // Check if there is a writable install folder.
  194. if(OC_Config::getValue('appstoreenabled', true)) {
  195. if( OC_App::getInstallPath() === null || !is_writable(OC_App::getInstallPath()) || !is_readable(OC_App::getInstallPath()) ) {
  196. $errors[]=array('error'=>"Can't write into apps directory",'hint'=>"You can usually fix this by giving the webserver user write access to the apps directory
  197. in owncloud or disabling the appstore in the config file.");
  198. }
  199. }
  200. $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
  201. //check for correct file permissions
  202. if(!stristr(PHP_OS, 'WIN')) {
  203. $permissionsModHint="Please change the permissions to 0770 so that the directory cannot be listed by other users.";
  204. $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)),-3);
  205. if(substr($prems,-1)!='0') {
  206. OC_Helper::chmodr($CONFIG_DATADIRECTORY,0770);
  207. clearstatcache();
  208. $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)),-3);
  209. if(substr($prems,2,1)!='0') {
  210. $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') is readable for other users<br/>','hint'=>$permissionsModHint);
  211. }
  212. }
  213. if( OC_Config::getValue( "enablebackup", false )) {
  214. $CONFIG_BACKUPDIRECTORY = OC_Config::getValue( "backupdirectory", OC::$SERVERROOT."/backup" );
  215. $prems=substr(decoct(@fileperms($CONFIG_BACKUPDIRECTORY)),-3);
  216. if(substr($prems,-1)!='0') {
  217. OC_Helper::chmodr($CONFIG_BACKUPDIRECTORY,0770);
  218. clearstatcache();
  219. $prems=substr(decoct(@fileperms($CONFIG_BACKUPDIRECTORY)),-3);
  220. if(substr($prems,2,1)!='0') {
  221. $errors[]=array('error'=>'Data directory ('.$CONFIG_BACKUPDIRECTORY.') is readable for other users<br/>','hint'=>$permissionsModHint);
  222. }
  223. }
  224. }
  225. }else{
  226. //TODO: permissions checks for windows hosts
  227. }
  228. // Create root dir.
  229. if(!is_dir($CONFIG_DATADIRECTORY)) {
  230. $success=@mkdir($CONFIG_DATADIRECTORY);
  231. if(!$success) {
  232. $errors[]=array('error'=>"Can't create data directory (".$CONFIG_DATADIRECTORY.")",'hint'=>"You can usually fix this by giving the webserver write access to the ownCloud directory '".OC::$SERVERROOT."' (in a terminal, use the command 'chown -R www-data:www-data /path/to/your/owncloud/install/data' ");
  233. }
  234. } else if(!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
  235. $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud<br/>','hint'=>$permissionsHint);
  236. }
  237. // check if all required php modules are present
  238. if(!class_exists('ZipArchive')) {
  239. $errors[]=array('error'=>'PHP module zip not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
  240. $web_server_restart= false;
  241. }
  242. if(!function_exists('mb_detect_encoding')) {
  243. $errors[]=array('error'=>'PHP module mb multibyte not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
  244. $web_server_restart= false;
  245. }
  246. if(!function_exists('ctype_digit')) {
  247. $errors[]=array('error'=>'PHP module ctype is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
  248. $web_server_restart= false;
  249. }
  250. if(!function_exists('json_encode')) {
  251. $errors[]=array('error'=>'PHP module JSON is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
  252. $web_server_restart= false;
  253. }
  254. if(!function_exists('imagepng')) {
  255. $errors[]=array('error'=>'PHP module GD is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
  256. $web_server_restart= false;
  257. }
  258. if(!function_exists('gzencode')) {
  259. $errors[]=array('error'=>'PHP module zlib is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
  260. $web_server_restart= false;
  261. }
  262. if(floatval(phpversion())<5.3) {
  263. $errors[]=array('error'=>'PHP 5.3 is required.<br/>','hint'=>'Please ask your server administrator to update PHP to version 5.3 or higher. PHP 5.2 is no longer supported by ownCloud and the PHP community.');
  264. $web_server_restart= false;
  265. }
  266. if(!defined('PDO::ATTR_DRIVER_NAME')) {
  267. $errors[]=array('error'=>'PHP PDO module is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
  268. $web_server_restart= false;
  269. }
  270. if($web_server_restart) {
  271. $errors[]=array('error'=>'PHP modules have been installed, but they are still listed as missing?<br/>','hint'=>'Please ask your server administrator to restart the web server.');
  272. }
  273. return $errors;
  274. }
  275. public static function displayLoginPage($display_lostpassword) {
  276. $parameters = array();
  277. $parameters['display_lostpassword'] = $display_lostpassword;
  278. if (!empty($_POST['user'])) {
  279. $parameters["username"] =
  280. OC_Util::sanitizeHTML($_POST['user']).'"';
  281. $parameters['user_autofocus'] = false;
  282. } else {
  283. $parameters["username"] = '';
  284. $parameters['user_autofocus'] = true;
  285. }
  286. $sectoken=rand(1000000,9999999);
  287. $_SESSION['sectoken']=$sectoken;
  288. $parameters["sectoken"] = $sectoken;
  289. if (isset($_REQUEST['redirect_url'])) {
  290. $redirect_url = OC_Util::sanitizeHTML($_REQUEST['redirect_url']);
  291. } else {
  292. $redirect_url = $_SERVER['REQUEST_URI'];
  293. }
  294. $parameters['redirect_url'] = $redirect_url;
  295. OC_Template::printGuestPage("", "login", $parameters);
  296. }
  297. /**
  298. * Check if the app is enabled, redirects to home if not
  299. */
  300. public static function checkAppEnabled($app) {
  301. if( !OC_App::isEnabled($app)) {
  302. header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' ));
  303. exit();
  304. }
  305. }
  306. /**
  307. * Check if the user is logged in, redirects to home if not. With
  308. * redirect URL parameter to the request URI.
  309. */
  310. public static function checkLoggedIn() {
  311. // Check if we are a user
  312. if( !OC_User::isLoggedIn()) {
  313. header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php', array('redirect_url' => urlencode($_SERVER["REQUEST_URI"]))));
  314. exit();
  315. }
  316. }
  317. /**
  318. * Check if the user is a admin, redirects to home if not
  319. */
  320. public static function checkAdminUser() {
  321. // Check if we are a user
  322. self::checkLoggedIn();
  323. if( !OC_Group::inGroup( OC_User::getUser(), 'admin' )) {
  324. header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' ));
  325. exit();
  326. }
  327. }
  328. /**
  329. * Check if the user is a subadmin, redirects to home if not
  330. * @return array $groups where the current user is subadmin
  331. */
  332. public static function checkSubAdminUser() {
  333. // Check if we are a user
  334. self::checkLoggedIn();
  335. if(OC_Group::inGroup(OC_User::getUser(),'admin')) {
  336. return true;
  337. }
  338. if(!OC_SubAdmin::isSubAdmin(OC_User::getUser())) {
  339. header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' ));
  340. exit();
  341. }
  342. return true;
  343. }
  344. /**
  345. * Redirect to the user default page
  346. */
  347. public static function redirectToDefaultPage() {
  348. if(isset($_REQUEST['redirect_url']) && (substr($_REQUEST['redirect_url'], 0, strlen(OC::$WEBROOT)) == OC::$WEBROOT || $_REQUEST['redirect_url'][0] == '/')) {
  349. $location = $_REQUEST['redirect_url'];
  350. }
  351. else if (isset(OC::$REQUESTEDAPP) && !empty(OC::$REQUESTEDAPP)) {
  352. $location = OC_Helper::linkToAbsolute( OC::$REQUESTEDAPP, 'index.php' );
  353. }
  354. else {
  355. $defaultpage = OC_Appconfig::getValue('core', 'defaultpage');
  356. if ($defaultpage) {
  357. $location = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/'.$defaultpage);
  358. }
  359. else {
  360. $location = OC_Helper::linkToAbsolute( 'files', 'index.php' );
  361. }
  362. }
  363. OC_Log::write('core', 'redirectToDefaultPage: '.$location, OC_Log::DEBUG);
  364. header( 'Location: '.$location );
  365. exit();
  366. }
  367. /**
  368. * get an id unqiue for this instance
  369. * @return string
  370. */
  371. public static function getInstanceId() {
  372. $id=OC_Config::getValue('instanceid',null);
  373. if(is_null($id)) {
  374. $id=uniqid();
  375. OC_Config::setValue('instanceid',$id);
  376. }
  377. return $id;
  378. }
  379. /**
  380. * @brief Register an get/post call. This is important to prevent CSRF attacks
  381. * Todo: Write howto
  382. * @return $token Generated token.
  383. */
  384. public static function callRegister() {
  385. //mamimum time before token exires
  386. $maxtime=(60*60); // 1 hour
  387. // generate a random token.
  388. $token=mt_rand(1000,9000).mt_rand(1000,9000).mt_rand(1000,9000);
  389. // store the token together with a timestamp in the session.
  390. $_SESSION['requesttoken-'.$token]=time();
  391. // cleanup old tokens garbage collector
  392. // only run every 20th time so we don't waste cpu cycles
  393. if(rand(0,20)==0) {
  394. foreach($_SESSION as $key=>$value) {
  395. // search all tokens in the session
  396. if(substr($key,0,12)=='requesttoken') {
  397. if($value+$maxtime<time()) {
  398. // remove outdated tokens
  399. unset($_SESSION[$key]);
  400. }
  401. }
  402. }
  403. }
  404. // return the token
  405. return($token);
  406. }
  407. /**
  408. * @brief Check an ajax get/post call if the request token is valid.
  409. * @return boolean False if request token is not set or is invalid.
  410. */
  411. public static function isCallRegistered() {
  412. //mamimum time before token exires
  413. $maxtime=(60*60); // 1 hour
  414. if(isset($_GET['requesttoken'])) {
  415. $token=$_GET['requesttoken'];
  416. }elseif(isset($_POST['requesttoken'])) {
  417. $token=$_POST['requesttoken'];
  418. }elseif(isset($_SERVER['HTTP_REQUESTTOKEN'])) {
  419. $token=$_SERVER['HTTP_REQUESTTOKEN'];
  420. }else{
  421. //no token found.
  422. return false;
  423. }
  424. if(isset($_SESSION['requesttoken-'.$token])) {
  425. $timestamp=$_SESSION['requesttoken-'.$token];
  426. if($timestamp+$maxtime<time()) {
  427. return false;
  428. }else{
  429. //token valid
  430. return true;
  431. }
  432. }else{
  433. return false;
  434. }
  435. }
  436. /**
  437. * @brief Check an ajax get/post call if the request token is valid. exit if not.
  438. * Todo: Write howto
  439. */
  440. public static function callCheck() {
  441. if(!OC_Util::isCallRegistered()) {
  442. exit;
  443. }
  444. }
  445. /**
  446. * @brief Public function to sanitize HTML
  447. *
  448. * This function is used to sanitize HTML and should be applied on any
  449. * string or array of strings before displaying it on a web page.
  450. *
  451. * @param string or array of strings
  452. * @return array with sanitized strings or a single sanitized string, depends on the input parameter.
  453. */
  454. public static function sanitizeHTML( &$value ) {
  455. if (is_array($value) || is_object($value)) array_walk_recursive($value,'OC_Util::sanitizeHTML');
  456. else $value = htmlentities($value, ENT_QUOTES, 'UTF-8'); //Specify encoding for PHP<5.4
  457. return $value;
  458. }
  459. /**
  460. * Check if the htaccess file is working by creating a test file in the data directory and trying to access via http
  461. */
  462. public static function ishtaccessworking() {
  463. // testdata
  464. $filename='/htaccesstest.txt';
  465. $testcontent='testcontent';
  466. // creating a test file
  467. $testfile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$filename;
  468. $fp = @fopen($testfile, 'w');
  469. @fwrite($fp, $testcontent);
  470. @fclose($fp);
  471. // accessing the file via http
  472. $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/data'.$filename);
  473. $fp = @fopen($url, 'r');
  474. $content=@fread($fp, 2048);
  475. @fclose($fp);
  476. // cleanup
  477. @unlink($testfile);
  478. // does it work ?
  479. if($content==$testcontent) {
  480. return(false);
  481. }else{
  482. return(true);
  483. }
  484. }
  485. }