util.php 16 KB

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