summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/MDB2/Driver/Function/sqlite3.php4
-rw-r--r--lib/MDB2/Driver/Reverse/sqlite3.php2
-rw-r--r--lib/MDB2/Driver/sqlite3.php21
-rwxr-xr-xlib/app.php79
-rw-r--r--lib/appconfig.php6
-rw-r--r--lib/archive.php10
-rw-r--r--lib/archive/tar.php19
-rw-r--r--lib/archive/zip.php10
-rw-r--r--lib/backgroundjob.php52
-rw-r--r--lib/base.php223
-rw-r--r--lib/cache.php9
-rw-r--r--lib/connector/sabre/auth.php2
-rw-r--r--lib/connector/sabre/directory.php28
-rw-r--r--lib/connector/sabre/file.php4
-rw-r--r--lib/connector/sabre/locks.php12
-rw-r--r--lib/connector/sabre/node.php60
-rw-r--r--lib/connector/sabre/principal.php8
-rw-r--r--lib/connector/sabre/quotaplugin.php59
-rw-r--r--lib/db.php99
-rw-r--r--lib/eventsource.php10
-rw-r--r--lib/filecache.php181
-rw-r--r--lib/filecache/cached.php8
-rw-r--r--lib/filecache/update.php30
-rw-r--r--lib/filechunking.php2
-rw-r--r--lib/fileproxy.php12
-rw-r--r--lib/fileproxy/fileoperations.php62
-rw-r--r--lib/fileproxy/quota.php72
-rw-r--r--lib/files.php131
-rw-r--r--lib/filestorage.php13
-rw-r--r--lib/filestorage/common.php65
-rw-r--r--lib/filestorage/commontest.php6
-rw-r--r--lib/filestorage/local.php40
-rw-r--r--lib/filesystem.php167
-rw-r--r--lib/filesystemview.php83
-rw-r--r--lib/group.php11
-rw-r--r--lib/group/dummy.php10
-rw-r--r--lib/group/example.php2
-rw-r--r--lib/helper.php136
-rw-r--r--lib/image.php383
-rw-r--r--lib/installer.php54
-rw-r--r--lib/json.php19
-rw-r--r--lib/l10n.php33
-rw-r--r--lib/l10n/ar.php9
-rw-r--r--lib/l10n/bg_BG.php4
-rw-r--r--lib/l10n/ca.php10
-rw-r--r--lib/l10n/cs_CZ.php10
-rw-r--r--lib/l10n/da.php3
-rw-r--r--lib/l10n/de.php14
-rw-r--r--lib/l10n/de_DE.php34
-rw-r--r--lib/l10n/el.php10
-rw-r--r--lib/l10n/eo.php10
-rw-r--r--lib/l10n/es.php10
-rw-r--r--lib/l10n/es_AR.php10
-rw-r--r--lib/l10n/et_EE.php4
-rw-r--r--lib/l10n/eu.php10
-rw-r--r--lib/l10n/fa.php4
-rw-r--r--lib/l10n/fi_FI.php10
-rw-r--r--lib/l10n/fr.php10
-rw-r--r--lib/l10n/gl.php28
-rw-r--r--lib/l10n/he.php10
-rw-r--r--lib/l10n/hr.php15
-rw-r--r--lib/l10n/hu_HU.php3
-rw-r--r--lib/l10n/ia.php8
-rw-r--r--lib/l10n/id.php28
-rw-r--r--lib/l10n/it.php10
-rw-r--r--lib/l10n/ja_JP.php10
-rw-r--r--lib/l10n/ka_GE.php20
-rw-r--r--lib/l10n/ko.php34
-rw-r--r--lib/l10n/ku_IQ.php5
-rw-r--r--lib/l10n/lb.php6
-rw-r--r--lib/l10n/lt_LT.php10
-rw-r--r--lib/l10n/lv.php8
-rw-r--r--lib/l10n/mk.php8
-rw-r--r--lib/l10n/ms_MY.php8
-rw-r--r--lib/l10n/nb_NO.php9
-rw-r--r--lib/l10n/nl.php12
-rw-r--r--lib/l10n/nn_NO.php9
-rw-r--r--lib/l10n/oc.php2
-rw-r--r--lib/l10n/pl.php10
-rw-r--r--lib/l10n/pl_PL.php3
-rw-r--r--lib/l10n/pt_BR.php10
-rw-r--r--lib/l10n/pt_PT.php10
-rw-r--r--lib/l10n/ro.php3
-rw-r--r--lib/l10n/ru.php10
-rw-r--r--lib/l10n/ru_RU.php10
-rw-r--r--lib/l10n/si_LK.php30
-rw-r--r--lib/l10n/sk_SK.php13
-rw-r--r--lib/l10n/sl.php28
-rw-r--r--lib/l10n/sr.php34
-rw-r--r--lib/l10n/sr@latin.php9
-rw-r--r--lib/l10n/sv.php10
-rw-r--r--lib/l10n/ta_LK.php34
-rw-r--r--lib/l10n/th_TH.php10
-rw-r--r--lib/l10n/tr.php9
-rw-r--r--lib/l10n/uk.php13
-rw-r--r--lib/l10n/vi.php10
-rw-r--r--lib/l10n/zh_CN.GB2312.php4
-rw-r--r--lib/l10n/zh_CN.php10
-rw-r--r--lib/l10n/zh_TW.php10
-rw-r--r--lib/log.php25
-rw-r--r--lib/log/owncloud.php4
-rw-r--r--lib/mail.php8
-rw-r--r--lib/migrate.php60
-rw-r--r--lib/migration/content.php10
-rw-r--r--lib/minimizer.php21
-rw-r--r--lib/ocs.php221
-rw-r--r--lib/ocsclient.php108
-rw-r--r--lib/preferences.php2
-rw-r--r--lib/public/backgroundjob.php23
-rw-r--r--lib/public/constants.php38
-rw-r--r--lib/public/contacts.php103
-rw-r--r--lib/public/db.php23
-rw-r--r--lib/public/share.php2569
-rw-r--r--lib/public/util.php6
-rwxr-xr-x[-rw-r--r--]lib/request.php10
-rw-r--r--lib/route.php116
-rw-r--r--lib/router.php173
-rw-r--r--lib/search.php4
-rw-r--r--lib/search/provider/file.php15
-rw-r--r--lib/search/result.php2
-rw-r--r--lib/setup.php527
-rw-r--r--lib/streamwrappers.php30
-rw-r--r--lib/template.php57
-rw-r--r--lib/templatelayout.php12
-rw-r--r--lib/updater.php22
-rw-r--r--lib/user.php37
-rw-r--r--lib/user/database.php11
-rw-r--r--lib/user/http.php6
-rwxr-xr-xlib/util.php374
-rw-r--r--lib/vcategories.php634
-rw-r--r--lib/vobject.php40
131 files changed, 5423 insertions, 2790 deletions
diff --git a/lib/MDB2/Driver/Function/sqlite3.php b/lib/MDB2/Driver/Function/sqlite3.php
index 235a106e183..4147a48199f 100644
--- a/lib/MDB2/Driver/Function/sqlite3.php
+++ b/lib/MDB2/Driver/Function/sqlite3.php
@@ -92,9 +92,9 @@ class MDB2_Driver_Function_sqlite3 extends MDB2_Driver_Function_Common
function substring($value, $position = 1, $length = null)
{
if (!is_null($length)) {
- return "substr($value,$position,$length)";
+ return "substr($value, $position, $length)";
}
- return "substr($value,$position,length($value))";
+ return "substr($value, $position, length($value))";
}
// }}}
diff --git a/lib/MDB2/Driver/Reverse/sqlite3.php b/lib/MDB2/Driver/Reverse/sqlite3.php
index 36626478ce8..97037809549 100644
--- a/lib/MDB2/Driver/Reverse/sqlite3.php
+++ b/lib/MDB2/Driver/Reverse/sqlite3.php
@@ -476,7 +476,7 @@ class MDB2_Driver_Reverse_sqlite3 extends MDB2_Driver_Reverse_Common
$definition['unique'] = true;
$count = count($column_names);
for ($i=0; $i<$count; ++$i) {
- $column_name = strtok($column_names[$i]," ");
+ $column_name = strtok($column_names[$i], " ");
$collation = strtok(" ");
$definition['fields'][$column_name] = array(
'position' => $i+1
diff --git a/lib/MDB2/Driver/sqlite3.php b/lib/MDB2/Driver/sqlite3.php
index 9757e4faf94..fa4c91c1269 100644
--- a/lib/MDB2/Driver/sqlite3.php
+++ b/lib/MDB2/Driver/sqlite3.php
@@ -153,7 +153,7 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
if($this->connection) {
return $this->connection->escapeString($text);
}else{
- return str_replace("'","''",$text);//TODO; more
+ return str_replace("'", "''", $text);//TODO; more
}
}
@@ -276,7 +276,7 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
* @access public
* @since 2.1.1
*/
- function setTransactionIsolation($isolation,$options=array())
+ function setTransactionIsolation($isolation, $options=array())
{
$this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true));
switch ($isolation) {
@@ -351,7 +351,7 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
}
if ($database_file !== ':memory:') {
- if(!strpos($database_file,'.db')) {
+ if(!strpos($database_file, '.db')) {
$database_file="$datadir/$database_file.db";
}
if (!file_exists($database_file)) {
@@ -387,7 +387,7 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
$php_errormsg = '';
$this->connection = new SQLite3($database_file);
- if(is_callable(array($this->connection,'busyTimeout'))) {//busy timout is only available in php>=5.3
+ if(is_callable(array($this->connection, 'busyTimeout'))) {//busy timout is only available in php>=5.3
$this->connection->busyTimeout(100);
}
$this->_lasterror = $this->connection->lastErrorMsg();
@@ -397,8 +397,7 @@ class MDB2_Driver_sqlite3 extends MDB2_Driver_Common
}
if ($this->fix_assoc_fields_names ||
- $this->options['portability'] & MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES)
- {
+ $this->options['portability'] & MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES) {
$this->connection->exec("PRAGMA short_column_names = 1");
$this->fix_assoc_fields_names = true;
}
@@ -1142,9 +1141,9 @@ class MDB2_Statement_sqlite3 extends MDB2_Statement_Common
function bindValue($parameter, $value, $type = null) {
if($type) {
$type=$this->getParamType($type);
- $this->statement->bindValue($parameter,$value,$type);
+ $this->statement->bindValue($parameter, $value, $type);
}else{
- $this->statement->bindValue($parameter,$value);
+ $this->statement->bindValue($parameter, $value);
}
return MDB2_OK;
}
@@ -1165,9 +1164,9 @@ class MDB2_Statement_sqlite3 extends MDB2_Statement_Common
function bindParam($parameter, &$value, $type = null) {
if($type) {
$type=$this->getParamType($type);
- $this->statement->bindParam($parameter,$value,$type);
+ $this->statement->bindParam($parameter, $value, $type);
}else{
- $this->statement->bindParam($parameter,$value);
+ $this->statement->bindParam($parameter, $value);
}
return MDB2_OK;
}
@@ -1318,7 +1317,7 @@ class MDB2_Statement_sqlite3 extends MDB2_Statement_Common
}else{
$types=null;
}
- $err = $this->bindValueArray($values,$types);
+ $err = $this->bindValueArray($values, $types);
if (PEAR::isError($err)) {
return $this->db->raiseError(MDB2_ERROR, null, null,
'Binding Values failed with message: ' . $err->getMessage(), __FUNCTION__);
diff --git a/lib/app.php b/lib/app.php
index 395230156f6..5d4fbbd9c23 100755
--- a/lib/app.php
+++ b/lib/app.php
@@ -63,7 +63,7 @@ class OC_App{
if (!defined('DEBUG') || !DEBUG) {
if (is_null($types)
- && empty(OC_Util::$core_scripts)
+ && empty(OC_Util::$core_scripts)
&& empty(OC_Util::$core_styles)) {
OC_Util::$core_scripts = OC_Util::$scripts;
OC_Util::$scripts = array();
@@ -92,7 +92,7 @@ class OC_App{
* @param string/array $types
* @return bool
*/
- public static function isType($app,$types) {
+ public static function isType($app, $types) {
if(is_string($types)) {
$types=array($types);
}
@@ -185,7 +185,7 @@ class OC_App{
}else{
$download=OC_OCSClient::getApplicationDownload($app, 1);
if(isset($download['downloadlink']) and $download['downloadlink']!='') {
- $app=OC_Installer::installApp(array('source'=>'http','href'=>$download['downloadlink']));
+ $app=OC_Installer::installApp(array('source'=>'http', 'href'=>$download['downloadlink']));
}
}
}
@@ -253,6 +253,8 @@ class OC_App{
* highlighting the current position of the user.
*/
public static function setActiveNavigationEntry( $id ) {
+ // load all the apps, to make sure we have all the navigation entries
+ self::loadApps();
self::$activeapp = $id;
return true;
}
@@ -282,33 +284,33 @@ class OC_App{
// by default, settings only contain the help menu
if(OC_Config::getValue('knowledgebaseenabled', true)==true) {
$settings = array(
- array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "help.php" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" ))
+ array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkToRoute( "settings_help" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" ))
);
}
// if the user is logged-in
if (OC_User::isLoggedIn()) {
// personal menu
- $settings[] = array( "id" => "personal", "order" => 1, "href" => OC_Helper::linkTo( "settings", "personal.php" ), "name" => $l->t("Personal"), "icon" => OC_Helper::imagePath( "settings", "personal.svg" ));
+ $settings[] = array( "id" => "personal", "order" => 1, "href" => OC_Helper::linkToRoute( "settings_personal" ), "name" => $l->t("Personal"), "icon" => OC_Helper::imagePath( "settings", "personal.svg" ));
// if there are some settings forms
if(!empty(self::$settingsForms))
// settings menu
- $settings[]=array( "id" => "settings", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "settings.php" ), "name" => $l->t("Settings"), "icon" => OC_Helper::imagePath( "settings", "settings.svg" ));
+ $settings[]=array( "id" => "settings", "order" => 1000, "href" => OC_Helper::linkToRoute( "settings_settings" ), "name" => $l->t("Settings"), "icon" => OC_Helper::imagePath( "settings", "settings.svg" ));
//SubAdmins are also allowed to access user management
if(OC_SubAdmin::isSubAdmin($_SESSION["user_id"]) || OC_Group::inGroup( $_SESSION["user_id"], "admin" )) {
// admin users menu
- $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" ));
+ $settings[] = array( "id" => "core_users", "order" => 2, "href" => OC_Helper::linkToRoute( "settings_users" ), "name" => $l->t("Users"), "icon" => OC_Helper::imagePath( "settings", "users.svg" ));
}
// if the user is an admin
if(OC_Group::inGroup( $_SESSION["user_id"], "admin" )) {
// admin apps menu
- $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" ));
+ $settings[] = array( "id" => "core_apps", "order" => 3, "href" => OC_Helper::linkToRoute( "settings_apps" ).'?installed', "name" => $l->t("Apps"), "icon" => OC_Helper::imagePath( "settings", "apps.svg" ));
- $settings[]=array( "id" => "admin", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "admin.php" ), "name" => $l->t("Admin"), "icon" => OC_Helper::imagePath( "settings", "admin.svg" ));
+ $settings[]=array( "id" => "admin", "order" => 1000, "href" => OC_Helper::linkToRoute( "settings_admin" ), "name" => $l->t("Admin"), "icon" => OC_Helper::imagePath( "settings", "admin.svg" ));
}
}
@@ -319,7 +321,6 @@ class OC_App{
/// This is private as well. It simply works, so don't ask for more details
private static function proceedNavigation( $list ) {
foreach( $list as &$naventry ) {
- $naventry['subnavigation'] = array();
if( $naventry['id'] == self::$activeapp ) {
$naventry['active'] = true;
}
@@ -390,9 +391,8 @@ class OC_App{
*/
public static function getAppVersion($appid) {
$file= self::getAppPath($appid).'/appinfo/version';
- $version=@file_get_contents($file);
- if($version) {
- return trim($version);
+ if(is_file($file) && $version = trim(file_get_contents($file))) {
+ return $version;
}else{
$appData=self::getAppInfo($appid);
return isset($appData['version'])? $appData['version'] : '';
@@ -406,7 +406,7 @@ class OC_App{
* @return array
* @note all data is read from info.xml, not just pre-defined fields
*/
- public static function getAppInfo($appid,$path=false) {
+ public static function getAppInfo($appid, $path=false) {
if($path) {
$file=$appid;
}else{
@@ -458,7 +458,7 @@ class OC_App{
}
}
self::$appInfo[$appid]=$data;
-
+
return $data;
}
@@ -470,8 +470,6 @@ class OC_App{
* entries are sorted by the key 'order' ascending. Additional to the keys
* given for each app the following keys exist:
* - active: boolean, signals if the user is on this navigation entry
- * - children: array that is empty if the key 'active' is false or
- * contains the subentries if the key 'active' is true
*/
public static function getNavigation() {
$navigation = self::proceedNavigation( self::$navigation );
@@ -485,6 +483,12 @@ class OC_App{
public static function getCurrentApp() {
$script=substr($_SERVER["SCRIPT_NAME"], strlen(OC::$WEBROOT)+1);
$topFolder=substr($script, 0, strpos($script, '/'));
+ if (empty($topFolder)) {
+ $path_info = OC_Request::getPathInfo();
+ if ($path_info) {
+ $topFolder=substr($path_info, 1, strpos($path_info, '/', 1)-1);
+ }
+ }
if($topFolder=='apps') {
$length=strlen($topFolder);
return substr($script, $length+1, strpos($script, '/', $length+1)-$length-1);
@@ -521,21 +525,21 @@ class OC_App{
/**
* register a settings form to be shown
*/
- public static function registerSettings($app,$page) {
+ public static function registerSettings($app, $page) {
self::$settingsForms[]= $app.'/'.$page.'.php';
}
/**
* register an admin form to be shown
*/
- public static function registerAdmin($app,$page) {
+ public static function registerAdmin($app, $page) {
self::$adminForms[]= $app.'/'.$page.'.php';
}
/**
* register a personal form to be shown
*/
- public static function registerPersonal($app,$page) {
+ public static function registerPersonal($app, $page) {
self::$personalForms[]= $app.'/'.$page.'.php';
}
@@ -545,34 +549,31 @@ class OC_App{
* @todo: change the name of this method to getInstalledApps, which is more accurate
*/
public static function getAllApps() {
-
+
$apps=array();
-
+
foreach ( OC::$APPSROOTS as $apps_dir ) {
if(! is_readable($apps_dir['path'])) {
- OC_Log::write('core', 'unable to read app folder : ' .$apps_dir['path'] , OC_Log::WARN);
+ OC_Log::write('core', 'unable to read app folder : ' .$apps_dir['path'], OC_Log::WARN);
continue;
}
$dh = opendir( $apps_dir['path'] );
-
+
while( $file = readdir( $dh ) ) {
-
- if (
- $file[0] != '.'
- and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php' )
- ) {
-
+
+ if ($file[0] != '.' and is_file($apps_dir['path'].'/'.$file.'/appinfo/app.php')) {
+
$apps[] = $file;
-
+
}
-
+
}
-
+
}
-
+
return $apps;
}
-
+
/**
* @brief: get a list of all apps on apps.owncloud.com
* @return array, multi-dimensional array of apps. Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description
@@ -584,7 +585,7 @@ class OC_App{
if ( ! $categories = array_keys( $catagoryNames ) ) {
return false;
}
-
+
$page = 0;
$remoteApps = OC_OCSClient::getApplications( $categories, $page, $filter );
$app1 = array();
@@ -659,7 +660,7 @@ class OC_App{
$version = OC_Util::getVersion();
foreach($apps as $app) {
// check if the app is compatible with this version of ownCloud
- $info = OC_App::getAppInfo($app);
+ $info = OC_App::getAppInfo($app);
if(!isset($info['require']) or (($version[0].'.'.$version[1])>$info['require'])) {
OC_Log::write('core', 'App "'.$info['name'].'" ('.$app.') can\'t be used because it is not compatible with this version of ownCloud', OC_Log::ERROR);
OC_App::disable( $app );
@@ -689,6 +690,10 @@ class OC_App{
* @param string $appid
*/
public static function updateApp($appid) {
+ if(file_exists(self::getAppPath($appid).'/appinfo/preupdate.php')) {
+ self::loadApp($appid);
+ include self::getAppPath($appid).'/appinfo/preupdate.php';
+ }
if(file_exists(self::getAppPath($appid).'/appinfo/database.xml')) {
OC_DB::updateDbFromStructure(self::getAppPath($appid).'/appinfo/database.xml');
}
diff --git a/lib/appconfig.php b/lib/appconfig.php
index 6604e854d55..1f2d576af87 100644
--- a/lib/appconfig.php
+++ b/lib/appconfig.php
@@ -107,7 +107,7 @@ class OC_Appconfig{
* @param string $key
* @return bool
*/
- public static function hasKey($app,$key) {
+ public static function hasKey($app, $key) {
$exists = self::getKeys( $app );
return in_array( $key, $exists );
}
@@ -123,7 +123,7 @@ class OC_Appconfig{
*/
public static function setValue( $app, $key, $value ) {
// Does the key exist? yes: update. No: insert
- if(! self::hasKey($app,$key)) {
+ if(! self::hasKey($app, $key)) {
$query = OC_DB::prepare( 'INSERT INTO `*PREFIX*appconfig` ( `appid`, `configkey`, `configvalue` ) VALUES( ?, ?, ? )' );
$query->execute( array( $app, $key, $value ));
}
@@ -170,7 +170,7 @@ class OC_Appconfig{
* @param key
* @return array
*/
- public static function getValues($app,$key) {
+ public static function getValues($app, $key) {
if($app!==false and $key!==false) {
return false;
}
diff --git a/lib/archive.php b/lib/archive.php
index a9c245eaf43..61239c82076 100644
--- a/lib/archive.php
+++ b/lib/archive.php
@@ -42,14 +42,14 @@ abstract class OC_Archive{
* @param string source either a local file or string data
* @return bool
*/
- abstract function addFile($path,$source='');
+ abstract function addFile($path, $source='');
/**
* rename a file or folder in the archive
* @param string source
* @param string dest
* @return bool
*/
- abstract function rename($source,$dest);
+ abstract function rename($source, $dest);
/**
* get the uncompressed size of a file in the archive
* @param string path
@@ -85,7 +85,7 @@ abstract class OC_Archive{
* @param string dest
* @return bool
*/
- abstract function extractFile($path,$dest);
+ abstract function extractFile($path, $dest);
/**
* extract the archive
* @param string path
@@ -111,14 +111,14 @@ abstract class OC_Archive{
* @param string mode
* @return resource
*/
- abstract function getStream($path,$mode);
+ abstract function getStream($path, $mode);
/**
* add a folder and all it's content
* @param string $path
* @param string source
* @return bool
*/
- function addRecursive($path,$source) {
+ function addRecursive($path, $source) {
if($dh=opendir($source)) {
$this->addFolder($path);
while($file=readdir($dh)) {
diff --git a/lib/archive/tar.php b/lib/archive/tar.php
index 86d39b88968..0fa633c6038 100644
--- a/lib/archive/tar.php
+++ b/lib/archive/tar.php
@@ -6,7 +6,7 @@
* See the COPYING-README file.
*/
-require_once '3rdparty/Archive/Tar.php';
+require_once 'Archive/Tar.php';
class OC_Archive_TAR extends OC_Archive{
const PLAIN=0;
@@ -23,7 +23,7 @@ class OC_Archive_TAR extends OC_Archive{
private $path;
function __construct($source) {
- $types=array(null,'gz','bz');
+ $types=array(null, 'gz', 'bz');
$this->path=$source;
$this->tar=new Archive_Tar($source, $types[self::getTarType($source)]);
}
@@ -84,7 +84,7 @@ class OC_Archive_TAR extends OC_Archive{
* @param string source either a local file or string data
* @return bool
*/
- function addFile($path,$source='') {
+ function addFile($path, $source='') {
if($this->fileExists($path)) {
$this->remove($path);
}
@@ -107,7 +107,7 @@ class OC_Archive_TAR extends OC_Archive{
* @param string dest
* @return bool
*/
- function rename($source,$dest) {
+ function rename($source, $dest) {
//no proper way to delete, rename entire archive, rename file and remake archive
$tmp=OCP\Files::tmpFolder();
$this->tar->extract($tmp);
@@ -130,8 +130,7 @@ class OC_Archive_TAR extends OC_Archive{
if( $file == $header['filename']
or $file.'/' == $header['filename']
or '/'.$file.'/' == $header['filename']
- or '/'.$file == $header['filename'])
- {
+ or '/'.$file == $header['filename']) {
return $header;
}
}
@@ -214,7 +213,7 @@ class OC_Archive_TAR extends OC_Archive{
* @param string dest
* @return bool
*/
- function extractFile($path,$dest) {
+ function extractFile($path, $dest) {
$tmp=OCP\Files::tmpFolder();
if(!$this->fileExists($path)) {
return false;
@@ -294,7 +293,7 @@ class OC_Archive_TAR extends OC_Archive{
* @param string mode
* @return resource
*/
- function getStream($path,$mode) {
+ function getStream($path, $mode) {
if(strrpos($path, '.')!==false) {
$ext=substr($path, strrpos($path, '.'));
}else{
@@ -309,7 +308,7 @@ class OC_Archive_TAR extends OC_Archive{
if($mode=='r' or $mode=='rb') {
return fopen($tmpFile, $mode);
}else{
- OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
+ OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this, 'writeBack');
self::$tempFiles[$tmpFile]=$path;
return fopen('close://'.$tmpFile, $mode);
}
@@ -334,7 +333,7 @@ class OC_Archive_TAR extends OC_Archive{
$this->tar->_close();
$this->tar=null;
}
- $types=array(null,'gz','bz');
+ $types=array(null, 'gz', 'bz');
$this->tar=new Archive_Tar($this->path, $types[self::getTarType($this->path)]);
}
}
diff --git a/lib/archive/zip.php b/lib/archive/zip.php
index d016c692e35..1c967baa08f 100644
--- a/lib/archive/zip.php
+++ b/lib/archive/zip.php
@@ -35,7 +35,7 @@ class OC_Archive_ZIP extends OC_Archive{
* @param string source either a local file or string data
* @return bool
*/
- function addFile($path,$source='') {
+ function addFile($path, $source='') {
if($source and $source[0]=='/' and file_exists($source)) {
$result=$this->zip->addFile($source, $path);
}else{
@@ -53,7 +53,7 @@ class OC_Archive_ZIP extends OC_Archive{
* @param string dest
* @return bool
*/
- function rename($source,$dest) {
+ function rename($source, $dest) {
$source=$this->stripPath($source);
$dest=$this->stripPath($dest);
$this->zip->renameName($source, $dest);
@@ -119,7 +119,7 @@ class OC_Archive_ZIP extends OC_Archive{
* @param string dest
* @return bool
*/
- function extractFile($path,$dest) {
+ function extractFile($path, $dest) {
$fp = $this->zip->getStream($path);
file_put_contents($dest, $fp);
}
@@ -158,7 +158,7 @@ class OC_Archive_ZIP extends OC_Archive{
* @param string mode
* @return resource
*/
- function getStream($path,$mode) {
+ function getStream($path, $mode) {
if($mode=='r' or $mode=='rb') {
return $this->zip->getStream($path);
} else {
@@ -171,7 +171,7 @@ class OC_Archive_ZIP extends OC_Archive{
$ext='';
}
$tmpFile=OCP\Files::tmpFile($ext);
- OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
+ OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this, 'writeBack');
if($this->fileExists($path)) {
$this->extractFile($path, $tmpFile);
}
diff --git a/lib/backgroundjob.php b/lib/backgroundjob.php
new file mode 100644
index 00000000000..28b5ce3af20
--- /dev/null
+++ b/lib/backgroundjob.php
@@ -0,0 +1,52 @@
+<?php
+/**
+* ownCloud
+*
+* @author Jakob Sack
+* @copyright 2012 Jakob Sack owncloud@jakobsack.de
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* 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.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+/**
+ * This class does the dirty work.
+ */
+class OC_BackgroundJob{
+ /**
+ * @brief get the execution type of background jobs
+ * @return string
+ *
+ * This method returns the type how background jobs are executed. If the user
+ * did not select something, the type is ajax.
+ */
+ public static function getExecutionType() {
+ return OC_Appconfig::getValue( 'core', 'backgroundjobs_mode', 'ajax' );
+ }
+
+ /**
+ * @brief sets the background jobs execution type
+ * @param $type execution type
+ * @return boolean
+ *
+ * This method sets the execution type of the background jobs. Possible types
+ * are "none", "ajax", "webcron", "cron"
+ */
+ public static function setExecutionType( $type ) {
+ if( !in_array( $type, array('none', 'ajax', 'webcron', 'cron'))) {
+ return false;
+ }
+ return OC_Appconfig::setValue( 'core', 'backgroundjobs_mode', $type );
+ }
+}
diff --git a/lib/base.php b/lib/base.php
index ad485342d2d..d9a0e2c757f 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -20,6 +20,8 @@
*
*/
+require_once 'public/constants.php';
+
/**
* Class that is a namespace for all global OC variables
* No, we can not put this class in its own file because it is used by
@@ -67,6 +69,10 @@ class OC{
* check if owncloud runs in cli mode
*/
public static $CLI = false;
+ /*
+ * OC router
+ */
+ protected static $router = null;
/**
* SPL autoload
*/
@@ -99,6 +105,12 @@ class OC{
elseif(strpos($className, 'Doctrine\\DBAL')===0) {
$path = 'doctrine-dbal/lib/'.str_replace('\\', '/', $className) . '.php';
}
+ elseif(strpos($className, 'Symfony\\Component\\Routing\\')===0) {
+ $path = 'symfony/routing/'.str_replace('\\', '/', $className) . '.php';
+ }
+ elseif(strpos($className, 'Sabre\\VObject')===0) {
+ $path = str_replace('\\', '/', $className) . '.php';
+ }
elseif(strpos($className, 'Test_')===0) {
$path = 'tests/lib/'.strtolower(str_replace('_', '/', substr($className, 5)) . '.php');
}else{
@@ -182,7 +194,7 @@ class OC{
OC::$SERVERROOT.'/lib'.PATH_SEPARATOR.
OC::$SERVERROOT.'/config'.PATH_SEPARATOR.
OC::$THIRDPARTYROOT.'/3rdparty'.PATH_SEPARATOR.
- implode($paths,PATH_SEPARATOR).PATH_SEPARATOR.
+ implode($paths, PATH_SEPARATOR).PATH_SEPARATOR.
get_include_path().PATH_SEPARATOR.
OC::$SERVERROOT
);
@@ -217,6 +229,14 @@ class OC{
$installedVersion=OC_Config::getValue('version', '0.0.0');
$currentVersion=implode('.', OC_Util::getVersion());
if (version_compare($currentVersion, $installedVersion, '>')) {
+ // Check if the .htaccess is existing - this is needed for upgrades from really old ownCloud versions
+ if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
+ if(!OC_Util::ishtaccessworking()) {
+ if(!file_exists(OC::$SERVERROOT.'/data/.htaccess')) {
+ OC_Setup::protectDataDirectory();
+ }
+ }
+ }
OC_Log::write('core', 'starting upgrade from '.$installedVersion.' to '.$currentVersion, OC_Log::DEBUG);
$result=OC_DB::updateDbFromStructure(OC::$SERVERROOT.'/db_structure.xml');
if(!$result) {
@@ -225,7 +245,7 @@ class OC{
}
if(file_exists(OC::$SERVERROOT."/config/config.php") and !is_writable(OC::$SERVERROOT."/config/config.php")) {
$tmpl = new OC_Template( '', 'error', 'guest' );
- $tmpl->assign('errors', array(1=>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")));
+ $tmpl->assign('errors', array(1=>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")));
$tmpl->printPage();
exit;
}
@@ -246,16 +266,15 @@ class OC{
OC_Util::addScript( "jquery-1.7.2.min" );
OC_Util::addScript( "jquery-ui-1.8.16.custom.min" );
OC_Util::addScript( "jquery-showpassword" );
- OC_Util::addScript( "jquery.infieldlabel.min" );
+ OC_Util::addScript( "jquery.infieldlabel" );
OC_Util::addScript( "jquery-tipsy" );
OC_Util::addScript( "oc-dialogs" );
OC_Util::addScript( "js" );
- // request protection token MUST be defined after the jquery library but before any $('document').ready()
- OC_Util::addScript( "requesttoken" );
OC_Util::addScript( "eventsource" );
OC_Util::addScript( "config" );
//OC_Util::addScript( "multiselect" );
OC_Util::addScript('search', 'result');
+ OC_Util::addScript('router');
if( OC_Config::getValue( 'installed', false )) {
if( OC_Appconfig::getValue( 'core', 'backgroundjobs_mode', 'ajax' ) == 'ajax' ) {
@@ -270,13 +289,44 @@ class OC{
}
public static function initSession() {
+ // prevents javascript from accessing php session cookies
ini_set('session.cookie_httponly', '1;');
+
+ // (re)-initialize session
session_start();
+
+ // regenerate session id periodically to avoid session fixation
+ if (!isset($_SESSION['SID_CREATED'])) {
+ $_SESSION['SID_CREATED'] = time();
+ } else if (time() - $_SESSION['SID_CREATED'] > 900) {
+ session_regenerate_id(true);
+ $_SESSION['SID_CREATED'] = time();
+ }
+
+ // session timeout
+ if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 3600)) {
+ if (isset($_COOKIE[session_name()])) {
+ setcookie(session_name(), '', time() - 42000, '/');
+ }
+ session_unset();
+ session_destroy();
+ session_start();
+ }
+ $_SESSION['LAST_ACTIVITY'] = time();
+ }
+
+ public static function getRouter() {
+ if (!isset(OC::$router)) {
+ OC::$router = new OC_Router();
+ OC::$router->loadRoutes();
+ }
+
+ return OC::$router;
}
public static function init() {
// register autoloader
- spl_autoload_register(array('OC','autoload'));
+ spl_autoload_register(array('OC', 'autoload'));
setlocale(LC_ALL, 'en_US.UTF-8');
// set some stuff
@@ -291,7 +341,7 @@ class OC{
ini_set('arg_separator.output', '&amp;');
// try to switch magic quotes off.
- if(function_exists('set_magic_quotes_runtime')) {
+ if(get_magic_quotes_gpc()) {
@set_magic_quotes_runtime(false);
}
@@ -312,6 +362,10 @@ class OC{
//try to set the session lifetime to 60min
@ini_set('gc_maxlifetime', '3600');
+ //copy http auth headers for apache+php-fcgid work around
+ if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) {
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION'];
+ }
//set http auth headers for apache+php-cgi work around
if (isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches)) {
@@ -329,6 +383,10 @@ class OC{
self::initPaths();
+ register_shutdown_function(array('OC_Log', 'onShutdown'));
+ set_error_handler(array('OC_Log', 'onError'));
+ set_exception_handler(array('OC_Log', 'onException'));
+
// set debug mode if an xdebug session is active
if (!defined('DEBUG') || !DEBUG) {
if(isset($_COOKIE['XDEBUG_SESSION'])) {
@@ -381,16 +439,12 @@ class OC{
//setup extra user backends
OC_User::setupBackends();
- // register cache cleanup jobs
- OC_BackgroundJob_RegularTask::register('OC_Cache_FileGlobal', 'gc');
- OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener');
-
- // Check for blacklisted files
- OC_Hook::connect('OC_Filesystem', 'write', 'OC_Filesystem', 'isBlacklisted');
- OC_Hook::connect('OC_Filesystem', 'rename', 'OC_Filesystem', 'isBlacklisted');
+ self::registerCacheHooks();
+ self::registerFilesystemHooks();
+ self::registerShareHooks();
//make sure temporary files are cleaned up
- register_shutdown_function(array('OC_Helper','cleanTmp'));
+ register_shutdown_function(array('OC_Helper', 'cleanTmp'));
//parse the given parameters
self::$REQUESTEDAPP = (isset($_GET['app']) && trim($_GET['app']) != '' && !is_null($_GET['app'])?str_replace(array('\0', '/', '\\', '..'), '', strip_tags($_GET['app'])):OC_Config::getValue('defaultapp', 'files'));
@@ -423,21 +477,39 @@ class OC{
}
/**
+ * register hooks for the cache
+ */
+ public static function registerCacheHooks() {
+ // register cache cleanup jobs
+ OC_BackgroundJob_RegularTask::register('OC_Cache_FileGlobal', 'gc');
+ OC_Hook::connect('OC_User', 'post_login', 'OC_Cache_File', 'loginListener');
+ }
+
+ /**
+ * register hooks for the filesystem
+ */
+ public static function registerFilesystemHooks() {
+ // Check for blacklisted files
+ OC_Hook::connect('OC_Filesystem', 'write', 'OC_Filesystem', 'isBlacklisted');
+ OC_Hook::connect('OC_Filesystem', 'rename', 'OC_Filesystem', 'isBlacklisted');
+ }
+
+ /**
+ * register hooks for sharing
+ */
+ public static function registerShareHooks() {
+ OC_Hook::connect('OC_User', 'post_deleteUser', 'OCP\Share', 'post_deleteUser');
+ OC_Hook::connect('OC_User', 'post_addToGroup', 'OCP\Share', 'post_addToGroup');
+ OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OCP\Share', 'post_removeFromGroup');
+ OC_Hook::connect('OC_User', 'post_deleteGroup', 'OCP\Share', 'post_deleteGroup');
+ }
+
+ /**
* @brief Handle the request
*/
public static function handleRequest() {
if (!OC_Config::getValue('installed', false)) {
- // Check for autosetup:
- $autosetup_file = OC::$SERVERROOT."/config/autoconfig.php";
- if( file_exists( $autosetup_file )) {
- OC_Log::write('core', 'Autoconfig file found, setting up owncloud...', OC_Log::INFO);
- include $autosetup_file;
- $_POST['install'] = 'true';
- $_POST = array_merge ($_POST, $AUTOCONFIG);
- unlink($autosetup_file);
- }
- OC_Util::addScript('setup');
- require_once 'setup.php';
+ require_once 'core/setup.php';
exit();
}
// Handle WebDAV
@@ -445,9 +517,21 @@ class OC{
header('location: '.OC_Helper::linkToRemote('webdav'));
return;
}
+ try {
+ OC::getRouter()->match(OC_Request::getPathInfo());
+ return;
+ } catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
+ //header('HTTP/1.0 404 Not Found');
+ } catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) {
+ OC_Response::setStatus(405);
+ return;
+ }
+ $app = OC::$REQUESTEDAPP;
+ $file = OC::$REQUESTEDFILE;
+ $param = array('app' => $app, 'file' => $file);
// Handle app css files
- if(substr(OC::$REQUESTEDFILE, -3) == 'css') {
- self::loadCSSFile();
+ if(substr($file, -3) == 'css') {
+ self::loadCSSFile($param);
return;
}
// Someone is logged in :
@@ -455,16 +539,16 @@ class OC{
OC_App::loadApps();
OC_User::setupBackends();
if(isset($_GET["logout"]) and ($_GET["logout"])) {
+ OC_Preferences::deleteKey(OC_User::getUser(), 'login_token', $_COOKIE['oc_token']);
OC_User::logout();
header("Location: ".OC::$WEBROOT.'/');
}else{
- $app = OC::$REQUESTEDAPP;
- $file = OC::$REQUESTEDFILE;
if(is_null($file)) {
- $file = 'index.php';
+ $param['file'] = 'index.php';
}
- $file_ext = substr($file, -3);
- if ($file_ext != 'php'|| !self::loadAppScriptFile($app, $file)) {
+ $file_ext = substr($param['file'], -3);
+ if ($file_ext != 'php'
+ || !self::loadAppScriptFile($param)) {
header('HTTP/1.0 404 Not Found');
}
}
@@ -474,7 +558,10 @@ class OC{
self::handleLogin();
}
- protected static function loadAppScriptFile($app, $file) {
+ public static function loadAppScriptFile($param) {
+ OC_App::loadApps();
+ $app = $param['app'];
+ $file = $param['file'];
$app_path = OC_App::getAppPath($app);
$file = $app_path . '/' . $file;
unset($app, $app_path);
@@ -485,9 +572,9 @@ class OC{
return false;
}
- protected static function loadCSSFile() {
- $app = OC::$REQUESTEDAPP;
- $file = OC::$REQUESTEDFILE;
+ public static function loadCSSFile($param) {
+ $app = $param['app'];
+ $file = $param['file'];
$app_path = OC_App::getAppPath($app);
if (file_exists($app_path . '/' . $file)) {
$app_web_path = OC_App::getAppWebPath($app);
@@ -500,28 +587,38 @@ class OC{
protected static function handleLogin() {
OC_App::loadApps(array('prelogin'));
- $error = false;
+ $error = array();
// remember was checked after last login
if (OC::tryRememberLogin()) {
- // nothing more to do
+ $error[] = 'invalidcookie';
// Someone wants to log in :
} elseif (OC::tryFormLogin()) {
- $error = true;
+ $error[] = 'invalidpassword';
// The user is already authenticated using Apaches AuthType Basic... very usable in combination with LDAP
} elseif (OC::tryBasicAuthLogin()) {
- $error = true;
+ $error[] = 'invalidpassword';
+ }
+ OC_Util::displayLoginPage(array_unique($error));
+ }
+
+ protected static function cleanupLoginTokens($user) {
+ $cutoff = time() - OC_Config::getValue('remember_login_cookie_lifetime', 60*60*24*15);
+ $tokens = OC_Preferences::getKeys($user, 'login_token');
+ foreach($tokens as $token) {
+ $time = OC_Preferences::getValue($user, 'login_token', $token);
+ if ($time < $cutoff) {
+ OC_Preferences::deleteKey($user, 'login_token', $token);
+ }
}
- OC_Util::displayLoginPage($error);
}
protected static function tryRememberLogin() {
if(!isset($_COOKIE["oc_remember_login"])
|| !isset($_COOKIE["oc_token"])
|| !isset($_COOKIE["oc_username"])
- || !$_COOKIE["oc_remember_login"])
- {
+ || !$_COOKIE["oc_remember_login"]) {
return false;
}
OC_App::loadApps(array('authentication'));
@@ -529,15 +626,30 @@ class OC{
OC_Log::write('core', 'Trying to login from cookie', OC_Log::DEBUG);
}
// confirm credentials in cookie
- if(isset($_COOKIE['oc_token']) && OC_User::userExists($_COOKIE['oc_username']) &&
- OC_Preferences::getValue($_COOKIE['oc_username'], "login", "token") === $_COOKIE['oc_token'])
- {
- OC_User::setUserId($_COOKIE['oc_username']);
- OC_Util::redirectToDefaultPage();
- }
- else {
- OC_User::unsetMagicInCookie();
+ if(isset($_COOKIE['oc_token']) && OC_User::userExists($_COOKIE['oc_username'])) {
+ // delete outdated cookies
+ self::cleanupLoginTokens($_COOKIE['oc_username']);
+ // get stored tokens
+ $tokens = OC_Preferences::getKeys($_COOKIE['oc_username'], 'login_token');
+ // test cookies token against stored tokens
+ if (in_array($_COOKIE['oc_token'], $tokens, true)) {
+ // replace successfully used token with a new one
+ OC_Preferences::deleteKey($_COOKIE['oc_username'], 'login_token', $_COOKIE['oc_token']);
+ $token = OC_Util::generate_random_bytes(32);
+ OC_Preferences::setValue($_COOKIE['oc_username'], 'login_token', $token, time());
+ OC_User::setMagicInCookie($_COOKIE['oc_username'], $token);
+ // login
+ OC_User::setUserId($_COOKIE['oc_username']);
+ OC_Util::redirectToDefaultPage();
+ // doesn't return
+ }
+ // if you reach this point you have changed your password
+ // or you are an attacker
+ // we can not delete tokens here because users may reach
+ // this point multiple times after a password change
+ OC_Log::write('core', 'Authentication cookie rejected for user '.$_COOKIE['oc_username'], OC_Log::WARN);
}
+ OC_User::unsetMagicInCookie();
return true;
}
@@ -552,12 +664,13 @@ class OC{
OC_User::setupBackends();
if(OC_User::login($_POST["user"], $_POST["password"])) {
+ self::cleanupLoginTokens($_POST['user']);
if(!empty($_POST["remember_login"])) {
if(defined("DEBUG") && DEBUG) {
OC_Log::write('core', 'Setting remember login to cookie', OC_Log::DEBUG);
}
- $token = md5($_POST["user"].time().$_POST['password']);
- OC_Preferences::setValue($_POST['user'], 'login', 'token', $token);
+ $token = OC_Util::generate_random_bytes(32);
+ OC_Preferences::setValue($_POST['user'], 'login_token', $token, time());
OC_User::setMagicInCookie($_POST["user"], $token);
}
else {
@@ -576,7 +689,7 @@ class OC{
}
OC_App::loadApps(array('authentication'));
if (OC_User::login($_SERVER["PHP_AUTH_USER"], $_SERVER["PHP_AUTH_PW"])) {
- //OC_Log::write('core',"Logged in with HTTP Authentication",OC_Log::DEBUG);
+ //OC_Log::write('core',"Logged in with HTTP Authentication", OC_Log::DEBUG);
OC_User::unsetMagicInCookie();
$_REQUEST['redirect_url'] = (isset($_SERVER['REQUEST_URI'])?$_SERVER['REQUEST_URI']:'');
OC_Util::redirectToDefaultPage();
diff --git a/lib/cache.php b/lib/cache.php
index 62003793d5f..bc74ed83f8b 100644
--- a/lib/cache.php
+++ b/lib/cache.php
@@ -144,4 +144,13 @@ class OC_Cache {
return self::$isFast;
}
+ static public function generateCacheKeyFromFiles($files) {
+ $key = '';
+ sort($files);
+ foreach($files as $file) {
+ $stat = stat($file);
+ $key .= $file.$stat['mtime'].$stat['size'];
+ }
+ return md5($key);
+ }
}
diff --git a/lib/connector/sabre/auth.php b/lib/connector/sabre/auth.php
index 0c34c7ea29f..db8f005745a 100644
--- a/lib/connector/sabre/auth.php
+++ b/lib/connector/sabre/auth.php
@@ -37,7 +37,7 @@ class OC_Connector_Sabre_Auth extends Sabre_DAV_Auth_Backend_AbstractBasic {
} else {
OC_Util::setUpFS();//login hooks may need early access to the filesystem
if(OC_User::login($username, $password)) {
- OC_Util::setUpFS($username);
+ OC_Util::setUpFS(OC_User::getUser());
return true;
}
else{
diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php
index 413efef73b7..6076aed6fcd 100644
--- a/lib/connector/sabre/directory.php
+++ b/lib/connector/sabre/directory.php
@@ -116,7 +116,6 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
* @return Sabre_DAV_INode[]
*/
public function getChildren() {
-
$folder_content = OC_Files::getDirectoryContent($this->path);
$paths = array();
foreach($folder_content as $info) {
@@ -124,15 +123,22 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
}
$properties = array_fill_keys($paths, array());
if(count($paths)>0) {
- $placeholders = join(',', array_fill(0, count($paths), '?'));
- $query = OC_DB::prepare( 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ?' . ' AND `propertypath` IN ('.$placeholders.')' );
- array_unshift($paths, OC_User::getUser()); // prepend userid
- $result = $query->execute( $paths );
- while($row = $result->fetchRow()) {
- $propertypath = $row['propertypath'];
- $propertyname = $row['propertyname'];
- $propertyvalue = $row['propertyvalue'];
- $properties[$propertypath][$propertyname] = $propertyvalue;
+ //
+ // the number of arguments within IN conditions are limited in most databases
+ // we chunk $paths into arrays of 200 items each to meet this criteria
+ //
+ $chunks = array_chunk($paths, 200, false);
+ foreach ($chunks as $pack) {
+ $placeholders = join(',', array_fill(0, count($pack), '?'));
+ $query = OC_DB::prepare( 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ?' . ' AND `propertypath` IN ('.$placeholders.')' );
+ array_unshift($pack, OC_User::getUser()); // prepend userid
+ $result = $query->execute( $pack );
+ while($row = $result->fetchRow()) {
+ $propertypath = $row['propertypath'];
+ $propertyname = $row['propertyname'];
+ $propertyvalue = $row['propertyvalue'];
+ $properties[$propertypath][$propertyname] = $propertyvalue;
+ }
}
}
@@ -200,7 +206,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
public function getProperties($properties) {
$props = parent::getProperties($properties);
if (in_array(self::GETETAG_PROPERTYNAME, $properties) && !isset($props[self::GETETAG_PROPERTYNAME])) {
- $props[self::GETETAG_PROPERTYNAME]
+ $props[self::GETETAG_PROPERTYNAME]
= OC_Connector_Sabre_Node::getETagPropertyForPath($this->path);
}
return $props;
diff --git a/lib/connector/sabre/file.php b/lib/connector/sabre/file.php
index 5bd38240d44..8d963a1cf8d 100644
--- a/lib/connector/sabre/file.php
+++ b/lib/connector/sabre/file.php
@@ -45,7 +45,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
*/
public function put($data) {
- OC_Filesystem::file_put_contents($this->path,$data);
+ OC_Filesystem::file_put_contents($this->path, $data);
return OC_Connector_Sabre_Node::getETagPropertyForPath($this->path);
}
@@ -57,7 +57,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
*/
public function get() {
- return OC_Filesystem::fopen($this->path,'rb');
+ return OC_Filesystem::fopen($this->path, 'rb');
}
diff --git a/lib/connector/sabre/locks.php b/lib/connector/sabre/locks.php
index dbcc57558e0..a72d003bc72 100644
--- a/lib/connector/sabre/locks.php
+++ b/lib/connector/sabre/locks.php
@@ -45,10 +45,10 @@ class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract {
// but otherwise reading locks from SQLite Databases will return
// nothing
$query = 'SELECT * FROM `*PREFIX*locks` WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( `uri` = ?)';
- $params = array(OC_User::getUser(),$uri);
+ $params = array(OC_User::getUser(), $uri);
// We need to check locks for every part in the uri.
- $uriParts = explode('/',$uri);
+ $uriParts = explode('/', $uri);
// We already covered the last part of the uri
array_pop($uriParts);
@@ -102,14 +102,14 @@ class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract {
* @param Sabre_DAV_Locks_LockInfo $lockInfo
* @return bool
*/
- public function lock($uri,Sabre_DAV_Locks_LockInfo $lockInfo) {
+ public function lock($uri, Sabre_DAV_Locks_LockInfo $lockInfo) {
// We're making the lock timeout 5 minutes
$lockInfo->timeout = 300;
$lockInfo->created = time();
$lockInfo->uri = $uri;
- $locks = $this->getLocks($uri,false);
+ $locks = $this->getLocks($uri, false);
$exists = false;
foreach($locks as $lock) {
if ($lock->token == $lockInfo->token) $exists = true;
@@ -134,10 +134,10 @@ class OC_Connector_Sabre_Locks extends Sabre_DAV_Locks_Backend_Abstract {
* @param Sabre_DAV_Locks_LockInfo $lockInfo
* @return bool
*/
- public function unlock($uri,Sabre_DAV_Locks_LockInfo $lockInfo) {
+ public function unlock($uri, Sabre_DAV_Locks_LockInfo $lockInfo) {
$query = OC_DB::prepare( 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND `uri` = ? AND `token` = ?' );
- $result = $query->execute( array(OC_User::getUser(),$uri,$lockInfo->token));
+ $result = $query->execute( array(OC_User::getUser(), $uri, $lockInfo->token));
return $result->numRows() === 1;
diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php
index 72de9723774..52350072fb2 100644
--- a/lib/connector/sabre/node.php
+++ b/lib/connector/sabre/node.php
@@ -26,6 +26,13 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
/**
+ * Allow configuring the method used to generate Etags
+ *
+ * @var array(class_name, function_name)
+ */
+ public static $ETagFunction = null;
+
+ /**
* The path to the current node
*
* @var string
@@ -43,8 +50,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
protected $property_cache = null;
/**
- * Sets up the node, expects a full path name
- *
+ * @brief Sets up the node, expects a full path name
* @param string $path
* @return void
*/
@@ -55,8 +61,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
/**
- * Returns the name of the node
- *
+ * @brief Returns the name of the node
* @return string
*/
public function getName() {
@@ -67,8 +72,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
}
/**
- * Renames the node
- *
+ * @brief Renames the node
* @param string $name The new name
* @return void
*/
@@ -80,12 +84,12 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
$newPath = $parentPath . '/' . $newName;
$oldPath = $this->path;
- OC_Filesystem::rename($this->path,$newPath);
+ OC_Filesystem::rename($this->path, $newPath);
$this->path = $newPath;
$query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertypath` = ? WHERE `userid` = ? AND `propertypath` = ?' );
- $query->execute( array( $newPath,OC_User::getUser(), $oldPath ));
+ $query->execute( array( $newPath, OC_User::getUser(), $oldPath ));
}
@@ -95,7 +99,8 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
}
/**
- * Make sure the fileinfo cache is filled. Uses OC_FileCache or a direct stat
+ * @brief Ensure that the fileinfo cache is filled
+ & @note Uses OC_FileCache or a direct stat
*/
protected function getFileinfoCache() {
if (!isset($this->fileinfo_cache)) {
@@ -114,8 +119,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
}
/**
- * Returns the last modification time, as a unix timestamp
- *
+ * @brief Returns the last modification time, as a unix timestamp
* @return int
*/
public function getLastModified() {
@@ -134,8 +138,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
}
/**
- * Updates properties on this node,
- *
+ * @brief Updates properties on this node,
* @param array $mutations
* @see Sabre_DAV_IProperties::updateProperties
* @return bool|array
@@ -156,10 +159,10 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
} else {
if(!array_key_exists( $propertyName, $existing )) {
$query = OC_DB::prepare( 'INSERT INTO `*PREFIX*properties` (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)' );
- $query->execute( array( OC_User::getUser(), $this->path, $propertyName,$propertyValue ));
+ $query->execute( array( OC_User::getUser(), $this->path, $propertyName, $propertyValue ));
} else {
$query = OC_DB::prepare( 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ? WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?' );
- $query->execute( array( $propertyValue,OC_User::getUser(), $this->path, $propertyName ));
+ $query->execute( array( $propertyValue, OC_User::getUser(), $this->path, $propertyName ));
}
}
}
@@ -170,15 +173,13 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
}
/**
- * Returns a list of properties for this nodes.;
- *
- * The properties list is a list of propertynames the client requested,
- * encoded as xmlnamespace#tagName, for example:
- * http://www.example.org/namespace#author
- * If the array is empty, all properties should be returned
- *
+ * @brief Returns a list of properties for this nodes.;
* @param array $properties
- * @return void
+ * @return array
+ * @note The properties list is a list of propertynames the client
+ * requested, encoded as xmlnamespace#tagName, for example:
+ * http://www.example.org/namespace#author If the array is empty, all
+ * properties should be returned
*/
public function getProperties($properties) {
if (is_null($this->property_cache)) {
@@ -204,16 +205,21 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
}
/**
- * Creates a ETag for this path.
+ * @brief Creates a ETag for this path.
* @param string $path Path of the file
* @return string|null Returns null if the ETag can not effectively be determined
*/
static protected function createETag($path) {
- return uniqid('', true);
+ if(self::$ETagFunction) {
+ $hash = call_user_func(self::$ETagFunction, $path);
+ return $hash;
+ }else{
+ return uniqid('', true);
+ }
}
/**
- * Returns the ETag surrounded by double-quotes for this path.
+ * @brief Returns the ETag surrounded by double-quotes for this path.
* @param string $path Path of the file
* @return string|null Returns null if the ETag can not effectively be determined
*/
@@ -229,7 +235,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
}
/**
- * Remove the ETag from the cache.
+ * @brief Remove the ETag from the cache.
* @param string $path Path of the file
*/
static public function removeETagPropertyForPath($path) {
diff --git a/lib/connector/sabre/principal.php b/lib/connector/sabre/principal.php
index ee95ae63306..04be410ac85 100644
--- a/lib/connector/sabre/principal.php
+++ b/lib/connector/sabre/principal.php
@@ -46,7 +46,7 @@ class OC_Connector_Sabre_Principal implements Sabre_DAVACL_IPrincipalBackend {
* @return array
*/
public function getPrincipalByPath($path) {
- list($prefix,$name) = explode('/', $path);
+ list($prefix, $name) = explode('/', $path);
if ($prefix == 'principals' && OC_User::userExists($name)) {
return array(
@@ -83,7 +83,7 @@ class OC_Connector_Sabre_Principal implements Sabre_DAVACL_IPrincipalBackend {
* @return array
*/
public function getGroupMembership($principal) {
- list($prefix,$name) = Sabre_DAV_URLUtil::splitPath($principal);
+ list($prefix, $name) = Sabre_DAV_URLUtil::splitPath($principal);
$group_membership = array();
if ($prefix == 'principals') {
@@ -115,11 +115,11 @@ class OC_Connector_Sabre_Principal implements Sabre_DAVACL_IPrincipalBackend {
public function setGroupMemberSet($principal, array $members) {
throw new Sabre_DAV_Exception('Setting members of the group is not supported yet');
}
-
+
function updatePrincipal($path, $mutations) {
return 0;
}
-
+
function searchPrincipals($prefixPath, array $searchProperties) {
return 0;
}
diff --git a/lib/connector/sabre/quotaplugin.php b/lib/connector/sabre/quotaplugin.php
new file mode 100644
index 00000000000..a56a65ad863
--- /dev/null
+++ b/lib/connector/sabre/quotaplugin.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * This plugin check user quota and deny creating files when they exceeds the quota.
+ *
+ * @copyright Copyright (C) 2012 entreCables S.L. All rights reserved.
+ * @author Sergio Cambra
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class OC_Connector_Sabre_QuotaPlugin extends Sabre_DAV_ServerPlugin {
+
+ /**
+ * Reference to main server object
+ *
+ * @var Sabre_DAV_Server
+ */
+ private $server;
+
+ /**
+ * This initializes the plugin.
+ *
+ * This function is called by Sabre_DAV_Server, after
+ * addPlugin is called.
+ *
+ * This method should set up the requires event subscriptions.
+ *
+ * @param Sabre_DAV_Server $server
+ * @return void
+ */
+ public function initialize(Sabre_DAV_Server $server) {
+
+ $this->server = $server;
+ $this->server->subscribeEvent('beforeWriteContent', array($this, 'checkQuota'), 10);
+ $this->server->subscribeEvent('beforeCreateFile', array($this, 'checkQuota'), 10);
+
+ }
+
+ /**
+ * This method is called before any HTTP method and forces users to be authenticated
+ *
+ * @param string $method
+ * @throws Sabre_DAV_Exception
+ * @return bool
+ */
+ public function checkQuota($uri, $data = null) {
+ $expected = $this->server->httpRequest->getHeader('X-Expected-Entity-Length');
+ $length = $expected ? $expected : $this->server->httpRequest->getHeader('Content-Length');
+ if ($length) {
+ if (substr($uri, 0, 1)!=='/') {
+ $uri='/'.$uri;
+ }
+ list($parentUri, $newName) = Sabre_DAV_URLUtil::splitPath($uri);
+ if ($length > OC_Filesystem::free_space($parentUri)) {
+ throw new Sabre_DAV_Exception('Quota exceeded. File is too big.');
+ }
+ }
+ return true;
+ }
+}
diff --git a/lib/db.php b/lib/db.php
index a6500a2e3bd..2e21a11d545 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -92,8 +92,8 @@ class OC_DB {
$pass = OC_Config::getValue( "dbpassword", "" );
$type = OC_Config::getValue( "dbtype", "sqlite" );
if(strpos($host, ':')) {
- list($host, $port)=explode(':', $host,2);
- }else{
+ list($host, $port)=explode(':', $host, 2);
+ } else {
$port=false;
}
@@ -192,9 +192,9 @@ class OC_DB {
}catch(PDOException $e) {
$entry = 'DB Error: "'.$e->getMessage().'"<br />';
$entry .= 'Offending command was: '.htmlentities($query).'<br />';
- OC_Log::write('core', $entry,OC_Log::FATAL);
+ OC_Log::write('core', $entry, OC_Log::FATAL);
error_log('DB error: '.$entry);
- die( $entry );
+ OC_Template::printErrorPage( $entry );
}
$result=new DoctrineStatementWrapper($result);
}
@@ -213,12 +213,19 @@ class OC_DB {
*/
public static function insertid($table=null) {
self::connect();
- if($table !== null) {
- $prefix = OC_Config::getValue( "dbtableprefix", "oc_" );
- $suffix = OC_Config::getValue( "dbsequencesuffix", "_id_seq" );
- $table = str_replace( '*PREFIX*', $prefix, $table ).$suffix;
+ $type = OC_Config::getValue( "dbtype", "sqlite" );
+ if( $type == 'pgsql' ) {
+ $query = self::prepare('SELECT lastval() AS id');
+ $row = $query->execute()->fetchRow();
+ return $row['id'];
+ } else {
+ if($table !== null) {
+ $prefix = OC_Config::getValue( "dbtableprefix", "oc_" );
+ $suffix = OC_Config::getValue( "dbsequencesuffix", "_id_seq" );
+ $table = str_replace( '*PREFIX*', $prefix, $table ).$suffix;
+ }
+ return self::$connection->lastInsertId($table);
}
- return self::$connection->lastInsertId($table);
}
/**
@@ -301,6 +308,78 @@ class OC_DB {
}
/**
+ * @brief Insert a row if a matching row doesn't exists.
+ * @param string $table. The table to insert into in the form '*PREFIX*tableName'
+ * @param array $input. An array of fieldname/value pairs
+ * @returns The return value from PDOStatementWrapper->execute()
+ */
+ public static function insertIfNotExist($table, $input) {
+ self::connect();
+ $prefix = OC_Config::getValue( "dbtableprefix", "oc_" );
+ $table = str_replace( '*PREFIX*', $prefix, $table );
+
+ if(is_null(self::$type)) {
+ self::$type=OC_Config::getValue( "dbtype", "sqlite" );
+ }
+ $type = self::$type;
+
+ $query = '';
+ // differences in escaping of table names ('`' for mysql) and getting the current timestamp
+ if( $type == 'sqlite' || $type == 'sqlite3' ) {
+ // NOTE: For SQLite we have to use this clumsy approach
+ // otherwise all fieldnames used must have a unique key.
+ $query = 'SELECT * FROM "' . $table . '" WHERE ';
+ foreach($input as $key => $value) {
+ $query .= $key . " = '" . $value . '\' AND ';
+ }
+ $query = substr($query, 0, strlen($query) - 5);
+ try {
+ $stmt = self::prepare($query);
+ $result = $stmt->execute();
+ } catch(PDOException $e) {
+ $entry = 'DB Error: "'.$e->getMessage() . '"<br />';
+ $entry .= 'Offending command was: ' . $query . '<br />';
+ OC_Log::write('core', $entry, OC_Log::FATAL);
+ error_log('DB error: '.$entry);
+ OC_Template::printErrorPage( $entry );
+ }
+
+ if($result->numRows() == 0) {
+ $query = 'INSERT INTO "' . $table . '" ("'
+ . implode('","', array_keys($input)) . '") VALUES("'
+ . implode('","', array_values($input)) . '")';
+ } else {
+ return true;
+ }
+ } elseif( $type == 'pgsql' || $type == 'oci' || $type == 'mysql') {
+ $query = 'INSERT INTO `' .$table . '` ('
+ . implode(',', array_keys($input)) . ') SELECT \''
+ . implode('\',\'', array_values($input)) . '\' FROM ' . $table . ' WHERE ';
+
+ foreach($input as $key => $value) {
+ $query .= $key . " = '" . $value . '\' AND ';
+ }
+ $query = substr($query, 0, strlen($query) - 5);
+ $query .= ' HAVING COUNT(*) = 0';
+ }
+
+ // TODO: oci should be use " (quote) instead of ` (backtick).
+ //OC_Log::write('core', __METHOD__ . ', type: ' . $type . ', query: ' . $query, OC_Log::DEBUG);
+
+ try {
+ $result = self::prepare($query);
+ } catch(PDOException $e) {
+ $entry = 'DB Error: "'.$e->getMessage() . '"<br />';
+ $entry .= 'Offending command was: ' . $query.'<br />';
+ OC_Log::write('core', $entry, OC_Log::FATAL);
+ error_log('DB error: ' . $entry);
+ OC_Template::printErrorPage( $entry );
+ }
+
+ return $result->execute();
+ }
+
+ /**
* @brief does minor changes to query
* @param string $query Query string
* @return string corrected query string
@@ -403,7 +482,7 @@ class OC_DB {
return false;
}
}
-
+
/**
* returns the error code and message as a string for logging
* works with DoctrineException
diff --git a/lib/eventsource.php b/lib/eventsource.php
index 900b5b101e6..1b8033943a1 100644
--- a/lib/eventsource.php
+++ b/lib/eventsource.php
@@ -32,13 +32,13 @@ class OC_EventSource{
private $fallBackId=0;
public function __construct() {
- @ob_end_clean();
+ OC_Util::obEnd();
header('Cache-Control: no-cache');
$this->fallback=isset($_GET['fallback']) and $_GET['fallback']=='true';
if($this->fallback) {
$this->fallBackId=$_GET['fallback_id'];
header("Content-Type: text/html");
- echo str_repeat('<span></span>'.PHP_EOL,10); //dummy data to keep IE happy
+ echo str_repeat('<span></span>'.PHP_EOL, 10); //dummy data to keep IE happy
}else{
header("Content-Type: text/event-stream");
}
@@ -56,7 +56,7 @@ class OC_EventSource{
*
* if only one paramater is given, a typeless message will be send with that paramater as data
*/
- public function send($type,$data=null) {
+ public function send($type, $data=null) {
if(is_null($data)) {
$data=$type;
$type=null;
@@ -78,6 +78,6 @@ class OC_EventSource{
* close the connection of the even source
*/
public function close() {
- $this->send('__internal__','close');//server side closing can be an issue, let the client do it
+ $this->send('__internal__', 'close');//server side closing can be an issue, let the client do it
}
-} \ No newline at end of file
+}
diff --git a/lib/filecache.php b/lib/filecache.php
index 8fcb6fd9404..7bf98f43a37 100644
--- a/lib/filecache.php
+++ b/lib/filecache.php
@@ -28,6 +28,7 @@
* It will try to keep the data up to date but changes from outside ownCloud can invalidate the cache
*/
class OC_FileCache{
+
/**
* get the filesystem info from the cache
* @param string path
@@ -42,15 +43,15 @@ class OC_FileCache{
* - encrypted
* - versioned
*/
- public static function get($path,$root=false) {
- if(OC_FileCache_Update::hasUpdated($path,$root)) {
+ public static function get($path, $root=false) {
+ if(OC_FileCache_Update::hasUpdated($path, $root)) {
if($root===false) {//filesystem hooks are only valid for the default root
- OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path));
+ OC_Hook::emit('OC_Filesystem', 'post_write', array('path'=>$path));
}else{
- OC_FileCache_Update::update($path,$root);
+ OC_FileCache_Update::update($path, $root);
}
}
- return OC_FileCache_Cached::get($path,$root);
+ return OC_FileCache_Cached::get($path, $root);
}
/**
@@ -58,22 +59,22 @@ class OC_FileCache{
* @param string $path
* @param array data
* @param string root (optional)
- *
- * $data is an assiciative array in the same format as returned by get
+ * @note $data is an associative array in the same format as returned
+ * by get
*/
- public static function put($path,$data,$root=false) {
+ public static function put($path, $data, $root=false) {
if($root===false) {
$root=OC_Filesystem::getRoot();
}
- $fullpath=$root.$path;
+ $fullpath=OC_Filesystem::normalizePath($root.'/'.$path);
$parent=self::getParentId($fullpath);
- $id=self::getId($fullpath,'');
+ $id=self::getId($fullpath, '');
if(isset(OC_FileCache_Cached::$savedData[$fullpath])) {
- $data=array_merge(OC_FileCache_Cached::$savedData[$fullpath],$data);
+ $data=array_merge(OC_FileCache_Cached::$savedData[$fullpath], $data);
unset(OC_FileCache_Cached::$savedData[$fullpath]);
}
if($id!=-1) {
- self::update($id,$data);
+ self::update($id, $data);
return;
}
@@ -102,9 +103,9 @@ class OC_FileCache{
$data['versioned']=(int)$data['versioned'];
$user=OC_User::getUser();
$query=OC_DB::prepare('INSERT INTO `*PREFIX*fscache`(`parent`, `name`, `path`, `path_hash`, `size`, `mtime`, `ctime`, `mimetype`, `mimepart`,`user`,`writable`,`encrypted`,`versioned`) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)');
- $result=$query->execute(array($parent,basename($fullpath),$fullpath,md5($fullpath),$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable'],$data['encrypted'],$data['versioned']));
+ $result=$query->execute(array($parent, basename($fullpath), $fullpath, md5($fullpath), $data['size'], $data['mtime'], $data['ctime'], $data['mimetype'], $mimePart, $user, $data['writable'], $data['encrypted'], $data['versioned']));
if(OC_DB::isError($result)) {
- OC_Log::write('files','error while writing file('.$fullpath.') to cache',OC_Log::ERROR);
+ OC_Log::write('files', 'error while writing file('.$fullpath.') to cache', OC_Log::ERROR);
}
if($cache=OC_Cache::getUserCache(true)) {
@@ -117,10 +118,10 @@ class OC_FileCache{
* @param int $id
* @param array $data
*/
- private static function update($id,$data) {
+ private static function update($id, $data) {
$arguments=array();
$queryParts=array();
- foreach(array('size','mtime','ctime','mimetype','encrypted','versioned','writable') as $attribute) {
+ foreach(array('size','mtime','ctime','mimetype','encrypted','versioned', 'writable') as $attribute) {
if(isset($data[$attribute])) {
//Convert to int it args are false
if($data[$attribute] === false) {
@@ -137,11 +138,13 @@ class OC_FileCache{
}
$arguments[]=$id;
- $sql = 'UPDATE `*PREFIX*fscache` SET '.implode(' , ',$queryParts).' WHERE `id`=?';
- $query=OC_DB::prepare($sql);
- $result=$query->execute($arguments);
- if(OC_DB::isError($result)) {
- OC_Log::write('files','error while updating file('.$id.') in cache',OC_Log::ERROR);
+ if(!empty($queryParts)) {
+ $sql = 'UPDATE `*PREFIX*fscache` SET '.implode(' , ', $queryParts).' WHERE `id`=?';
+ $query=OC_DB::prepare($sql);
+ $result=$query->execute($arguments);
+ if(OC_DB::isError($result)) {
+ OC_Log::write('files', 'error while updating file('.$id.') in cache', OC_Log::ERROR);
+ }
}
}
@@ -151,7 +154,7 @@ class OC_FileCache{
* @param string newPath
* @param string root (optional)
*/
- public static function move($oldPath,$newPath,$root=false) {
+ public static function move($oldPath, $newPath, $root=false) {
if($root===false) {
$root=OC_Filesystem::getRoot();
}
@@ -163,10 +166,10 @@ class OC_FileCache{
$newPath=$root.$newPath;
$newParent=self::getParentId($newPath);
$query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `parent`=? ,`name`=?, `path`=?, `path_hash`=? WHERE `path_hash`=?');
- $query->execute(array($newParent,basename($newPath),$newPath,md5($newPath),md5($oldPath)));
+ $query->execute(array($newParent, basename($newPath), $newPath, md5($newPath), md5($oldPath)));
if(($cache=OC_Cache::getUserCache(true)) && $cache->hasKey('fileid/'.$oldPath)) {
- $cache->set('fileid/'.$newPath,$cache->get('fileid/'.$oldPath));
+ $cache->set('fileid/'.$newPath, $cache->get('fileid/'.$oldPath));
$cache->remove('fileid/'.$oldPath);
}
@@ -175,11 +178,11 @@ class OC_FileCache{
$updateQuery=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `path`=?, `path_hash`=? WHERE `path_hash`=?');
while($row= $query->execute(array($oldPath.'/%'))->fetchRow()) {
$old=$row['path'];
- $new=$newPath.substr($old,$oldLength);
- $updateQuery->execute(array($new,md5($new),md5($old)));
+ $new=$newPath.substr($old, $oldLength);
+ $updateQuery->execute(array($new, md5($new), md5($old)));
if(($cache=OC_Cache::getUserCache(true)) && $cache->hasKey('fileid/'.$old)) {
- $cache->set('fileid/'.$new,$cache->get('fileid/'.$old));
+ $cache->set('fileid/'.$new, $cache->get('fileid/'.$old));
$cache->remove('fileid/'.$old);
}
}
@@ -190,7 +193,7 @@ class OC_FileCache{
* @param string path
* @param string root (optional)
*/
- public static function delete($path,$root=false) {
+ public static function delete($path, $root=false) {
if($root===false) {
$root=OC_Filesystem::getRoot();
}
@@ -203,7 +206,7 @@ class OC_FileCache{
OC_Cache::remove('fileid/'.$root.$path);
}
-
+
/**
* return array of filenames matching the querty
* @param string $query
@@ -211,23 +214,29 @@ class OC_FileCache{
* @param string root (optional)
* @return array of filepaths
*/
- public static function search($search,$returnData=false,$root=false) {
+ public static function search($search, $returnData=false, $root=false) {
if($root===false) {
$root=OC_Filesystem::getRoot();
}
$rootLen=strlen($root);
if(!$returnData) {
- $query=OC_DB::prepare('SELECT `path` FROM `*PREFIX*fscache` WHERE `name` LIKE ? AND `user`=?');
+ $select = '`path`';
}else{
- $query=OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `name` LIKE ? AND `user`=?');
+ $select = '*';
+ }
+ if (OC_Config::getValue('dbtype') === 'oci8') {
+ $where = 'LOWER(`name`) LIKE LOWER(?) AND `user`=?';
+ } else {
+ $where = '`name` LIKE ? AND `user`=?';
}
- $result=$query->execute(array("%$search%",OC_User::getUser()));
+ $query=OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*fscache` WHERE '.$where);
+ $result=$query->execute(array("%$search%", OC_User::getUser()));
$names=array();
while($row=$result->fetchRow()) {
if(!$returnData) {
- $names[]=substr($row['path'],$rootLen);
+ $names[]=substr($row['path'], $rootLen);
}else{
- $row['path']=substr($row['path'],$rootLen);
+ $row['path']=substr($row['path'], $rootLen);
$names[]=$row;
}
}
@@ -249,11 +258,11 @@ class OC_FileCache{
* - encrypted
* - versioned
*/
- public static function getFolderContent($path,$root=false,$mimetype_filter='') {
- if(OC_FileCache_Update::hasUpdated($path,$root,true)) {
- OC_FileCache_Update::updateFolder($path,$root);
+ public static function getFolderContent($path, $root=false, $mimetype_filter='') {
+ if(OC_FileCache_Update::hasUpdated($path, $root, true)) {
+ OC_FileCache_Update::updateFolder($path, $root);
}
- return OC_FileCache_Cached::getFolderContent($path,$root,$mimetype_filter);
+ return OC_FileCache_Cached::getFolderContent($path, $root, $mimetype_filter);
}
/**
@@ -262,8 +271,8 @@ class OC_FileCache{
* @param string root (optional)
* @return bool
*/
- public static function inCache($path,$root=false) {
- return self::getId($path,$root)!=-1;
+ public static function inCache($path, $root=false) {
+ return self::getId($path, $root)!=-1;
}
/**
@@ -272,7 +281,7 @@ class OC_FileCache{
* @param string root (optional)
* @return int
*/
- public static function getId($path,$root=false) {
+ public static function getId($path, $root=false) {
if($root===false) {
$root=OC_Filesystem::getRoot();
}
@@ -285,7 +294,7 @@ class OC_FileCache{
$query=OC_DB::prepare('SELECT `id` FROM `*PREFIX*fscache` WHERE `path_hash`=?');
$result=$query->execute(array(md5($fullPath)));
if(OC_DB::isError($result)) {
- OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR);
+ OC_Log::write('files', 'error while getting file id of '.$path, OC_Log::ERROR);
return -1;
}
@@ -296,7 +305,7 @@ class OC_FileCache{
$id=-1;
}
if($cache=OC_Cache::getUserCache(true)) {
- $cache->set('fileid/'.$fullPath,$id);
+ $cache->set('fileid/'.$fullPath, $id);
}
return $id;
@@ -308,19 +317,19 @@ class OC_FileCache{
* @param string user (optional)
* @return string
*/
- public static function getPath($id,$user='') {
+ public static function getPath($id, $user='') {
if(!$user) {
$user=OC_User::getUser();
}
$query=OC_DB::prepare('SELECT `path` FROM `*PREFIX*fscache` WHERE `id`=? AND `user`=?');
- $result=$query->execute(array($id,$user));
+ $result=$query->execute(array($id, $user));
$row=$result->fetchRow();
$path=$row['path'];
$root='/'.$user.'/files';
- if(substr($path,0,strlen($root))!=$root) {
+ if(substr($path, 0, strlen($root))!=$root) {
return false;
}
- return substr($path,strlen($root));
+ return substr($path, strlen($root));
}
/**
@@ -332,7 +341,7 @@ class OC_FileCache{
if($path=='/') {
return -1;
}else{
- return self::getId(dirname($path),'');
+ return self::getId(dirname($path), '');
}
}
@@ -342,27 +351,40 @@ class OC_FileCache{
* @param int $sizeDiff
* @param string root (optinal)
*/
- public static function increaseSize($path,$sizeDiff, $root=false) {
+ public static function increaseSize($path, $sizeDiff, $root=false) {
if($sizeDiff==0) return;
- $id=self::getId($path,$root);
+ $item = OC_FileCache_Cached::get($path);
+ //stop walking up the filetree if we hit a non-folder
+ if($item['mimetype'] !== 'httpd/unix-directory'){
+ return;
+ }
+ $id = $item['id'];
while($id!=-1) {//walk up the filetree increasing the size of all parent folders
$query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `size`=`size`+? WHERE `id`=?');
- $query->execute(array($sizeDiff,$id));
- $id=self::getParentId($path);
+ $query->execute(array($sizeDiff, $id));
+ if($path == '' or $path =='/'){
+ return;
+ }
$path=dirname($path);
+ $parent = OC_FileCache_Cached::get($path);
+ $id = $parent['id'];
+ //stop walking up the filetree if we hit a non-folder
+ if($parent['mimetype'] !== 'httpd/unix-directory'){
+ return;
+ }
}
}
/**
* recursively scan the filesystem and fill the cache
* @param string $path
- * @param OC_EventSource $enventSource (optional)
- * @param int count (optional)
- * @param string root (optional)
+ * @param OC_EventSource $eventSource (optional)
+ * @param int $count (optional)
+ * @param string $root (optional)
*/
- public static function scan($path,$eventSource=false,&$count=0,$root=false) {
+ public static function scan($path, $eventSource=false,&$count=0, $root=false) {
if($eventSource) {
- $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
+ $eventSource->send('scanning', array('file'=>$path, 'count'=>$count));
}
$lastSend=$count;
// NOTE: Ugly hack to prevent shared files from going into the cache (the source already exists somewhere in the cache)
@@ -374,7 +396,7 @@ class OC_FileCache{
}else{
$view=new OC_FilesystemView($root);
}
- self::scanFile($path,$root);
+ self::scanFile($path, $root);
$dh=$view->opendir($path.'/');
$totalSize=0;
if($dh) {
@@ -382,21 +404,21 @@ class OC_FileCache{
if($filename != '.' and $filename != '..') {
$file=$path.'/'.$filename;
if($view->is_dir($file.'/')) {
- self::scan($file,$eventSource,$count,$root);
+ self::scan($file, $eventSource, $count, $root);
}else{
- $totalSize+=self::scanFile($file,$root);
+ $totalSize+=self::scanFile($file, $root);
$count++;
if($count>$lastSend+25 and $eventSource) {
$lastSend=$count;
- $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
+ $eventSource->send('scanning', array('file'=>$path, 'count'=>$count));
}
}
}
}
}
- OC_FileCache_Update::cleanFolder($path,$root);
- self::increaseSize($path,$totalSize,$root);
+ OC_FileCache_Update::cleanFolder($path, $root);
+ self::increaseSize($path, $totalSize, $root);
}
/**
@@ -405,7 +427,7 @@ class OC_FileCache{
* @param string root (optional)
* @return int size of the scanned file
*/
- public static function scanFile($path,$root=false) {
+ public static function scanFile($path, $root=false) {
// NOTE: Ugly hack to prevent shared files from going into the cache (the source already exists somewhere in the cache)
if (substr($path, 0, 7) == '/Shared') {
return;
@@ -430,7 +452,7 @@ class OC_FileCache{
if($path=='/') {
$path='';
}
- self::put($path,$stat,$root);
+ self::put($path, $stat, $root);
return $stat['size'];
}
@@ -442,12 +464,12 @@ class OC_FileCache{
* @return array of file paths
*
* $part1 and $part2 together form the complete mimetype.
- * e.g. searchByMime('text','plain')
+ * e.g. searchByMime('text', 'plain')
*
* seccond mimetype part can be ommited
* e.g. searchByMime('audio')
*/
- public static function searchByMime($part1,$part2=null,$root=false) {
+ public static function searchByMime($part1, $part2=null, $root=false) {
if($root===false) {
$root=OC_Filesystem::getRoot();
}
@@ -456,14 +478,14 @@ class OC_FileCache{
$user=OC_User::getUser();
if(!$part2) {
$query=OC_DB::prepare('SELECT `path` FROM `*PREFIX*fscache` WHERE `mimepart`=? AND `user`=? AND `path` LIKE ?');
- $result=$query->execute(array($part1,$user, $root));
+ $result=$query->execute(array($part1, $user, $root));
}else{
$query=OC_DB::prepare('SELECT `path` FROM `*PREFIX*fscache` WHERE `mimetype`=? AND `user`=? AND `path` LIKE ? ');
- $result=$query->execute(array($part1.'/'.$part2,$user, $root));
+ $result=$query->execute(array($part1.'/'.$part2, $user, $root));
}
$names=array();
while($row=$result->fetchRow()) {
- $names[]=substr($row['path'],$rootLen);
+ $names[]=substr($row['path'], $rootLen);
}
return $names;
}
@@ -494,18 +516,19 @@ class OC_FileCache{
* trigger an update for the cache by setting the mtimes to 0
* @param string $user (optional)
*/
- public static function triggerUpdate($user=''){
+ public static function triggerUpdate($user='') {
if($user) {
- $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 WHERE `user`=? AND `mimetype`="httpd/unix-directory"');
- $query->execute(array($user));
+ $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 WHERE `user`=? AND `mimetype`= ? ');
+ $query->execute(array($user,'httpd/unix-directory'));
}else{
- $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 AND `mimetype`="httpd/unix-directory"');
- $query->execute();
+ $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 AND `mimetype`= ? ');
+ $query->execute(array('httpd/unix-directory'));
}
}
}
//watch for changes and try to keep the cache up to date
-OC_Hook::connect('OC_Filesystem','post_write','OC_FileCache_Update','fileSystemWatcherWrite');
-OC_Hook::connect('OC_Filesystem','post_delete','OC_FileCache_Update','fileSystemWatcherDelete');
-OC_Hook::connect('OC_Filesystem','post_rename','OC_FileCache_Update','fileSystemWatcherRename');
+OC_Hook::connect('OC_Filesystem', 'post_write', 'OC_FileCache_Update', 'fileSystemWatcherWrite');
+OC_Hook::connect('OC_Filesystem', 'post_delete', 'OC_FileCache_Update', 'fileSystemWatcherDelete');
+OC_Hook::connect('OC_Filesystem', 'post_rename', 'OC_FileCache_Update', 'fileSystemWatcherRename');
+OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_FileCache_Update', 'deleteFromUser');
diff --git a/lib/filecache/cached.php b/lib/filecache/cached.php
index 9b1eb4f7803..5e0a00746b9 100644
--- a/lib/filecache/cached.php
+++ b/lib/filecache/cached.php
@@ -13,12 +13,12 @@
class OC_FileCache_Cached{
public static $savedData=array();
- public static function get($path,$root=false) {
+ public static function get($path, $root=false) {
if($root===false) {
$root=OC_Filesystem::getRoot();
}
$path=$root.$path;
- $stmt=OC_DB::prepare('SELECT `path`,`ctime`,`mtime`,`mimetype`,`size`,`encrypted`,`versioned`,`writable` FROM `*PREFIX*fscache` WHERE `path_hash`=?');
+ $stmt=OC_DB::prepare('SELECT `id`, `path`,`ctime`,`mtime`,`mimetype`,`size`,`encrypted`,`versioned`,`writable` FROM `*PREFIX*fscache` WHERE `path_hash`=?');
if ( ! OC_DB::isError($stmt) ) {
$result=$stmt->execute(array(md5($path)));
if ( ! OC_DB::isError($result) ) {
@@ -61,7 +61,7 @@ class OC_FileCache_Cached{
* - encrypted
* - versioned
*/
- public static function getFolderContent($path,$root=false,$mimetype_filter='') {
+ public static function getFolderContent($path, $root=false, $mimetype_filter='') {
if($root===false) {
$root=OC_Filesystem::getRoot();
}
@@ -78,4 +78,4 @@ class OC_FileCache_Cached{
return false;
}
}
-} \ No newline at end of file
+}
diff --git a/lib/filecache/update.php b/lib/filecache/update.php
index 4a5ea873b17..bc403113e7c 100644
--- a/lib/filecache/update.php
+++ b/lib/filecache/update.php
@@ -18,7 +18,7 @@ class OC_FileCache_Update{
* @param boolean folder
* @return bool
*/
- public static function hasUpdated($path,$root=false,$folder=false) {
+ public static function hasUpdated($path, $root=false, $folder=false) {
if($root===false) {
$view=OC_Filesystem::getView();
}else{
@@ -46,14 +46,14 @@ class OC_FileCache_Update{
/**
* delete non existing files from the cache
*/
- public static function cleanFolder($path,$root=false) {
+ public static function cleanFolder($path, $root=false) {
if($root===false) {
$view=OC_Filesystem::getView();
}else{
$view=new OC_FilesystemView($root);
}
- $cachedContent=OC_FileCache_Cached::getFolderContent($path,$root);
+ $cachedContent=OC_FileCache_Cached::getFolderContent($path, $root);
foreach($cachedContent as $fileData) {
$path=$fileData['path'];
$file=$view->getRelativePath($path);
@@ -72,7 +72,7 @@ class OC_FileCache_Update{
* @param string path
* @param string root (optional)
*/
- public static function updateFolder($path,$root=false) {
+ public static function updateFolder($path, $root=false) {
if($root===false) {
$view=OC_Filesystem::getView();
}else{
@@ -85,7 +85,7 @@ class OC_FileCache_Update{
$file=$path.'/'.$filename;
$isDir=$view->is_dir($file);
if(self::hasUpdated($file, $root, $isDir)) {
- if($isDir){
+ if($isDir) {
self::updateFolder($file, $root);
}elseif($root===false) {//filesystem hooks are only valid for the default root
OC_Hook::emit('OC_Filesystem', 'post_write', array('path'=>$file));
@@ -143,7 +143,7 @@ class OC_FileCache_Update{
* @param string path
* @param string root (optional)
*/
- public static function update($path,$root=false) {
+ public static function update($path, $root=false) {
if($root===false) {
$view=OC_Filesystem::getView();
}else{
@@ -153,7 +153,7 @@ class OC_FileCache_Update{
$mimetype=$view->getMimeType($path);
$size=0;
- $cached=OC_FileCache_Cached::get($path,$root);
+ $cached=OC_FileCache_Cached::get($path, $root);
$cachedSize=isset($cached['size'])?$cached['size']:0;
if($view->is_dir($path.'/')) {
@@ -165,7 +165,7 @@ class OC_FileCache_Update{
$mtime=$view->filemtime($path.'/');
$ctime=$view->filectime($path.'/');
$writable=$view->is_writable($path.'/');
- OC_FileCache::put($path, array('size'=>$size,'mtime'=>$mtime,'ctime'=>$ctime,'mimetype'=>$mimetype,'writable'=>$writable));
+ OC_FileCache::put($path, array('size'=>$size,'mtime'=>$mtime,'ctime'=>$ctime,'mimetype'=>$mimetype, 'writable'=>$writable));
}else{
$count=0;
OC_FileCache::scan($path, null, $count, $root);
@@ -174,7 +174,7 @@ class OC_FileCache_Update{
}else{
$size=OC_FileCache::scanFile($path, $root);
}
- if($path !== '' and $path !== '/'){
+ if($path !== '' and $path !== '/') {
OC_FileCache::increaseSize(dirname($path), $size-$cachedSize, $root);
}
}
@@ -184,7 +184,7 @@ class OC_FileCache_Update{
* @param string path
* @param string root (optional)
*/
- public static function delete($path,$root=false) {
+ public static function delete($path, $root=false) {
$cached=OC_FileCache_Cached::get($path, $root);
if(!isset($cached['size'])) {
return;
@@ -200,7 +200,7 @@ class OC_FileCache_Update{
* @param string newPath
* @param string root (optional)
*/
- public static function rename($oldPath,$newPath,$root=false) {
+ public static function rename($oldPath, $newPath, $root=false) {
if(!OC_FileCache::inCache($oldPath, $root)) {
return;
}
@@ -216,4 +216,12 @@ class OC_FileCache_Update{
OC_FileCache::increaseSize(dirname($newPath), $oldSize, $root);
OC_FileCache::move($oldPath, $newPath);
}
+
+ /**
+ * delete files owned by user from the cache
+ * @param string $parameters$parameters["uid"])
+ */
+ public static function deleteFromUser($parameters) {
+ OC_FileCache::clear($parameters["uid"]);
+ }
}
diff --git a/lib/filechunking.php b/lib/filechunking.php
index 5ab33c77ad7..55a4d730430 100644
--- a/lib/filechunking.php
+++ b/lib/filechunking.php
@@ -59,7 +59,7 @@ class OC_FileChunking {
for($i=0; $i < $this->info['chunkcount']; $i++) {
$chunk = $cache->get($prefix.$i);
$cache->remove($prefix.$i);
- $count += fwrite($f,$chunk);
+ $count += fwrite($f, $chunk);
}
return $count;
}
diff --git a/lib/fileproxy.php b/lib/fileproxy.php
index 17380c656a3..2f81bde64a1 100644
--- a/lib/fileproxy.php
+++ b/lib/fileproxy.php
@@ -51,8 +51,8 @@ class OC_FileProxy{
*
* this implements a dummy proxy for all operations
*/
- public function __call($function,$arguments) {
- if(substr($function,0,3)=='pre') {
+ public function __call($function, $arguments) {
+ if(substr($function, 0, 3)=='pre') {
return true;
}else{
return $arguments[1];
@@ -70,7 +70,7 @@ class OC_FileProxy{
public static function getProxies($operation) {
$proxies=array();
foreach(self::$proxies as $proxy) {
- if(method_exists($proxy,$operation)) {
+ if(method_exists($proxy, $operation)) {
$proxies[]=$proxy;
}
}
@@ -85,7 +85,7 @@ class OC_FileProxy{
$proxies=self::getProxies($operation);
foreach($proxies as $proxy) {
if(!is_null($filepath2)) {
- if($proxy->$operation($filepath,$filepath2)===false) {
+ if($proxy->$operation($filepath, $filepath2)===false) {
return false;
}
}else{
@@ -97,14 +97,14 @@ class OC_FileProxy{
return true;
}
- public static function runPostProxies($operation,$path,$result) {
+ public static function runPostProxies($operation, $path, $result) {
if(!self::$enabled) {
return $result;
}
$operation='post'.$operation;
$proxies=self::getProxies($operation);
foreach($proxies as $proxy) {
- $result=$proxy->$operation($path,$result);
+ $result=$proxy->$operation($path, $result);
}
return $result;
}
diff --git a/lib/fileproxy/fileoperations.php b/lib/fileproxy/fileoperations.php
index fe7edafad2b..516629adaec 100644
--- a/lib/fileproxy/fileoperations.php
+++ b/lib/fileproxy/fileoperations.php
@@ -1,37 +1,37 @@
<?php
-/**
- * ownCloud
- *
- * @author Bjoern Schiessle
- * @copyright 2012 Bjoern Schiessle <schiessle@owncloud.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/**
- * check if standard file operations
+/**
+ * ownCloud
+ *
+ * @author Bjoern Schiessle
+ * @copyright 2012 Bjoern Schiessle <schiessle@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
-
-class OC_FileProxy_FileOperations extends OC_FileProxy{
- static $rootView;
- public function premkdir($path) {
- if(!self::$rootView){
- self::$rootView = new OC_FilesystemView('');
+/**
+ * check if standard file operations
+ */
+
+class OC_FileProxy_FileOperations extends OC_FileProxy{
+ static $rootView;
+
+ public function premkdir($path) {
+ if(!self::$rootView) {
+ self::$rootView = new OC_FilesystemView('');
}
- return !self::$rootView->file_exists($path);
+ return !self::$rootView->file_exists($path);
}
-
+
} \ No newline at end of file
diff --git a/lib/fileproxy/quota.php b/lib/fileproxy/quota.php
index 5a0dbdb6fe2..742e02d471b 100644
--- a/lib/fileproxy/quota.php
+++ b/lib/fileproxy/quota.php
@@ -27,77 +27,83 @@
class OC_FileProxy_Quota extends OC_FileProxy{
static $rootView;
- private $userQuota=-1;
+ private $userQuota=array();
/**
- * get the quota for the current user
+ * get the quota for the user
+ * @param user
* @return int
*/
- private function getQuota() {
- if($this->userQuota!=-1) {
- return $this->userQuota;
+ private function getQuota($user) {
+ if(in_array($user, $this->userQuota)) {
+ return $this->userQuota[$user];
}
- $userQuota=OC_Preferences::getValue(OC_User::getUser(),'files','quota','default');
+ $userQuota=OC_Preferences::getValue($user, 'files', 'quota', 'default');
if($userQuota=='default') {
- $userQuota=OC_AppConfig::getValue('files','default_quota','none');
+ $userQuota=OC_AppConfig::getValue('files', 'default_quota', 'none');
}
if($userQuota=='none') {
- $this->userQuota=0;
+ $this->userQuota[$user]=-1;
}else{
- $this->userQuota=OC_Helper::computerFileSize($userQuota);
+ $this->userQuota[$user]=OC_Helper::computerFileSize($userQuota);
}
- return $this->userQuota;
+ return $this->userQuota[$user];
}
/**
- * get the free space in the users home folder
+ * get the free space in the path's owner home folder
+ * @param path
* @return int
*/
- private function getFreeSpace() {
- $rootInfo=OC_FileCache_Cached::get('');
+ private function getFreeSpace($path) {
+ $storage=OC_Filesystem::getStorage($path);
+ $owner=$storage->getOwner($path);
+
+ $totalSpace=$this->getQuota($owner);
+ if($totalSpace==-1) {
+ return -1;
+ }
+
+ $rootInfo=OC_FileCache::get('', "/".$owner."/files");
// TODO Remove after merge of share_api
- if (OC_FileCache::inCache('/Shared')) {
- $sharedInfo=OC_FileCache_Cached::get('/Shared');
+ if (OC_FileCache::inCache('/Shared', "/".$owner."/files")) {
+ $sharedInfo=OC_FileCache::get('/Shared', "/".$owner."/files");
} else {
$sharedInfo = null;
}
$usedSpace=isset($rootInfo['size'])?$rootInfo['size']:0;
$usedSpace=isset($sharedInfo['size'])?$usedSpace-$sharedInfo['size']:$usedSpace;
- $totalSpace=$this->getQuota();
- if($totalSpace==0) {
- return 0;
- }
return $totalSpace-$usedSpace;
}
-
- public function postFree_space($path,$space) {
- $free=$this->getFreeSpace();
- if($free==0) {
+
+ public function postFree_space($path, $space) {
+ $free=$this->getFreeSpace($path);
+ if($free==-1) {
return $space;
}
- return min($free,$space);
+ return min($free, $space);
}
- public function preFile_put_contents($path,$data) {
+ public function preFile_put_contents($path, $data) {
if (is_resource($data)) {
$data = '';//TODO: find a way to get the length of the stream without emptying it
}
- return (strlen($data)<$this->getFreeSpace() or $this->getFreeSpace()==0);
+ return (strlen($data)<$this->getFreeSpace($path) or $this->getFreeSpace($path)==-1);
}
- public function preCopy($path1,$path2) {
- if(!self::$rootView){
+ public function preCopy($path1, $path2) {
+ if(!self::$rootView) {
self::$rootView = new OC_FilesystemView('');
}
- return (self::$rootView->filesize($path1)<$this->getFreeSpace() or $this->getFreeSpace()==0);
+ return (self::$rootView->filesize($path1)<$this->getFreeSpace($path2) or $this->getFreeSpace($path2)==-1);
}
- public function preFromTmpFile($tmpfile,$path) {
- return (filesize($tmpfile)<$this->getFreeSpace() or $this->getFreeSpace()==0);
+ public function preFromTmpFile($tmpfile, $path) {
+ return (filesize($tmpfile)<$this->getFreeSpace($path) or $this->getFreeSpace($path)==-1);
}
- public function preFromUploadedFile($tmpfile,$path) {
- return (filesize($tmpfile)<$this->getFreeSpace() or $this->getFreeSpace()==0);
+ public function preFromUploadedFile($tmpfile, $path) {
+ return (filesize($tmpfile)<$this->getFreeSpace($path) or $this->getFreeSpace($path)==-1);
}
}
diff --git a/lib/files.php b/lib/files.php
index 2b2b8b42dc4..b4a4145a493 100644
--- a/lib/files.php
+++ b/lib/files.php
@@ -42,16 +42,20 @@ class OC_Files {
* - versioned
*/
public static function getFileInfo($path) {
+ $path = OC_Filesystem::normalizePath($path);
if (($path == '/Shared' || substr($path, 0, 8) == '/Shared/') && OC_App::isEnabled('files_sharing')) {
if ($path == '/Shared') {
list($info) = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP_ROOT);
- }else{
- $info['size'] = OC_Filesystem::filesize($path);
- $info['mtime'] = OC_Filesystem::filemtime($path);
- $info['ctime'] = OC_Filesystem::filectime($path);
- $info['mimetype'] = OC_Filesystem::getMimeType($path);
- $info['encrypted'] = false;
- $info['versioned'] = false;
+ } else {
+ $info = array();
+ if (OC_Filesystem::file_exists($path)) {
+ $info['size'] = OC_Filesystem::filesize($path);
+ $info['mtime'] = OC_Filesystem::filemtime($path);
+ $info['ctime'] = OC_Filesystem::filectime($path);
+ $info['mimetype'] = OC_Filesystem::getMimeType($path);
+ $info['encrypted'] = false;
+ $info['versioned'] = false;
+ }
}
} else {
$info = OC_FileCache::get($path);
@@ -87,16 +91,16 @@ class OC_Files {
foreach ($files as &$file) {
$file['directory'] = $directory;
$file['type'] = ($file['mimetype'] == 'httpd/unix-directory') ? 'dir' : 'file';
- $permissions = OCP\Share::PERMISSION_READ;
+ $permissions = OCP\PERMISSION_READ;
// NOTE: Remove check when new encryption is merged
if (!$file['encrypted']) {
- $permissions |= OCP\Share::PERMISSION_SHARE;
+ $permissions |= OCP\PERMISSION_SHARE;
}
if ($file['type'] == 'dir' && $file['writable']) {
- $permissions |= OCP\Share::PERMISSION_CREATE;
+ $permissions |= OCP\PERMISSION_CREATE;
}
if ($file['writable']) {
- $permissions |= OCP\Share::PERMISSION_UPDATE | OCP\Share::PERMISSION_DELETE;
+ $permissions |= OCP\PERMISSION_UPDATE | OCP\PERMISSION_DELETE;
}
$file['permissions'] = $permissions;
}
@@ -135,18 +139,27 @@ class OC_Files {
* @param file $file ; seperated list of files to download
* @param boolean $only_header ; boolean to only send header of the request
*/
- public static function get($dir,$files, $only_header = false) {
- if(strpos($files,';')) {
- $files=explode(';',$files);
+ public static function get($dir, $files, $only_header = false) {
+ $xsendfile = false;
+ if (isset($_SERVER['MOD_X_SENDFILE_ENABLED']) ||
+ isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) {
+ $xsendfile = true;
+ }
+ if(strpos($files, ';')) {
+ $files=explode(';', $files);
}
if(is_array($files)) {
- self::validateZipDownload($dir,$files);
+ self::validateZipDownload($dir, $files);
$executionTime = intval(ini_get('max_execution_time'));
set_time_limit(0);
$zip = new ZipArchive();
- $filename = OC_Helper::tmpFile('.zip');
- if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) {
+ if ($xsendfile) {
+ $filename = OC_Helper::tmpFileNoClean('.zip');
+ }else{
+ $filename = OC_Helper::tmpFile('.zip');
+ }
+ if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) {
exit("cannot open <$filename>\n");
}
foreach($files as $file) {
@@ -154,31 +167,35 @@ class OC_Files {
if(OC_Filesystem::is_file($file)) {
$tmpFile=OC_Filesystem::toTmpFile($file);
self::$tmpFiles[]=$tmpFile;
- $zip->addFile($tmpFile,basename($file));
+ $zip->addFile($tmpFile, basename($file));
}elseif(OC_Filesystem::is_dir($file)) {
- self::zipAddDir($file,$zip);
+ self::zipAddDir($file, $zip);
}
}
$zip->close();
set_time_limit($executionTime);
}elseif(OC_Filesystem::is_dir($dir.'/'.$files)) {
- self::validateZipDownload($dir,$files);
+ self::validateZipDownload($dir, $files);
$executionTime = intval(ini_get('max_execution_time'));
set_time_limit(0);
$zip = new ZipArchive();
- $filename = OC_Helper::tmpFile('.zip');
- if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) {
+ if ($xsendfile) {
+ $filename = OC_Helper::tmpFileNoClean('.zip');
+ }else{
+ $filename = OC_Helper::tmpFile('.zip');
+ }
+ if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) {
exit("cannot open <$filename>\n");
}
$file=$dir.'/'.$files;
- self::zipAddDir($file,$zip);
+ self::zipAddDir($file, $zip);
$zip->close();
set_time_limit($executionTime);
}else{
$zip=false;
$filename=$dir.'/'.$files;
}
- @ob_end_clean();
+ OC_Util::obEnd();
if($zip or OC_Filesystem::is_readable($filename)) {
header('Content-Disposition: attachment; filename="'.basename($filename).'"');
header('Content-Transfer-Encoding: binary');
@@ -187,13 +204,18 @@ class OC_Files {
ini_set('zlib.output_compression', 'off');
header('Content-Type: application/zip');
header('Content-Length: ' . filesize($filename));
+ self::addSendfileHeader($filename);
}else{
header('Content-Type: '.OC_Filesystem::getMimeType($filename));
+ $storage = OC_Filesystem::getStorage($filename);
+ if ($storage instanceof OC_Filestorage_Local) {
+ self::addSendfileHeader(OC_Filesystem::getLocalFile($filename));
+ }
}
}elseif($zip or !OC_Filesystem::file_exists($filename)) {
header("HTTP/1.0 404 Not Found");
$tmpl = new OC_Template( '', '404', 'guest' );
- $tmpl->assign('file',$filename);
+ $tmpl->assign('file', $filename);
$tmpl->printPage();
}else{
header("HTTP/1.0 403 Forbidden");
@@ -205,7 +227,7 @@ class OC_Files {
return ;
}
if($zip) {
- $handle=fopen($filename,'r');
+ $handle=fopen($filename, 'r');
if ($handle) {
$chunkSize = 8*1024;// 1 MB chunks
while (!feof($handle)) {
@@ -213,7 +235,9 @@ class OC_Files {
flush();
}
}
- unlink($filename);
+ if (!$xsendfile) {
+ unlink($filename);
+ }
}else{
OC_Filesystem::readfile($filename);
}
@@ -224,20 +248,29 @@ class OC_Files {
}
}
- public static function zipAddDir($dir,$zip,$internalDir='') {
+ private static function addSendfileHeader($filename) {
+ if (isset($_SERVER['MOD_X_SENDFILE_ENABLED'])) {
+ header("X-Sendfile: " . $filename);
+ }
+ if (isset($_SERVER['MOD_X_ACCEL_REDIRECT_ENABLED'])) {
+ header("X-Accel-Redirect: " . $filename);
+ }
+ }
+
+ public static function zipAddDir($dir, $zip, $internalDir='') {
$dirname=basename($dir);
$zip->addEmptyDir($internalDir.$dirname);
$internalDir.=$dirname.='/';
- $files=OC_Files::getdirectorycontent($dir);
+ $files=OC_Files::getDirectoryContent($dir);
foreach($files as $file) {
$filename=$file['name'];
$file=$dir.'/'.$filename;
if(OC_Filesystem::is_file($file)) {
$tmpFile=OC_Filesystem::toTmpFile($file);
OC_Files::$tmpFiles[]=$tmpFile;
- $zip->addFile($tmpFile,$internalDir.$filename);
+ $zip->addFile($tmpFile, $internalDir.$filename);
}elseif(OC_Filesystem::is_dir($file)) {
- self::zipAddDir($file,$zip,$internalDir);
+ self::zipAddDir($file, $zip, $internalDir);
}
}
}
@@ -249,11 +282,11 @@ class OC_Files {
* @param dir $targetDir
* @param file $target
*/
- public static function move($sourceDir,$source,$targetDir,$target) {
+ public static function move($sourceDir, $source, $targetDir, $target) {
if(OC_User::isLoggedIn() && ($sourceDir != '' || $source != 'Shared')) {
$targetFile=self::normalizePath($targetDir.'/'.$target);
$sourceFile=self::normalizePath($sourceDir.'/'.$source);
- return OC_Filesystem::rename($sourceFile,$targetFile);
+ return OC_Filesystem::rename($sourceFile, $targetFile);
} else {
return false;
}
@@ -267,11 +300,11 @@ class OC_Files {
* @param dir $targetDir
* @param file $target
*/
- public static function copy($sourceDir,$source,$targetDir,$target) {
+ public static function copy($sourceDir, $source, $targetDir, $target) {
if(OC_User::isLoggedIn()) {
$targetFile=$targetDir.'/'.$target;
$sourceFile=$sourceDir.'/'.$source;
- return OC_Filesystem::copy($sourceFile,$targetFile);
+ return OC_Filesystem::copy($sourceFile, $targetFile);
}
}
@@ -282,7 +315,7 @@ class OC_Files {
* @param file $name
* @param type $type
*/
- public static function newFile($dir,$name,$type) {
+ public static function newFile($dir, $name, $type) {
if(OC_User::isLoggedIn()) {
$file=$dir.'/'.$name;
if($type=='dir') {
@@ -305,7 +338,7 @@ class OC_Files {
* @param dir $dir
* @param file $name
*/
- public static function delete($dir,$file) {
+ public static function delete($dir, $file) {
if(OC_User::isLoggedIn() && ($dir!= '' || $file != 'Shared')) {
$file=$dir.'/'.$file;
return OC_Filesystem::unlink($file);
@@ -389,12 +422,12 @@ class OC_Files {
* @param string file
* @return string guessed mime type
*/
- static function pull($source,$token,$dir,$file) {
- $tmpfile=tempnam(get_temp_dir(),'remoteCloudFile');
- $fp=fopen($tmpfile,'w+');
+ static function pull($source, $token, $dir, $file) {
+ $tmpfile=tempnam(get_temp_dir(), 'remoteCloudFile');
+ $fp=fopen($tmpfile, 'w+');
$url=$source.="/files/pull.php?token=$token";
$ch=curl_init();
- curl_setopt($ch,CURLOPT_URL,$url);
+ curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_exec($ch);
fclose($fp);
@@ -402,7 +435,7 @@ class OC_Files {
$httpCode=$info['http_code'];
curl_close($ch);
if($httpCode==200 or $httpCode==0) {
- OC_Filesystem::fromTmpFile($tmpfile,$dir.'/'.$file);
+ OC_Filesystem::fromTmpFile($tmpfile, $dir.'/'.$file);
return true;
}else{
return false;
@@ -423,8 +456,8 @@ class OC_Files {
$size -=1;
} else {
$size=OC_Helper::humanFileSize($size);
- $size=substr($size,0,-1);//strip the B
- $size=str_replace(' ','',$size); //remove the space between the size and the postfix
+ $size=substr($size, 0, -1);//strip the B
+ $size=str_replace(' ', '', $size); //remove the space between the size and the postfix
}
//don't allow user to break his config -- broken or malicious size input
@@ -447,7 +480,7 @@ class OC_Files {
$setting = 'php_value '.$key.' '.$size;
$hasReplaced = 0;
$content = preg_replace($pattern, $setting, $htaccess, 1, $hasReplaced);
- if($content !== NULL) {
+ if($content !== null) {
$htaccess = $content;
}
if($hasReplaced == 0) {
@@ -459,7 +492,7 @@ class OC_Files {
if(is_writable(OC::$SERVERROOT.'/.htaccess')) {
file_put_contents(OC::$SERVERROOT.'/.htaccess', $htaccess);
return OC_Helper::computerFileSize($size);
- } else { OC_Log::write('files','Can\'t write upload limit to '.OC::$SERVERROOT.'/.htaccess. Please check the file permissions',OC_Log::WARN); }
+ } else { OC_Log::write('files', 'Can\'t write upload limit to '.OC::$SERVERROOT.'/.htaccess. Please check the file permissions', OC_Log::WARN); }
return false;
}
@@ -474,18 +507,18 @@ class OC_Files {
$old='';
while($old!=$path) {//replace any multiplicity of slashes with a single one
$old=$path;
- $path=str_replace('//','/',$path);
+ $path=str_replace('//', '/', $path);
}
return $path;
}
}
-function fileCmp($a,$b) {
+function fileCmp($a, $b) {
if($a['type']=='dir' and $b['type']!='dir') {
return -1;
}elseif($a['type']!='dir' and $b['type']=='dir') {
return 1;
}else{
- return strnatcasecmp($a['name'],$b['name']);
+ return strnatcasecmp($a['name'], $b['name']);
}
}
diff --git a/lib/filestorage.php b/lib/filestorage.php
index 5bfd09253d5..dd65f4421b7 100644
--- a/lib/filestorage.php
+++ b/lib/filestorage.php
@@ -42,13 +42,13 @@ abstract class OC_Filestorage{
abstract public function filectime($path);
abstract public function filemtime($path);
abstract public function file_get_contents($path);
- abstract public function file_put_contents($path,$data);
+ abstract public function file_put_contents($path, $data);
abstract public function unlink($path);
- abstract public function rename($path1,$path2);
- abstract public function copy($path1,$path2);
- abstract public function fopen($path,$mode);
+ abstract public function rename($path1, $path2);
+ abstract public function copy($path1, $path2);
+ abstract public function fopen($path, $mode);
abstract public function getMimeType($path);
- abstract public function hash($type,$path,$raw = false);
+ abstract public function hash($type, $path, $raw = false);
abstract public function free_space($path);
abstract public function search($query);
abstract public function touch($path, $mtime=null);
@@ -62,5 +62,6 @@ abstract class OC_Filestorage{
* hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed.
* returning true for other changes in the folder is optional
*/
- abstract public function hasUpdated($path,$time);
+ abstract public function hasUpdated($path, $time);
+ abstract public function getOwner($path);
}
diff --git a/lib/filestorage/common.php b/lib/filestorage/common.php
index 351714437c5..b97eb79d8d4 100644
--- a/lib/filestorage/common.php
+++ b/lib/filestorage/common.php
@@ -89,25 +89,25 @@ abstract class OC_Filestorage_Common extends OC_Filestorage {
}
return fread($handle, $size);
}
- public function file_put_contents($path,$data) {
+ public function file_put_contents($path, $data) {
$handle = $this->fopen($path, "w");
return fwrite($handle, $data);
}
// abstract public function unlink($path);
- public function rename($path1,$path2) {
- if($this->copy($path1,$path2)) {
+ public function rename($path1, $path2) {
+ if($this->copy($path1, $path2)) {
return $this->unlink($path1);
}else{
return false;
}
}
- public function copy($path1,$path2) {
- $source=$this->fopen($path1,'r');
- $target=$this->fopen($path2,'w');
- $count=OC_Helper::streamCopy($source,$target);
+ public function copy($path1, $path2) {
+ $source=$this->fopen($path1, 'r');
+ $target=$this->fopen($path2, 'w');
+ $count=OC_Helper::streamCopy($source, $target);
return $count>0;
}
-// abstract public function fopen($path,$mode);
+// abstract public function fopen($path, $mode);
/**
* @brief Deletes all files and folders recursively within a directory
@@ -188,25 +188,25 @@ abstract class OC_Filestorage_Common extends OC_Filestorage {
if($this->is_dir($path)) {
return 'httpd/unix-directory';
}
- $source=$this->fopen($path,'r');
+ $source=$this->fopen($path, 'r');
if(!$source) {
return false;
}
- $head=fread($source,8192);//8kb should suffice to determine a mimetype
- if($pos=strrpos($path,'.')) {
- $extension=substr($path,$pos);
+ $head=fread($source, 8192);//8kb should suffice to determine a mimetype
+ if($pos=strrpos($path, '.')) {
+ $extension=substr($path, $pos);
}else{
$extension='';
}
$tmpFile=OC_Helper::tmpFile($extension);
- file_put_contents($tmpFile,$head);
+ file_put_contents($tmpFile, $head);
$mime=OC_Helper::getMimeType($tmpFile);
unlink($tmpFile);
return $mime;
}
- public function hash($type,$path,$raw = false) {
+ public function hash($type, $path, $raw = false) {
$tmpFile=$this->getLocalFile();
- $hash=hash($type,$tmpFile,$raw);
+ $hash=hash($type, $tmpFile, $raw);
unlink($tmpFile);
return $hash;
}
@@ -218,35 +218,35 @@ abstract class OC_Filestorage_Common extends OC_Filestorage {
return $this->toTmpFile($path);
}
private function toTmpFile($path) {//no longer in the storage api, still usefull here
- $source=$this->fopen($path,'r');
+ $source=$this->fopen($path, 'r');
if(!$source) {
return false;
}
- if($pos=strrpos($path,'.')) {
- $extension=substr($path,$pos);
+ if($pos=strrpos($path, '.')) {
+ $extension=substr($path, $pos);
}else{
$extension='';
}
$tmpFile=OC_Helper::tmpFile($extension);
- $target=fopen($tmpFile,'w');
- OC_Helper::streamCopy($source,$target);
+ $target=fopen($tmpFile, 'w');
+ OC_Helper::streamCopy($source, $target);
return $tmpFile;
}
public function getLocalFolder($path) {
$baseDir=OC_Helper::tmpFolder();
- $this->addLocalFolder($path,$baseDir);
+ $this->addLocalFolder($path, $baseDir);
return $baseDir;
}
- private function addLocalFolder($path,$target) {
+ private function addLocalFolder($path, $target) {
if($dh=$this->opendir($path)) {
while($file=readdir($dh)) {
if($file!=='.' and $file!=='..') {
if($this->is_dir($path.'/'.$file)) {
mkdir($target.'/'.$file);
- $this->addLocalFolder($path.'/'.$file,$target.'/'.$file);
+ $this->addLocalFolder($path.'/'.$file, $target.'/'.$file);
}else{
$tmp=$this->toTmpFile($path.'/'.$file);
- rename($tmp,$target.'/'.$file);
+ rename($tmp, $target.'/'.$file);
}
}
}
@@ -254,17 +254,17 @@ abstract class OC_Filestorage_Common extends OC_Filestorage {
}
// abstract public function touch($path, $mtime=null);
- protected function searchInDir($query,$dir='') {
+ protected function searchInDir($query, $dir='') {
$files=array();
$dh=$this->opendir($dir);
if($dh) {
while($item=readdir($dh)) {
if ($item == '.' || $item == '..') continue;
- if(strstr(strtolower($item),strtolower($query))!==false) {
+ if(strstr(strtolower($item), strtolower($query))!==false) {
$files[]=$dir.'/'.$item;
}
if($this->is_dir($dir.'/'.$item)) {
- $files=array_merge($files,$this->searchInDir($query,$dir.'/'.$item));
+ $files=array_merge($files, $this->searchInDir($query, $dir.'/'.$item));
}
}
}
@@ -276,7 +276,16 @@ abstract class OC_Filestorage_Common extends OC_Filestorage {
* @param int $time
* @return bool
*/
- public function hasUpdated($path,$time) {
+ public function hasUpdated($path, $time) {
return $this->filemtime($path)>$time;
}
+
+ /**
+ * get the owner of a path
+ * @param $path The path to get the owner
+ * @return string uid or false
+ */
+ public function getOwner($path) {
+ return OC_User::getUser();
+ }
}
diff --git a/lib/filestorage/commontest.php b/lib/filestorage/commontest.php
index b88bb232c36..3b038b3fda9 100644
--- a/lib/filestorage/commontest.php
+++ b/lib/filestorage/commontest.php
@@ -63,13 +63,13 @@ class OC_Filestorage_CommonTest extends OC_Filestorage_Common{
public function unlink($path) {
return $this->storage->unlink($path);
}
- public function fopen($path,$mode) {
- return $this->storage->fopen($path,$mode);
+ public function fopen($path, $mode) {
+ return $this->storage->fopen($path, $mode);
}
public function free_space($path) {
return $this->storage->free_space($path);
}
public function touch($path, $mtime=null) {
- return $this->storage->touch($path,$mtime);
+ return $this->storage->touch($path, $mtime);
}
} \ No newline at end of file
diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php
index 80aa548047c..6fe45acf8c5 100644
--- a/lib/filestorage/local.php
+++ b/lib/filestorage/local.php
@@ -6,7 +6,7 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{
protected $datadir;
public function __construct($arguments) {
$this->datadir=$arguments['datadir'];
- if(substr($this->datadir,-1)!=='/') {
+ if(substr($this->datadir, -1)!=='/') {
$this->datadir.='/';
}
}
@@ -20,8 +20,8 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{
return opendir($this->datadir.$path);
}
public function is_dir($path) {
- if(substr($path,-1)=='/') {
- $path=substr($path,0,-1);
+ if(substr($path, -1)=='/') {
+ $path=substr($path, 0, -1);
}
return is_dir($this->datadir.$path);
}
@@ -78,38 +78,38 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{
public function file_get_contents($path) {
return file_get_contents($this->datadir.$path);
}
- public function file_put_contents($path,$data) {
- return file_put_contents($this->datadir.$path,$data);
+ public function file_put_contents($path, $data) {
+ return file_put_contents($this->datadir.$path, $data);
}
public function unlink($path) {
return $this->delTree($path);
}
- public function rename($path1,$path2) {
+ public function rename($path1, $path2) {
if (!$this->isUpdatable($path1)) {
- OC_Log::write('core','unable to rename, file is not writable : '.$path1,OC_Log::ERROR);
+ OC_Log::write('core', 'unable to rename, file is not writable : '.$path1, OC_Log::ERROR);
return false;
}
if(! $this->file_exists($path1)) {
- OC_Log::write('core','unable to rename, file does not exists : '.$path1,OC_Log::ERROR);
+ OC_Log::write('core', 'unable to rename, file does not exists : '.$path1, OC_Log::ERROR);
return false;
}
- if($return=rename($this->datadir.$path1,$this->datadir.$path2)) {
+ if($return=rename($this->datadir.$path1, $this->datadir.$path2)) {
}
return $return;
}
- public function copy($path1,$path2) {
+ public function copy($path1, $path2) {
if($this->is_dir($path2)) {
if(!$this->file_exists($path2)) {
$this->mkdir($path2);
}
- $source=substr($path1,strrpos($path1,'/')+1);
+ $source=substr($path1, strrpos($path1, '/')+1);
$path2.=$source;
}
- return copy($this->datadir.$path1,$this->datadir.$path2);
+ return copy($this->datadir.$path1, $this->datadir.$path2);
}
- public function fopen($path,$mode) {
- if($return=fopen($this->datadir.$path,$mode)) {
+ public function fopen($path, $mode) {
+ if($return=fopen($this->datadir.$path, $mode)) {
switch($mode) {
case 'r':
break;
@@ -156,8 +156,8 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{
return $return;
}
- public function hash($path,$type,$raw=false) {
- return hash_file($type,$this->datadir.$path,$raw);
+ public function hash($path, $type, $raw=false) {
+ return hash_file($type, $this->datadir.$path, $raw);
}
public function free_space($path) {
@@ -174,15 +174,15 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{
return $this->datadir.$path;
}
- protected function searchInDir($query,$dir='') {
+ protected function searchInDir($query, $dir='') {
$files=array();
foreach (scandir($this->datadir.$dir) as $item) {
if ($item == '.' || $item == '..') continue;
- if(strstr(strtolower($item),strtolower($query))!==false) {
+ if(strstr(strtolower($item), strtolower($query))!==false) {
$files[]=$dir.'/'.$item;
}
if(is_dir($this->datadir.$dir.'/'.$item)) {
- $files=array_merge($files,$this->searchInDir($query,$dir.'/'.$item));
+ $files=array_merge($files, $this->searchInDir($query, $dir.'/'.$item));
}
}
return $files;
@@ -193,7 +193,7 @@ class OC_Filestorage_Local extends OC_Filestorage_Common{
* @param int $time
* @return bool
*/
- public function hasUpdated($path,$time) {
+ public function hasUpdated($path, $time) {
return $this->filemtime($path)>$time;
}
}
diff --git a/lib/filesystem.php b/lib/filesystem.php
index da524d7f181..aa03593908d 100644
--- a/lib/filesystem.php
+++ b/lib/filesystem.php
@@ -35,10 +35,10 @@
* post_create(path)
* delete(path, &run)
* post_delete(path)
- * rename(oldpath,newpath, &run)
- * post_rename(oldpath,newpath)
- * copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emited in that order)
- * post_rename(oldpath,newpath)
+ * rename(oldpath, newpath, &run)
+ * post_rename(oldpath, newpath)
+ * copy(oldpath, newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emited in that order)
+ * post_rename(oldpath, newpath)
*
* the &run parameter can be set to false to prevent the operation from occuring
*/
@@ -46,6 +46,7 @@
class OC_Filesystem{
static private $storages=array();
static private $mounts=array();
+ static private $loadedUsers=array();
public static $loaded=false;
/**
* @var OC_Filestorage $defaultInstance
@@ -147,21 +148,21 @@ class OC_Filesystem{
* @return string
*/
static public function getMountPoint($path) {
- OC_Hook::emit(self::CLASSNAME,'get_mountpoint',array('path'=>$path));
+ OC_Hook::emit(self::CLASSNAME, 'get_mountpoint', array('path'=>$path));
if(!$path) {
$path='/';
}
if($path[0]!=='/') {
$path='/'.$path;
}
- $path=str_replace('//', '/',$path);
+ $path=str_replace('//', '/', $path);
$foundMountPoint='';
$mountPoints=array_keys(OC_Filesystem::$mounts);
foreach($mountPoints as $mountpoint) {
if($mountpoint==$path) {
return $mountpoint;
}
- if(strpos($path,$mountpoint)===0 and strlen($mountpoint)>strlen($foundMountPoint)) {
+ if(strpos($path, $mountpoint)===0 and strlen($mountpoint)>strlen($foundMountPoint)) {
$foundMountPoint=$mountpoint;
}
}
@@ -175,75 +176,95 @@ class OC_Filesystem{
*/
static public function getInternalPath($path) {
$mountPoint=self::getMountPoint($path);
- $internalPath=substr($path,strlen($mountPoint));
+ $internalPath=substr($path, strlen($mountPoint));
return $internalPath;
}
+
+ static private function mountPointsLoaded($user) {
+ return in_array($user, self::$loadedUsers);
+ }
+
/**
* get the storage object for a path
* @param string path
* @return OC_Filestorage
*/
static public function getStorage($path) {
+ $user = ltrim(substr($path, 0, strpos($path, '/', 1)), '/');
+ // check mount points if file was shared from a different user
+ if ($user != OC_User::getUser() && !self::mountPointsLoaded($user)) {
+ OC_Util::loadUserMountPoints($user);
+ self::loadSystemMountPoints($user);
+ self::$loadedUsers[] = $user;
+ }
+
$mountpoint=self::getMountPoint($path);
if($mountpoint) {
if(!isset(OC_Filesystem::$storages[$mountpoint])) {
$mount=OC_Filesystem::$mounts[$mountpoint];
- OC_Filesystem::$storages[$mountpoint]=OC_Filesystem::createStorage($mount['class'],$mount['arguments']);
+ OC_Filesystem::$storages[$mountpoint]=OC_Filesystem::createStorage($mount['class'], $mount['arguments']);
}
return OC_Filesystem::$storages[$mountpoint];
}
}
- static public function init($root) {
- if(self::$defaultInstance) {
- return false;
- }
- self::$defaultInstance=new OC_FilesystemView($root);
-
- //load custom mount config
+ static private function loadSystemMountPoints($user) {
if(is_file(OC::$SERVERROOT.'/config/mount.php')) {
- $mountConfig=include(OC::$SERVERROOT.'/config/mount.php');
+ $mountConfig=include OC::$SERVERROOT.'/config/mount.php';
if(isset($mountConfig['global'])) {
foreach($mountConfig['global'] as $mountPoint=>$options) {
- self::mount($options['class'],$options['options'],$mountPoint);
+ self::mount($options['class'], $options['options'], $mountPoint);
}
}
-
+
if(isset($mountConfig['group'])) {
foreach($mountConfig['group'] as $group=>$mounts) {
- if(OC_Group::inGroup(OC_User::getUser(),$group)) {
+ if(OC_Group::inGroup($user, $group)) {
foreach($mounts as $mountPoint=>$options) {
- $mountPoint=self::setUserVars($mountPoint);
+ $mountPoint=self::setUserVars($mountPoint, $user);
foreach($options as &$option) {
- $option=self::setUserVars($option);
+ $option=self::setUserVars($option, $user);
}
- self::mount($options['class'],$options['options'],$mountPoint);
+ self::mount($options['class'], $options['options'], $mountPoint);
}
}
}
}
-
+
if(isset($mountConfig['user'])) {
- foreach($mountConfig['user'] as $user=>$mounts) {
- if($user==='all' or strtolower($user)===strtolower(OC_User::getUser())) {
+ foreach($mountConfig['user'] as $mountUser=>$mounts) {
+ if($user==='all' or strtolower($mountUser)===strtolower($user)) {
foreach($mounts as $mountPoint=>$options) {
- $mountPoint=self::setUserVars($mountPoint);
+ $mountPoint=self::setUserVars($mountPoint, $user);
foreach($options as &$option) {
- $option=self::setUserVars($option);
+ $option=self::setUserVars($option, $user);
}
- self::mount($options['class'],$options['options'],$mountPoint);
+ self::mount($options['class'], $options['options'], $mountPoint);
}
}
}
}
-
+
$mtime=filemtime(OC::$SERVERROOT.'/config/mount.php');
- $previousMTime=OC_Appconfig::getValue('files','mountconfigmtime',0);
+ $previousMTime=OC_Appconfig::getValue('files', 'mountconfigmtime', 0);
if($mtime>$previousMTime) {//mount config has changed, filecache needs to be updated
OC_FileCache::triggerUpdate();
- OC_Appconfig::setValue('files','mountconfigmtime',$mtime);
+ OC_Appconfig::setValue('files', 'mountconfigmtime', $mtime);
}
+ }
+ }
+
+ static public function init($root, $user = '') {
+ if(self::$defaultInstance) {
+ return false;
}
+ self::$defaultInstance=new OC_FilesystemView($root);
+
+ //load custom mount config
+ if (!isset($user)) {
+ $user = OC_User::getUser();
+ }
+ self::loadSystemMountPoints($user);
self::$loaded=true;
}
@@ -253,8 +274,12 @@ class OC_Filesystem{
* @param string intput
* @return string
*/
- private static function setUserVars($input) {
- return str_replace('$user',OC_User::getUser(),$input);
+ private static function setUserVars($input, $user) {
+ if (isset($user)) {
+ return str_replace('$user', $user, $input);
+ } else {
+ return str_replace('$user', OC_User::getUser(), $input);
+ }
}
/**
@@ -278,7 +303,7 @@ class OC_Filesystem{
* @param array arguments
* @return OC_Filestorage
*/
- static private function createStorage($class,$arguments) {
+ static private function createStorage($class, $arguments) {
if(class_exists($class)) {
try {
return new $class($arguments);
@@ -287,7 +312,7 @@ class OC_Filesystem{
return false;
}
}else{
- OC_Log::write('core','storage backend '.$class.' not found',OC_Log::ERROR);
+ OC_Log::write('core', 'storage backend '.$class.' not found', OC_Log::ERROR);
return false;
}
}
@@ -324,14 +349,14 @@ class OC_Filesystem{
* @param OC_Filestorage storage
* @param string mountpoint
*/
- static public function mount($class,$arguments,$mountpoint) {
+ static public function mount($class, $arguments, $mountpoint) {
if($mountpoint[0]!='/') {
$mountpoint='/'.$mountpoint;
}
- if(substr($mountpoint,-1)!=='/') {
+ if(substr($mountpoint, -1)!=='/') {
$mountpoint=$mountpoint.'/';
}
- self::$mounts[$mountpoint]=array('class'=>$class,'arguments'=>$arguments);
+ self::$mounts[$mountpoint]=array('class'=>$class, 'arguments'=>$arguments);
}
/**
@@ -371,10 +396,14 @@ class OC_Filesystem{
* @return bool
*/
static public function isValidPath($path) {
+ $path = self::normalizePath($path);
if(!$path || $path[0]!=='/') {
$path='/'.$path;
}
- if(strstr($path,'/../') || strrchr($path, '/') === '/..' ) {
+ if(strstr($path, '/../') || strrchr($path, '/') === '/..' ) {
+ return false;
+ }
+ if(self::isFileBlacklisted($path)) {
return false;
}
return true;
@@ -386,20 +415,22 @@ class OC_Filesystem{
* @param array $data from hook
*/
static public function isBlacklisted($data) {
- $blacklist = array('.htaccess');
if (isset($data['path'])) {
$path = $data['path'];
} else if (isset($data['newpath'])) {
$path = $data['newpath'];
}
if (isset($path)) {
- $filename = strtolower(basename($path));
- if (in_array($filename, $blacklist)) {
- $data['run'] = false;
- }
+ $data['run'] = !self::isFileBlacklisted($path);
}
}
+ static public function isFileBlacklisted($path) {
+ $blacklist = array('.htaccess');
+ $filename = strtolower(basename($path));
+ return in_array($filename, $blacklist);
+ }
+
/**
* following functions are equivilent to their php buildin equivilents for arguments/return values.
*/
@@ -475,33 +506,33 @@ class OC_Filesystem{
static public function file_get_contents($path) {
return self::$defaultInstance->file_get_contents($path);
}
- static public function file_put_contents($path,$data) {
- return self::$defaultInstance->file_put_contents($path,$data);
+ static public function file_put_contents($path, $data) {
+ return self::$defaultInstance->file_put_contents($path, $data);
}
static public function unlink($path) {
return self::$defaultInstance->unlink($path);
}
- static public function rename($path1,$path2) {
- return self::$defaultInstance->rename($path1,$path2);
+ static public function rename($path1, $path2) {
+ return self::$defaultInstance->rename($path1, $path2);
}
- static public function copy($path1,$path2) {
- return self::$defaultInstance->copy($path1,$path2);
+ static public function copy($path1, $path2) {
+ return self::$defaultInstance->copy($path1, $path2);
}
- static public function fopen($path,$mode) {
- return self::$defaultInstance->fopen($path,$mode);
+ static public function fopen($path, $mode) {
+ return self::$defaultInstance->fopen($path, $mode);
}
static public function toTmpFile($path) {
return self::$defaultInstance->toTmpFile($path);
}
- static public function fromTmpFile($tmpFile,$path) {
- return self::$defaultInstance->fromTmpFile($tmpFile,$path);
+ static public function fromTmpFile($tmpFile, $path) {
+ return self::$defaultInstance->fromTmpFile($tmpFile, $path);
}
static public function getMimeType($path) {
return self::$defaultInstance->getMimeType($path);
}
- static public function hash($type,$path, $raw = false) {
- return self::$defaultInstance->hash($type,$path, $raw);
+ static public function hash($type, $path, $raw = false) {
+ return self::$defaultInstance->hash($type, $path, $raw);
}
static public function free_space($path='/') {
@@ -517,8 +548,8 @@ class OC_Filesystem{
* @param int $time
* @return bool
*/
- static public function hasUpdated($path,$time) {
- return self::$defaultInstance->hasUpdated($path,$time);
+ static public function hasUpdated($path, $time) {
+ return self::$defaultInstance->hasUpdated($path, $time);
}
static public function removeETagHook($params, $root = false) {
@@ -544,23 +575,23 @@ class OC_Filesystem{
* @param bool $stripTrailingSlash
* @return string
*/
- public static function normalizePath($path,$stripTrailingSlash=true) {
+ public static function normalizePath($path, $stripTrailingSlash=true) {
if($path=='') {
return '/';
}
//no windows style slashes
- $path=str_replace('\\','/',$path);
+ $path=str_replace('\\', '/', $path);
//add leading slash
if($path[0]!=='/') {
$path='/'.$path;
}
//remove trainling slash
- if($stripTrailingSlash and strlen($path)>1 and substr($path,-1,1)==='/') {
- $path=substr($path,0,-1);
+ if($stripTrailingSlash and strlen($path)>1 and substr($path, -1, 1)==='/') {
+ $path=substr($path, 0, -1);
}
//remove duplicate slashes
- while(strpos($path,'//')!==false) {
- $path=str_replace('//','/',$path);
+ while(strpos($path, '//')!==false) {
+ $path=str_replace('//', '/', $path);
}
//normalize unicode if possible
if(class_exists('Normalizer')) {
@@ -569,9 +600,9 @@ class OC_Filesystem{
return $path;
}
}
-OC_Hook::connect('OC_Filesystem','post_write', 'OC_Filesystem','removeETagHook');
-OC_Hook::connect('OC_Filesystem','post_delete','OC_Filesystem','removeETagHook');
-OC_Hook::connect('OC_Filesystem','post_rename','OC_Filesystem','removeETagHook');
+OC_Hook::connect('OC_Filesystem', 'post_write', 'OC_Filesystem', 'removeETagHook');
+OC_Hook::connect('OC_Filesystem', 'post_delete', 'OC_Filesystem', 'removeETagHook');
+OC_Hook::connect('OC_Filesystem', 'post_rename', 'OC_Filesystem', 'removeETagHook');
OC_Util::setupFS();
require_once 'filecache.php';
diff --git a/lib/filesystemview.php b/lib/filesystemview.php
index 2950ced5f9e..e944ae5045d 100644
--- a/lib/filesystemview.php
+++ b/lib/filesystemview.php
@@ -47,11 +47,8 @@ class OC_FilesystemView {
$this->fakeRoot=$root;
}
- public function getAbsolutePath($path) {
- if(!$path) {
- $path='/';
- }
- if($path[0]!=='/') {
+ public function getAbsolutePath($path = '/') {
+ if(!$path || $path[0]!=='/') {
$path='/'.$path;
}
return $this->fakeRoot.$path;
@@ -142,7 +139,7 @@ class OC_FilesystemView {
* @return string
*/
public function getLocalFile($path) {
- $parent=substr($path, 0, strrpos($path,'/'));
+ $parent=substr($path, 0, strrpos($path, '/'));
if(OC_Filesystem::isValidPath($parent) and $storage=$this->getStorage($path)) {
return $storage->getLocalFile($this->getInternalPath($path));
}
@@ -152,7 +149,7 @@ class OC_FilesystemView {
* @return string
*/
public function getLocalFolder($path) {
- $parent=substr($path, 0, strrpos($path,'/'));
+ $parent=substr($path, 0, strrpos($path, '/'));
if(OC_Filesystem::isValidPath($parent) and $storage=$this->getStorage($path)) {
return $storage->getLocalFolder($this->getInternalPath($path));
}
@@ -198,7 +195,7 @@ class OC_FilesystemView {
return $this->basicOperation('filesize', $path);
}
public function readfile($path) {
- @ob_end_clean();
+ OC_Util::obEnd();
$handle=$this->fopen($path, 'rb');
if ($handle) {
$chunkSize = 8192;// 8 MB chunks
@@ -215,13 +212,13 @@ class OC_FilesystemView {
* @deprecated Replaced by isReadable() as part of CRUDS
*/
public function is_readable($path) {
- return $this->basicOperation('isReadable',$path);
+ return $this->basicOperation('isReadable', $path);
}
/**
* @deprecated Replaced by isCreatable(), isUpdatable(), isDeletable() as part of CRUDS
*/
public function is_writable($path) {
- return $this->basicOperation('isUpdatable',$path);
+ return $this->basicOperation('isUpdatable', $path);
}
public function isCreatable($path) {
return $this->basicOperation('isCreatable', $path);
@@ -251,6 +248,9 @@ class OC_FilesystemView {
return $this->basicOperation('filemtime', $path);
}
public function touch($path, $mtime=null) {
+ if(!is_null($mtime) and !is_numeric($mtime)) {
+ $mtime = strtotime($mtime);
+ }
return $this->basicOperation('touch', $path, array('write'), $mtime);
}
public function file_get_contents($path) {
@@ -263,7 +263,7 @@ class OC_FilesystemView {
$path = $this->getRelativePath($absolutePath);
$exists = $this->file_exists($path);
$run = true;
- if( $this->fakeRoot==OC_Filesystem::getRoot() ){
+ if( $this->fakeRoot==OC_Filesystem::getRoot() ) {
if(!$exists) {
OC_Hook::emit(
OC_Filesystem::CLASSNAME,
@@ -291,7 +291,7 @@ class OC_FilesystemView {
$count=OC_Helper::streamCopy($data, $target);
fclose($target);
fclose($data);
- if( $this->fakeRoot==OC_Filesystem::getRoot() ){
+ if( $this->fakeRoot==OC_Filesystem::getRoot() ) {
if(!$exists) {
OC_Hook::emit(
OC_Filesystem::CLASSNAME,
@@ -322,8 +322,8 @@ class OC_FilesystemView {
return $this->basicOperation( 'deleteAll', $directory, array('delete'), $empty );
}
public function rename($path1, $path2) {
- $postFix1=(substr($path1,-1,1)==='/')?'/':'';
- $postFix2=(substr($path2,-1,1)==='/')?'/':'';
+ $postFix1=(substr($path1, -1, 1)==='/')?'/':'';
+ $postFix2=(substr($path2, -1, 1)==='/')?'/':'';
$absolutePath1 = OC_Filesystem::normalizePath($this->getAbsolutePath($path1));
$absolutePath2 = OC_Filesystem::normalizePath($this->getAbsolutePath($path2));
if(OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2) and OC_Filesystem::isValidPath($path2)) {
@@ -334,7 +334,7 @@ class OC_FilesystemView {
return false;
}
$run=true;
- if( $this->fakeRoot==OC_Filesystem::getRoot() ){
+ if( $this->fakeRoot==OC_Filesystem::getRoot() ) {
OC_Hook::emit(
OC_Filesystem::CLASSNAME, OC_Filesystem::signal_rename,
array(
@@ -359,7 +359,7 @@ class OC_FilesystemView {
$storage1->unlink($this->getInternalPath($path1.$postFix1));
$result = $count>0;
}
- if( $this->fakeRoot==OC_Filesystem::getRoot() ){
+ if( $this->fakeRoot==OC_Filesystem::getRoot() ) {
OC_Hook::emit(
OC_Filesystem::CLASSNAME,
OC_Filesystem::signal_post_rename,
@@ -374,8 +374,8 @@ class OC_FilesystemView {
}
}
public function copy($path1, $path2) {
- $postFix1=(substr($path1,-1,1)==='/')?'/':'';
- $postFix2=(substr($path2,-1,1)==='/')?'/':'';
+ $postFix1=(substr($path1, -1, 1)==='/')?'/':'';
+ $postFix2=(substr($path2, -1, 1)==='/')?'/':'';
$absolutePath1 = OC_Filesystem::normalizePath($this->getAbsolutePath($path1));
$absolutePath2 = OC_Filesystem::normalizePath($this->getAbsolutePath($path2));
if(OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2) and OC_Filesystem::isValidPath($path2)) {
@@ -386,7 +386,7 @@ class OC_FilesystemView {
return false;
}
$run=true;
- if( $this->fakeRoot==OC_Filesystem::getRoot() ){
+ if( $this->fakeRoot==OC_Filesystem::getRoot() ) {
OC_Hook::emit(
OC_Filesystem::CLASSNAME,
OC_Filesystem::signal_copy,
@@ -430,7 +430,10 @@ class OC_FilesystemView {
$target = $this->fopen($path2.$postFix2, 'w');
$result = OC_Helper::streamCopy($source, $target);
}
- if( $this->fakeRoot==OC_Filesystem::getRoot() ){
+ if( $this->fakeRoot==OC_Filesystem::getRoot() ) {
+ // If the file to be copied originates within
+ // the user's data directory
+
OC_Hook::emit(
OC_Filesystem::CLASSNAME,
OC_Filesystem::signal_post_copy,
@@ -451,11 +454,33 @@ class OC_FilesystemView {
OC_Filesystem::signal_post_write,
array( OC_Filesystem::signal_param_path => $path2)
);
- } else { // no real copy, file comes from somewhere else, e.g. version rollback -> just update the file cache and the webdav properties without all the other post_write actions
- OC_FileCache_Update::update($path2, $this->fakeRoot);
+
+ } else {
+ // If this is not a normal file copy operation
+ // and the file originates somewhere else
+ // (e.g. a version rollback operation), do not
+ // perform all the other post_write actions
+
+ // Update webdav properties
OC_Filesystem::removeETagHook(array("path" => $path2), $this->fakeRoot);
+
+ $splitPath2 = explode( '/', $path2 );
+
+ // Only cache information about files
+ // that are being copied from within
+ // the user files directory. Caching
+ // other files, like VCS backup files,
+ // serves no purpose
+ if ( $splitPath2[1] == 'files' ) {
+
+ OC_FileCache_Update::update($path2, $this->fakeRoot);
+
+ }
+
}
+
return $result;
+
}
}
}
@@ -486,7 +511,7 @@ class OC_FilesystemView {
$hooks[]='write';
break;
default:
- OC_Log::write('core','invalid mode ('.$mode.') for '.$path,OC_Log::ERROR);
+ OC_Log::write('core', 'invalid mode ('.$mode.') for '.$path, OC_Log::ERROR);
}
return $this->basicOperation('fopen', $path, $hooks, $mode);
@@ -498,7 +523,7 @@ class OC_FilesystemView {
$extension='';
$extOffset=strpos($path, '.');
if($extOffset !== false) {
- $extension=substr($path, strrpos($path,'.'));
+ $extension=substr($path, strrpos($path, '.'));
}
$tmpFile = OC_Helper::tmpFile($extension);
file_put_contents($tmpFile, $source);
@@ -527,7 +552,7 @@ class OC_FilesystemView {
return $this->basicOperation('getMimeType', $path);
}
public function hash($type, $path, $raw = false) {
- $postFix=(substr($path,-1,1)==='/')?'/':'';
+ $postFix=(substr($path, -1, 1)==='/')?'/':'';
$absolutePath = OC_Filesystem::normalizePath($this->getAbsolutePath($path));
if (OC_FileProxy::runPreProxies('hash', $absolutePath) && OC_Filesystem::isValidPath($path)) {
$path = $this->getRelativePath($absolutePath);
@@ -567,7 +592,7 @@ class OC_FilesystemView {
* OC_Filestorage for delegation to a storage backend for execution
*/
private function basicOperation($operation, $path, $hooks=array(), $extraParam=null) {
- $postFix=(substr($path,-1,1)==='/')?'/':'';
+ $postFix=(substr($path, -1, 1)==='/')?'/':'';
$absolutePath = OC_Filesystem::normalizePath($this->getAbsolutePath($path));
if(OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam) and OC_Filesystem::isValidPath($path)) {
$path = $this->getRelativePath($absolutePath);
@@ -575,7 +600,7 @@ class OC_FilesystemView {
return false;
}
$internalPath = $this->getInternalPath($path.$postFix);
- $run=$this->runHooks($hooks,$path);
+ $run=$this->runHooks($hooks, $path);
if($run and $storage = $this->getStorage($path.$postFix)) {
if(!is_null($extraParam)) {
$result = $storage->$operation($internalPath, $extraParam);
@@ -585,7 +610,7 @@ class OC_FilesystemView {
$result = OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result);
if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()) {
if($operation!='fopen') {//no post hooks for fopen, the file stream is still open
- $this->runHooks($hooks,$path,true);
+ $this->runHooks($hooks, $path, true);
}
}
return $result;
@@ -594,7 +619,7 @@ class OC_FilesystemView {
return null;
}
- private function runHooks($hooks,$path,$post=false) {
+ private function runHooks($hooks, $path, $post=false) {
$prefix=($post)?'post_':'';
$run=true;
if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()) {
diff --git a/lib/group.php b/lib/group.php
index 66892a99b60..ed9482418bd 100644
--- a/lib/group.php
+++ b/lib/group.php
@@ -65,15 +65,8 @@ class OC_Group {
*
* Tries to create a new group. If the group name already exists, false will
* be returned. Basic checking of Group name
- *
- * Allowed characters in the username are: "a-z", "A-Z", "0-9" and "_.@-"
*/
public static function createGroup( $gid ) {
- // Check the name for bad characters
- // Allowed are: "a-z", "A-Z", "0-9" and "_.@-"
- if( preg_match( '/[^a-zA-Z0-9 _\.@\-]/', $gid )) {
- return false;
- }
// No empty group names!
if( !$gid ) {
return false;
@@ -146,7 +139,7 @@ class OC_Group {
*/
public static function inGroup( $uid, $gid ) {
foreach(self::$_usedBackends as $backend) {
- if($backend->inGroup($uid,$gid)) {
+ if($backend->inGroup($uid, $gid)) {
return true;
}
}
@@ -230,7 +223,7 @@ class OC_Group {
public static function getUserGroups( $uid ) {
$groups=array();
foreach(self::$_usedBackends as $backend) {
- $groups=array_merge($backend->getUserGroups($uid),$groups);
+ $groups=array_merge($backend->getUserGroups($uid), $groups);
}
asort($groups);
return $groups;
diff --git a/lib/group/dummy.php b/lib/group/dummy.php
index 8116dcbd675..9516fd52ff8 100644
--- a/lib/group/dummy.php
+++ b/lib/group/dummy.php
@@ -69,7 +69,7 @@ class OC_Group_Dummy extends OC_Group_Backend {
*/
public function inGroup($uid, $gid) {
if(isset($this->groups[$gid])) {
- return (array_search($uid,$this->groups[$gid])!==false);
+ return (array_search($uid, $this->groups[$gid])!==false);
}else{
return false;
}
@@ -85,7 +85,7 @@ class OC_Group_Dummy extends OC_Group_Backend {
*/
public function addToGroup($uid, $gid) {
if(isset($this->groups[$gid])) {
- if(array_search($uid,$this->groups[$gid])===false) {
+ if(array_search($uid, $this->groups[$gid])===false) {
$this->groups[$gid][]=$uid;
return true;
}else{
@@ -104,9 +104,9 @@ class OC_Group_Dummy extends OC_Group_Backend {
*
* removes the user from a group.
*/
- public function removeFromGroup($uid,$gid) {
+ public function removeFromGroup($uid, $gid) {
if(isset($this->groups[$gid])) {
- if(($index=array_search($uid,$this->groups[$gid]))!==false) {
+ if(($index=array_search($uid, $this->groups[$gid]))!==false) {
unset($this->groups[$gid][$index]);
}else{
return false;
@@ -128,7 +128,7 @@ class OC_Group_Dummy extends OC_Group_Backend {
$groups=array();
$allGroups=array_keys($this->groups);
foreach($allGroups as $group) {
- if($this->inGroup($uid,$group)) {
+ if($this->inGroup($uid, $group)) {
$groups[]=$group;
}
}
diff --git a/lib/group/example.php b/lib/group/example.php
index 76d12629763..3519b9ed92f 100644
--- a/lib/group/example.php
+++ b/lib/group/example.php
@@ -73,7 +73,7 @@ abstract class OC_Group_Example {
*
* removes the user from a group.
*/
- abstract public static function removeFromGroup($uid,$gid);
+ abstract public static function removeFromGroup($uid, $gid);
/**
* @brief Get all groups a user belongs to
diff --git a/lib/helper.php b/lib/helper.php
index 2c221ddf195..5dec7fadfb4 100644
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -29,6 +29,20 @@ class OC_Helper {
private static $tmpFiles=array();
/**
+ * @brief Creates an url using a defined route
+ * @param $route
+ * @param $parameters
+ * @param $args array with param=>value, will be appended to the returned url
+ * @returns the url
+ *
+ * Returns a url to the given app and file.
+ */
+ public static function linkToRoute( $route, $parameters = array() ) {
+ $urlLinkTo = OC::getRouter()->generate($route, $parameters);
+ return $urlLinkTo;
+ }
+
+ /**
* @brief Creates an url
* @param string $app app
* @param string $file file
@@ -44,8 +58,8 @@ class OC_Helper {
// Check if the app is in the app folder
if( $app_path && file_exists( $app_path.'/'.$file )) {
if(substr($file, -3) == 'php' || substr($file, -3) == 'css') {
- $urlLinkTo = OC::$WEBROOT . '/?app=' . $app;
- $urlLinkTo .= ($file!='index.php')?'&getfile=' . urlencode($file):'';
+ $urlLinkTo = OC::$WEBROOT . '/index.php/apps/' . $app;
+ $urlLinkTo .= ($file!='index.php') ? '/' . $file : '';
}else{
$urlLinkTo = OC_App::getAppWebPath($app) . '/' . $file;
}
@@ -101,6 +115,17 @@ class OC_Helper {
}
/**
+ * @brief Creates an url for remote use
+ * @param string $service id
+ * @return string the url
+ *
+ * Returns a url to the given service.
+ */
+ public static function linkToRemoteBase( $service ) {
+ return self::linkTo( '', 'remote.php') . '/' . $service;
+ }
+
+ /**
* @brief Creates an absolute url for remote use
* @param string $service id
* @return string the url
@@ -108,7 +133,7 @@ class OC_Helper {
* Returns a absolute url to the given service.
*/
public static function linkToRemote( $service, $add_slash = true ) {
- return self::linkToAbsolute( '', 'remote.php') . '/' . $service . (($add_slash && $service[strlen($service)-1]!='/')?'/':'');
+ return self::makeURLAbsolute(self::linkToRemoteBase($service)) . (($add_slash && $service[strlen($service)-1]!='/')?'/':'');
}
/**
@@ -178,7 +203,7 @@ class OC_Helper {
return OC::$WEBROOT."/core/img/filetypes/$mimetype.png";
}
//try only the first part of the filetype
- $mimetype=substr($mimetype,0,strpos($mimetype,'-'));
+ $mimetype=substr($mimetype, 0, strpos($mimetype, '-'));
if( file_exists( OC::$SERVERROOT."/core/img/filetypes/$mimetype.png" )) {
return OC::$WEBROOT."/core/img/filetypes/$mimetype.png";
}
@@ -263,18 +288,18 @@ class OC_Helper {
if($file != '.' && $file != '..') {
$fullpath = $path.'/'.$file;
if(is_link($fullpath))
- return FALSE;
+ return false;
elseif(!is_dir($fullpath) && !@chmod($fullpath, $filemode))
- return FALSE;
+ return false;
elseif(!self::chmodr($fullpath, $filemode))
- return FALSE;
+ return false;
}
}
closedir($dh);
if(@chmod($path, $filemode))
- return TRUE;
+ return true;
else
- return FALSE;
+ return false;
}
/**
@@ -294,7 +319,7 @@ class OC_Helper {
self::copyr("$src/$file", "$dest/$file");
}
}
- }elseif(file_exists($src)) {
+ }elseif(file_exists($src) && !OC_Filesystem::isFileBlacklisted($src)) {
copy($src, $dest);
}
}
@@ -330,29 +355,29 @@ class OC_Helper {
* does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead
*/
static function getMimeType($path) {
- $isWrapped=(strpos($path,'://')!==false) and (substr($path,0,7)=='file://');
+ $isWrapped=(strpos($path, '://')!==false) and (substr($path, 0, 7)=='file://');
if (@is_dir($path)) {
// directories are easy
return "httpd/unix-directory";
}
- if(strpos($path,'.')) {
+ if(strpos($path, '.')) {
//try to guess the type by the file extension
- if(!self::$mimetypes || self::$mimetypes != include('mimetypes.list.php')) {
- self::$mimetypes=include('mimetypes.list.php');
+ if(!self::$mimetypes || self::$mimetypes != include 'mimetypes.list.php') {
+ self::$mimetypes=include 'mimetypes.list.php';
}
$extension=strtolower(strrchr(basename($path), "."));
- $extension=substr($extension,1);//remove leading .
+ $extension=substr($extension, 1);//remove leading .
$mimeType=(isset(self::$mimetypes[$extension]))?self::$mimetypes[$extension]:'application/octet-stream';
}else{
$mimeType='application/octet-stream';
}
if($mimeType=='application/octet-stream' and function_exists('finfo_open') and function_exists('finfo_file') and $finfo=finfo_open(FILEINFO_MIME)) {
- $info = @strtolower(finfo_file($finfo,$path));
+ $info = @strtolower(finfo_file($finfo, $path));
if($info) {
- $mimeType=substr($info,0,strpos($info,';'));
+ $mimeType=substr($info, 0, strpos($info, ';'));
}
finfo_close($finfo);
}
@@ -362,20 +387,15 @@ class OC_Helper {
}
if (!$isWrapped and $mimeType=='application/octet-stream' && OC_Helper::canExecute("file")) {
// it looks like we have a 'file' command,
- // lets see it it does have mime support
+ // lets see if it does have mime support
$path=escapeshellarg($path);
$fp = popen("file -i -b $path 2>/dev/null", "r");
$reply = fgets($fp);
pclose($fp);
- //trim the character set from the end of the response
- $mimeType=substr($reply,0,strrpos($reply,' '));
- $mimeType=substr($mimeType,0,strrpos($mimeType,"\n"));
-
- //trim ;
- if (strpos($mimeType, ';') !== false) {
- $mimeType = strstr($mimeType, ';', true);
- }
+ // we have smth like 'text/x-c++; charset=us-ascii\n'
+ // and need to eliminate everything starting with semicolon including trailing LF
+ $mimeType = preg_replace('/;.*/ms', '', trim($reply));
}
return $mimeType;
@@ -392,8 +412,8 @@ class OC_Helper {
return finfo_buffer($finfo, $data);
}else{
$tmpFile=OC_Helper::tmpFile();
- $fh=fopen($tmpFile,'wb');
- fwrite($fh,$data,8024);
+ $fh=fopen($tmpFile, 'wb');
+ fwrite($fh, $data, 8024);
fclose($fh);
$mime=self::getMimeType($tmpFile);
unset($tmpFile);
@@ -455,16 +475,16 @@ class OC_Helper {
$dirs = explode(PATH_SEPARATOR, $path);
// WARNING : We have to check if open_basedir is enabled :
$obd = ini_get('open_basedir');
- if($obd != "none"){
+ if($obd != "none") {
$obd_values = explode(PATH_SEPARATOR, $obd);
- if(count($obd_values) > 0 and $obd_values[0]){
+ if(count($obd_values) > 0 and $obd_values[0]) {
// open_basedir is in effect !
// We need to check if the program is in one of these dirs :
$dirs = $obd_values;
}
}
- foreach($dirs as $dir){
- foreach($exts as $ext){
+ foreach($dirs as $dir) {
+ foreach($exts as $ext) {
if($check_fn("$dir/$name".$ext))
return true;
}
@@ -478,13 +498,13 @@ class OC_Helper {
* @param resource $target
* @return int the number of bytes copied
*/
- public static function streamCopy($source,$target) {
+ public static function streamCopy($source, $target) {
if(!$source or !$target) {
return false;
}
$count=0;
while(!feof($source)) {
- $count+=fwrite($target,fread($source,8192));
+ $count+=fwrite($target, fread($source, 8192));
}
return $count;
}
@@ -498,13 +518,34 @@ class OC_Helper {
*/
public static function tmpFile($postfix='') {
$file=get_temp_dir().'/'.md5(time().rand()).$postfix;
- $fh=fopen($file,'w');
+ $fh=fopen($file, 'w');
fclose($fh);
self::$tmpFiles[]=$file;
return $file;
}
/**
+ * create a temporary file with an unique filename. It will not be deleted
+ * automatically
+ * @param string $postfix
+ * @return string
+ *
+ */
+ public static function tmpFileNoClean($postfix='') {
+ $tmpDirNoClean=get_temp_dir().'/oc-noclean/';
+ if (!file_exists($tmpDirNoClean) || !is_dir($tmpDirNoClean)) {
+ if (file_exists($tmpDirNoClean)) {
+ unlink($tmpDirNoClean);
+ }
+ mkdir($tmpDirNoClean);
+ }
+ $file=$tmpDirNoClean.md5(time().rand()).$postfix;
+ $fh=fopen($file,'w');
+ fclose($fh);
+ return $file;
+ }
+
+ /**
* create a temporary folder with an unique filename
* @return string
*
@@ -540,6 +581,16 @@ class OC_Helper {
}
/**
+ * remove all files created by self::tmpFileNoClean
+ */
+ public static function cleanTmpNoClean() {
+ $tmpDirNoCleanFile=get_temp_dir().'/oc-noclean/';
+ if(file_exists($tmpDirNoCleanFile)) {
+ self::rmdirr($tmpDirNoCleanFile);
+ }
+ }
+
+ /**
* Adds a suffix to the name in case the file exists
*
* @param $path
@@ -692,4 +743,19 @@ class OC_Helper {
return false;
}
+
+ /**
+ * Shortens str to maxlen by replacing characters in the middle with '...', eg.
+ * ellipsis('a very long string with lots of useless info to make a better example', 14) becomes 'a very ...example'
+ * @param string $str the string
+ * @param string $maxlen the maximum length of the result
+ * @return string with at most maxlen characters
+ */
+ public static function ellipsis($str, $maxlen) {
+ if (strlen($str) > $maxlen) {
+ $characters = floor($maxlen / 2);
+ return substr($str, 0, $characters) . '...' . substr($str, -1 * $characters);
+ }
+ return $str;
+ }
}
diff --git a/lib/image.php b/lib/image.php
index 861353e039d..2043a452541 100644
--- a/lib/image.php
+++ b/lib/image.php
@@ -20,32 +20,13 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
-
-//From user comments at http://dk2.php.net/manual/en/function.exif-imagetype.php
-if ( ! function_exists( 'exif_imagetype' ) ) {
- function exif_imagetype ( $filename ) {
- if ( ( $info = getimagesize( $filename ) ) !== false ) {
- return $info[2];
- }
- return false;
- }
-}
-
-function ellipsis($str, $maxlen) {
- if (strlen($str) > $maxlen) {
- $characters = floor($maxlen / 2);
- return substr($str, 0, $characters) . '...' . substr($str, -1 * $characters);
- }
- return $str;
-}
-
/**
* Class for basic image manipulation
- *
*/
class OC_Image {
protected $resource = false; // tmp resource.
protected $imagetype = IMAGETYPE_PNG; // Default to png if file type isn't evident.
+ protected $bit_depth = 24;
protected $filepath = null;
/**
@@ -66,7 +47,7 @@ class OC_Image {
public function __construct($imageref = null) {
//OC_Log::write('core',__METHOD__.'(): start', OC_Log::DEBUG);
if(!extension_loaded('gd') || !function_exists('gd_info')) {
- OC_Log::write('core',__METHOD__.'(): GD module not installed', OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): GD module not installed', OC_Log::ERROR);
return false;
}
if(!is_null($imageref)) {
@@ -112,7 +93,7 @@ class OC_Image {
*/
public function widthTopLeft() {
$o = $this->getOrientation();
- OC_Log::write('core','OC_Image->widthTopLeft() Orientation: '.$o, OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->widthTopLeft() Orientation: '.$o, OC_Log::DEBUG);
switch($o) {
case -1:
case 1:
@@ -137,7 +118,7 @@ class OC_Image {
*/
public function heightTopLeft() {
$o = $this->getOrientation();
- OC_Log::write('core','OC_Image->heightTopLeft() Orientation: '.$o, OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->heightTopLeft() Orientation: '.$o, OC_Log::DEBUG);
switch($o) {
case -1:
case 1:
@@ -172,7 +153,7 @@ class OC_Image {
public function save($filepath=null) {
if($filepath === null && $this->filepath === null) {
- OC_Log::write('core',__METHOD__.'(): called with no path.', OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): called with no path.', OC_Log::ERROR);
return false;
} elseif($filepath === null && $this->filepath !== null) {
$filepath = $this->filepath;
@@ -188,10 +169,10 @@ class OC_Image {
if (!file_exists(dirname($filepath)))
mkdir(dirname($filepath), 0777, true);
if(!is_writable(dirname($filepath))) {
- OC_Log::write('core',__METHOD__.'(): Directory \''.dirname($filepath).'\' is not writable.', OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): Directory \''.dirname($filepath).'\' is not writable.', OC_Log::ERROR);
return false;
} elseif(is_writable(dirname($filepath)) && file_exists($filepath) && !is_writable($filepath)) {
- OC_Log::write('core',__METHOD__.'(): File \''.$filepath.'\' is not writable.', OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): File \''.$filepath.'\' is not writable.', OC_Log::ERROR);
return false;
}
}
@@ -214,9 +195,11 @@ class OC_Image {
$retval = imagexbm($this->resource, $filepath);
break;
case IMAGETYPE_WBMP:
- case IMAGETYPE_BMP:
$retval = imagewbmp($this->resource, $filepath);
break;
+ case IMAGETYPE_BMP:
+ $retval = imagebmp($this->resource, $filepath, $this->bit_depth);
+ break;
default:
$retval = imagepng($this->resource, $filepath);
}
@@ -244,7 +227,7 @@ class OC_Image {
ob_start();
$res = imagepng($this->resource);
if (!$res) {
- OC_Log::write('core','OC_Image->data. Error getting image data.',OC_Log::ERROR);
+ OC_Log::write('core', 'OC_Image->data. Error getting image data.', OC_Log::ERROR);
}
return ob_get_clean();
}
@@ -263,15 +246,15 @@ class OC_Image {
*/
public function getOrientation() {
if(!is_callable('exif_read_data')) {
- OC_Log::write('core','OC_Image->fixOrientation() Exif module not enabled.', OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->fixOrientation() Exif module not enabled.', OC_Log::DEBUG);
return -1;
}
if(!$this->valid()) {
- OC_Log::write('core','OC_Image->fixOrientation() No image loaded.', OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->fixOrientation() No image loaded.', OC_Log::DEBUG);
return -1;
}
if(is_null($this->filepath) || !is_readable($this->filepath)) {
- OC_Log::write('core','OC_Image->fixOrientation() No readable file path set.', OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->fixOrientation() No readable file path set.', OC_Log::DEBUG);
return -1;
}
$exif = @exif_read_data($this->filepath, 'IFD0');
@@ -291,7 +274,7 @@ class OC_Image {
*/
public function fixOrientation() {
$o = $this->getOrientation();
- OC_Log::write('core','OC_Image->fixOrientation() Orientation: '.$o, OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->fixOrientation() Orientation: '.$o, OC_Log::DEBUG);
$rotate = 0;
$flip = false;
switch($o) {
@@ -341,15 +324,15 @@ class OC_Image {
$this->resource = $res;
return true;
} else {
- OC_Log::write('core','OC_Image->fixOrientation() Error during alphasaving.', OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->fixOrientation() Error during alphasaving.', OC_Log::DEBUG);
return false;
}
} else {
- OC_Log::write('core','OC_Image->fixOrientation() Error during alphablending.', OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->fixOrientation() Error during alphablending.', OC_Log::DEBUG);
return false;
}
} else {
- OC_Log::write('core','OC_Image->fixOrientation() Error during oriention fixing.', OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->fixOrientation() Error during oriention fixing.', OC_Log::DEBUG);
return false;
}
}
@@ -365,7 +348,7 @@ class OC_Image {
if(get_resource_type($imageref) == 'gd') {
$this->resource = $imageref;
return $this->resource;
- } elseif(in_array(get_resource_type($imageref), array('file','stream'))) {
+ } elseif(in_array(get_resource_type($imageref), array('file', 'stream'))) {
return $this->loadFromFileHandle($imageref);
}
} elseif($this->loadFromFile($imageref) !== false) {
@@ -375,7 +358,7 @@ class OC_Image {
} elseif($this->loadFromData($imageref) !== false) {
return $this->resource;
} else {
- OC_Log::write('core',__METHOD__.'(): couldn\'t load anything. Giving up!', OC_Log::DEBUG);
+ OC_Log::write('core', __METHOD__.'(): couldn\'t load anything. Giving up!', OC_Log::DEBUG);
return false;
}
}
@@ -387,7 +370,7 @@ class OC_Image {
* @returns An image resource or false on error
*/
public function loadFromFileHandle($handle) {
- OC_Log::write('core',__METHOD__.'(): Trying', OC_Log::DEBUG);
+ OC_Log::write('core', __METHOD__.'(): Trying', OC_Log::DEBUG);
$contents = stream_get_contents($handle);
if($this->loadFromData($contents)) {
return $this->resource;
@@ -402,7 +385,7 @@ class OC_Image {
public function loadFromFile($imagepath=false) {
if(!is_file($imagepath) || !file_exists($imagepath) || !is_readable($imagepath)) {
// Debug output disabled because this method is tried before loadFromBase64?
- OC_Log::write('core','OC_Image->loadFromFile, couldn\'t load: '.ellipsis($imagepath, 50), OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: '.$imagepath, OC_Log::DEBUG);
return false;
}
$itype = exif_imagetype($imagepath);
@@ -411,38 +394,40 @@ class OC_Image {
if (imagetypes() & IMG_GIF) {
$this->resource = imagecreatefromgif($imagepath);
} else {
- OC_Log::write('core','OC_Image->loadFromFile, GIF images not supported: '.$imagepath, OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->loadFromFile, GIF images not supported: '.$imagepath, OC_Log::DEBUG);
}
break;
case IMAGETYPE_JPEG:
if (imagetypes() & IMG_JPG) {
$this->resource = imagecreatefromjpeg($imagepath);
} else {
- OC_Log::write('core','OC_Image->loadFromFile, JPG images not supported: '.$imagepath, OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->loadFromFile, JPG images not supported: '.$imagepath, OC_Log::DEBUG);
}
break;
case IMAGETYPE_PNG:
if (imagetypes() & IMG_PNG) {
$this->resource = imagecreatefrompng($imagepath);
} else {
- OC_Log::write('core','OC_Image->loadFromFile, PNG images not supported: '.$imagepath, OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->loadFromFile, PNG images not supported: '.$imagepath, OC_Log::DEBUG);
}
break;
case IMAGETYPE_XBM:
if (imagetypes() & IMG_XPM) {
$this->resource = imagecreatefromxbm($imagepath);
} else {
- OC_Log::write('core','OC_Image->loadFromFile, XBM/XPM images not supported: '.$imagepath, OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->loadFromFile, XBM/XPM images not supported: '.$imagepath, OC_Log::DEBUG);
}
break;
case IMAGETYPE_WBMP:
- case IMAGETYPE_BMP:
if (imagetypes() & IMG_WBMP) {
$this->resource = imagecreatefromwbmp($imagepath);
} else {
- OC_Log::write('core','OC_Image->loadFromFile, (W)BMP images not supported: '.$imagepath, OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->loadFromFile, WBMP images not supported: '.$imagepath, OC_Log::DEBUG);
}
break;
+ case IMAGETYPE_BMP:
+ $this->resource = $this->imagecreatefrombmp($imagepath);
+ break;
/*
case IMAGETYPE_TIFF_II: // (intel byte order)
break;
@@ -472,7 +457,7 @@ class OC_Image {
// this is mostly file created from encrypted file
$this->resource = imagecreatefromstring(\OC_Filesystem::file_get_contents(\OC_Filesystem::getLocalPath($imagepath)));
$itype = IMAGETYPE_PNG;
- OC_Log::write('core','OC_Image->loadFromFile, Default', OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->loadFromFile, Default', OC_Log::DEBUG);
break;
}
if($this->valid()) {
@@ -493,7 +478,7 @@ class OC_Image {
}
$this->resource = @imagecreatefromstring($str);
if(!$this->resource) {
- OC_Log::write('core','OC_Image->loadFromData, couldn\'t load', OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->loadFromData, couldn\'t load', OC_Log::DEBUG);
return false;
}
return $this->resource;
@@ -512,7 +497,7 @@ class OC_Image {
if($data) { // try to load from string data
$this->resource = @imagecreatefromstring($data);
if(!$this->resource) {
- OC_Log::write('core','OC_Image->loadFromBase64, couldn\'t load', OC_Log::DEBUG);
+ OC_Log::write('core', 'OC_Image->loadFromBase64, couldn\'t load', OC_Log::DEBUG);
return false;
}
return $this->resource;
@@ -522,13 +507,154 @@ class OC_Image {
}
/**
+ * Create a new image from file or URL
+ * @link http://www.programmierer-forum.de/function-imagecreatefrombmp-laeuft-mit-allen-bitraten-t143137.htm
+ * @version 1.00
+ * @param string $filename <p>
+ * Path to the BMP image.
+ * </p>
+ * @return resource an image resource identifier on success, <b>FALSE</b> on errors.
+ */
+ private function imagecreatefrombmp($filename) {
+ if (!($fh = fopen($filename, 'rb'))) {
+ trigger_error('imagecreatefrombmp: Can not open ' . $filename, E_USER_WARNING);
+ return false;
+ }
+ // read file header
+ $meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14));
+ // check for bitmap
+ if ($meta['type'] != 19778) {
+ trigger_error('imagecreatefrombmp: ' . $filename . ' is not a bitmap!', E_USER_WARNING);
+ return false;
+ }
+ // read image header
+ $meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40));
+ // read additional 16bit header
+ if ($meta['bits'] == 16) {
+ $meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12));
+ }
+ // set bytes and padding
+ $meta['bytes'] = $meta['bits'] / 8;
+ $this->bit_depth = $meta['bits']; //remember the bit depth for the imagebmp call
+ $meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4)- floor($meta['width'] * $meta['bytes'] / 4)));
+ if ($meta['decal'] == 4) {
+ $meta['decal'] = 0;
+ }
+ // obtain imagesize
+ if ($meta['imagesize'] < 1) {
+ $meta['imagesize'] = $meta['filesize'] - $meta['offset'];
+ // in rare cases filesize is equal to offset so we need to read physical size
+ if ($meta['imagesize'] < 1) {
+ $meta['imagesize'] = @filesize($filename) - $meta['offset'];
+ if ($meta['imagesize'] < 1) {
+ trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $filename . '!', E_USER_WARNING);
+ return false;
+ }
+ }
+ }
+ // calculate colors
+ $meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors'];
+ // read color palette
+ $palette = array();
+ if ($meta['bits'] < 16) {
+ $palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4));
+ // in rare cases the color value is signed
+ if ($palette[1] < 0) {
+ foreach ($palette as $i => $color) {
+ $palette[$i] = $color + 16777216;
+ }
+ }
+ }
+ // create gd image
+ $im = imagecreatetruecolor($meta['width'], $meta['height']);
+ $data = fread($fh, $meta['imagesize']);
+ $p = 0;
+ $vide = chr(0);
+ $y = $meta['height'] - 1;
+ $error = 'imagecreatefrombmp: ' . $filename . ' has not enough data!';
+ // loop through the image data beginning with the lower left corner
+ while ($y >= 0) {
+ $x = 0;
+ while ($x < $meta['width']) {
+ switch ($meta['bits']) {
+ case 32:
+ case 24:
+ if (!($part = substr($data, $p, 3))) {
+ trigger_error($error, E_USER_WARNING);
+ return $im;
+ }
+ $color = unpack('V', $part . $vide);
+ break;
+ case 16:
+ if (!($part = substr($data, $p, 2))) {
+ trigger_error($error, E_USER_WARNING);
+ return $im;
+ }
+ $color = unpack('v', $part);
+ $color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3);
+ break;
+ case 8:
+ $color = unpack('n', $vide . substr($data, $p, 1));
+ $color[1] = $palette[ $color[1] + 1 ];
+ break;
+ case 4:
+ $color = unpack('n', $vide . substr($data, floor($p), 1));
+ $color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F;
+ $color[1] = $palette[ $color[1] + 1 ];
+ break;
+ case 1:
+ $color = unpack('n', $vide . substr($data, floor($p), 1));
+ switch (($p * 8) % 8) {
+ case 0:
+ $color[1] = $color[1] >> 7;
+ break;
+ case 1:
+ $color[1] = ($color[1] & 0x40) >> 6;
+ break;
+ case 2:
+ $color[1] = ($color[1] & 0x20) >> 5;
+ break;
+ case 3:
+ $color[1] = ($color[1] & 0x10) >> 4;
+ break;
+ case 4:
+ $color[1] = ($color[1] & 0x8) >> 3;
+ break;
+ case 5:
+ $color[1] = ($color[1] & 0x4) >> 2;
+ break;
+ case 6:
+ $color[1] = ($color[1] & 0x2) >> 1;
+ break;
+ case 7:
+ $color[1] = ($color[1] & 0x1);
+ break;
+ }
+ $color[1] = $palette[ $color[1] + 1 ];
+ break;
+ default:
+ trigger_error('imagecreatefrombmp: ' . $filename . ' has ' . $meta['bits'] . ' bits and this is not supported!', E_USER_WARNING);
+ return false;
+ }
+ imagesetpixel($im, $x, $y, $color[1]);
+ $x++;
+ $p += $meta['bytes'];
+ }
+ $y--;
+ $p += $meta['decal'];
+ }
+ fclose($fh);
+ return $im;
+ }
+
+ /**
* @brief Resizes the image preserving ratio.
* @param $maxsize The maximum size of either the width or height.
* @returns bool
*/
public function resize($maxsize) {
if(!$this->valid()) {
- OC_Log::write('core',__METHOD__.'(): No image loaded', OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR);
return false;
}
$width_orig=imageSX($this->resource);
@@ -549,7 +675,7 @@ class OC_Image {
public function preciseResize($width, $height) {
if (!$this->valid()) {
- OC_Log::write('core',__METHOD__.'(): No image loaded', OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR);
return false;
}
$width_orig=imageSX($this->resource);
@@ -557,14 +683,14 @@ class OC_Image {
$process = imagecreatetruecolor($width, $height);
if ($process == false) {
- OC_Log::write('core',__METHOD__.'(): Error creating true color image',OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): Error creating true color image', OC_Log::ERROR);
imagedestroy($process);
return false;
}
imagecopyresampled($process, $this->resource, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
if ($process == false) {
- OC_Log::write('core',__METHOD__.'(): Error resampling process image '.$width.'x'.$height,OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): Error resampling process image '.$width.'x'.$height, OC_Log::ERROR);
imagedestroy($process);
return false;
}
@@ -580,7 +706,7 @@ class OC_Image {
*/
public function centerCrop($size=0) {
if(!$this->valid()) {
- OC_Log::write('core','OC_Image->centerCrop, No image loaded', OC_Log::ERROR);
+ OC_Log::write('core', 'OC_Image->centerCrop, No image loaded', OC_Log::ERROR);
return false;
}
$width_orig=imageSX($this->resource);
@@ -607,13 +733,13 @@ class OC_Image {
}
$process = imagecreatetruecolor($targetWidth, $targetHeight);
if ($process == false) {
- OC_Log::write('core','OC_Image->centerCrop. Error creating true color image',OC_Log::ERROR);
+ OC_Log::write('core', 'OC_Image->centerCrop. Error creating true color image', OC_Log::ERROR);
imagedestroy($process);
return false;
}
imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $targetWidth, $targetHeight, $width, $height);
if ($process == false) {
- OC_Log::write('core','OC_Image->centerCrop. Error resampling process image '.$width.'x'.$height,OC_Log::ERROR);
+ OC_Log::write('core', 'OC_Image->centerCrop. Error resampling process image '.$width.'x'.$height, OC_Log::ERROR);
imagedestroy($process);
return false;
}
@@ -627,23 +753,23 @@ class OC_Image {
* @param $x Horizontal position
* @param $y Vertical position
* @param $w Width
- * @param $h Hight
+ * @param $h Height
* @returns bool for success or failure
*/
public function crop($x, $y, $w, $h) {
if(!$this->valid()) {
- OC_Log::write('core',__METHOD__.'(): No image loaded', OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR);
return false;
}
$process = imagecreatetruecolor($w, $h);
if ($process == false) {
- OC_Log::write('core',__METHOD__.'(): Error creating true color image',OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): Error creating true color image', OC_Log::ERROR);
imagedestroy($process);
return false;
}
imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $w, $h, $w, $h);
if ($process == false) {
- OC_Log::write('core',__METHOD__.'(): Error resampling process image '.$w.'x'.$h,OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): Error resampling process image '.$w.'x'.$h, OC_Log::ERROR);
imagedestroy($process);
return false;
}
@@ -660,7 +786,7 @@ class OC_Image {
*/
public function fitIn($maxWidth, $maxHeight) {
if(!$this->valid()) {
- OC_Log::write('core',__METHOD__.'(): No image loaded', OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.'(): No image loaded', OC_Log::ERROR);
return false;
}
$width_orig=imageSX($this->resource);
@@ -669,7 +795,7 @@ class OC_Image {
$newWidth = min($maxWidth, $ratio*$maxHeight);
$newHeight = min($maxHeight, $maxWidth/$ratio);
-
+
$this->preciseResize(round($newWidth), round($newHeight));
return true;
}
@@ -685,3 +811,138 @@ class OC_Image {
$this->destroy();
}
}
+if ( ! function_exists( 'imagebmp') ) {
+ /**
+ * Output a BMP image to either the browser or a file
+ * @link http://www.ugia.cn/wp-data/imagebmp.php
+ * @author legend <legendsky@hotmail.com>
+ * @link http://www.programmierer-forum.de/imagebmp-gute-funktion-gefunden-t143716.htm
+ * @author mgutt <marc@gutt.it>
+ * @version 1.00
+ * @param resource $image
+ * @param string $filename [optional] <p>The path to save the file to.</p>
+ * @param int $bit [optional] <p>Bit depth, (default is 24).</p>
+ * @param int $compression [optional]
+ * @return bool <b>TRUE</b> on success or <b>FALSE</b> on failure.
+ */
+ function imagebmp($im, $filename='', $bit=24, $compression=0) {
+ if (!in_array($bit, array(1, 4, 8, 16, 24, 32))) {
+ $bit = 24;
+ }
+ else if ($bit == 32) {
+ $bit = 24;
+ }
+ $bits = pow(2, $bit);
+ imagetruecolortopalette($im, true, $bits);
+ $width = imagesx($im);
+ $height = imagesy($im);
+ $colors_num = imagecolorstotal($im);
+ $rgb_quad = '';
+ if ($bit <= 8) {
+ for ($i = 0; $i < $colors_num; $i++) {
+ $colors = imagecolorsforindex($im, $i);
+ $rgb_quad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0";
+ }
+ $bmp_data = '';
+ if ($compression == 0 || $bit < 8) {
+ $compression = 0;
+ $extra = '';
+ $padding = 4 - ceil($width / (8 / $bit)) % 4;
+ if ($padding % 4 != 0) {
+ $extra = str_repeat("\0", $padding);
+ }
+ for ($j = $height - 1; $j >= 0; $j --) {
+ $i = 0;
+ while ($i < $width) {
+ $bin = 0;
+ $limit = $width - $i < 8 / $bit ? (8 / $bit - $width + $i) * $bit : 0;
+ for ($k = 8 - $bit; $k >= $limit; $k -= $bit) {
+ $index = imagecolorat($im, $i, $j);
+ $bin |= $index << $k;
+ $i++;
+ }
+ $bmp_data .= chr($bin);
+ }
+ $bmp_data .= $extra;
+ }
+ }
+ // RLE8
+ else if ($compression == 1 && $bit == 8) {
+ for ($j = $height - 1; $j >= 0; $j--) {
+ $last_index = "\0";
+ $same_num = 0;
+ for ($i = 0; $i <= $width; $i++) {
+ $index = imagecolorat($im, $i, $j);
+ if ($index !== $last_index || $same_num > 255) {
+ if ($same_num != 0) {
+ $bmp_data .= chr($same_num) . chr($last_index);
+ }
+ $last_index = $index;
+ $same_num = 1;
+ }
+ else {
+ $same_num++;
+ }
+ }
+ $bmp_data .= "\0\0";
+ }
+ $bmp_data .= "\0\1";
+ }
+ $size_quad = strlen($rgb_quad);
+ $size_data = strlen($bmp_data);
+ }
+ else {
+ $extra = '';
+ $padding = 4 - ($width * ($bit / 8)) % 4;
+ if ($padding % 4 != 0) {
+ $extra = str_repeat("\0", $padding);
+ }
+ $bmp_data = '';
+ for ($j = $height - 1; $j >= 0; $j--) {
+ for ($i = 0; $i < $width; $i++) {
+ $index = imagecolorat($im, $i, $j);
+ $colors = imagecolorsforindex($im, $index);
+ if ($bit == 16) {
+ $bin = 0 << $bit;
+ $bin |= ($colors['red'] >> 3) << 10;
+ $bin |= ($colors['green'] >> 3) << 5;
+ $bin |= $colors['blue'] >> 3;
+ $bmp_data .= pack("v", $bin);
+ }
+ else {
+ $bmp_data .= pack("c*", $colors['blue'], $colors['green'], $colors['red']);
+ }
+ }
+ $bmp_data .= $extra;
+ }
+ $size_quad = 0;
+ $size_data = strlen($bmp_data);
+ $colors_num = 0;
+ }
+ $file_header = 'BM' . pack('V3', 54 + $size_quad + $size_data, 0, 54 + $size_quad);
+ $info_header = pack('V3v2V*', 0x28, $width, $height, 1, $bit, $compression, $size_data, 0, 0, $colors_num, 0);
+ if ($filename != '') {
+ $fp = fopen($filename, 'wb');
+ fwrite($fp, $file_header . $info_header . $rgb_quad . $bmp_data);
+ fclose($fp);
+ return true;
+ }
+ echo $file_header . $info_header. $rgb_quad . $bmp_data;
+ return true;
+ }
+}
+
+if ( ! function_exists( 'exif_imagetype' ) ) {
+ /**
+ * Workaround if exif_imagetype does not exist
+ * @link http://www.php.net/manual/en/function.exif-imagetype.php#80383
+ * @param string $filename
+ * @return string|boolean
+ */
+ function exif_imagetype ( $filename ) {
+ if ( ( $info = getimagesize( $filename ) ) !== false ) {
+ return $info[2];
+ }
+ return false;
+ }
+}
diff --git a/lib/installer.php b/lib/installer.php
index 9135c60fc05..7dc8b0cef8d 100644
--- a/lib/installer.php
+++ b/lib/installer.php
@@ -57,7 +57,7 @@ class OC_Installer{
*/
public static function installApp( $data = array()) {
if(!isset($data['source'])) {
- OC_Log::write('core','No source specified when installing app',OC_Log::ERROR);
+ OC_Log::write('core', 'No source specified when installing app', OC_Log::ERROR);
return false;
}
@@ -65,13 +65,13 @@ class OC_Installer{
if($data['source']=='http') {
$path=OC_Helper::tmpFile();
if(!isset($data['href'])) {
- OC_Log::write('core','No href specified when installing app from http',OC_Log::ERROR);
+ OC_Log::write('core', 'No href specified when installing app from http', OC_Log::ERROR);
return false;
}
- copy($data['href'],$path);
+ copy($data['href'], $path);
}else{
if(!isset($data['path'])) {
- OC_Log::write('core','No path specified when installing app from local file',OC_Log::ERROR);
+ OC_Log::write('core', 'No path specified when installing app from local file', OC_Log::ERROR);
return false;
}
$path=$data['path'];
@@ -80,13 +80,13 @@ class OC_Installer{
//detect the archive type
$mime=OC_Helper::getMimeType($path);
if($mime=='application/zip') {
- rename($path,$path.'.zip');
+ rename($path, $path.'.zip');
$path.='.zip';
}elseif($mime=='application/x-gzip') {
- rename($path,$path.'.tgz');
+ rename($path, $path.'.tgz');
$path.='.tgz';
}else{
- OC_Log::write('core','Archives of type '.$mime.' are not supported',OC_Log::ERROR);
+ OC_Log::write('core', 'Archives of type '.$mime.' are not supported', OC_Log::ERROR);
return false;
}
@@ -97,7 +97,7 @@ class OC_Installer{
if($archive=OC_Archive::open($path)) {
$archive->extract($extractDir);
} else {
- OC_Log::write('core','Failed to open archive when installing app',OC_Log::ERROR);
+ OC_Log::write('core', 'Failed to open archive when installing app', OC_Log::ERROR);
OC_Helper::rmdirr($extractDir);
if($data['source']=='http') {
unlink($path);
@@ -118,17 +118,17 @@ class OC_Installer{
}
}
if(!is_file($extractDir.'/appinfo/info.xml')) {
- OC_Log::write('core','App does not provide an info.xml file',OC_Log::ERROR);
+ OC_Log::write('core', 'App does not provide an info.xml file', OC_Log::ERROR);
OC_Helper::rmdirr($extractDir);
if($data['source']=='http') {
unlink($path);
}
return false;
}
- $info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml',true);
+ $info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml', true);
// check the code for not allowed calls
- if(!OC_Installer::checkCode($info['id'],$extractDir)) {
- OC_Log::write('core','App can\'t be installed because of not allowed code in the App',OC_Log::ERROR);
+ if(!OC_Installer::checkCode($info['id'], $extractDir)) {
+ OC_Log::write('core', 'App can\'t be installed because of not allowed code in the App', OC_Log::ERROR);
OC_Helper::rmdirr($extractDir);
return false;
}
@@ -136,14 +136,14 @@ class OC_Installer{
// check if the app is compatible with this version of ownCloud
$version=OC_Util::getVersion();
if(!isset($info['require']) or ($version[0]>$info['require'])) {
- OC_Log::write('core','App can\'t be installed because it is not compatible with this version of ownCloud',OC_Log::ERROR);
+ OC_Log::write('core', 'App can\'t be installed because it is not compatible with this version of ownCloud', OC_Log::ERROR);
OC_Helper::rmdirr($extractDir);
return false;
}
//check if an app with the same id is already installed
if(self::isInstalled( $info['id'] )) {
- OC_Log::write('core','App already installed',OC_Log::WARN);
+ OC_Log::write('core', 'App already installed', OC_Log::WARN);
OC_Helper::rmdirr($extractDir);
if($data['source']=='http') {
unlink($path);
@@ -154,7 +154,7 @@ class OC_Installer{
$basedir=OC_App::getInstallPath().'/'.$info['id'];
//check if the destination directory already exists
if(is_dir($basedir)) {
- OC_Log::write('core','App directory already exists',OC_Log::WARN);
+ OC_Log::write('core', 'App directory already exists', OC_Log::WARN);
OC_Helper::rmdirr($extractDir);
if($data['source']=='http') {
unlink($path);
@@ -168,14 +168,14 @@ class OC_Installer{
//copy the app to the correct place
if(@!mkdir($basedir)) {
- OC_Log::write('core','Can\'t create app folder. Please fix permissions. ('.$basedir.')',OC_Log::ERROR);
+ OC_Log::write('core', 'Can\'t create app folder. Please fix permissions. ('.$basedir.')', OC_Log::ERROR);
OC_Helper::rmdirr($extractDir);
if($data['source']=='http') {
unlink($path);
}
return false;
}
- OC_Helper::copyr($extractDir,$basedir);
+ OC_Helper::copyr($extractDir, $basedir);
//remove temporary files
OC_Helper::rmdirr($extractDir);
@@ -187,12 +187,12 @@ class OC_Installer{
//run appinfo/install.php
if((!isset($data['noinstall']) or $data['noinstall']==false) and file_exists($basedir.'/appinfo/install.php')) {
- include($basedir.'/appinfo/install.php');
+ include $basedir.'/appinfo/install.php';
}
//set the installed version
- OC_Appconfig::setValue($info['id'],'installed_version',OC_App::getAppVersion($info['id']));
- OC_Appconfig::setValue($info['id'],'enabled','no');
+ OC_Appconfig::setValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id']));
+ OC_Appconfig::setValue($info['id'], 'enabled', 'no');
//set remote/public handelers
foreach($info['remote'] as $name=>$path) {
@@ -248,7 +248,7 @@ class OC_Installer{
* -# including appinfo/upgrade.php
* -# setting the installed version
*
- * upgrade.php can determine the current installed version of the app using "OC_Appconfig::getValue($appid,'installed_version')"
+ * upgrade.php can determine the current installed version of the app using "OC_Appconfig::getValue($appid, 'installed_version')"
*/
public static function upgradeApp( $data = array()) {
// TODO: write function
@@ -296,7 +296,7 @@ class OC_Installer{
$enabled = isset($info['default_enable']);
if( $enabled ) {
OC_Installer::installShippedApp($filename);
- OC_Appconfig::setValue($filename,'enabled','yes');
+ OC_Appconfig::setValue($filename, 'enabled', 'yes');
}
}
}
@@ -320,10 +320,10 @@ class OC_Installer{
//run appinfo/install.php
if(is_file(OC_App::getAppPath($app)."/appinfo/install.php")) {
- include(OC_App::getAppPath($app)."/appinfo/install.php");
+ include OC_App::getAppPath($app)."/appinfo/install.php";
}
$info=OC_App::getAppInfo($app);
- OC_Appconfig::setValue($app,'installed_version',OC_App::getAppVersion($app));
+ OC_Appconfig::setValue($app, 'installed_version', OC_App::getAppVersion($app));
//set remote/public handelers
foreach($info['remote'] as $name=>$path) {
@@ -344,7 +344,7 @@ class OC_Installer{
* @param string $folder the folder of the app to check
* @returns true for app is o.k. and false for app is not o.k.
*/
- public static function checkCode($appname,$folder) {
+ public static function checkCode($appname, $folder) {
$blacklist=array(
'exec(',
@@ -360,7 +360,7 @@ class OC_Installer{
// check if grep is installed
$grep = exec('which grep');
if($grep=='') {
- OC_Log::write('core','grep not installed. So checking the code of the app "'.$appname.'" was not possible',OC_Log::ERROR);
+ OC_Log::write('core', 'grep not installed. So checking the code of the app "'.$appname.'" was not possible', OC_Log::ERROR);
return true;
}
@@ -370,7 +370,7 @@ class OC_Installer{
$result = exec($cmd);
// bad pattern found
if($result<>'') {
- OC_Log::write('core','App "'.$appname.'" is using a not allowed call "'.$bl.'". Installation refused.',OC_Log::ERROR);
+ OC_Log::write('core', 'App "'.$appname.'" is using a not allowed call "'.$bl.'". Installation refused.', OC_Log::ERROR);
return false;
}
}
diff --git a/lib/json.php b/lib/json.php
index 518c3c87c49..204430411c0 100644
--- a/lib/json.php
+++ b/lib/json.php
@@ -58,6 +58,7 @@ class OC_JSON{
*/
public static function checkAdminUser() {
self::checkLoggedIn();
+ self::verifyUser();
if( !OC_Group::inGroup( OC_User::getUser(), 'admin' )) {
$l = OC_L10N::get('lib');
self::error(array( 'data' => array( 'message' => $l->t('Authentication error') )));
@@ -70,7 +71,8 @@ class OC_JSON{
*/
public static function checkSubAdminUser() {
self::checkLoggedIn();
- if(!OC_Group::inGroup(OC_User::getUser(),'admin') && !OC_SubAdmin::isSubAdmin(OC_User::getUser())) {
+ self::verifyUser();
+ if(!OC_Group::inGroup(OC_User::getUser(), 'admin') && !OC_SubAdmin::isSubAdmin(OC_User::getUser())) {
$l = OC_L10N::get('lib');
self::error(array( 'data' => array( 'message' => $l->t('Authentication error') )));
exit();
@@ -78,6 +80,19 @@ class OC_JSON{
}
/**
+ * Check if the user verified the login with his password
+ */
+ public static function verifyUser() {
+ if(OC_Config::getValue('enhancedauth', false) === true) {
+ if(!isset($_SESSION['verifiedLogin']) OR $_SESSION['verifiedLogin'] < time()) {
+ $l = OC_L10N::get('lib');
+ self::error(array( 'data' => array( 'message' => $l->t('Authentication error') )));
+ exit();
+ }
+ }
+ }
+
+ /**
* Send json error msg
*/
public static function error($data = array()) {
@@ -105,7 +120,7 @@ class OC_JSON{
/**
* Encode and print $data in json format
*/
- public static function encodedPrint($data,$setContentType=true) {
+ public static function encodedPrint($data, $setContentType=true) {
// Disable mimesniffing, don't move this to setContentTypeHeader!
header( 'X-Content-Type-Options: nosniff' );
if($setContentType) {
diff --git a/lib/l10n.php b/lib/l10n.php
index 4eb4c323d88..f172710e5d7 100644
--- a/lib/l10n.php
+++ b/lib/l10n.php
@@ -58,22 +58,24 @@ class OC_L10N{
* Localization
*/
private $localizations = array(
- 'date' => 'd.m.Y',
- 'datetime' => 'd.m.Y H:i:s',
- 'time' => 'H:i:s');
+ 'jsdate' => 'dd.mm.yy',
+ 'date' => '%d.%m.%Y',
+ 'datetime' => '%d.%m.%Y %H:%M:%S',
+ 'time' => '%H:%M:%S',
+ 'firstday' => 0);
/**
* get an L10N instance
* @return OC_L10N
*/
- public static function get($app,$lang=null) {
+ public static function get($app, $lang=null) {
if(is_null($lang)) {
if(!isset(self::$instances[$app])) {
self::$instances[$app]=new OC_L10N($app);
}
return self::$instances[$app];
}else{
- return new OC_L10N($app,$lang);
+ return new OC_L10N($app, $lang);
}
}
@@ -118,7 +120,7 @@ class OC_L10N{
OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/lib/l10n/') ||
OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/settings')) && file_exists($i18ndir.$lang.'.php')) {
// Include the file, save the data from $CONFIG
- include(strip_tags($i18ndir).strip_tags($lang).'.php');
+ include strip_tags($i18ndir).strip_tags($lang).'.php';
if(isset($TRANSLATIONS) && is_array($TRANSLATIONS)) {
$this->translations = $TRANSLATIONS;
}
@@ -126,7 +128,7 @@ class OC_L10N{
if(file_exists(OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php')) {
// Include the file, save the data from $CONFIG
- include(OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php');
+ include OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php';
if(isset($LOCALIZATIONS) && is_array($LOCALIZATIONS)) {
$this->localizations = array_merge($this->localizations, $LOCALIZATIONS);
}
@@ -165,7 +167,7 @@ class OC_L10N{
*
*/
public function tA($textArray) {
- OC_Log::write('core', 'DEPRECATED: the method tA is deprecated and will be removed soon.',OC_Log::WARN);
+ OC_Log::write('core', 'DEPRECATED: the method tA is deprecated and will be removed soon.', OC_Log::WARN);
$result = array();
foreach($textArray as $key => $text) {
$result[$key] = (string)$this->t($text);
@@ -216,8 +218,21 @@ class OC_L10N{
case 'time':
if($data instanceof DateTime) return $data->format($this->localizations[$type]);
elseif(is_string($data)) $data = strtotime($data);
- return date($this->localizations[$type], $data);
+ $locales = array(self::findLanguage());
+ if (strlen($locales[0]) == 2) {
+ $locales[] = $locales[0].'_'.strtoupper($locales[0]);
+ }
+ setlocale(LC_TIME, $locales);
+ $format = $this->localizations[$type];
+ // Check for Windows to find and replace the %e modifier correctly
+ if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
+ $format = preg_replace('#(?<!%)((?:%%)*)%e#', '\1%#d', $format);
+ }
+ return strftime($format, $data);
break;
+ case 'firstday':
+ case 'jsdate':
+ return $this->localizations[$type];
default:
return false;
}
diff --git a/lib/l10n/ar.php b/lib/l10n/ar.php
new file mode 100644
index 00000000000..3ae226f04fd
--- /dev/null
+++ b/lib/l10n/ar.php
@@ -0,0 +1,9 @@
+<?php $TRANSLATIONS = array(
+"Help" => "المساعدة",
+"Personal" => "شخصي",
+"Settings" => "تعديلات",
+"Users" => "المستخدمين",
+"Authentication error" => "لم يتم التأكد من الشخصية بنجاح",
+"Files" => "الملفات",
+"Text" => "معلومات إضافية"
+);
diff --git a/lib/l10n/bg_BG.php b/lib/l10n/bg_BG.php
new file mode 100644
index 00000000000..3eb0660d944
--- /dev/null
+++ b/lib/l10n/bg_BG.php
@@ -0,0 +1,4 @@
+<?php $TRANSLATIONS = array(
+"Personal" => "Лично",
+"Authentication error" => "Проблем с идентификацията"
+);
diff --git a/lib/l10n/ca.php b/lib/l10n/ca.php
index 031207227ec..b3321ef82e1 100644
--- a/lib/l10n/ca.php
+++ b/lib/l10n/ca.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "L'aplicació no està habilitada",
"Authentication error" => "Error d'autenticació",
"Token expired. Please reload page." => "El testimoni ha expirat. Torneu a carregar la pàgina.",
+"Files" => "Fitxers",
+"Text" => "Text",
+"Images" => "Imatges",
"seconds ago" => "segons enrere",
"1 minute ago" => "fa 1 minut",
"%d minutes ago" => "fa %d minuts",
+"1 hour ago" => "fa 1 hora",
+"%d hours ago" => "fa %d hores",
"today" => "avui",
"yesterday" => "ahir",
"%d days ago" => "fa %d dies",
"last month" => "el mes passat",
-"months ago" => "mesos enrere",
+"%d months ago" => "fa %d mesos",
"last year" => "l'any passat",
"years ago" => "fa anys",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s està disponible. Obtén <a href=\"%s\">més informació</a>",
"up to date" => "actualitzat",
-"updates check is disabled" => "la comprovació d'actualitzacions està desactivada"
+"updates check is disabled" => "la comprovació d'actualitzacions està desactivada",
+"Could not find category \"%s\"" => "No s'ha trobat la categoria \"%s\""
);
diff --git a/lib/l10n/cs_CZ.php b/lib/l10n/cs_CZ.php
index 00815f97533..fa11e886774 100644
--- a/lib/l10n/cs_CZ.php
+++ b/lib/l10n/cs_CZ.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Aplikace není povolena",
"Authentication error" => "Chyba ověření",
"Token expired. Please reload page." => "Token vypršel. Obnovte prosím stránku.",
+"Files" => "Soubory",
+"Text" => "Text",
+"Images" => "Obrázky",
"seconds ago" => "před vteřinami",
"1 minute ago" => "před 1 minutou",
"%d minutes ago" => "před %d minutami",
+"1 hour ago" => "před hodinou",
+"%d hours ago" => "před %d hodinami",
"today" => "dnes",
"yesterday" => "včera",
"%d days ago" => "před %d dny",
"last month" => "minulý měsíc",
-"months ago" => "před měsíci",
+"%d months ago" => "Před %d měsíci",
"last year" => "loni",
"years ago" => "před lety",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s je dostupná. Získat <a href=\"%s\">více informací</a>",
"up to date" => "aktuální",
-"updates check is disabled" => "kontrola aktualizací je vypnuta"
+"updates check is disabled" => "kontrola aktualizací je vypnuta",
+"Could not find category \"%s\"" => "Nelze nalézt kategorii \"%s\""
);
diff --git a/lib/l10n/da.php b/lib/l10n/da.php
index 09124c18290..7458b329782 100644
--- a/lib/l10n/da.php
+++ b/lib/l10n/da.php
@@ -12,6 +12,8 @@
"Application is not enabled" => "Programmet er ikke aktiveret",
"Authentication error" => "Adgangsfejl",
"Token expired. Please reload page." => "Adgang er udløbet. Genindlæs siden.",
+"Files" => "Filer",
+"Text" => "SMS",
"seconds ago" => "sekunder siden",
"1 minute ago" => "1 minut siden",
"%d minutes ago" => "%d minutter siden",
@@ -19,7 +21,6 @@
"yesterday" => "I går",
"%d days ago" => "%d dage siden",
"last month" => "Sidste måned",
-"months ago" => "måneder siden",
"last year" => "Sidste år",
"years ago" => "år siden",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s er tilgængelig. Få <a href=\"%s\">mere information</a>",
diff --git a/lib/l10n/de.php b/lib/l10n/de.php
index 8c81be16582..7724d8c684f 100644
--- a/lib/l10n/de.php
+++ b/lib/l10n/de.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Die Anwendung ist nicht aktiviert",
"Authentication error" => "Authentifizierungs-Fehler",
"Token expired. Please reload page." => "Token abgelaufen. Bitte lade die Seite neu.",
-"seconds ago" => "Vor wenigen Sekunden",
+"Files" => "Dateien",
+"Text" => "Text",
+"Images" => "Bilder",
+"seconds ago" => "Gerade eben",
"1 minute ago" => "Vor einer Minute",
"%d minutes ago" => "Vor %d Minuten",
+"1 hour ago" => "Vor einer Stunde",
+"%d hours ago" => "Vor %d Stunden",
"today" => "Heute",
"yesterday" => "Gestern",
"%d days ago" => "Vor %d Tag(en)",
"last month" => "Letzten Monat",
-"months ago" => "Vor Monaten",
+"%d months ago" => "Vor %d Monaten",
"last year" => "Letztes Jahr",
-"years ago" => "Vor Jahren",
+"years ago" => "Vor wenigen Jahren",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s ist verfügbar. <a href=\"%s\">Weitere Informationen</a>",
"up to date" => "aktuell",
-"updates check is disabled" => "Die Update-Überprüfung ist ausgeschaltet"
+"updates check is disabled" => "Die Update-Überprüfung ist ausgeschaltet",
+"Could not find category \"%s\"" => "Die Kategorie \"%s\" konnte nicht gefunden werden."
);
diff --git a/lib/l10n/de_DE.php b/lib/l10n/de_DE.php
new file mode 100644
index 00000000000..95596a7a33a
--- /dev/null
+++ b/lib/l10n/de_DE.php
@@ -0,0 +1,34 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Hilfe",
+"Personal" => "Persönlich",
+"Settings" => "Einstellungen",
+"Users" => "Benutzer",
+"Apps" => "Apps",
+"Admin" => "Administrator",
+"ZIP download is turned off." => "Der ZIP-Download ist deaktiviert.",
+"Files need to be downloaded one by one." => "Die Dateien müssen einzeln heruntergeladen werden.",
+"Back to Files" => "Zurück zu \"Dateien\"",
+"Selected files too large to generate zip file." => "Die gewählten Dateien sind zu groß, um eine ZIP-Datei zu erstellen.",
+"Application is not enabled" => "Die Anwendung ist nicht aktiviert",
+"Authentication error" => "Authentifizierungs-Fehler",
+"Token expired. Please reload page." => "Token abgelaufen. Bitte laden Sie die Seite neu.",
+"Files" => "Dateien",
+"Text" => "Text",
+"Images" => "Bilder",
+"seconds ago" => "Gerade eben",
+"1 minute ago" => "Vor einer Minute",
+"%d minutes ago" => "Vor %d Minuten",
+"1 hour ago" => "Vor einer Stunde",
+"%d hours ago" => "Vor %d Stunden",
+"today" => "Heute",
+"yesterday" => "Gestern",
+"%d days ago" => "Vor %d Tag(en)",
+"last month" => "Letzten Monat",
+"%d months ago" => "Vor %d Monaten",
+"last year" => "Letztes Jahr",
+"years ago" => "Vor wenigen Jahren",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s ist verfügbar. <a href=\"%s\">Weitere Informationen</a>",
+"up to date" => "aktuell",
+"updates check is disabled" => "Die Update-Überprüfung ist ausgeschaltet",
+"Could not find category \"%s\"" => "Die Kategorie \"%s\" konnte nicht gefunden werden."
+);
diff --git a/lib/l10n/el.php b/lib/l10n/el.php
index e4e12490711..315b995ecc9 100644
--- a/lib/l10n/el.php
+++ b/lib/l10n/el.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Δεν ενεργοποιήθηκε η εφαρμογή",
"Authentication error" => "Σφάλμα πιστοποίησης",
"Token expired. Please reload page." => "Το αναγνωριστικό έληξε. Παρακαλώ φορτώστε ξανά την σελίδα.",
+"Files" => "Αρχεία",
+"Text" => "Κείμενο",
+"Images" => "Εικόνες",
"seconds ago" => "δευτερόλεπτα πριν",
"1 minute ago" => "1 λεπτό πριν",
"%d minutes ago" => "%d λεπτά πριν",
+"1 hour ago" => "1 ώρα πριν",
+"%d hours ago" => "%d ώρες πριν",
"today" => "σήμερα",
"yesterday" => "χθές",
"%d days ago" => "%d ημέρες πριν",
"last month" => "τον προηγούμενο μήνα",
-"months ago" => "μήνες πριν",
+"%d months ago" => "%d μήνες πριν",
"last year" => "τον προηγούμενο χρόνο",
"years ago" => "χρόνια πριν",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s είναι διαθέσιμα. Δείτε <a href=\"%s\">περισσότερες πληροφορίες</a>",
"up to date" => "ενημερωμένο",
-"updates check is disabled" => "ο έλεγχος ενημερώσεων είναι απενεργοποιημένος"
+"updates check is disabled" => "ο έλεγχος ενημερώσεων είναι απενεργοποιημένος",
+"Could not find category \"%s\"" => "Αδυναμία εύρεσης κατηγορίας \"%s\""
);
diff --git a/lib/l10n/eo.php b/lib/l10n/eo.php
index b3c1c52ecee..dac11ffe7e6 100644
--- a/lib/l10n/eo.php
+++ b/lib/l10n/eo.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "La aplikaĵo ne estas kapabligita",
"Authentication error" => "Aŭtentiga eraro",
"Token expired. Please reload page." => "Ĵetono eksvalidiĝis. Bonvolu reŝargi la paĝon.",
+"Files" => "Dosieroj",
+"Text" => "Teksto",
+"Images" => "Bildoj",
"seconds ago" => "sekundojn antaŭe",
"1 minute ago" => "antaŭ 1 minuto",
"%d minutes ago" => "antaŭ %d minutoj",
+"1 hour ago" => "antaŭ 1 horo",
+"%d hours ago" => "antaŭ %d horoj",
"today" => "hodiaŭ",
"yesterday" => "hieraŭ",
"%d days ago" => "antaŭ %d tagoj",
"last month" => "lasta monato",
-"months ago" => "monatojn antaŭe",
+"%d months ago" => "antaŭ %d monatoj",
"last year" => "lasta jaro",
"years ago" => "jarojn antaŭe",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s haveblas. Ekhavu <a href=\"%s\">pli da informo</a>",
"up to date" => "ĝisdata",
-"updates check is disabled" => "ĝisdateckontrolo estas malkapabligita"
+"updates check is disabled" => "ĝisdateckontrolo estas malkapabligita",
+"Could not find category \"%s\"" => "Ne troviĝis kategorio “%s”"
);
diff --git a/lib/l10n/es.php b/lib/l10n/es.php
index 6d2a310ca3b..f843c42dfd3 100644
--- a/lib/l10n/es.php
+++ b/lib/l10n/es.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "La aplicación no está habilitada",
"Authentication error" => "Error de autenticación",
"Token expired. Please reload page." => "Token expirado. Por favor, recarga la página.",
+"Files" => "Archivos",
+"Text" => "Texto",
+"Images" => "Imágenes",
"seconds ago" => "hace segundos",
"1 minute ago" => "hace 1 minuto",
"%d minutes ago" => "hace %d minutos",
+"1 hour ago" => "Hace 1 hora",
+"%d hours ago" => "Hace %d horas",
"today" => "hoy",
"yesterday" => "ayer",
"%d days ago" => "hace %d días",
"last month" => "este mes",
-"months ago" => "hace meses",
+"%d months ago" => "Hace %d meses",
"last year" => "este año",
"years ago" => "hace años",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s está disponible. Obtén <a href=\"%s\">más información</a>",
"up to date" => "actualizado",
-"updates check is disabled" => "comprobar actualizaciones está desactivado"
+"updates check is disabled" => "comprobar actualizaciones está desactivado",
+"Could not find category \"%s\"" => "No puede encontrar la categoria \"%s\""
);
diff --git a/lib/l10n/es_AR.php b/lib/l10n/es_AR.php
index fd50027d8a1..2bbffd39e9e 100644
--- a/lib/l10n/es_AR.php
+++ b/lib/l10n/es_AR.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "La aplicación no está habilitada",
"Authentication error" => "Error de autenticación",
"Token expired. Please reload page." => "Token expirado. Por favor, recargá la página.",
+"Files" => "Archivos",
+"Text" => "Texto",
+"Images" => "Imágenes",
"seconds ago" => "hace unos segundos",
"1 minute ago" => "hace 1 minuto",
"%d minutes ago" => "hace %d minutos",
+"1 hour ago" => "1 hora atrás",
+"%d hours ago" => "%d horas atrás",
"today" => "hoy",
"yesterday" => "ayer",
"%d days ago" => "hace %d días",
"last month" => "este mes",
-"months ago" => "hace meses",
+"%d months ago" => "%d meses atrás",
"last year" => "este año",
"years ago" => "hace años",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s está disponible. Conseguí <a href=\"%s\">más información</a>",
"up to date" => "actualizado",
-"updates check is disabled" => "comprobar actualizaciones está desactivado"
+"updates check is disabled" => "comprobar actualizaciones está desactivado",
+"Could not find category \"%s\"" => "No fue posible encontrar la categoría \"%s\""
);
diff --git a/lib/l10n/et_EE.php b/lib/l10n/et_EE.php
index 87f222af838..906abf9430a 100644
--- a/lib/l10n/et_EE.php
+++ b/lib/l10n/et_EE.php
@@ -12,6 +12,9 @@
"Application is not enabled" => "Rakendus pole sisse lülitatud",
"Authentication error" => "Autentimise viga",
"Token expired. Please reload page." => "Kontrollkood aegus. Paelun lae leht uuesti.",
+"Files" => "Failid",
+"Text" => "Tekst",
+"Images" => "Pildid",
"seconds ago" => "sekundit tagasi",
"1 minute ago" => "1 minut tagasi",
"%d minutes ago" => "%d minutit tagasi",
@@ -19,7 +22,6 @@
"yesterday" => "eile",
"%d days ago" => "%d päeva tagasi",
"last month" => "eelmisel kuul",
-"months ago" => "kuud tagasi",
"last year" => "eelmisel aastal",
"years ago" => "aastat tagasi",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s on saadaval. Vaata <a href=\"%s\">lisainfot</a>",
diff --git a/lib/l10n/eu.php b/lib/l10n/eu.php
index 461bf458778..5d47ecbda23 100644
--- a/lib/l10n/eu.php
+++ b/lib/l10n/eu.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Aplikazioa ez dago gaituta",
"Authentication error" => "Autentikazio errorea",
"Token expired. Please reload page." => "Tokena iraungitu da. Mesedez birkargatu orria.",
+"Files" => "Fitxategiak",
+"Text" => "Testua",
+"Images" => "Irudiak",
"seconds ago" => "orain dela segundu batzuk",
"1 minute ago" => "orain dela minutu 1",
"%d minutes ago" => "orain dela %d minutu",
+"1 hour ago" => "orain dela ordu bat",
+"%d hours ago" => "orain dela %d ordu",
"today" => "gaur",
"yesterday" => "atzo",
"%d days ago" => "orain dela %d egun",
"last month" => "joan den hilabetea",
-"months ago" => "orain dela hilabete batzuk",
+"%d months ago" => "orain dela %d hilabete",
"last year" => "joan den urtea",
"years ago" => "orain dela urte batzuk",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s eskuragarri dago. Lortu <a href=\"%s\">informazio gehiago</a>",
"up to date" => "eguneratuta",
-"updates check is disabled" => "eguneraketen egiaztapena ez dago gaituta"
+"updates check is disabled" => "eguneraketen egiaztapena ez dago gaituta",
+"Could not find category \"%s\"" => "Ezin da \"%s\" kategoria aurkitu"
);
diff --git a/lib/l10n/fa.php b/lib/l10n/fa.php
index 3579329820f..ce7c7c6e970 100644
--- a/lib/l10n/fa.php
+++ b/lib/l10n/fa.php
@@ -4,13 +4,15 @@
"Settings" => "تنظیمات",
"Users" => "کاربران",
"Admin" => "مدیر",
+"Authentication error" => "خطا در اعتبار سنجی",
+"Files" => "پرونده‌ها",
+"Text" => "متن",
"seconds ago" => "ثانیه‌ها پیش",
"1 minute ago" => "1 دقیقه پیش",
"%d minutes ago" => "%d دقیقه پیش",
"today" => "امروز",
"yesterday" => "دیروز",
"last month" => "ماه قبل",
-"months ago" => "ماه‌های قبل",
"last year" => "سال قبل",
"years ago" => "سال‌های قبل"
);
diff --git a/lib/l10n/fi_FI.php b/lib/l10n/fi_FI.php
index 6f0ebcd16e6..6a5734e978d 100644
--- a/lib/l10n/fi_FI.php
+++ b/lib/l10n/fi_FI.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Sovellusta ei ole otettu käyttöön",
"Authentication error" => "Todennusvirhe",
"Token expired. Please reload page." => "Valtuutus vanheni. Lataa sivu uudelleen.",
+"Files" => "Tiedostot",
+"Text" => "Teksti",
+"Images" => "Kuvat",
"seconds ago" => "sekuntia sitten",
"1 minute ago" => "1 minuutti sitten",
"%d minutes ago" => "%d minuuttia sitten",
+"1 hour ago" => "1 tunti sitten",
+"%d hours ago" => "%d tuntia sitten",
"today" => "tänään",
"yesterday" => "eilen",
"%d days ago" => "%d päivää sitten",
"last month" => "viime kuussa",
-"months ago" => "kuukautta sitten",
+"%d months ago" => "%d kuukautta sitten",
"last year" => "viime vuonna",
"years ago" => "vuotta sitten",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s on saatavilla. Lue <a href=\"%s\">lisätietoja</a>",
"up to date" => "ajan tasalla",
-"updates check is disabled" => "päivitysten tarkistus on pois käytöstä"
+"updates check is disabled" => "päivitysten tarkistus on pois käytöstä",
+"Could not find category \"%s\"" => "Luokkaa \"%s\" ei löytynyt"
);
diff --git a/lib/l10n/fr.php b/lib/l10n/fr.php
index c10259e6376..218c22c1d53 100644
--- a/lib/l10n/fr.php
+++ b/lib/l10n/fr.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "L'application n'est pas activée",
"Authentication error" => "Erreur d'authentification",
"Token expired. Please reload page." => "La session a expiré. Veuillez recharger la page.",
+"Files" => "Fichiers",
+"Text" => "Texte",
+"Images" => "Images",
"seconds ago" => "à l'instant",
"1 minute ago" => "il y a 1 minute",
"%d minutes ago" => "il y a %d minutes",
+"1 hour ago" => "Il y a une heure",
+"%d hours ago" => "Il y a %d heures",
"today" => "aujourd'hui",
"yesterday" => "hier",
"%d days ago" => "il y a %d jours",
"last month" => "le mois dernier",
-"months ago" => "il y a plusieurs mois",
+"%d months ago" => "Il y a %d mois",
"last year" => "l'année dernière",
"years ago" => "il y a plusieurs années",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s est disponible. Obtenez <a href=\"%s\">plus d'informations</a>",
"up to date" => "À jour",
-"updates check is disabled" => "la vérification des mises à jour est désactivée"
+"updates check is disabled" => "la vérification des mises à jour est désactivée",
+"Could not find category \"%s\"" => "Impossible de trouver la catégorie \"%s\""
);
diff --git a/lib/l10n/gl.php b/lib/l10n/gl.php
index 7a9de627c2d..fd59cff02fa 100644
--- a/lib/l10n/gl.php
+++ b/lib/l10n/gl.php
@@ -1,28 +1,34 @@
<?php $TRANSLATIONS = array(
"Help" => "Axuda",
"Personal" => "Personal",
-"Settings" => "Preferencias",
+"Settings" => "Configuracións",
"Users" => "Usuarios",
-"Apps" => "Apps",
+"Apps" => "Aplicativos",
"Admin" => "Administración",
-"ZIP download is turned off." => "Descargas ZIP está deshabilitadas",
-"Files need to be downloaded one by one." => "Os ficheiros necesitan ser descargados de un en un",
-"Back to Files" => "Voltar a ficheiros",
-"Selected files too large to generate zip file." => "Os ficheiros seleccionados son demasiado grandes para xerar un ficheiro ZIP",
-"Application is not enabled" => "O aplicativo non está habilitado",
+"ZIP download is turned off." => "As descargas ZIP están desactivadas",
+"Files need to be downloaded one by one." => "Os ficheiros necesitan ser descargados de un en un.",
+"Back to Files" => "Volver aos ficheiros",
+"Selected files too large to generate zip file." => "Os ficheiros seleccionados son demasiado grandes como para xerar un ficheiro zip.",
+"Application is not enabled" => "O aplicativo non está activado",
"Authentication error" => "Erro na autenticación",
-"Token expired. Please reload page." => "Testemuño caducado. Por favor recargue a páxina.",
+"Token expired. Please reload page." => "Token caducado. Recarga a páxina.",
+"Files" => "Ficheiros",
+"Text" => "Texto",
+"Images" => "Imaxes",
"seconds ago" => "hai segundos",
"1 minute ago" => "hai 1 minuto",
"%d minutes ago" => "hai %d minutos",
+"1 hour ago" => "1 hora antes",
+"%d hours ago" => "%d horas antes",
"today" => "hoxe",
"yesterday" => "onte",
"%d days ago" => "hai %d días",
"last month" => "último mes",
-"months ago" => "meses atrás",
+"%d months ago" => "%d meses antes",
"last year" => "último ano",
"years ago" => "anos atrás",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s está dispoñible. Obteña <a href=\"%s\">máis información</a>",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s está dispoñible. Obtén <a href=\"%s\">máis información</a>",
"up to date" => "ao día",
-"updates check is disabled" => "comprobación de actualizacións está deshabilitada"
+"updates check is disabled" => "a comprobación de actualizacións está desactivada",
+"Could not find category \"%s\"" => "Non se puido atopar a categoría «%s»"
);
diff --git a/lib/l10n/he.php b/lib/l10n/he.php
index 149637d09d2..078a731afc0 100644
--- a/lib/l10n/he.php
+++ b/lib/l10n/he.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "יישומים אינם מופעלים",
"Authentication error" => "שגיאת הזדהות",
"Token expired. Please reload page." => "פג תוקף. נא לטעון שוב את הדף.",
+"Files" => "קבצים",
+"Text" => "טקסט",
+"Images" => "תמונות",
"seconds ago" => "שניות",
"1 minute ago" => "לפני דקה אחת",
"%d minutes ago" => "לפני %d דקות",
+"1 hour ago" => "לפני שעה",
+"%d hours ago" => "לפני %d שעות",
"today" => "היום",
"yesterday" => "אתמול",
"%d days ago" => "לפני %d ימים",
"last month" => "חודש שעבר",
-"months ago" => "חודשים",
+"%d months ago" => "לפני %d חודשים",
"last year" => "שנה שעברה",
"years ago" => "שנים",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s זמין. קבלת <a href=\"%s\">מידע נוסף</a>",
"up to date" => "עדכני",
-"updates check is disabled" => "בדיקת עדכונים מנוטרלת"
+"updates check is disabled" => "בדיקת עדכונים מנוטרלת",
+"Could not find category \"%s\"" => "לא ניתן למצוא את הקטגוריה „%s“"
);
diff --git a/lib/l10n/hr.php b/lib/l10n/hr.php
new file mode 100644
index 00000000000..62305c15711
--- /dev/null
+++ b/lib/l10n/hr.php
@@ -0,0 +1,15 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Pomoć",
+"Personal" => "Osobno",
+"Settings" => "Postavke",
+"Users" => "Korisnici",
+"Authentication error" => "Greška kod autorizacije",
+"Files" => "Datoteke",
+"Text" => "Tekst",
+"seconds ago" => "sekundi prije",
+"today" => "danas",
+"yesterday" => "jučer",
+"last month" => "prošli mjesec",
+"last year" => "prošlu godinu",
+"years ago" => "godina"
+);
diff --git a/lib/l10n/hu_HU.php b/lib/l10n/hu_HU.php
index eb074b79c61..63704a978c5 100644
--- a/lib/l10n/hu_HU.php
+++ b/lib/l10n/hu_HU.php
@@ -12,6 +12,8 @@
"Application is not enabled" => "Az alkalmazás nincs engedélyezve",
"Authentication error" => "Hitelesítési hiba",
"Token expired. Please reload page." => "A token lejárt. Frissítsd az oldalt.",
+"Files" => "Fájlok",
+"Text" => "Szöveg",
"seconds ago" => "másodperccel ezelőtt",
"1 minute ago" => "1 perccel ezelőtt",
"%d minutes ago" => "%d perccel ezelőtt",
@@ -19,7 +21,6 @@
"yesterday" => "tegnap",
"%d days ago" => "%d évvel ezelőtt",
"last month" => "múlt hónapban",
-"months ago" => "hónappal ezelőtt",
"last year" => "tavaly",
"years ago" => "évvel ezelőtt"
);
diff --git a/lib/l10n/ia.php b/lib/l10n/ia.php
new file mode 100644
index 00000000000..05b2c88e1ed
--- /dev/null
+++ b/lib/l10n/ia.php
@@ -0,0 +1,8 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Adjuta",
+"Personal" => "Personal",
+"Settings" => "Configurationes",
+"Users" => "Usatores",
+"Files" => "Files",
+"Text" => "Texto"
+);
diff --git a/lib/l10n/id.php b/lib/l10n/id.php
new file mode 100644
index 00000000000..e31b4caf4f5
--- /dev/null
+++ b/lib/l10n/id.php
@@ -0,0 +1,28 @@
+<?php $TRANSLATIONS = array(
+"Help" => "bantu",
+"Personal" => "perseorangan",
+"Settings" => "pengaturan",
+"Users" => "pengguna",
+"Apps" => "aplikasi",
+"Admin" => "admin",
+"ZIP download is turned off." => "download ZIP sedang dimatikan",
+"Files need to be downloaded one by one." => "file harus di unduh satu persatu",
+"Back to Files" => "kembali ke daftar file",
+"Selected files too large to generate zip file." => "file yang dipilih terlalu besar untuk membuat file zip",
+"Application is not enabled" => "aplikasi tidak diaktifkan",
+"Authentication error" => "autentikasi bermasalah",
+"Token expired. Please reload page." => "token kadaluarsa.mohon perbaharui laman.",
+"Text" => "teks",
+"seconds ago" => "beberapa detik yang lalu",
+"1 minute ago" => "1 menit lalu",
+"%d minutes ago" => "%d menit lalu",
+"today" => "hari ini",
+"yesterday" => "kemarin",
+"%d days ago" => "%d hari lalu",
+"last month" => "bulan kemarin",
+"last year" => "tahun kemarin",
+"years ago" => "beberapa tahun lalu",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s tersedia. dapatkan <a href=\"%s\"> info lebih lanjut</a>",
+"up to date" => "terbaru",
+"updates check is disabled" => "pengecekan pembaharuan sedang non-aktifkan"
+);
diff --git a/lib/l10n/it.php b/lib/l10n/it.php
index c4c7d90610b..c0fb0babfb3 100644
--- a/lib/l10n/it.php
+++ b/lib/l10n/it.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "L'applicazione non è abilitata",
"Authentication error" => "Errore di autenticazione",
"Token expired. Please reload page." => "Token scaduto. Ricarica la pagina.",
+"Files" => "File",
+"Text" => "Testo",
+"Images" => "Immagini",
"seconds ago" => "secondi fa",
"1 minute ago" => "1 minuto fa",
"%d minutes ago" => "%d minuti fa",
+"1 hour ago" => "1 ora fa",
+"%d hours ago" => "%d ore fa",
"today" => "oggi",
"yesterday" => "ieri",
"%d days ago" => "%d giorni fa",
"last month" => "il mese scorso",
-"months ago" => "mesi fa",
+"%d months ago" => "%d mesi fa",
"last year" => "l'anno scorso",
"years ago" => "anni fa",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s è disponibile. Ottieni <a href=\"%s\">ulteriori informazioni</a>",
"up to date" => "aggiornato",
-"updates check is disabled" => "il controllo degli aggiornamenti è disabilitato"
+"updates check is disabled" => "il controllo degli aggiornamenti è disabilitato",
+"Could not find category \"%s\"" => "Impossibile trovare la categoria \"%s\""
);
diff --git a/lib/l10n/ja_JP.php b/lib/l10n/ja_JP.php
index 10f7276703a..854734c9764 100644
--- a/lib/l10n/ja_JP.php
+++ b/lib/l10n/ja_JP.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "アプリケーションは無効です",
"Authentication error" => "認証エラー",
"Token expired. Please reload page." => "トークンが無効になりました。ページを再読込してください。",
+"Files" => "ファイル",
+"Text" => "TTY TDD",
+"Images" => "画像",
"seconds ago" => "秒前",
"1 minute ago" => "1分前",
"%d minutes ago" => "%d 分前",
+"1 hour ago" => "1 時間前",
+"%d hours ago" => "%d 時間前",
"today" => "今日",
"yesterday" => "昨日",
"%d days ago" => "%d 日前",
"last month" => "先月",
-"months ago" => "月前",
+"%d months ago" => "%d 分前",
"last year" => "昨年",
"years ago" => "年前",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s が利用可能です。<a href=\"%s\">詳細情報</a> を確認ください",
"up to date" => "最新です",
-"updates check is disabled" => "更新チェックは無効です"
+"updates check is disabled" => "更新チェックは無効です",
+"Could not find category \"%s\"" => "カテゴリ \"%s\" が見つかりませんでした"
);
diff --git a/lib/l10n/ka_GE.php b/lib/l10n/ka_GE.php
new file mode 100644
index 00000000000..ff623827216
--- /dev/null
+++ b/lib/l10n/ka_GE.php
@@ -0,0 +1,20 @@
+<?php $TRANSLATIONS = array(
+"Help" => "დახმარება",
+"Personal" => "პირადი",
+"Settings" => "პარამეტრები",
+"Users" => "მომხმარებელი",
+"Apps" => "აპლიკაციები",
+"Admin" => "ადმინისტრატორი",
+"Authentication error" => "ავთენტიფიკაციის შეცდომა",
+"Files" => "ფაილები",
+"Text" => "ტექსტი",
+"seconds ago" => "წამის წინ",
+"1 minute ago" => "1 წუთის წინ",
+"today" => "დღეს",
+"yesterday" => "გუშინ",
+"last month" => "გასულ თვეში",
+"last year" => "ბოლო წელს",
+"years ago" => "წლის წინ",
+"up to date" => "განახლებულია",
+"updates check is disabled" => "განახლების ძებნა გათიშულია"
+);
diff --git a/lib/l10n/ko.php b/lib/l10n/ko.php
new file mode 100644
index 00000000000..6f32e3b54ec
--- /dev/null
+++ b/lib/l10n/ko.php
@@ -0,0 +1,34 @@
+<?php $TRANSLATIONS = array(
+"Help" => "도움말",
+"Personal" => "개인의",
+"Settings" => "설정",
+"Users" => "사용자",
+"Apps" => "어플리케이션",
+"Admin" => "관리자",
+"ZIP download is turned off." => "ZIP 다운로드가 꺼졌습니다.",
+"Files need to be downloaded one by one." => "파일 차례대로 다운로드가 필요합니다.",
+"Back to Files" => "파일로 돌아가기",
+"Selected files too large to generate zip file." => "zip 파일 생성하기 위한 너무 많은 파일들이 선택되었습니다.",
+"Application is not enabled" => "응용프로그램이 사용 가능하지 않습니다.",
+"Authentication error" => "인증 오류",
+"Token expired. Please reload page." => "토큰 만료. 페이지를 새로고침 해주세요.",
+"Files" => "파일",
+"Text" => "문자 번호",
+"Images" => "그림",
+"seconds ago" => "초 전",
+"1 minute ago" => "1분 전",
+"%d minutes ago" => "%d 분 전",
+"1 hour ago" => "1 시간 전",
+"%d hours ago" => "%d 시간 전",
+"today" => "오늘",
+"yesterday" => "어제",
+"%d days ago" => "%d 일 전",
+"last month" => "지난 달",
+"%d months ago" => "%d 달 전",
+"last year" => "지난 해",
+"years ago" => "작년",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s은 가능합니다. 더 자세한 정보는 <a href=\"%s\">이곳</a>으로..",
+"up to date" => "최신",
+"updates check is disabled" => "업데이트 확인이 비활성화 되어있습니다.",
+"Could not find category \"%s\"" => "\"%s\" 카테고리를 찾을 수 없습니다."
+);
diff --git a/lib/l10n/ku_IQ.php b/lib/l10n/ku_IQ.php
new file mode 100644
index 00000000000..f89871f23c9
--- /dev/null
+++ b/lib/l10n/ku_IQ.php
@@ -0,0 +1,5 @@
+<?php $TRANSLATIONS = array(
+"Help" => "یارمەتی",
+"Settings" => "ده‌ستكاری",
+"Users" => "به‌كارهێنه‌ر"
+);
diff --git a/lib/l10n/lb.php b/lib/l10n/lb.php
new file mode 100644
index 00000000000..baee630e897
--- /dev/null
+++ b/lib/l10n/lb.php
@@ -0,0 +1,6 @@
+<?php $TRANSLATIONS = array(
+"Personal" => "Perséinlech",
+"Settings" => "Astellungen",
+"Authentication error" => "Authentifikatioun's Fehler",
+"Text" => "SMS"
+);
diff --git a/lib/l10n/lt_LT.php b/lib/l10n/lt_LT.php
index c6702a62287..b84c155633b 100644
--- a/lib/l10n/lt_LT.php
+++ b/lib/l10n/lt_LT.php
@@ -11,11 +11,19 @@
"Selected files too large to generate zip file." => "Pasirinkti failai per dideli archyvavimui į ZIP.",
"Application is not enabled" => "Programa neįjungta",
"Authentication error" => "Autentikacijos klaida",
+"Token expired. Please reload page." => "Sesija baigėsi. Prašome perkrauti puslapį.",
+"Files" => "Failai",
+"Text" => "Žinučių",
+"seconds ago" => "prieš kelias sekundes",
"1 minute ago" => "prieš 1 minutę",
"%d minutes ago" => "prieš %d minučių",
"today" => "šiandien",
"yesterday" => "vakar",
"%d days ago" => "prieš %d dienų",
"last month" => "praėjusį mėnesį",
-"last year" => "pereitais metais"
+"last year" => "pereitais metais",
+"years ago" => "prieš metus",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s yra galimas. Platesnė <a href=\"%s\">informacija čia</a>",
+"up to date" => "pilnai atnaujinta",
+"updates check is disabled" => "atnaujinimų tikrinimas išjungtas"
);
diff --git a/lib/l10n/lv.php b/lib/l10n/lv.php
new file mode 100644
index 00000000000..3330d0e6b70
--- /dev/null
+++ b/lib/l10n/lv.php
@@ -0,0 +1,8 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Palīdzība",
+"Personal" => "Personīgi",
+"Settings" => "Iestatījumi",
+"Users" => "Lietotāji",
+"Authentication error" => "Ielogošanās kļūme",
+"Files" => "Faili"
+);
diff --git a/lib/l10n/mk.php b/lib/l10n/mk.php
new file mode 100644
index 00000000000..a06073e808a
--- /dev/null
+++ b/lib/l10n/mk.php
@@ -0,0 +1,8 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Помош",
+"Personal" => "Лично",
+"Settings" => "Параметри",
+"Users" => "Корисници",
+"Files" => "Датотеки",
+"Text" => "Текст"
+);
diff --git a/lib/l10n/ms_MY.php b/lib/l10n/ms_MY.php
new file mode 100644
index 00000000000..86c7e51b486
--- /dev/null
+++ b/lib/l10n/ms_MY.php
@@ -0,0 +1,8 @@
+<?php $TRANSLATIONS = array(
+"Personal" => "Peribadi",
+"Settings" => "Tetapan",
+"Users" => "Pengguna",
+"Authentication error" => "Ralat pengesahan",
+"Files" => "Fail-fail",
+"Text" => "Teks"
+);
diff --git a/lib/l10n/nb_NO.php b/lib/l10n/nb_NO.php
index f751a41d5eb..b01e0979889 100644
--- a/lib/l10n/nb_NO.php
+++ b/lib/l10n/nb_NO.php
@@ -12,6 +12,9 @@
"Application is not enabled" => "Applikasjon er ikke påslått",
"Authentication error" => "Autentiseringsfeil",
"Token expired. Please reload page." => "Symbol utløpt. Vennligst last inn siden på nytt.",
+"Files" => "Filer",
+"Text" => "Tekst",
+"Images" => "Bilder",
"seconds ago" => "sekunder siden",
"1 minute ago" => "1 minuitt siden",
"%d minutes ago" => "%d minutter siden",
@@ -19,7 +22,9 @@
"yesterday" => "i går",
"%d days ago" => "%d dager siden",
"last month" => "forrige måned",
-"months ago" => "måneder siden",
"last year" => "i fjor",
-"years ago" => "år siden"
+"years ago" => "år siden",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s er tilgjengelig. Få <a href=\"%s\">mer informasjon</a>",
+"up to date" => "oppdatert",
+"updates check is disabled" => "versjonssjekk er avslått"
);
diff --git a/lib/l10n/nl.php b/lib/l10n/nl.php
index c650071c03c..087cf23a627 100644
--- a/lib/l10n/nl.php
+++ b/lib/l10n/nl.php
@@ -4,7 +4,7 @@
"Settings" => "Instellingen",
"Users" => "Gebruikers",
"Apps" => "Apps",
-"Admin" => "Administrator",
+"Admin" => "Beheerder",
"ZIP download is turned off." => "ZIP download is uitgeschakeld.",
"Files need to be downloaded one by one." => "Bestanden moeten één voor één worden gedownload.",
"Back to Files" => "Terug naar bestanden",
@@ -12,17 +12,23 @@
"Application is not enabled" => "De applicatie is niet actief",
"Authentication error" => "Authenticatie fout",
"Token expired. Please reload page." => "Token verlopen. Herlaad de pagina.",
+"Files" => "Bestanden",
+"Text" => "Tekst",
+"Images" => "Afbeeldingen",
"seconds ago" => "seconden geleden",
"1 minute ago" => "1 minuut geleden",
"%d minutes ago" => "%d minuten geleden",
+"1 hour ago" => "1 uur geleden",
+"%d hours ago" => "%d uren geleden",
"today" => "vandaag",
"yesterday" => "gisteren",
"%d days ago" => "%d dagen geleden",
"last month" => "vorige maand",
-"months ago" => "maanden geleden",
+"%d months ago" => "%d maanden geleden",
"last year" => "vorig jaar",
"years ago" => "jaar geleden",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s is beschikbaar. Verkrijg <a href=\"%s\">meer informatie</a>",
"up to date" => "bijgewerkt",
-"updates check is disabled" => "Meest recente versie controle is uitgeschakeld"
+"updates check is disabled" => "Meest recente versie controle is uitgeschakeld",
+"Could not find category \"%s\"" => "Kon categorie \"%s\" niet vinden"
);
diff --git a/lib/l10n/nn_NO.php b/lib/l10n/nn_NO.php
new file mode 100644
index 00000000000..faf7440320a
--- /dev/null
+++ b/lib/l10n/nn_NO.php
@@ -0,0 +1,9 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Hjelp",
+"Personal" => "Personleg",
+"Settings" => "Innstillingar",
+"Users" => "Brukarar",
+"Authentication error" => "Feil i autentisering",
+"Files" => "Filer",
+"Text" => "Tekst"
+);
diff --git a/lib/l10n/oc.php b/lib/l10n/oc.php
index ffc0588becc..89161393380 100644
--- a/lib/l10n/oc.php
+++ b/lib/l10n/oc.php
@@ -9,6 +9,7 @@
"Files need to be downloaded one by one." => "Los fichièrs devan èsser avalcargats un per un.",
"Back to Files" => "Torna cap als fichièrs",
"Authentication error" => "Error d'autentificacion",
+"Files" => "Fichièrs",
"seconds ago" => "segonda a",
"1 minute ago" => "1 minuta a",
"%d minutes ago" => "%d minutas a",
@@ -16,7 +17,6 @@
"yesterday" => "ièr",
"%d days ago" => "%d jorns a",
"last month" => "mes passat",
-"months ago" => "meses a",
"last year" => "an passat",
"years ago" => "ans a",
"up to date" => "a jorn",
diff --git a/lib/l10n/pl.php b/lib/l10n/pl.php
index 087aaa227d3..6f84a328ed9 100644
--- a/lib/l10n/pl.php
+++ b/lib/l10n/pl.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Aplikacja nie jest włączona",
"Authentication error" => "Błąd uwierzytelniania",
"Token expired. Please reload page." => "Token wygasł. Proszę ponownie załadować stronę.",
+"Files" => "Pliki",
+"Text" => "Połączenie tekstowe",
+"Images" => "Obrazy",
"seconds ago" => "sekund temu",
"1 minute ago" => "1 minutę temu",
"%d minutes ago" => "%d minut temu",
+"1 hour ago" => "1 godzine temu",
+"%d hours ago" => "%d godzin temu",
"today" => "dzisiaj",
"yesterday" => "wczoraj",
"%d days ago" => "%d dni temu",
"last month" => "ostatni miesiąc",
-"months ago" => "miesięcy temu",
+"%d months ago" => "%d miesiecy temu",
"last year" => "ostatni rok",
"years ago" => "lat temu",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s jest dostępna. Uzyskaj <a href=\"%s\">więcej informacji</a>",
"up to date" => "Aktualne",
-"updates check is disabled" => "wybór aktualizacji jest wyłączony"
+"updates check is disabled" => "wybór aktualizacji jest wyłączony",
+"Could not find category \"%s\"" => "Nie można odnaleźć kategorii \"%s\""
);
diff --git a/lib/l10n/pl_PL.php b/lib/l10n/pl_PL.php
new file mode 100644
index 00000000000..67cf0a33259
--- /dev/null
+++ b/lib/l10n/pl_PL.php
@@ -0,0 +1,3 @@
+<?php $TRANSLATIONS = array(
+"Settings" => "Ustawienia"
+);
diff --git a/lib/l10n/pt_BR.php b/lib/l10n/pt_BR.php
index 1455eabbc94..fb7087d35d7 100644
--- a/lib/l10n/pt_BR.php
+++ b/lib/l10n/pt_BR.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Aplicação não está habilitada",
"Authentication error" => "Erro de autenticação",
"Token expired. Please reload page." => "Token expirou. Por favor recarregue a página.",
+"Files" => "Arquivos",
+"Text" => "Texto",
+"Images" => "Imagens",
"seconds ago" => "segundos atrás",
"1 minute ago" => "1 minuto atrás",
"%d minutes ago" => "%d minutos atrás",
+"1 hour ago" => "1 hora atrás",
+"%d hours ago" => "%d horas atrás",
"today" => "hoje",
"yesterday" => "ontem",
"%d days ago" => "%d dias atrás",
"last month" => "último mês",
-"months ago" => "meses atrás",
+"%d months ago" => "%d meses atrás",
"last year" => "último ano",
"years ago" => "anos atrás",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s está disponível. Obtenha <a href=\"%s\">mais informações</a>",
"up to date" => "atualizado",
-"updates check is disabled" => "checagens de atualização estão desativadas"
+"updates check is disabled" => "checagens de atualização estão desativadas",
+"Could not find category \"%s\"" => "Impossível localizar categoria \"%s\""
);
diff --git a/lib/l10n/pt_PT.php b/lib/l10n/pt_PT.php
index c3cee207a16..84867c4c37c 100644
--- a/lib/l10n/pt_PT.php
+++ b/lib/l10n/pt_PT.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "A aplicação não está activada",
"Authentication error" => "Erro na autenticação",
"Token expired. Please reload page." => "O token expirou. Por favor recarregue a página.",
+"Files" => "Ficheiros",
+"Text" => "Texto",
+"Images" => "Imagens",
"seconds ago" => "há alguns segundos",
"1 minute ago" => "há 1 minuto",
"%d minutes ago" => "há %d minutos",
+"1 hour ago" => "Há 1 horas",
+"%d hours ago" => "Há %d horas",
"today" => "hoje",
"yesterday" => "ontem",
"%d days ago" => "há %d dias",
"last month" => "mês passado",
-"months ago" => "há meses",
+"%d months ago" => "Há %d meses atrás",
"last year" => "ano passado",
"years ago" => "há anos",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s está disponível. Obtenha <a href=\"%s\">mais informação</a>",
"up to date" => "actualizado",
-"updates check is disabled" => "a verificação de actualizações está desligada"
+"updates check is disabled" => "a verificação de actualizações está desligada",
+"Could not find category \"%s\"" => "Não foi encontrado a categoria \"%s\""
);
diff --git a/lib/l10n/ro.php b/lib/l10n/ro.php
index 5fffeec2335..27912550e17 100644
--- a/lib/l10n/ro.php
+++ b/lib/l10n/ro.php
@@ -12,6 +12,8 @@
"Application is not enabled" => "Aplicația nu este activată",
"Authentication error" => "Eroare la autentificare",
"Token expired. Please reload page." => "Token expirat. Te rugăm să reîncarci pagina.",
+"Files" => "Fișiere",
+"Text" => "Text",
"seconds ago" => "secunde în urmă",
"1 minute ago" => "1 minut în urmă",
"%d minutes ago" => "%d minute în urmă",
@@ -19,7 +21,6 @@
"yesterday" => "ieri",
"%d days ago" => "%d zile în urmă",
"last month" => "ultima lună",
-"months ago" => "luni în urmă",
"last year" => "ultimul an",
"years ago" => "ani în urmă",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s este disponibil. Vezi <a href=\"%s\">mai multe informații</a>",
diff --git a/lib/l10n/ru.php b/lib/l10n/ru.php
index 74425f0e134..3ed55f8e9dc 100644
--- a/lib/l10n/ru.php
+++ b/lib/l10n/ru.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Приложение не разрешено",
"Authentication error" => "Ошибка аутентификации",
"Token expired. Please reload page." => "Токен просрочен. Перезагрузите страницу.",
+"Files" => "Файлы",
+"Text" => "Текст",
+"Images" => "Изображения",
"seconds ago" => "менее минуты",
"1 minute ago" => "1 минуту назад",
"%d minutes ago" => "%d минут назад",
+"1 hour ago" => "час назад",
+"%d hours ago" => "%d часов назад",
"today" => "сегодня",
"yesterday" => "вчера",
"%d days ago" => "%d дней назад",
"last month" => "в прошлом месяце",
-"months ago" => "месяцы назад",
+"%d months ago" => "%d месяцев назад",
"last year" => "в прошлом году",
"years ago" => "годы назад",
"%s is available. Get <a href=\"%s\">more information</a>" => "Возможно обновление до %s. <a href=\"%s\">Подробнее</a>",
"up to date" => "актуальная версия",
-"updates check is disabled" => "проверка обновлений отключена"
+"updates check is disabled" => "проверка обновлений отключена",
+"Could not find category \"%s\"" => "Категория \"%s\" не найдена"
);
diff --git a/lib/l10n/ru_RU.php b/lib/l10n/ru_RU.php
index decf63efb97..ba7d39f9eb0 100644
--- a/lib/l10n/ru_RU.php
+++ b/lib/l10n/ru_RU.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Приложение не запущено",
"Authentication error" => "Ошибка аутентификации",
"Token expired. Please reload page." => "Маркер истек. Пожалуйста, перезагрузите страницу.",
+"Files" => "Файлы",
+"Text" => "Текст",
+"Images" => "Изображения",
"seconds ago" => "секунд назад",
"1 minute ago" => "1 минуту назад",
"%d minutes ago" => "%d минут назад",
+"1 hour ago" => "1 час назад",
+"%d hours ago" => "%d часов назад",
"today" => "сегодня",
"yesterday" => "вчера",
"%d days ago" => "%d дней назад",
"last month" => "в прошлом месяце",
-"months ago" => "месяц назад",
+"%d months ago" => "%d месяцев назад",
"last year" => "в прошлом году",
"years ago" => "год назад",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s доступно. Получите <a href=\"%s\">more information</a>",
"up to date" => "до настоящего времени",
-"updates check is disabled" => "Проверка обновлений отключена"
+"updates check is disabled" => "Проверка обновлений отключена",
+"Could not find category \"%s\"" => "Не удалось найти категорию \"%s\""
);
diff --git a/lib/l10n/si_LK.php b/lib/l10n/si_LK.php
new file mode 100644
index 00000000000..25624acf705
--- /dev/null
+++ b/lib/l10n/si_LK.php
@@ -0,0 +1,30 @@
+<?php $TRANSLATIONS = array(
+"Help" => "උදව්",
+"Personal" => "පෞද්ගලික",
+"Settings" => "සිටුවම්",
+"Users" => "පරිශීලකයන්",
+"Apps" => "යෙදුම්",
+"Admin" => "පරිපාලක",
+"ZIP download is turned off." => "ZIP භාගත කිරීම් අක්‍රියයි",
+"Files need to be downloaded one by one." => "ගොනු එකින් එක භාගත යුතුයි",
+"Back to Files" => "ගොනු වෙතට නැවත යන්න",
+"Selected files too large to generate zip file." => "තෝරාගත් ගොනු ZIP ගොනුවක් තැනීමට විශාල වැඩිය.",
+"Application is not enabled" => "යෙදුම සක්‍රිය කර නොමැත",
+"Authentication error" => "සත්‍යාපනය කිරීමේ දෝශයක්",
+"Token expired. Please reload page." => "ටෝකනය කල් ඉකුත් වී ඇත. පිටුව නැවුම් කරන්න",
+"Files" => "ගොනු",
+"Text" => "පෙළ",
+"Images" => "අනු රූ",
+"seconds ago" => "තත්පරයන්ට පෙර",
+"1 minute ago" => "1 මිනිත්තුවකට පෙර",
+"%d minutes ago" => "%d මිනිත්තුවන්ට පෙර",
+"today" => "අද",
+"yesterday" => "ඊයේ",
+"%d days ago" => "%d දිනකට පෙර",
+"last month" => "පෙර මාසයේ",
+"last year" => "පෙර අවුරුද්දේ",
+"years ago" => "අවුරුදු කීපයකට පෙර",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s යොදාගත හැක. <a href=\"%s\">තව විස්තර</a> ලබාගන්න",
+"up to date" => "යාවත්කාලීනයි",
+"updates check is disabled" => "යාවත්කාලීන බව පරීක්ෂණය අක්‍රියයි"
+);
diff --git a/lib/l10n/sk_SK.php b/lib/l10n/sk_SK.php
index 33b329c30bb..98a5b5ca677 100644
--- a/lib/l10n/sk_SK.php
+++ b/lib/l10n/sk_SK.php
@@ -11,15 +11,24 @@
"Selected files too large to generate zip file." => "Zvolené súbory sú príliž veľké na vygenerovanie zip súboru.",
"Application is not enabled" => "Aplikácia nie je zapnutá",
"Authentication error" => "Chyba autentifikácie",
+"Token expired. Please reload page." => "Token vypršal. Obnovte, prosím, stránku.",
+"Files" => "Súbory",
+"Text" => "Text",
+"Images" => "Obrázky",
+"seconds ago" => "pred sekundami",
"1 minute ago" => "pred 1 minútou",
"%d minutes ago" => "pred %d minútami",
+"1 hour ago" => "Pred 1 hodinou",
+"%d hours ago" => "Pred %d hodinami.",
"today" => "dnes",
"yesterday" => "včera",
"%d days ago" => "pred %d dňami",
"last month" => "minulý mesiac",
-"months ago" => "pred mesiacmi",
+"%d months ago" => "Pred %d mesiacmi.",
"last year" => "minulý rok",
"years ago" => "pred rokmi",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s je dostupné. Získať <a href=\"%s\">viac informácií</a>",
"up to date" => "aktuálny",
-"updates check is disabled" => "sledovanie aktualizácií je vypnuté"
+"updates check is disabled" => "sledovanie aktualizácií je vypnuté",
+"Could not find category \"%s\"" => "Nemožno nájsť danú kategóriu \"%s\""
);
diff --git a/lib/l10n/sl.php b/lib/l10n/sl.php
index eac839e78f3..391d932c4ee 100644
--- a/lib/l10n/sl.php
+++ b/lib/l10n/sl.php
@@ -3,26 +3,32 @@
"Personal" => "Osebno",
"Settings" => "Nastavitve",
"Users" => "Uporabniki",
-"Apps" => "Aplikacije",
-"Admin" => "Skrbnik",
-"ZIP download is turned off." => "ZIP prenos je onemogočen.",
-"Files need to be downloaded one by one." => "Datoteke morajo biti prenešene posamezno.",
+"Apps" => "Programi",
+"Admin" => "Skrbništvo",
+"ZIP download is turned off." => "Prejem datotek ZIP je onemogočen.",
+"Files need to be downloaded one by one." => "Datoteke je mogoče prejeti le posamič.",
"Back to Files" => "Nazaj na datoteke",
-"Selected files too large to generate zip file." => "Izbrane datoteke so prevelike, da bi lahko ustvarili zip datoteko.",
-"Application is not enabled" => "Aplikacija ni omogočena",
+"Selected files too large to generate zip file." => "Izbrane datoteke so prevelike za ustvarjanje datoteke arhiva zip.",
+"Application is not enabled" => "Program ni omogočen",
"Authentication error" => "Napaka overitve",
-"Token expired. Please reload page." => "Žeton je potekel. Prosimo, če spletno stran znova naložite.",
+"Token expired. Please reload page." => "Žeton je potekel. Spletišče je traba znova naložiti.",
+"Files" => "Datoteke",
+"Text" => "Besedilo",
+"Images" => "Slike",
"seconds ago" => "pred nekaj sekundami",
"1 minute ago" => "pred minuto",
"%d minutes ago" => "pred %d minutami",
+"1 hour ago" => "Pred 1 uro",
+"%d hours ago" => "Pred %d urami",
"today" => "danes",
"yesterday" => "včeraj",
"%d days ago" => "pred %d dnevi",
"last month" => "prejšnji mesec",
-"months ago" => "pred nekaj meseci",
+"%d months ago" => "Pred %d meseci",
"last year" => "lani",
"years ago" => "pred nekaj leti",
-"%s is available. Get <a href=\"%s\">more information</a>" => "%s je na voljo. <a href=\"%s\">Več informacij.</a>",
-"up to date" => "ažuren",
-"updates check is disabled" => "preverjanje za posodobitve je onemogočeno"
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s je na voljo. <a href=\"%s\">Več podrobnosti.</a>",
+"up to date" => "posodobljeno",
+"updates check is disabled" => "preverjanje za posodobitve je onemogočeno",
+"Could not find category \"%s\"" => "Kategorije \"%s\" ni bilo mogoče najti."
);
diff --git a/lib/l10n/sr.php b/lib/l10n/sr.php
new file mode 100644
index 00000000000..2ae7400ba79
--- /dev/null
+++ b/lib/l10n/sr.php
@@ -0,0 +1,34 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Помоћ",
+"Personal" => "Лично",
+"Settings" => "Подешавања",
+"Users" => "Корисници",
+"Apps" => "Апликације",
+"Admin" => "Администрација",
+"ZIP download is turned off." => "Преузимање ZIP-а је искључено.",
+"Files need to be downloaded one by one." => "Датотеке морате преузимати једну по једну.",
+"Back to Files" => "Назад на датотеке",
+"Selected files too large to generate zip file." => "Изабране датотеке су превелике да бисте направили ZIP датотеку.",
+"Application is not enabled" => "Апликација није омогућена",
+"Authentication error" => "Грешка при провери идентитета",
+"Token expired. Please reload page." => "Жетон је истекао. Поново учитајте страницу.",
+"Files" => "Датотеке",
+"Text" => "Текст",
+"Images" => "Слике",
+"seconds ago" => "пре неколико секунди",
+"1 minute ago" => "пре 1 минут",
+"%d minutes ago" => "пре %d минута",
+"1 hour ago" => "пре 1 сат",
+"%d hours ago" => "пре %d сата/и",
+"today" => "данас",
+"yesterday" => "јуче",
+"%d days ago" => "пре %d дана",
+"last month" => "прошлог месеца",
+"%d months ago" => "пре %d месеца/и",
+"last year" => "прошле године",
+"years ago" => "година раније",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s је доступна. Погледајте <a href=\"%s\">више информација</a>.",
+"up to date" => "је ажурна.",
+"updates check is disabled" => "провера ажурирања је онемогућена.",
+"Could not find category \"%s\"" => "Не могу да пронађем категорију „%s“."
+);
diff --git a/lib/l10n/sr@latin.php b/lib/l10n/sr@latin.php
new file mode 100644
index 00000000000..3fc1f61eafa
--- /dev/null
+++ b/lib/l10n/sr@latin.php
@@ -0,0 +1,9 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Pomoć",
+"Personal" => "Lično",
+"Settings" => "Podešavanja",
+"Users" => "Korisnici",
+"Authentication error" => "Greška pri autentifikaciji",
+"Files" => "Fajlovi",
+"Text" => "Tekst"
+);
diff --git a/lib/l10n/sv.php b/lib/l10n/sv.php
index 3d377133f22..5799e2dd1a8 100644
--- a/lib/l10n/sv.php
+++ b/lib/l10n/sv.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Applikationen är inte aktiverad",
"Authentication error" => "Fel vid autentisering",
"Token expired. Please reload page." => "Ogiltig token. Ladda om sidan.",
+"Files" => "Filer",
+"Text" => "Text",
+"Images" => "Bilder",
"seconds ago" => "sekunder sedan",
"1 minute ago" => "1 minut sedan",
"%d minutes ago" => "%d minuter sedan",
+"1 hour ago" => "1 timme sedan",
+"%d hours ago" => "%d timmar sedan",
"today" => "idag",
"yesterday" => "igår",
"%d days ago" => "%d dagar sedan",
"last month" => "förra månaden",
-"months ago" => "månader sedan",
+"%d months ago" => "%d månader sedan",
"last year" => "förra året",
"years ago" => "år sedan",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s finns. Få <a href=\"%s\">mer information</a>",
"up to date" => "uppdaterad",
-"updates check is disabled" => "uppdateringskontroll är inaktiverad"
+"updates check is disabled" => "uppdateringskontroll är inaktiverad",
+"Could not find category \"%s\"" => "Kunde inte hitta kategorin \"%s\""
);
diff --git a/lib/l10n/ta_LK.php b/lib/l10n/ta_LK.php
new file mode 100644
index 00000000000..c76394bcb4f
--- /dev/null
+++ b/lib/l10n/ta_LK.php
@@ -0,0 +1,34 @@
+<?php $TRANSLATIONS = array(
+"Help" => "உதவி",
+"Personal" => "தனிப்பட்ட",
+"Settings" => "அமைப்புகள்",
+"Users" => "பயனாளர்கள்",
+"Apps" => "செயலிகள்",
+"Admin" => "நிர்வாகம்",
+"ZIP download is turned off." => "வீசொலிப் பூட்டு பதிவிறக்கம் நிறுத்தப்பட்டுள்ளது.",
+"Files need to be downloaded one by one." => "கோப்புகள்ஒன்றன் பின் ஒன்றாக பதிவிறக்கப்படவேண்டும்.",
+"Back to Files" => "கோப்புகளுக்கு செல்க",
+"Selected files too large to generate zip file." => "வீ சொலிக் கோப்புகளை உருவாக்குவதற்கு தெரிவுசெய்யப்பட்ட கோப்புகள் மிகப்பெரியவை",
+"Application is not enabled" => "செயலி இயலுமைப்படுத்தப்படவில்லை",
+"Authentication error" => "அத்தாட்சிப்படுத்தலில் வழு",
+"Token expired. Please reload page." => "அடையாளவில்லை காலாவதியாகிவிட்டது. தயவுசெய்து பக்கத்தை மீள் ஏற்றுக.",
+"Files" => "கோப்புகள்",
+"Text" => "உரை",
+"Images" => "படங்கள்",
+"seconds ago" => "செக்கன்களுக்கு முன்",
+"1 minute ago" => "1 நிமிடத்திற்கு முன் ",
+"%d minutes ago" => "%d நிமிடங்களுக்கு முன்",
+"1 hour ago" => "1 மணித்தியாலத்திற்கு முன்",
+"%d hours ago" => "%d மணித்தியாலத்திற்கு முன்",
+"today" => "இன்று",
+"yesterday" => "நேற்று",
+"%d days ago" => "%d நாட்களுக்கு முன்",
+"last month" => "கடந்த மாதம்",
+"%d months ago" => "%d மாதத்திற்கு முன்",
+"last year" => "கடந்த வருடம்",
+"years ago" => "வருடங்களுக்கு முன்",
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s இன்னும் இருக்கின்றன. <a href=\"%s\">மேலதிக தகவல்களுக்கு</a> எடுக்க",
+"up to date" => "நவீன",
+"updates check is disabled" => "இற்றைப்படுத்தலை சரிபார்ப்பதை செயலற்றதாக்குக",
+"Could not find category \"%s\"" => "பிரிவு \"%s\" ஐ கண்டுப்பிடிக்க முடியவில்லை"
+);
diff --git a/lib/l10n/th_TH.php b/lib/l10n/th_TH.php
index 2aa2ffaba8c..75fa02f84b0 100644
--- a/lib/l10n/th_TH.php
+++ b/lib/l10n/th_TH.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "แอพพลิเคชั่นดังกล่าวยังไม่ได้เปิดใช้งาน",
"Authentication error" => "เกิดข้อผิดพลาดในสิทธิ์การเข้าใช้งาน",
"Token expired. Please reload page." => "รหัสยืนยันความถูกต้องหมดอายุแล้ว กรุณาโหลดหน้าเว็บใหม่อีกครั้ง",
+"Files" => "ไฟล์",
+"Text" => "ข้อความ",
+"Images" => "รูปภาพ",
"seconds ago" => "วินาทีที่ผ่านมา",
"1 minute ago" => "1 นาทีมาแล้ว",
"%d minutes ago" => "%d นาทีที่ผ่านมา",
+"1 hour ago" => "1 ชั่วโมงก่อนหน้านี้",
+"%d hours ago" => "%d ชั่วโมงก่อนหน้านี้",
"today" => "วันนี้",
"yesterday" => "เมื่อวานนี้",
"%d days ago" => "%d วันที่ผ่านมา",
"last month" => "เดือนที่แล้ว",
-"months ago" => "เดือนมาแล้ว",
+"%d months ago" => "%d เดือนมาแล้ว",
"last year" => "ปีที่แล้ว",
"years ago" => "ปีที่ผ่านมา",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s พร้อมให้ใช้งานได้แล้ว. <a href=\"%s\">ดูรายละเอียดเพิ่มเติม</a>",
"up to date" => "ทันสมัย",
-"updates check is disabled" => "การตรวจสอบชุดอัพเดทถูกปิดใช้งานไว้"
+"updates check is disabled" => "การตรวจสอบชุดอัพเดทถูกปิดใช้งานไว้",
+"Could not find category \"%s\"" => "ไม่พบหมวดหมู่ \"%s\""
);
diff --git a/lib/l10n/tr.php b/lib/l10n/tr.php
new file mode 100644
index 00000000000..69067d7ec57
--- /dev/null
+++ b/lib/l10n/tr.php
@@ -0,0 +1,9 @@
+<?php $TRANSLATIONS = array(
+"Help" => "Yardı",
+"Personal" => "Kişisel",
+"Settings" => "Ayarlar",
+"Users" => "Kullanıcılar",
+"Authentication error" => "Kimlik doğrulama hatası",
+"Files" => "Dosyalar",
+"Text" => "Metin"
+);
diff --git a/lib/l10n/uk.php b/lib/l10n/uk.php
index 423aa12b2d7..f5d52f8682d 100644
--- a/lib/l10n/uk.php
+++ b/lib/l10n/uk.php
@@ -11,15 +11,24 @@
"Selected files too large to generate zip file." => "Вибрані фали завеликі для генерування zip файлу.",
"Application is not enabled" => "Додаток не увімкнений",
"Authentication error" => "Помилка автентифікації",
+"Token expired. Please reload page." => "Строк дії токена скінчився. Будь ласка, перезавантажте сторінку.",
+"Files" => "Файли",
+"Text" => "Текст",
+"Images" => "Зображення",
"seconds ago" => "секунди тому",
"1 minute ago" => "1 хвилину тому",
"%d minutes ago" => "%d хвилин тому",
+"1 hour ago" => "1 годину тому",
+"%d hours ago" => "%d годин тому",
"today" => "сьогодні",
"yesterday" => "вчора",
"%d days ago" => "%d днів тому",
"last month" => "минулого місяця",
-"months ago" => "місяці тому",
+"%d months ago" => "%d місяців тому",
"last year" => "минулого року",
"years ago" => "роки тому",
-"updates check is disabled" => "перевірка оновлень відключена"
+"%s is available. Get <a href=\"%s\">more information</a>" => "%s доступно. Отримати <a href=\"%s\">детальну інформацію</a>",
+"up to date" => "оновлено",
+"updates check is disabled" => "перевірка оновлень відключена",
+"Could not find category \"%s\"" => "Не вдалося знайти категорію \"%s\""
);
diff --git a/lib/l10n/vi.php b/lib/l10n/vi.php
index fc41d69819a..8b7242ae611 100644
--- a/lib/l10n/vi.php
+++ b/lib/l10n/vi.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "Ứng dụng không được BẬT",
"Authentication error" => "Lỗi xác thực",
"Token expired. Please reload page." => "Mã Token đã hết hạn. Hãy tải lại trang.",
+"Files" => "Các tập tin",
+"Text" => "Văn bản",
+"Images" => "Hình ảnh",
"seconds ago" => "1 giây trước",
"1 minute ago" => "1 phút trước",
"%d minutes ago" => "%d phút trước",
+"1 hour ago" => "1 giờ trước",
+"%d hours ago" => "%d giờ trước",
"today" => "hôm nay",
"yesterday" => "hôm qua",
"%d days ago" => "%d ngày trước",
"last month" => "tháng trước",
-"months ago" => "tháng trước",
+"%d months ago" => "%d tháng trước",
"last year" => "năm trước",
"years ago" => "năm trước",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s có sẵn. <a href=\"%s\">xem thêm ở đây</a>",
"up to date" => "đến ngày",
-"updates check is disabled" => "đã TĂT chức năng cập nhật "
+"updates check is disabled" => "đã TĂT chức năng cập nhật ",
+"Could not find category \"%s\"" => "không thể tìm thấy mục \"%s\""
);
diff --git a/lib/l10n/zh_CN.GB2312.php b/lib/l10n/zh_CN.GB2312.php
index 4b0a5e9f4d2..08975e44598 100644
--- a/lib/l10n/zh_CN.GB2312.php
+++ b/lib/l10n/zh_CN.GB2312.php
@@ -12,6 +12,9 @@
"Application is not enabled" => "应用未启用",
"Authentication error" => "验证错误",
"Token expired. Please reload page." => "会话过期。请刷新页面。",
+"Files" => "文件",
+"Text" => "文本",
+"Images" => "图片",
"seconds ago" => "秒前",
"1 minute ago" => "1 分钟前",
"%d minutes ago" => "%d 分钟前",
@@ -19,7 +22,6 @@
"yesterday" => "昨天",
"%d days ago" => "%d 天前",
"last month" => "上个月",
-"months ago" => "月前",
"last year" => "去年",
"years ago" => "年前",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s 不可用。获知 <a href=\"%s\">详情</a>",
diff --git a/lib/l10n/zh_CN.php b/lib/l10n/zh_CN.php
index 8229c77d2dd..c3af288b727 100644
--- a/lib/l10n/zh_CN.php
+++ b/lib/l10n/zh_CN.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "不需要程序",
"Authentication error" => "认证错误",
"Token expired. Please reload page." => "Token 过期,请刷新页面。",
+"Files" => "文件",
+"Text" => "文本",
+"Images" => "图像",
"seconds ago" => "几秒前",
"1 minute ago" => "1分钟前",
"%d minutes ago" => "%d 分钟前",
+"1 hour ago" => "1小时前",
+"%d hours ago" => "%d小时前",
"today" => "今天",
"yesterday" => "昨天",
"%d days ago" => "%d 天前",
"last month" => "上月",
-"months ago" => "几月前",
+"%d months ago" => "%d 月前",
"last year" => "上年",
"years ago" => "几年前",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s 已存在. 点此 <a href=\"%s\">获取更多信息</a>",
"up to date" => "已更新。",
-"updates check is disabled" => "检查更新功能被关闭。"
+"updates check is disabled" => "检查更新功能被关闭。",
+"Could not find category \"%s\"" => "无法找到分类 \"%s\""
);
diff --git a/lib/l10n/zh_TW.php b/lib/l10n/zh_TW.php
index c9a26a53b2a..4dbf89c2e0e 100644
--- a/lib/l10n/zh_TW.php
+++ b/lib/l10n/zh_TW.php
@@ -12,17 +12,23 @@
"Application is not enabled" => "應用程式未啟用",
"Authentication error" => "認證錯誤",
"Token expired. Please reload page." => "Token 過期. 請重新整理頁面",
+"Files" => "檔案",
+"Text" => "文字",
+"Images" => "圖片",
"seconds ago" => "幾秒前",
"1 minute ago" => "1 分鐘前",
"%d minutes ago" => "%d 分鐘前",
+"1 hour ago" => "1小時之前",
+"%d hours ago" => "%d小時之前",
"today" => "今天",
"yesterday" => "昨天",
"%d days ago" => "%d 天前",
"last month" => "上個月",
-"months ago" => "幾個月前",
+"%d months ago" => "%d個月之前",
"last year" => "去年",
"years ago" => "幾年前",
"%s is available. Get <a href=\"%s\">more information</a>" => "%s 已經可用. 取得 <a href=\"%s\">更多資訊</a>",
"up to date" => "最新的",
-"updates check is disabled" => "檢查更新已停用"
+"updates check is disabled" => "檢查更新已停用",
+"Could not find category \"%s\"" => "找不到分類-\"%s\""
);
diff --git a/lib/log.php b/lib/log.php
index 6de99b4ea6b..e9cededa5c0 100644
--- a/lib/log.php
+++ b/lib/log.php
@@ -39,4 +39,29 @@ class OC_Log {
$log_class::write($app, $message, $level);
}
}
+
+ //Fatal errors handler
+ public static function onShutdown() {
+ $error = error_get_last();
+ if($error) {
+ //ob_end_clean();
+ self::write('PHP', $error['message'] . ' at ' . $error['file'] . '#' . $error['line'], self::FATAL);
+ } else {
+ return true;
+ }
+ }
+
+ // Uncaught exception handler
+ public static function onException($exception) {
+ self::write('PHP', $exception->getMessage() . ' at ' . $exception->getFile() . '#' . $exception->getLine(), self::FATAL);
+ }
+
+ //Recoverable errors handler
+ public static function onError($number, $message, $file, $line) {
+ if (error_reporting() === 0) {
+ return;
+ }
+ self::write('PHP', $message . ' at ' . $file . '#' . $line, self::WARN);
+
+ }
}
diff --git a/lib/log/owncloud.php b/lib/log/owncloud.php
index d4644163ad5..ec43208d833 100644
--- a/lib/log/owncloud.php
+++ b/lib/log/owncloud.php
@@ -44,9 +44,9 @@ class OC_Log_Owncloud {
* @param int level
*/
public static function write($app, $message, $level) {
- $minLevel=min(OC_Config::getValue( "loglevel", OC_Log::WARN ),OC_Log::ERROR);
+ $minLevel=min(OC_Config::getValue( "loglevel", OC_Log::WARN ), OC_Log::ERROR);
if($level>=$minLevel) {
- $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level,'time'=>time());
+ $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level, 'time'=>time());
$fh=fopen(self::$logFile, 'a');
fwrite($fh, json_encode($entry)."\n");
fclose($fh);
diff --git a/lib/mail.php b/lib/mail.php
index 8d30fff9f28..c78fcce88d4 100644
--- a/lib/mail.php
+++ b/lib/mail.php
@@ -27,7 +27,7 @@ class OC_Mail {
* @param string $fromname
* @param bool $html
*/
- public static function send($toaddress,$toname,$subject,$mailtext,$fromaddress,$fromname,$html=0,$altbody='',$ccaddress='',$ccname='',$bcc='') {
+ public static function send($toaddress,$toname,$subject,$mailtext,$fromaddress,$fromname,$html=0,$altbody='',$ccaddress='',$ccname='', $bcc='') {
$SMTPMODE = OC_Config::getValue( 'mail_smtpmode', 'sendmail' );
$SMTPHOST = OC_Config::getValue( 'mail_smtphost', '127.0.0.1' );
@@ -56,13 +56,13 @@ class OC_Mail {
$mailo->From =$fromaddress;
$mailo->FromName = $fromname;;
$mailo->Sender =$fromaddress;
- $a=explode(' ',$toaddress);
+ $a=explode(' ', $toaddress);
try {
foreach($a as $ad) {
- $mailo->AddAddress($ad,$toname);
+ $mailo->AddAddress($ad, $toname);
}
- if($ccaddress<>'') $mailo->AddCC($ccaddress,$ccname);
+ if($ccaddress<>'') $mailo->AddCC($ccaddress, $ccname);
if($bcc<>'') $mailo->AddBCC($bcc);
$mailo->AddReplyTo($fromaddress, $fromname);
diff --git a/lib/migrate.php b/lib/migrate.php
index 611a935ee5d..2cc0a3067b8 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -66,7 +66,7 @@ class OC_Migrate{
foreach($apps as $app) {
$path = OC_App::getAppPath($app) . '/appinfo/migrate.php';
if( file_exists( $path ) ) {
- include( $path );
+ include $path;
}
}
}
@@ -91,7 +91,7 @@ class OC_Migrate{
if( self::$exporttype == 'user' ) {
// Check user exists
self::$uid = is_null($uid) ? OC_User::getUser() : $uid;
- if(!OC_User::userExists(self::$uid)){
+ if(!OC_User::userExists(self::$uid)) {
return json_encode( array( 'success' => false) );
}
}
@@ -200,7 +200,7 @@ class OC_Migrate{
$scan = scandir( $extractpath );
// Check for export_info.json
if( !in_array( 'export_info.json', $scan ) ) {
- OC_Log::write( 'migration', 'Invalid import file, export_info.json note found', OC_Log::ERROR );
+ OC_Log::write( 'migration', 'Invalid import file, export_info.json not found', OC_Log::ERROR );
return json_encode( array( 'success' => false ) );
}
$json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) );
@@ -235,12 +235,19 @@ class OC_Migrate{
return json_encode( array( 'success' => false ) );
}
// Copy data
- if( !self::copy_r( $extractpath . $json->exporteduser, $datadir . '/' . self::$uid ) ) {
- return json_encode( array( 'success' => false ) );
+ $userfolder = $extractpath . $json->exporteduser;
+ $newuserfolder = $datadir . '/' . self::$uid;
+ foreach(scandir($userfolder) as $file){
+ if($file !== '.' && $file !== '..' && is_dir($file)) {
+ // Then copy the folder over
+ OC_Helper::copyr($userfolder.'/'.$file, $newuserfolder.'/'.$file);
+ }
}
// Import user app data
- if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ) {
- return json_encode( array( 'success' => false ) );
+ if(file_exists($extractpath . $json->exporteduser . '/migration.db')) {
+ if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ) {
+ return json_encode( array( 'success' => false ) );
+ }
}
// All done!
if( !self::unlink_r( $extractpath ) ) {
@@ -305,37 +312,6 @@ class OC_Migrate{
}
/**
- * @brief copies recursively
- * @param $path string path to source folder
- * @param $dest string path to destination
- * @return bool
- */
- private static function copy_r( $path, $dest ) {
- if( is_dir($path) ) {
- @mkdir( $dest );
- $objects = scandir( $path );
- if( sizeof( $objects ) > 0 ) {
- foreach( $objects as $file ) {
- if( $file == "." || $file == ".." || $file == ".htaccess")
- continue;
- // go on
- if( is_dir( $path . '/' . $file ) ) {
- self::copy_r( $path .'/' . $file, $dest . '/' . $file );
- } else {
- copy( $path . '/' . $file, $dest . '/' . $file );
- }
- }
- }
- return true;
- }
- elseif( is_file( $path ) ) {
- return copy( $path, $dest );
- } else {
- return false;
- }
- }
-
- /**
* @brief tries to extract the import zip
* @param $path string path to the zip
* @return string path to extract location (with a trailing slash) or false on failure
@@ -347,7 +323,7 @@ class OC_Migrate{
OC_Log::write( 'migration', 'Zip not found', OC_Log::ERROR );
return false;
}
- if ( self::$zip->open( $path ) != TRUE ) {
+ if ( self::$zip->open( $path ) != true ) {
OC_Log::write( 'migration', "Failed to open zip file", OC_Log::ERROR );
return false;
}
@@ -576,7 +552,7 @@ class OC_Migrate{
OC_Log::write('migration', 'createZip() called but $zip and/or $zippath have not been set', OC_Log::ERROR);
return false;
}
- if ( self::$zip->open( self::$zippath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE ) !== TRUE ) {
+ if ( self::$zip->open( self::$zippath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE ) !== true ) {
OC_Log::write('migration', 'Failed to create the zip with error: '.self::$zip->getStatusString(), OC_Log::ERROR);
return false;
} else {
@@ -611,11 +587,11 @@ class OC_Migrate{
if( file_exists( $db ) ) {
// Connect to the db
if(!self::connectDB( $db )) {
- OC_Log::write('migration','Failed to connect to migration.db',OC_Log::ERROR);
+ OC_Log::write('migration', 'Failed to connect to migration.db', OC_Log::ERROR);
return false;
}
} else {
- OC_Log::write('migration','Migration.db not found at: '.$db, OC_Log::FATAL );
+ OC_Log::write('migration', 'Migration.db not found at: '.$db, OC_Log::FATAL );
return false;
}
diff --git a/lib/migration/content.php b/lib/migration/content.php
index 89b1e782d86..00df62f0c7f 100644
--- a/lib/migration/content.php
+++ b/lib/migration/content.php
@@ -48,16 +48,16 @@ class OC_Migration_Content{
// @brief prepares the db
// @param $query the sql query to prepare
public function prepare( $query ) {
-
+
// Only add database to tmpfiles if actually used
if( !is_null( $this->db ) ) {
// Get db path
$db = $this->db->getDatabase();
- if(!in_array($db, $this->tmpfiles)){
+ if(!in_array($db, $this->tmpfiles)) {
$this->tmpfiles[] = $db;
}
}
-
+
// Optimize the query
$query = $this->processQuery( $query );
@@ -152,7 +152,7 @@ class OC_Migration_Content{
$sql = "INSERT INTO `" . $options['table'] . '` ( `';
$fieldssql = implode( '`, `', $fields );
$sql .= $fieldssql . "` ) VALUES( ";
- $valuessql = substr( str_repeat( '?, ', count( $fields ) ),0,-2 );
+ $valuessql = substr( str_repeat( '?, ', count( $fields ) ), 0, -2 );
$sql .= $valuessql . " )";
// Make the query
$query = $this->prepare( $sql );
@@ -205,7 +205,7 @@ class OC_Migration_Content{
}
closedir($dirhandle);
} else {
- OC_Log::write('admin_export',"Was not able to open directory: " . $dir,OC_Log::ERROR);
+ OC_Log::write('admin_export', "Was not able to open directory: " . $dir, OC_Log::ERROR);
return false;
}
return true;
diff --git a/lib/minimizer.php b/lib/minimizer.php
index d50ab0d2397..db522de74dc 100644
--- a/lib/minimizer.php
+++ b/lib/minimizer.php
@@ -2,14 +2,11 @@
abstract class OC_Minimizer {
public function generateETag($files) {
- $etag = '';
- sort($files);
+ $fullpath_files = array();
foreach($files as $file_info) {
- $file = $file_info[0] . '/' . $file_info[2];
- $stat = stat($file);
- $etag .= $file.$stat['mtime'].$stat['size'];
+ $fullpath_files[] = $file_info[0] . '/' . $file_info[2];
}
- return md5($etag);
+ return OC_Cache::generateCacheKeyFromFiles($fullpath_files);
}
abstract public function minimizeFiles($files);
@@ -33,6 +30,12 @@ abstract class OC_Minimizer {
$cache->set($cache_key.'.gz', $gzout);
OC_Response::setETagHeader($etag);
}
+ // on some systems (e.g. SLES 11, but not Ubuntu) mod_deflate and zlib compression will compress the output twice.
+ // This results in broken core.css and core.js. To avoid it, we switch off zlib compression.
+ // Since mod_deflate is still active, Apache will compress what needs to be compressed, i.e. no disadvantage.
+ if(function_exists('apache_get_modules') && ini_get('zlib.output_compression') && in_array('mod_deflate', apache_get_modules())) {
+ ini_set('zlib.output_compression', 'Off');
+ }
if ($encoding = OC_Request::acceptGZip()) {
header('Content-Encoding: '.$encoding);
$out = $gzout;
@@ -51,11 +54,11 @@ abstract class OC_Minimizer {
}
if (!function_exists('gzdecode')) {
- function gzdecode($data,$maxlength=null,&$filename='',&$error='')
+ function gzdecode($data, $maxlength=null, &$filename='', &$error='')
{
- if (strcmp(substr($data,0,9),"\x1f\x8b\x8\0\0\0\0\0\0")) {
+ if (strcmp(substr($data, 0, 9),"\x1f\x8b\x8\0\0\0\0\0\0")) {
return null; // Not the GZIP format we expect (See RFC 1952)
}
- return gzinflate(substr($data,10,-8));
+ return gzinflate(substr($data, 10, -8));
}
}
diff --git a/lib/ocs.php b/lib/ocs.php
index 7350c3c8821..1a0abf0e367 100644
--- a/lib/ocs.php
+++ b/lib/ocs.php
@@ -23,7 +23,8 @@
*
*/
-
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Exception\MethodNotAllowedException;
/**
* Class to handle open collaboration services API requests
@@ -92,91 +93,144 @@ class OC_OCS {
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
+ $router = new OC_Router();
+ $router->useCollection('root');
// CONFIG
- // apiconfig - GET - CONFIG
- if(($method=='get') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'config')) {
- OC_OCS::apiconfig($format);
+ $router->create('config', '/config.{format}')
+ ->defaults(array('format' => $format))
+ ->action('OC_OCS', 'apiConfig')
+ ->requirements(array('format'=>'xml|json'));
// 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);
+ $router->create('person_check', '/person/check.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $login = OC_OCS::readData('post', 'login', 'text');
+ $passwd = OC_OCS::readData('post', 'password', 'text');
+ OC_OCS::personCheck($format, $login, $passwd);
+ })
+ ->requirements(array('format'=>'xml|json'));
// 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);
-
+ $router->create('activity_get', '/activity.{format}')
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $page = OC_OCS::readData('get', 'page', 'int', 0);
+ $pagesize = OC_OCS::readData('get', 'pagesize', 'int', 10);
+ if($pagesize<1 or $pagesize>100) $pagesize=10;
+ OC_OCS::activityGet($format, $page, $pagesize);
+ })
+ ->requirements(array('format'=>'xml|json'));
// 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);
-
+ $router->create('activity_put', '/activity.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $message = OC_OCS::readData('post', 'message', 'text');
+ OC_OCS::activityPut($format, $message);
+ })
+ ->requirements(array('format'=>'xml|json'));
// 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);
- }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-4] == 'getattribute')) {
-
- $key=$ex[$paracount-2];
- $app=$ex[$paracount-3];
- OC_OCS::privateDataGet($format, $app, $key);
-
+ $router->create('privatedata_get',
+ '/privatedata/getattribute/{app}/{key}.{format}')
+ ->defaults(array('app' => '', 'key' => '', 'format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $app = addslashes(strip_tags($parameters['app']));
+ $key = addslashes(strip_tags($parameters['key']));
+ OC_OCS::privateDataGet($format, $app, $key);
+ })
+ ->requirements(array('format'=>'xml|json'));
// 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);
+ $router->create('privatedata_set',
+ '/privatedata/setattribute/{app}/{key}.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $app = addslashes(strip_tags($parameters['app']));
+ $key = addslashes(strip_tags($parameters['key']));
+ $value=OC_OCS::readData('post', 'value', 'text');
+ OC_OCS::privateDataSet($format, $app, $key, $value);
+ })
+ ->requirements(array('format'=>'xml|json'));
// 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);
+ $router->create('privatedata_delete',
+ '/privatedata/deleteattribute/{app}/{key}.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $app = addslashes(strip_tags($parameters['app']));
+ $key = addslashes(strip_tags($parameters['key']));
+ OC_OCS::privateDataDelete($format, $app, $key);
+ })
+ ->requirements(array('format'=>'xml|json'));
// CLOUD
// systemWebApps
- }elseif(($method=='get') and ($ex[$paracount-5] == 'v1.php') and ($ex[$paracount-4]=='cloud') and ($ex[$paracount-3] == 'system') and ($ex[$paracount-2] == 'webapps')) {
- OC_OCS::systemwebapps($format);
+ $router->create('system_webapps',
+ '/cloud/system/webapps.{format}')
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ OC_OCS::systemwebapps($format);
+ })
+ ->requirements(array('format'=>'xml|json'));
// 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);
-
+ $router->create('quota_get',
+ '/cloud/user/{user}.{format}')
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $user = $parameters['user'];
+ OC_OCS::quotaGet($format, $user);
+ })
+ ->requirements(array('format'=>'xml|json'));
// 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);
+ $router->create('quota_set',
+ '/cloud/user/{user}.{format}')
+ ->post()
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $user = $parameters['user'];
+ $quota = self::readData('post', 'quota', 'int');
+ OC_OCS::quotaSet($format, $user, $quota);
+ })
+ ->requirements(array('format'=>'xml|json'));
// keygetpublic
- }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'publickey')) {
- $user=$ex[$paracount-3];
- OC_OCS::publicKeyGet($format, $user);
+ $router->create('keygetpublic',
+ '/cloud/user/{user}/publickey.{format}')
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $user = $parameters['user'];
+ OC_OCS::publicKeyGet($format, $user);
+ })
+ ->requirements(array('format'=>'xml|json'));
// keygetprivate
- }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'privatekey')) {
- $user=$ex[$paracount-3];
- OC_OCS::privateKeyGet($format, $user);
+ $router->create('keygetpublic',
+ '/cloud/user/{user}/privatekey.{format}')
+ ->defaults(array('format' => $format))
+ ->action(function ($parameters) {
+ $format = $parameters['format'];
+ $user = $parameters['user'];
+ OC_OCS::privateKeyGet($format, $user);
+ })
+ ->requirements(array('format'=>'xml|json'));
// add more calls here
@@ -190,13 +244,17 @@ class OC_OCS {
// sharing
// versioning
// news (rss)
-
-
-
- }else{
- $txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n";
+ try {
+ $router->match($_SERVER['PATH_INFO']);
+ } catch (ResourceNotFoundException $e) {
+ $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));
+ } catch (MethodNotAllowedException $e) {
+ OC_Response::setStatus(405);
}
exit();
}
@@ -268,7 +326,7 @@ class OC_OCS {
* @param int $itemsperpage
* @return string xml/json
*/
- private static function generateXml($format,$status,$statuscode,$message,$data=array(),$tag='',$tagattribute='',$dimension=-1,$itemscount='',$itemsperpage='') {
+ private static function generateXml($format, $status, $statuscode, $message, $data=array(), $tag='', $tagattribute='', $dimension=-1, $itemscount='', $itemsperpage='') {
if($format=='json') {
$json=array();
$json['status']=$status;
@@ -288,7 +346,7 @@ class OC_OCS {
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($itemscount<>'') xmlwriter_write_element($writer, 'totalitems', $itemscount);
if(!empty($itemsperpage)) xmlwriter_write_element($writer, 'itemsperpage', $itemsperpage);
xmlwriter_end_element($writer);
if($dimension=='0') {
@@ -303,7 +361,7 @@ class OC_OCS {
xmlwriter_end_element($writer);
}elseif($dimension=='2') {
- xmlwriter_start_element($writer,'data');
+ xmlwriter_start_element($writer, 'data');
foreach($data as $entry) {
xmlwriter_start_element($writer, $tag);
if(!empty($tagattribute)) {
@@ -358,14 +416,14 @@ class OC_OCS {
}
}
- public static function toXml($writer,$data,$node) {
+ 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);
+ OC_OCS::toxml($writer, $value, $node);
xmlwriter_end_element($writer);
}else{
xmlwriter_write_element($writer, $key, $value);
@@ -378,7 +436,8 @@ class OC_OCS {
* @param string $format
* @return string xml/json
*/
- private static function apiConfig($format) {
+ public static function apiConfig($parameters) {
+ $format = $parameters['format'];
$user=OC_OCS::checkpassword(false);
$url=substr(OCP\Util::getServerHost().$_SERVER['SCRIPT_NAME'], 0, -11).'';
@@ -397,7 +456,7 @@ class OC_OCS {
* @param string $passwd
* @return string xml/json
*/
- private static function personCheck($format,$login,$passwd) {
+ private static function personCheck($format, $login, $passwd) {
if($login<>'') {
if(OC_User::login($login, $passwd)) {
$xml['person']['personid']=$login;
@@ -424,7 +483,7 @@ class OC_OCS {
//TODO
- $txt=OC_OCS::generatexml($format, 'ok', 100, '', $xml, 'activity', 'full', 2, $totalcount,$pagesize);
+ $txt=OC_OCS::generatexml($format, 'ok', 100, '', $xml, 'activity', 'full', 2, $totalcount, $pagesize);
echo($txt);
}
@@ -434,7 +493,7 @@ class OC_OCS {
* @param string $message
* @return string xml/json
*/
- private static function activityPut($format,$message) {
+ private static function activityPut($format, $message) {
// not implemented in ownCloud
$user=OC_OCS::checkpassword();
echo(OC_OCS::generatexml($format, 'ok', 100, ''));
@@ -565,7 +624,7 @@ class OC_OCS {
foreach($apps as $app) {
$info=OC_App::getAppInfo($app);
if(isset($info['standalone'])) {
- $newvalue=array('name'=>$info['name'],'url'=>OC_Helper::linkToAbsolute($app,''),'icon'=>'');
+ $newvalue=array('name'=>$info['name'], 'url'=>OC_Helper::linkToAbsolute($app, ''), 'icon'=>'');
$values[]=$newvalue;
}
@@ -582,7 +641,7 @@ class OC_OCS {
* @param string $user
* @return string xml/json
*/
- private static function quotaGet($format,$user) {
+ private static function quotaGet($format, $user) {
$login=OC_OCS::checkpassword();
if(OC_Group::inGroup($login, 'admin') or ($login==$user)) {
@@ -621,7 +680,7 @@ class OC_OCS {
* @param string $quota
* @return string xml/json
*/
- private static function quotaSet($format,$user,$quota) {
+ private static function quotaSet($format, $user, $quota) {
$login=OC_OCS::checkpassword();
if(OC_Group::inGroup($login, 'admin')) {
@@ -644,7 +703,7 @@ class OC_OCS {
* @param string $user
* @return string xml/json
*/
- private static function publicKeyGet($format,$user) {
+ private static function publicKeyGet($format, $user) {
$login=OC_OCS::checkpassword();
if(OC_User::userExists($user)) {
@@ -662,7 +721,7 @@ class OC_OCS {
* @param string $user
* @return string xml/json
*/
- private static function privateKeyGet($format,$user) {
+ private static function privateKeyGet($format, $user) {
$login=OC_OCS::checkpassword();
if(OC_Group::inGroup($login, 'admin') or ($login==$user)) {
diff --git a/lib/ocsclient.php b/lib/ocsclient.php
index 794bc972f57..12e5026a877 100644
--- a/lib/ocsclient.php
+++ b/lib/ocsclient.php
@@ -55,20 +55,11 @@ class OC_OCSClient{
* This function calls an OCS server and returns the response. It also sets a sane timeout
*/
private static function getOCSresponse($url) {
- // set a sensible timeout of 10 sec to stay responsive even if the server is down.
- $ctx = stream_context_create(
- array(
- 'http' => array(
- 'timeout' => 10
- )
- )
- );
- $data=@file_get_contents($url, 0, $ctx);
+ $data = \OC_Util::getUrlContent($url);
return($data);
}
-
- /**
+ /**
* @brief Get all the categories from the OCS server
* @returns array with category ids
* @note returns NULL if config value appstoreenabled is set to false
@@ -76,12 +67,12 @@ class OC_OCSClient{
*/
public static function getCategories() {
if(OC_Config::getValue('appstoreenabled', true)==false) {
- return NULL;
+ return null;
}
$url=OC_OCSClient::getAppStoreURL().'/content/categories';
$xml=OC_OCSClient::getOCSresponse($url);
- if($xml==FALSE) {
- return NULL;
+ if($xml==false) {
+ return null;
}
$data=simplexml_load_string($xml);
@@ -105,25 +96,25 @@ class OC_OCSClient{
*
* This function returns a list of all the applications on the OCS server
*/
- public static function getApplications($categories,$page,$filter) {
+ public static function getApplications($categories, $page, $filter) {
if(OC_Config::getValue('appstoreenabled', true)==false) {
return(array());
}
if(is_array($categories)) {
- $categoriesstring=implode('x',$categories);
+ $categoriesstring=implode('x', $categories);
}else{
$categoriesstring=$categories;
}
- $version='&version='.implode('x',\OC_Util::getVersion());
+ $version='&version='.implode('x', \OC_Util::getVersion());
$filterurl='&filter='.urlencode($filter);
$url=OC_OCSClient::getAppStoreURL().'/content/data?categories='.urlencode($categoriesstring).'&sortmode=new&page='.urlencode($page).'&pagesize=100'.$filterurl.$version;
$apps=array();
$xml=OC_OCSClient::getOCSresponse($url);
- if($xml==FALSE) {
- return NULL;
+ if($xml==false) {
+ return null;
}
$data=simplexml_load_string($xml);
@@ -156,14 +147,14 @@ class OC_OCSClient{
*/
public static function getApplication($id) {
if(OC_Config::getValue('appstoreenabled', true)==false) {
- return NULL;
+ return null;
}
$url=OC_OCSClient::getAppStoreURL().'/content/data/'.urlencode($id);
$xml=OC_OCSClient::getOCSresponse($url);
- if($xml==FALSE) {
- OC_Log::write('core','Unable to parse OCS content',OC_Log::FATAL);
- return NULL;
+ if($xml==false) {
+ OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL);
+ return null;
}
$data=simplexml_load_string($xml);
@@ -192,16 +183,16 @@ class OC_OCSClient{
*
* This function returns an download url for an applications from the OCS server
*/
- public static function getApplicationDownload($id,$item) {
+ public static function getApplicationDownload($id, $item) {
if(OC_Config::getValue('appstoreenabled', true)==false) {
- return NULL;
+ return null;
}
$url=OC_OCSClient::getAppStoreURL().'/content/download/'.urlencode($id).'/'.urlencode($item);
$xml=OC_OCSClient::getOCSresponse($url);
- if($xml==FALSE) {
- OC_Log::write('core','Unable to parse OCS content',OC_Log::FATAL);
- return NULL;
+ if($xml==false) {
+ OC_Log::write('core', 'Unable to parse OCS content', OC_Log::FATAL);
+ return null;
}
$data=simplexml_load_string($xml);
@@ -222,40 +213,35 @@ class OC_OCSClient{
*
* This function returns a list of all the knowledgebase entries from the OCS server
*/
- public static function getKnownledgebaseEntries($page,$pagesize,$search='') {
- if(OC_Config::getValue('knowledgebaseenabled', true)==false) {
- $kbe=array();
- $kbe['totalitems']=0;
- return $kbe;
- }
-
- $p= (int) $page;
- $s= (int) $pagesize;
- if($search<>'') $searchcmd='&search='.urlencode($search); else $searchcmd='';
- $url=OC_OCSClient::getKBURL().'/knowledgebase/data?type=150&page='.$p.'&pagesize='.$s.$searchcmd;
-
- $kbe=array();
- $xml=OC_OCSClient::getOCSresponse($url);
-
- if($xml==FALSE) {
- OC_Log::write('core','Unable to parse knowledgebase content',OC_Log::FATAL);
- return NULL;
- }
- $data=simplexml_load_string($xml);
-
- $tmp=$data->data->content;
- for($i = 0; $i < count($tmp); $i++) {
- $kb=array();
- $kb['id']=$tmp[$i]->id;
- $kb['name']=$tmp[$i]->name;
- $kb['description']=$tmp[$i]->description;
- $kb['answer']=$tmp[$i]->answer;
- $kb['preview1']=$tmp[$i]->smallpreviewpic1;
- $kb['detailpage']=$tmp[$i]->detailpage;
- $kbe[]=$kb;
+ public static function getKnownledgebaseEntries($page, $pagesize, $search='') {
+ $kbe = array('totalitems' => 0);
+ if(OC_Config::getValue('knowledgebaseenabled', true)) {
+ $p = (int) $page;
+ $s = (int) $pagesize;
+ $searchcmd = '';
+ if ($search) {
+ $searchcmd = '&search='.urlencode($search);
+ }
+ $url = OC_OCSClient::getKBURL().'/knowledgebase/data?type=150&page='. $p .'&pagesize='. $s . $searchcmd;
+ $xml = OC_OCSClient::getOCSresponse($url);
+ $data = @simplexml_load_string($xml);
+ if($data===false) {
+ OC_Log::write('core', 'Unable to parse knowledgebase content', OC_Log::FATAL);
+ return null;
+ }
+ $tmp = $data->data->content;
+ for($i = 0; $i < count($tmp); $i++) {
+ $kbe[] = array(
+ 'id' => $tmp[$i]->id,
+ 'name' => $tmp[$i]->name,
+ 'description' => $tmp[$i]->description,
+ 'answer' => $tmp[$i]->answer,
+ 'preview1' => $tmp[$i]->smallpreviewpic1,
+ 'detailpage' => $tmp[$i]->detailpage
+ );
+ }
+ $kbe['totalitems'] = $data->meta->totalitems;
}
- $total=$data->meta->totalitems;
- $kbe['totalitems']=$total;
return $kbe;
}
diff --git a/lib/preferences.php b/lib/preferences.php
index b198a18415c..6270457834d 100644
--- a/lib/preferences.php
+++ b/lib/preferences.php
@@ -139,7 +139,7 @@ class OC_Preferences{
public static function setValue( $user, $app, $key, $value ) {
// Check if the key does exist
$query = OC_DB::prepare( 'SELECT `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?' );
- $values=$query->execute(array($user,$app,$key))->fetchAll();
+ $values=$query->execute(array($user, $app, $key))->fetchAll();
$exists=(count($values)>0);
if( !$exists ) {
diff --git a/lib/public/backgroundjob.php b/lib/public/backgroundjob.php
index aba7d2b7620..601046fe691 100644
--- a/lib/public/backgroundjob.php
+++ b/lib/public/backgroundjob.php
@@ -47,6 +47,29 @@ namespace OCP;
*/
class BackgroundJob {
/**
+ * @brief get the execution type of background jobs
+ * @return string
+ *
+ * This method returns the type how background jobs are executed. If the user
+ * did not select something, the type is ajax.
+ */
+ public static function getExecutionType() {
+ return \OC_BackgroundJob::getExecutionType();
+ }
+
+ /**
+ * @brief sets the background jobs execution type
+ * @param $type execution type
+ * @return boolean
+ *
+ * This method sets the execution type of the background jobs. Possible types
+ * are "none", "ajax", "webcron", "cron"
+ */
+ public static function setExecutionType( $type ) {
+ return \OC_BackgroundJob::setExecutionType( $type );
+ }
+
+ /**
* @brief creates a regular task
* @param $klass class name
* @param $method method name
diff --git a/lib/public/constants.php b/lib/public/constants.php
new file mode 100644
index 00000000000..bc979c9031f
--- /dev/null
+++ b/lib/public/constants.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Tanghus
+ * @copyright 2012 Thomas Tanghus (thomas@tanghus.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * This file defines common constants used in ownCloud
+ */
+
+namespace OCP;
+
+/**
+ * CRUDS permissions.
+ */
+const PERMISSION_CREATE = 4;
+const PERMISSION_READ = 1;
+const PERMISSION_UPDATE = 2;
+const PERMISSION_DELETE = 8;
+const PERMISSION_SHARE = 16;
+const PERMISSION_ALL = 31;
+
diff --git a/lib/public/contacts.php b/lib/public/contacts.php
new file mode 100644
index 00000000000..5762fd28e02
--- /dev/null
+++ b/lib/public/contacts.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2012 Thomas Müller thomas.mueller@tmit.eu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * Public interface of ownCloud for apps to use.
+ * Contacts Class
+ *
+ */
+
+// use OCP namespace for all classes that are considered public.
+// This means that they should be used by apps instead of the internal ownCloud classes
+namespace OCP;
+
+/**
+ * This class provides access to the contacts app. Use this class exclusively if you want to access contacts.
+ *
+ * Contacts in general will be expressed as an array of key-value-pairs.
+ * The keys will match the property names defined in https://tools.ietf.org/html/rfc2426#section-1
+ *
+ * Proposed workflow for working with contacts:
+ * - search for the contacts
+ * - manipulate the results array
+ * - createOrUpdate will save the given contacts overwriting the existing data
+ *
+ * For updating it is mandatory to keep the id.
+ * Without an id a new contact will be created.
+ *
+ */
+class Contacts
+{
+ /**
+ * This function is used to search and find contacts within the users address books.
+ * In case $pattern is empty all contacts will be returned.
+ *
+ * @param string $pattern which should match within the $searchProperties
+ * @param array $searchProperties defines the properties within the query pattern should match
+ * @param array $options - for future use. One should always have options!
+ * @return array of contacts which are arrays of key-value-pairs
+ */
+ public static function search($pattern, $searchProperties = array(), $options = array()) {
+
+ // dummy results
+ return array(
+ array('id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => 'a@b.c', 'GEO' => '37.386013;-122.082932'),
+ array('id' => 5, 'FN' => 'Thomas Tanghus', 'EMAIL' => array('d@e.f', 'g@h.i')),
+ );
+ }
+
+ /**
+ * This function can be used to delete the contact identified by the given id
+ *
+ * @param object $id the unique identifier to a contact
+ * @return bool successful or not
+ */
+ public static function delete($id) {
+ return false;
+ }
+
+ /**
+ * This function is used to create a new contact if 'id' is not given or not present.
+ * Otherwise the contact will be updated by replacing the entire data set.
+ *
+ * @param array $properties this array if key-value-pairs defines a contact
+ * @return array representing the contact just created or updated
+ */
+ public static function createOrUpdate($properties) {
+
+ // dummy
+ return array('id' => 0, 'FN' => 'Thomas Müller', 'EMAIL' => 'a@b.c',
+ 'PHOTO' => 'VALUE=uri:http://www.abc.com/pub/photos/jqpublic.gif',
+ 'ADR' => ';;123 Main Street;Any Town;CA;91921-1234'
+ );
+ }
+
+ /**
+ * Check if contacts are available (e.g. contacts app enabled)
+ *
+ * @return bool true if enabled, false if not
+ */
+ public static function isEnabled() {
+ return false;
+ }
+
+}
diff --git a/lib/public/db.php b/lib/public/db.php
index 6ce62b27ca2..92ff8f93a22 100644
--- a/lib/public/db.php
+++ b/lib/public/db.php
@@ -42,10 +42,31 @@ class DB {
* SQL query via MDB2 prepare(), needs to be execute()'d!
*/
static public function prepare( $query, $limit=null, $offset=null ) {
- return(\OC_DB::prepare($query,$limit,$offset));
+ return(\OC_DB::prepare($query, $limit, $offset));
}
/**
+ * @brief Insert a row if a matching row doesn't exists.
+ * @param $table string The table name (will replace *PREFIX*) to perform the replace on.
+ * @param $input array
+ *
+ * The input array if in the form:
+ *
+ * array ( 'id' => array ( 'value' => 6,
+ * 'key' => true
+ * ),
+ * 'name' => array ('value' => 'Stoyan'),
+ * 'family' => array ('value' => 'Stefanov'),
+ * 'birth_date' => array ('value' => '1975-06-20')
+ * );
+ * @returns true/false
+ *
+ */
+ public static function insertIfNotExist($table, $input) {
+ return(\OC_DB::insertIfNotExist($table, $input));
+ }
+
+ /**
* @brief gets last value of autoincrement
* @param $table string The optional table name (will replace *PREFIX*) and add sequence suffix
* @returns id
diff --git a/lib/public/share.php b/lib/public/share.php
index 1db3a0b2c1d..d736871d244 100644
--- a/lib/public/share.php
+++ b/lib/public/share.php
@@ -1,1251 +1,1318 @@
-<?php
-/**
-* ownCloud
-*
-* @author Michael Gapczynski
-* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* 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.
-*
-* You should have received a copy of the GNU Affero General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
-*/
-namespace OCP;
-
-\OC_Hook::connect('OC_User', 'post_deleteUser', 'OCP\Share', 'post_deleteUser');
-\OC_Hook::connect('OC_User', 'post_addToGroup', 'OCP\Share', 'post_addToGroup');
-\OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OCP\Share', 'post_removeFromGroup');
-\OC_Hook::connect('OC_User', 'post_deleteGroup', 'OCP\Share', 'post_deleteGroup');
-
-/**
-* This class provides the ability for apps to share their content between users.
-* Apps must create a backend class that implements OCP\Share_Backend and register it with this class.
-*/
-class Share {
-
- const SHARE_TYPE_USER = 0;
- const SHARE_TYPE_GROUP = 1;
- const SHARE_TYPE_LINK = 3;
- const SHARE_TYPE_EMAIL = 4;
- const SHARE_TYPE_CONTACT = 5;
- const SHARE_TYPE_REMOTE = 6;
-
- /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
- * Construct permissions for share() and setPermissions with Or (|) e.g. Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
- * Check if permission is granted with And (&) e.g. Check if delete is granted: if ($permissions & PERMISSION_DELETE)
- * Remove permissions with And (&) and Not (~) e.g. Remove the update permission: $permissions &= ~PERMISSION_UPDATE
- * Apps are required to handle permissions on their own, this class only stores and manages the permissions of shares
- */
- const PERMISSION_CREATE = 4;
- const PERMISSION_READ = 1;
- const PERMISSION_UPDATE = 2;
- const PERMISSION_DELETE = 8;
- const PERMISSION_SHARE = 16;
-
- const FORMAT_NONE = -1;
- const FORMAT_STATUSES = -2;
- const FORMAT_SOURCES = -3;
-
- private static $shareTypeUserAndGroups = -1;
- private static $shareTypeGroupUserUnique = 2;
- private static $backends = array();
- private static $backendTypes = array();
-
- /**
- * @brief Register a sharing backend class that implements OCP\Share_Backend for an item type
- * @param string Item type
- * @param string Backend class
- * @param string (optional) Depends on item type
- * @param array (optional) List of supported file extensions if this item type depends on files
- * @return Returns true if backend is registered or false if error
- */
- public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
- if (self::isEnabled()) {
- if (!isset(self::$backendTypes[$itemType])) {
- self::$backendTypes[$itemType] = array('class' => $class, 'collectionOf' => $collectionOf, 'supportedFileExtensions' => $supportedFileExtensions);
- if(count(self::$backendTypes) === 1) {
- \OC_Util::addScript('core', 'share');
- \OC_Util::addStyle('core', 'share');
- }
- return true;
- }
- \OC_Log::write('OCP\Share', 'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class'].' is already registered for '.$itemType, \OC_Log::WARN);
- }
- return false;
- }
-
- /**
- * @brief Check if the Share API is enabled
- * @return Returns true if enabled or false
- *
- * The Share API is enabled by default if not configured
- *
- */
- public static function isEnabled() {
- if (\OC_Appconfig::getValue('core', 'shareapi_enabled', 'yes') == 'yes') {
- return true;
- }
- return false;
- }
-
- /**
- * @brief Get the items of item type shared with the current user
- * @param string Item type
- * @param int Format (optional) Format type must be defined by the backend
- * @param int Number of items to return (optional) Returns all by default
- * @return Return depends on format
- */
- public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false) {
- return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, $limit, $includeCollections);
- }
-
- /**
- * @brief Get the item of item type shared with the current user
- * @param string Item type
- * @param string Item target
- * @param int Format (optional) Format type must be defined by the backend
- * @return Return depends on format
- */
- public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) {
- return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, 1, $includeCollections);
- }
-
- /**
- * @brief Get the item of item type shared with the current user by source
- * @param string Item type
- * @param string Item source
- * @param int Format (optional) Format type must be defined by the backend
- * @return Return depends on format
- */
- public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) {
- return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, 1, $includeCollections, true);
- }
-
- /**
- * @brief Get the item of item type shared by a link
- * @param string Item type
- * @param string Item source
- * @param string Owner of link
- * @return Item
- */
- public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) {
- return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, null, 1);
- }
-
- /**
- * @brief Get the shared items of item type owned by the current user
- * @param string Item type
- * @param int Format (optional) Format type must be defined by the backend
- * @param int Number of items to return (optional) Returns all by default
- * @return Return depends on format
- */
- public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false) {
- return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format, $parameters, $limit, $includeCollections);
- }
-
- /**
- * @brief Get the shared item of item type owned by the current user
- * @param string Item type
- * @param string Item source
- * @param int Format (optional) Format type must be defined by the backend
- * @return Return depends on format
- */
- public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) {
- return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format, $parameters, -1, $includeCollections);
- }
-
- /**
- * @brief Share an item with a user, group, or via private link
- * @param string Item type
- * @param string Item source
- * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
- * @param string User or group the item is being shared with
- * @param int CRUDS permissions
- * @return bool Returns true on success or false on failure
- */
- public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions) {
- $uidOwner = \OC_User::getUser();
- $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
- // Verify share type and sharing conditions are met
- if ($shareType === self::SHARE_TYPE_USER) {
- if ($shareWith == $uidOwner) {
- $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is the item owner';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- if (!\OC_User::userExists($shareWith)) {
- $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' does not exist';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- if ($sharingPolicy == 'groups_only') {
- $inGroup = array_intersect(\OC_Group::getUserGroups($uidOwner), \OC_Group::getUserGroups($shareWith));
- if (empty($inGroup)) {
- $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is not a member of any groups that '.$uidOwner.' is a member of';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- }
- // Check if the item source is already shared with the user, either from the same owner or a different user
- if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
- // Only allow the same share to occur again if it is the same owner and is not a user share, this use case is for increasing permissions for a specific user
- if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
- $message = 'Sharing '.$itemSource.' failed, because this item is already shared with '.$shareWith;
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- }
- } else if ($shareType === self::SHARE_TYPE_GROUP) {
- if (!\OC_Group::groupExists($shareWith)) {
- $message = 'Sharing '.$itemSource.' failed, because the group '.$shareWith.' does not exist';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- if ($sharingPolicy == 'groups_only' && !\OC_Group::inGroup($uidOwner, $shareWith)) {
- $message = 'Sharing '.$itemSource.' failed, because '.$uidOwner.' is not a member of the group '.$shareWith;
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- // Check if the item source is already shared with the group, either from the same owner or a different user
- // The check for each user in the group is done inside the put() function
- if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
- // Only allow the same share to occur again if it is the same owner and is not a group share, this use case is for increasing permissions for a specific user
- if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
- $message = 'Sharing '.$itemSource.' failed, because this item is already shared with '.$shareWith;
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- }
- // Convert share with into an array with the keys group and users
- $group = $shareWith;
- $shareWith = array();
- $shareWith['group'] = $group;
- $shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner));
- } else if ($shareType === self::SHARE_TYPE_LINK) {
- if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
- if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, null, 1)) {
- // If password is set delete the old link
- if (isset($shareWith)) {
- self::delete($checkExists['id']);
- } else {
- $message = 'Sharing '.$itemSource.' failed, because this item is already shared with a link';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- }
- // Generate hash of password - same method as user passwords
- if (isset($shareWith)) {
- $forcePortable = (CRYPT_BLOWFISH != 1);
- $hasher = new \PasswordHash(8, $forcePortable);
- $shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', ''));
- }
- return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions);
- }
- $message = 'Sharing '.$itemSource.' failed, because sharing with links is not allowed';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- return false;
-// } else if ($shareType === self::SHARE_TYPE_CONTACT) {
-// if (!\OC_App::isEnabled('contacts')) {
-// $message = 'Sharing '.$itemSource.' failed, because the contacts app is not enabled';
-// \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
-// return false;
-// }
-// $vcard = \OC_Contacts_App::getContactVCard($shareWith);
-// if (!isset($vcard)) {
-// $message = 'Sharing '.$itemSource.' failed, because the contact does not exist';
-// \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
-// throw new \Exception($message);
-// }
-// $details = \OC_Contacts_VCard::structureContact($vcard);
-// // TODO Add ownCloud user to contacts vcard
-// if (!isset($details['EMAIL'])) {
-// $message = 'Sharing '.$itemSource.' failed, because no email address is associated with the contact';
-// \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
-// throw new \Exception($message);
-// }
-// return self::shareItem($itemType, $itemSource, self::SHARE_TYPE_EMAIL, $details['EMAIL'], $permissions);
- } else {
- // Future share types need to include their own conditions
- $message = 'Share type '.$shareType.' is not valid for '.$itemSource;
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- // If the item is a folder, scan through the folder looking for equivalent item types
- if ($itemType == 'folder') {
- $parentFolder = self::put('folder', $itemSource, $shareType, $shareWith, $uidOwner, $permissions, true);
- if ($parentFolder && $files = \OC_Files::getDirectoryContent($itemSource)) {
- for ($i = 0; $i < count($files); $i++) {
- $name = substr($files[$i]['name'], strpos($files[$i]['name'], $itemSource) - strlen($itemSource));
- if ($files[$i]['mimetype'] == 'httpd/unix-directory' && $children = \OC_Files::getDirectoryContent($name, '/')) {
- // Continue scanning into child folders
- array_push($files, $children);
- } else {
- // Check file extension for an equivalent item type to convert to
- $extension = strtolower(substr($itemSource, strrpos($itemSource, '.') + 1));
- foreach (self::$backends as $type => $backend) {
- if (isset($backend->dependsOn) && $backend->dependsOn == 'file' && isset($backend->supportedFileExtensions) && in_array($extension, $backend->supportedFileExtensions)) {
- $itemType = $type;
- break;
- }
- }
- // Pass on to put() to check if this item should be converted, the item won't be inserted into the database unless it can be converted
- self::put($itemType, $name, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder);
- }
- }
- return true;
- }
- return false;
- } else {
- // Put the item into the database
- return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions);
- }
- }
-
- /**
- * @brief Unshare an item from a user, group, or delete a private link
- * @param string Item type
- * @param string Item source
- * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
- * @param string User or group the item is being shared with
- * @return Returns true on success or false on failure
- */
- public static function unshare($itemType, $itemSource, $shareType, $shareWith) {
- if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(), self::FORMAT_NONE, null, 1)) {
- self::delete($item['id']);
- return true;
- }
- return false;
- }
-
- /**
- * @brief Unshare an item shared with the current user
- * @param string Item type
- * @param string Item target
- * @return Returns true on success or false on failure
- *
- * Unsharing from self is not allowed for items inside collections
- *
- */
- public static function unshareFromSelf($itemType, $itemTarget) {
- if ($item = self::getItemSharedWith($itemType, $itemTarget)) {
- if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) {
- // Insert an extra row for the group share and set permission to 0 to prevent it from showing up for the user
- $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
- $query->execute(array($item['item_type'], $item['item_source'], $item['item_target'], $item['id'], self::$shareTypeGroupUserUnique, \OC_User::getUser(), $item['uid_owner'], 0, $item['stime'], $item['file_source'], $item['file_target']));
- \OC_DB::insertid('*PREFIX*share');
- // Delete all reshares by this user of the group share
- self::delete($item['id'], true, \OC_User::getUser());
- } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
- // Set permission to 0 to prevent it from showing up for the user
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
- $query->execute(array(0, $item['id']));
- self::delete($item['id'], true);
- } else {
- self::delete($item['id']);
- }
- return true;
- }
- return false;
- }
-
- /**
- * @brief Set the permissions of an item for a specific user or group
- * @param string Item type
- * @param string Item source
- * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
- * @param string User or group the item is being shared with
- * @param int CRUDS permissions
- * @return Returns true on success or false on failure
- */
- public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) {
- if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) {
- // Check if this item is a reshare and verify that the permissions granted don't exceed the parent shared item
- if (isset($item['parent'])) {
- $query = \OC_DB::prepare('SELECT `permissions` FROM `*PREFIX*share` WHERE `id` = ?', 1);
- $result = $query->execute(array($item['parent']))->fetchRow();
- if (~(int)$result['permissions'] & $permissions) {
- $message = 'Setting permissions for '.$itemSource.' failed, because the permissions exceed permissions granted to '.\OC_User::getUser();
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- }
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
- $query->execute(array($permissions, $item['id']));
- // Check if permissions were removed
- if ($item['permissions'] & ~$permissions) {
- // If share permission is removed all reshares must be deleted
- if (($item['permissions'] & self::PERMISSION_SHARE) && (~$permissions & self::PERMISSION_SHARE)) {
- self::delete($item['id'], true);
- } else {
- $ids = array();
- $parents = array($item['id']);
- while (!empty($parents)) {
- $parents = "'".implode("','", $parents)."'";
- $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')');
- $result = $query->execute();
- // Reset parents array, only go through loop again if items are found that need permissions removed
- $parents = array();
- while ($item = $result->fetchRow()) {
- // Check if permissions need to be removed
- if ($item['permissions'] & ~$permissions) {
- // Add to list of items that need permissions removed
- $ids[] = $item['id'];
- $parents[] = $item['id'];
- }
- }
- }
- // Remove the permissions for all reshares of this item
- if (!empty($ids)) {
- $ids = "'".implode("','", $ids)."'";
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = `permissions` & ? WHERE `id` IN ('.$ids.')');
- $query->execute(array($permissions));
- }
- }
- }
- return true;
- }
- $message = 'Setting permissions for '.$itemSource.' failed, because the item was not found';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
-
- public static function setExpirationDate($itemType, $itemSource, $date) {
- if ($items = self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), self::FORMAT_NONE, null, -1, false)) {
- if (!empty($items)) {
- if ($date == '') {
- $date = null;
- } else {
- $date = new \DateTime($date);
- $date = date('Y-m-d H:i', $date->format('U') - $date->getOffset());
- }
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `id` = ?');
- foreach ($items as $item) {
- $query->execute(array($date, $item['id']));
- }
- return true;
- }
- }
- return false;
- }
-
- /**
- * @brief Get the backend class for the specified item type
- * @param string Item type
- * @return Sharing backend object
- */
- private static function getBackend($itemType) {
- if (isset(self::$backends[$itemType])) {
- return self::$backends[$itemType];
- } else if (isset(self::$backendTypes[$itemType]['class'])) {
- $class = self::$backendTypes[$itemType]['class'];
- if (class_exists($class)) {
- self::$backends[$itemType] = new $class;
- if (!(self::$backends[$itemType] instanceof Share_Backend)) {
- $message = 'Sharing backend '.$class.' must implement the interface OCP\Share_Backend';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- return self::$backends[$itemType];
- } else {
- $message = 'Sharing backend '.$class.' not found';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- }
- $message = 'Sharing backend for '.$itemType.' not found';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
-
- /**
- * @brief Get a list of collection item types for the specified item type
- * @param string Item type
- * @return array
- */
- private static function getCollectionItemTypes($itemType) {
- $collectionTypes = array($itemType);
- foreach (self::$backendTypes as $type => $backend) {
- if (in_array($backend['collectionOf'], $collectionTypes)) {
- $collectionTypes[] = $type;
- }
- }
- if (!self::getBackend($itemType) instanceof Share_Backend_Collection) {
- unset($collectionTypes[0]);
- }
- // Return array if collections were found or the item type is a collection itself - collections can be inside collections
- if (count($collectionTypes) > 0) {
- return $collectionTypes;
- }
- return false;
- }
-
- /**
- * @brief Get shared items from the database
- * @param string Item type
- * @param string Item source or target (optional)
- * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
- * @param string User or group the item is being shared with
- * @param string User that is the owner of shared items (optional)
- * @param int Format to convert items to with formatItems()
- * @param mixed Parameters to pass to formatItems()
- * @param int Number of items to return, -1 to return all matches (optional)
- * @param bool Include collection item types (optional)
- * @return mixed
- *
- * See public functions getItem(s)... for parameter usage
- *
- */
- private static function getItems($itemType, $item = null, $shareType = null, $shareWith = null, $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false, $itemShareWithBySource = false) {
- if (!self::isEnabled()) {
- if ($limit == 1 || (isset($uidOwner) && isset($item))) {
- return false;
- } else {
- return array();
- }
- }
- $backend = self::getBackend($itemType);
- // Get filesystem root to add it to the file target and remove from the file source, match file_source with the file cache
- if ($itemType == 'file' || $itemType == 'folder') {
- $root = \OC_Filesystem::getRoot();
- $where = 'INNER JOIN `*PREFIX*fscache` ON `file_source` = `*PREFIX*fscache`.`id`';
- if (!isset($item)) {
- $where .= ' WHERE `file_target` IS NOT NULL';
- }
- $fileDependent = true;
- $queryArgs = array();
- } else {
- $fileDependent = false;
- $root = '';
- if ($includeCollections && !isset($item) && ($collectionTypes = self::getCollectionItemTypes($itemType))) {
- // If includeCollections is true, find collections of this item type, e.g. a music album contains songs
- if (!in_array($itemType, $collectionTypes)) {
- $itemTypes = array_merge(array($itemType), $collectionTypes);
- } else {
- $itemTypes = $collectionTypes;
- }
- $placeholders = join(',', array_fill(0, count($itemTypes), '?'));
- $where .= ' WHERE item_type IN ('.$placeholders.'))';
- $queryArgs = $itemTypes;
- } else {
- $where = ' WHERE `item_type` = ?';
- $queryArgs = array($itemType);
- }
- }
- if (isset($shareType)) {
- // Include all user and group items
- if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
- $where .= ' AND `share_type` IN (?,?,?)';
- $queryArgs[] = self::SHARE_TYPE_USER;
- $queryArgs[] = self::SHARE_TYPE_GROUP;
- $queryArgs[] = self::$shareTypeGroupUserUnique;
- $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith));
- $placeholders = join(',', array_fill(0, count($userAndGroups), '?'));
- $where .= ' AND `share_with` IN ('.$placeholders.')';
- $queryArgs = array_merge($queryArgs, $userAndGroups);
- // Don't include own group shares
- $where .= ' AND `uid_owner` != ?';
- $queryArgs[] = $shareWith;
- } else {
- $where .= ' AND `share_type` = ?';
- $queryArgs[] = $shareType;
- if (isset($shareWith)) {
- $where .= ' AND `share_with` = ?';
- $queryArgs[] = $shareWith;
- }
- }
- }
- if (isset($uidOwner)) {
- $where .= ' AND `uid_owner` = ?';
- $queryArgs[] = $uidOwner;
- if (!isset($shareType)) {
- // Prevent unique user targets for group shares from being selected
- $where .= ' AND `share_type` != ?';
- $queryArgs[] = self::$shareTypeGroupUserUnique;
- }
- if ($itemType == 'file' || $itemType == 'folder') {
- $column = 'file_source';
- } else {
- $column = 'item_source';
- }
- } else {
- if ($itemType == 'file' || $itemType == 'folder') {
- $column = 'file_target';
- } else {
- $column = 'item_target';
- }
- }
- if (isset($item)) {
- if ($includeCollections && $collectionTypes = self::getCollectionItemTypes($itemType)) {
- $where .= ' AND (';
- } else {
- $where .= ' AND';
- }
- // If looking for own shared items, check item_source else check item_target
- if (isset($uidOwner) || $itemShareWithBySource) {
- // If item type is a file, file source needs to be checked in case the item was converted
- if ($itemType == 'file' || $itemType == 'folder') {
- $where .= ' `file_source` = ?';
- $column = 'file_source';
- } else {
- $where .= ' `item_source` = ?';
- $column = 'item_source';
- }
- } else {
- if ($itemType == 'file' || $itemType == 'folder') {
- $where .= ' `file_target` = ?';
- $item = \OC_Filesystem::normalizePath($item);
- } else {
- $where .= ' `item_target` = ?';
- }
- }
- $queryArgs[] = $item;
- if ($includeCollections && $collectionTypes) {
- $placeholders = join(',', array_fill(0, count($collectionTypes), '?'));
- $where .= ' OR item_type IN ('.$placeholders.'))';
- $queryArgs = array_merge($queryArgs, $collectionTypes);
- }
- }
- if ($limit != -1 && !$includeCollections) {
- if ($shareType == self::$shareTypeUserAndGroups) {
- // Make sure the unique user target is returned if it exists, unique targets should follow the group share in the database
- // If the limit is not 1, the filtering can be done later
- $where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
- }
- // The limit must be at least 3, because filtering needs to be done
- if ($limit < 3) {
- $queryLimit = 3;
- } else {
- $queryLimit = $limit;
- }
- } else {
- $queryLimit = null;
- }
- // TODO Optimize selects
- if ($format == self::FORMAT_STATUSES) {
- if ($itemType == 'file' || $itemType == 'folder') {
- $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `file_source`, `path`, `expiration`';
- } else {
- $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `expiration`';
- }
- } else {
- if (isset($uidOwner)) {
- if ($itemType == 'file' || $itemType == 'folder') {
- $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`, `expiration`';
- } else {
- $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`, `stime`, `file_source`, `expiration`';
- }
- } else {
- if ($fileDependent) {
- if (($itemType == 'file' || $itemType == 'folder') && $format == \OC_Share_Backend_File::FORMAT_FILE_APP || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT) {
- $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `uid_owner`, `share_type`, `share_with`, `file_source`, `path`, `file_target`, `permissions`, `expiration`, `name`, `ctime`, `mtime`, `mimetype`, `size`, `encrypted`, `versioned`, `writable`';
- } else {
- $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`';
- }
- } else {
- $select = '*';
- }
- }
- }
- $root = strlen($root);
- $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
- $result = $query->execute($queryArgs);
- $items = array();
- $targets = array();
- while ($row = $result->fetchRow()) {
- // Filter out duplicate group shares for users with unique targets
- if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
- $row['share_type'] = self::SHARE_TYPE_GROUP;
- $row['share_with'] = $items[$row['parent']]['share_with'];
- // Remove the parent group share
- unset($items[$row['parent']]);
- if ($row['permissions'] == 0) {
- continue;
- }
- } else if (!isset($uidOwner)) {
- // Check if the same target already exists
- if (isset($targets[$row[$column]])) {
- // Check if the same owner shared with the user twice through a group and user share - this is allowed
- $id = $targets[$row[$column]];
- if ($items[$id]['uid_owner'] == $row['uid_owner']) {
- // Switch to group share type to ensure resharing conditions aren't bypassed
- if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
- $items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
- $items[$id]['share_with'] = $row['share_with'];
- }
- // Switch ids if sharing permission is granted on only one share to ensure correct parent is used if resharing
- if (~(int)$items[$id]['permissions'] & self::PERMISSION_SHARE && (int)$row['permissions'] & self::PERMISSION_SHARE) {
- $items[$row['id']] = $items[$id];
- unset($items[$id]);
- $id = $row['id'];
- }
- // Combine the permissions for the item
- $items[$id]['permissions'] |= (int)$row['permissions'];
- continue;
- }
- } else {
- $targets[$row[$column]] = $row['id'];
- }
- }
- // Remove root from file source paths if retrieving own shared items
- if (isset($uidOwner) && isset($row['path'])) {
- if (isset($row['parent'])) {
- $row['path'] = '/Shared/'.basename($row['path']);
- } else {
- $row['path'] = substr($row['path'], $root);
- }
- }
- if (isset($row['expiration'])) {
- $time = new \DateTime();
- if ($row['expiration'] < date('Y-m-d H:i', $time->format('U') - $time->getOffset())) {
- self::delete($row['id']);
- continue;
- }
- }
- $items[$row['id']] = $row;
- }
- if (!empty($items)) {
- $collectionItems = array();
- foreach ($items as &$row) {
- // Return only the item instead of a 2-dimensional array
- if ($limit == 1 && $row['item_type'] == $itemType && $row[$column] == $item) {
- if ($format == self::FORMAT_NONE) {
- return $row;
- } else {
- break;
- }
- }
- // Check if this is a collection of the requested item type
- if ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
- if (($collectionBackend = self::getBackend($row['item_type'])) && $collectionBackend instanceof Share_Backend_Collection) {
- // Collections can be inside collections, check if the item is a collection
- if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
- $collectionItems[] = $row;
- } else {
- $collection = array();
- $collection['item_type'] = $row['item_type'];
- if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
- $collection['path'] = basename($row['path']);
- }
- $row['collection'] = $collection;
- // Fetch all of the children sources
- $children = $collectionBackend->getChildren($row[$column]);
- foreach ($children as $child) {
- $childItem = $row;
- $childItem['item_type'] = $itemType;
- if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
- $childItem['item_source'] = $child['source'];
- $childItem['item_target'] = $child['target'];
- }
- if ($backend instanceof Share_Backend_File_Dependent) {
- if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
- $childItem['file_source'] = $child['source'];
- } else {
- $childItem['file_source'] = \OC_FileCache::getId($child['file_path']);
- }
- $childItem['file_target'] = \OC_Filesystem::normalizePath($child['file_path']);
- }
- if (isset($item)) {
- if ($childItem[$column] == $item) {
- // Return only the item instead of a 2-dimensional array
- if ($limit == 1) {
- if ($format == self::FORMAT_NONE) {
- return $childItem;
- } else {
- // Unset the items array and break out of both loops
- $items = array();
- $items[] = $childItem;
- break 2;
- }
- } else {
- $collectionItems[] = $childItem;
- }
- }
- } else {
- $collectionItems[] = $childItem;
- }
- }
- }
- }
- // Remove collection item
- unset($items[$row['id']]);
- }
- }
- if (!empty($collectionItems)) {
- $items = array_merge($items, $collectionItems);
- }
- if ($format == self::FORMAT_NONE) {
- return $items;
- } else if ($format == self::FORMAT_STATUSES) {
- $statuses = array();
- // Switch column to path for files and folders, used for determining statuses inside of folders
- if ($itemType == 'file' || $itemType == 'folder') {
- $column = 'path';
- }
- foreach ($items as $item) {
- if ($item['share_type'] == self::SHARE_TYPE_LINK) {
- $statuses[$item[$column]] = true;
- } else if (!isset($statuses[$item[$column]])) {
- $statuses[$item[$column]] = false;
- }
- }
- return $statuses;
- } else {
- return $backend->formatItems($items, $format, $parameters);
- }
- } else if ($limit == 1 || (isset($uidOwner) && isset($item))) {
- return false;
- }
- return array();
- }
-
- /**
- * @brief Put shared item into the database
- * @param string Item type
- * @param string Item source
- * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
- * @param string User or group the item is being shared with
- * @param int CRUDS permissions
- * @param bool|array Parent folder target (optional)
- * @return bool Returns true on success or false on failure
- */
- private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder = null) {
- $backend = self::getBackend($itemType);
- // Check if this is a reshare
- if ($checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true)) {
- // Check if attempting to share back to owner
- if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
- $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is the original sharer';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- // Check if share permissions is granted
- if ((int)$checkReshare['permissions'] & self::PERMISSION_SHARE) {
- if (~(int)$checkReshare['permissions'] & $permissions) {
- $message = 'Sharing '.$itemSource.' failed, because the permissions exceed permissions granted to '.$uidOwner;
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- } else {
- // TODO Don't check if inside folder
- $parent = $checkReshare['id'];
- $itemSource = $checkReshare['item_source'];
- $fileSource = $checkReshare['file_source'];
- $suggestedItemTarget = $checkReshare['item_target'];
- $suggestedFileTarget = $checkReshare['file_target'];
- $filePath = $checkReshare['file_target'];
- }
- } else {
- $message = 'Sharing '.$itemSource.' failed, because resharing is not allowed';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- } else {
- $parent = null;
- $suggestedItemTarget = null;
- $suggestedFileTarget = null;
- if (!$backend->isValidSource($itemSource, $uidOwner)) {
- $message = 'Sharing '.$itemSource.' failed, because the sharing backend for '.$itemType.' could not find its source';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- $parent = null;
- if ($backend instanceof Share_Backend_File_Dependent) {
- $filePath = $backend->getFilePath($itemSource, $uidOwner);
- if ($itemType == 'file' || $itemType == 'folder') {
- $fileSource = $itemSource;
- } else {
- $fileSource = \OC_FileCache::getId($filePath);
- }
- if ($fileSource == -1) {
- $message = 'Sharing '.$itemSource.' failed, because the file could not be found in the file cache';
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
- } else {
- $filePath = null;
- $fileSource = null;
- }
- }
- $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
- // Share with a group
- if ($shareType == self::SHARE_TYPE_GROUP) {
- $groupItemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
- if (isset($fileSource)) {
- if ($parentFolder) {
- if ($parentFolder === true) {
- $groupFileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith['group'], $uidOwner, $suggestedFileTarget);
- // Set group default file target for future use
- $parentFolders[0]['folder'] = $groupFileTarget;
- } else {
- // Get group default file target
- $groupFileTarget = $parentFolder[0]['folder'].$itemSource;
- $parent = $parentFolder[0]['id'];
- }
- } else {
- $groupFileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith['group'], $uidOwner, $suggestedFileTarget);
- }
- } else {
- $groupFileTarget = null;
- }
- $query->execute(array($itemType, $itemSource, $groupItemTarget, $parent, $shareType, $shareWith['group'], $uidOwner, $permissions, time(), $fileSource, $groupFileTarget));
- // Save this id, any extra rows for this group share will need to reference it
- $parent = \OC_DB::insertid('*PREFIX*share');
- // Loop through all users of this group in case we need to add an extra row
- foreach ($shareWith['users'] as $uid) {
- $itemTarget = self::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedItemTarget, $parent);
- if (isset($fileSource)) {
- if ($parentFolder) {
- if ($parentFolder === true) {
- $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedFileTarget, $parent);
- if ($fileTarget != $groupFileTarget) {
- $parentFolders[$uid]['folder'] = $fileTarget;
- }
- } else if (isset($parentFolder[$uid])) {
- $fileTarget = $parentFolder[$uid]['folder'].$itemSource;
- $parent = $parentFolder[$uid]['id'];
- }
- } else {
- $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedFileTarget, $parent);
- }
- } else {
- $fileTarget = null;
- }
- // Insert an extra row for the group share if the item or file target is unique for this user
- if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) {
- $query->execute(array($itemType, $itemSource, $itemTarget, $parent, self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), $fileSource, $fileTarget));
- \OC_DB::insertid('*PREFIX*share');
- }
- }
- if ($parentFolder === true) {
- // Return parent folders to preserve file target paths for potential children
- return $parentFolders;
- }
- } else {
- $itemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedItemTarget);
- if (isset($fileSource)) {
- if ($parentFolder) {
- if ($parentFolder === true) {
- $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, $suggestedFileTarget);
- $parentFolders['folder'] = $fileTarget;
- } else {
- $fileTarget = $parentFolder['folder'].$itemSource;
- $parent = $parentFolder['id'];
- }
- } else {
- $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, $suggestedFileTarget);
- }
- } else {
- $fileTarget = null;
- }
- $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, $permissions, time(), $fileSource, $fileTarget));
- $id = \OC_DB::insertid('*PREFIX*share');
- if ($parentFolder === true) {
- $parentFolders['id'] = $id;
- // Return parent folder to preserve file target paths for potential children
- return $parentFolders;
- }
- }
- return true;
- }
-
- /**
- * @brief Generate a unique target for the item
- * @param string Item type
- * @param string Item source
- * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
- * @param string User or group the item is being shared with
- * @param string The suggested target originating from a reshare (optional)
- * @param int The id of the parent group share (optional)
- * @return string Item target
- */
- private static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedTarget = null, $groupParent = null) {
- $backend = self::getBackend($itemType);
- if ($shareType == self::SHARE_TYPE_LINK) {
- if (isset($suggestedTarget)) {
- return $suggestedTarget;
- }
- return $backend->generateTarget($itemSource, false);
- } else {
- if ($itemType == 'file' || $itemType == 'folder') {
- $column = 'file_target';
- $columnSource = 'file_source';
- } else {
- $column = 'item_target';
- $columnSource = 'item_source';
- }
- if ($shareType == self::SHARE_TYPE_USER) {
- // Share with is a user, so set share type to user and groups
- $shareType = self::$shareTypeUserAndGroups;
- $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith));
- } else {
- $userAndGroups = false;
- }
- $exclude = null;
- // Backend has 3 opportunities to generate a unique target
- for ($i = 0; $i < 2; $i++) {
- // Check if suggested target exists first
- if ($i == 0 && isset($suggestedTarget)) {
- $target = $suggestedTarget;
- } else {
- if ($shareType == self::SHARE_TYPE_GROUP) {
- $target = $backend->generateTarget($itemSource, false, $exclude);
- } else {
- $target = $backend->generateTarget($itemSource, $shareWith, $exclude);
- }
- if (is_array($exclude) && in_array($target, $exclude)) {
- break;
- }
- }
- // Check if target already exists
- $checkTarget = self::getItems($itemType, $target, $shareType, $shareWith);
- if (!empty($checkTarget)) {
- foreach ($checkTarget as $item) {
- // Skip item if it is the group parent row
- if (isset($groupParent) && $item['id'] == $groupParent) {
- if (count($checkTarget) == 1) {
- return $target;
- } else {
- continue;
- }
- }
- if ($item['uid_owner'] == $uidOwner) {
- if ($itemType == 'file' || $itemType == 'folder') {
- if ($item['file_source'] == \OC_FileCache::getId($itemSource)) {
- return $target;
- }
- } else if ($item['item_source'] == $itemSource) {
- return $target;
- }
- }
- }
- if (!isset($exclude)) {
- $exclude = array();
- }
- // Find similar targets to improve backend's chances to generate a unqiue target
- if ($userAndGroups) {
- if ($column == 'file_target') {
- $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` IN (\'file\', \'folder\') AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')');
- $result = $checkTargets->execute(array(self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique));
- } else {
- $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')');
- $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique));
- }
- } else {
- if ($column == 'file_target') {
- $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` IN (\'file\', \'folder\') AND `share_type` = ? AND `share_with` = ?');
- $result = $checkTargets->execute(array(self::SHARE_TYPE_GROUP, $shareWith));
- } else {
- $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` = ? AND `share_with` = ?');
- $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_GROUP, $shareWith));
- }
- }
- while ($row = $result->fetchRow()) {
- $exclude[] = $row[$column];
- }
- } else {
- return $target;
- }
- }
- }
- $message = 'Sharing backend registered for '.$itemType.' did not generate a unique target for '.$itemSource;
- \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
- throw new \Exception($message);
- }
-
- /**
- * @brief Delete all reshares of an item
- * @param int Id of item to delete
- * @param bool If true, exclude the parent from the delete (optional)
- * @param string The user that the parent was shared with (optinal)
- */
- private static function delete($parent, $excludeParent = false, $uidOwner = null) {
- $ids = array($parent);
- $parents = array($parent);
- while (!empty($parents)) {
- $parents = "'".implode("','", $parents)."'";
- // Check the owner on the first search of reshares, useful for finding and deleting the reshares by a single user of a group share
- if (count($ids) == 1 && isset($uidOwner)) {
- $query = \OC_DB::prepare('SELECT `id`, `uid_owner`, `item_type`, `item_target`, `parent` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') AND `uid_owner` = ?');
- $result = $query->execute(array($uidOwner));
- } else {
- $query = \OC_DB::prepare('SELECT `id`, `item_type`, `item_target`, `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')');
- $result = $query->execute();
- }
- // Reset parents array, only go through loop again if items are found
- $parents = array();
- while ($item = $result->fetchRow()) {
- // Search for a duplicate parent share, this occurs when an item is shared to the same user through a group and user or the same item is shared by different users
- $userAndGroups = array_merge(array($item['uid_owner']), \OC_Group::getUserGroups($item['uid_owner']));
- $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share` WHERE `item_type` = ? AND `item_target` = ? AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\') AND `uid_owner` != ? AND `id` != ?');
- $duplicateParent = $query->execute(array($item['item_type'], $item['item_target'], self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, $item['uid_owner'], $item['parent']))->fetchRow();
- if ($duplicateParent) {
- // Change the parent to the other item id if share permission is granted
- if ($duplicateParent['permissions'] & self::PERMISSION_SHARE) {
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` = ?');
- $query->execute(array($duplicateParent['id'], $item['id']));
- continue;
- }
- }
- $ids[] = $item['id'];
- $parents[] = $item['id'];
- }
- }
- if ($excludeParent) {
- unset($ids[0]);
- }
- if (!empty($ids)) {
- $ids = "'".implode("','", $ids)."'";
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$ids.')');
- $query->execute();
- }
- }
-
- /**
- * Hook Listeners
- */
-
- public static function post_deleteUser($arguments) {
- // Delete any items shared with the deleted user
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `share_with` = ? AND `share_type` = ? OR `share_type` = ?');
- $result = $query->execute(array($arguments['uid'], self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
- // Delete any items the deleted user shared
- $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `uid_owner` = ?');
- $result = $query->execute(array($arguments['uid']));
- while ($item = $result->fetchRow()) {
- self::delete($item['id']);
- }
- }
-
- public static function post_addToGroup($arguments) {
- // Find the group shares and check if the user needs a unique target
- $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?');
- $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid']));
- $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
- while ($item = $result->fetchRow()) {
- if ($item['item_type'] == 'file' || $item['item_type'] == 'file') {
- $itemTarget = null;
- } else {
- $itemTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, $arguments['uid'], $item['uid_owner'], $item['item_target'], $item['id']);
- }
- if (isset($item['file_source'])) {
- $fileTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, $arguments['uid'], $item['uid_owner'], $item['file_target'], $item['id']);
- } else {
- $fileTarget = null;
- }
- // Insert an extra row for the group share if the item or file target is unique for this user
- if ($itemTarget != $item['item_target'] || $fileTarget != $item['file_target']) {
- $query->execute(array($item['item_type'], $item['item_source'], $itemTarget, $item['id'], self::$shareTypeGroupUserUnique, $arguments['uid'], $item['uid_owner'], $item['permissions'], $item['stime'], $item['file_source'], $fileTarget));
- \OC_DB::insertid('*PREFIX*share');
- }
- }
- }
-
- public static function post_removeFromGroup($arguments) {
- // TODO Don't call if user deleted?
- $query = \OC_DB::prepare('SELECT `id`, `share_type` FROM `*PREFIX*share` WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)');
- $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'], self::$shareTypeGroupUserUnique, $arguments['uid']));
- while ($item = $result->fetchRow()) {
- if ($item['share_type'] == self::SHARE_TYPE_GROUP) {
- // Delete all reshares by this user of the group share
- self::delete($item['id'], true, $arguments['uid']);
- } else {
- self::delete($item['id']);
- }
- }
- }
-
- public static function post_deleteGroup($arguments) {
- $query = \OC_DB::prepare('SELECT id FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?');
- $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid']));
- while ($item = $result->fetchRow()) {
- self::delete($item['id']);
- }
- }
-
-}
-
-/**
-* Interface that apps must implement to share content.
-*/
-interface Share_Backend {
-
- /**
- * @brief Get the source of the item to be stored in the database
- * @param string Item source
- * @param string Owner of the item
- * @return mixed|array|false Source
- *
- * Return an array if the item is file dependent, the array needs two keys: 'item' and 'file'
- * Return false if the item does not exist for the user
- *
- * The formatItems() function will translate the source returned back into the item
- */
- public function isValidSource($itemSource, $uidOwner);
-
- /**
- * @brief Get a unique name of the item for the specified user
- * @param string Item source
- * @param string|false User the item is being shared with
- * @param array|null List of similar item names already existing as shared items
- * @return string Target name
- *
- * This function needs to verify that the user does not already have an item with this name.
- * If it does generate a new name e.g. name_#
- */
- public function generateTarget($itemSource, $shareWith, $exclude = null);
-
- /**
- * @brief Converts the shared item sources back into the item in the specified format
- * @param array Shared items
- * @param int Format
- * @return ?
- *
- * The items array is a 3-dimensional array with the item_source as the first key and the share id as the second key to an array with the share info.
- * The key/value pairs included in the share info depend on the function originally called:
- * If called by getItem(s)Shared: id, item_type, item, item_source, share_type, share_with, permissions, stime, file_source
- * If called by getItem(s)SharedWith: id, item_type, item, item_source, item_target, share_type, share_with, permissions, stime, file_source, file_target
- * This function allows the backend to control the output of shared items with custom formats.
- * It is only called through calls to the public getItem(s)Shared(With) functions.
- */
- public function formatItems($items, $format, $parameters = null);
-
-}
-
-/**
-* Interface for share backends that share content that is dependent on files.
-* Extends the Share_Backend interface.
-*/
-interface Share_Backend_File_Dependent extends Share_Backend {
-
- /**
- * @brief Get the file path of the item
- * @param
- * @param
- * @return
- */
- public function getFilePath($itemSource, $uidOwner);
-
-}
-
-/**
-* Interface for collections of of items implemented by another share backend.
-* Extends the Share_Backend interface.
-*/
-interface Share_Backend_Collection extends Share_Backend {
-
- /**
- * @brief Get the sources of the children of the item
- * @param string Item source
- * @return array Returns an array of children each inside an array with the keys: source, target, and file_path if applicable
- */
- public function getChildren($itemSource);
-
-}
+<?php
+/**
+* ownCloud
+*
+* @author Michael Gapczynski
+* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* 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.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+namespace OCP;
+
+/**
+* This class provides the ability for apps to share their content between users.
+* Apps must create a backend class that implements OCP\Share_Backend and register it with this class.
+*
+* It provides the following hooks:
+* - post_shared
+*/
+class Share {
+
+ const SHARE_TYPE_USER = 0;
+ const SHARE_TYPE_GROUP = 1;
+ const SHARE_TYPE_LINK = 3;
+ const SHARE_TYPE_EMAIL = 4;
+ const SHARE_TYPE_CONTACT = 5;
+ const SHARE_TYPE_REMOTE = 6;
+
+ /** CRUDS permissions (Create, Read, Update, Delete, Share) using a bitmask
+ * Construct permissions for share() and setPermissions with Or (|) e.g. Give user read and update permissions: PERMISSION_READ | PERMISSION_UPDATE
+ * Check if permission is granted with And (&) e.g. Check if delete is granted: if ($permissions & PERMISSION_DELETE)
+ * Remove permissions with And (&) and Not (~) e.g. Remove the update permission: $permissions &= ~PERMISSION_UPDATE
+ * Apps are required to handle permissions on their own, this class only stores and manages the permissions of shares
+ * @see lib/public/constants.php
+ */
+
+ const FORMAT_NONE = -1;
+ const FORMAT_STATUSES = -2;
+ const FORMAT_SOURCES = -3;
+
+ const TOKEN_LENGTH = 32; // see db_structure.xml
+
+ private static $shareTypeUserAndGroups = -1;
+ private static $shareTypeGroupUserUnique = 2;
+ private static $backends = array();
+ private static $backendTypes = array();
+
+ /**
+ * @brief Register a sharing backend class that implements OCP\Share_Backend for an item type
+ * @param string Item type
+ * @param string Backend class
+ * @param string (optional) Depends on item type
+ * @param array (optional) List of supported file extensions if this item type depends on files
+ * @return Returns true if backend is registered or false if error
+ */
+ public static function registerBackend($itemType, $class, $collectionOf = null, $supportedFileExtensions = null) {
+ if (self::isEnabled()) {
+ if (!isset(self::$backendTypes[$itemType])) {
+ self::$backendTypes[$itemType] = array('class' => $class, 'collectionOf' => $collectionOf, 'supportedFileExtensions' => $supportedFileExtensions);
+ if(count(self::$backendTypes) === 1) {
+ \OC_Util::addScript('core', 'share');
+ \OC_Util::addStyle('core', 'share');
+ }
+ return true;
+ }
+ \OC_Log::write('OCP\Share', 'Sharing backend '.$class.' not registered, '.self::$backendTypes[$itemType]['class'].' is already registered for '.$itemType, \OC_Log::WARN);
+ }
+ return false;
+ }
+
+ /**
+ * @brief Check if the Share API is enabled
+ * @return Returns true if enabled or false
+ *
+ * The Share API is enabled by default if not configured
+ *
+ */
+ public static function isEnabled() {
+ if (\OC_Appconfig::getValue('core', 'shareapi_enabled', 'yes') == 'yes') {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @brief Get the items of item type shared with the current user
+ * @param string Item type
+ * @param int Format (optional) Format type must be defined by the backend
+ * @param int Number of items to return (optional) Returns all by default
+ * @return Return depends on format
+ */
+ public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false) {
+ return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, $limit, $includeCollections);
+ }
+
+ /**
+ * @brief Get the item of item type shared with the current user
+ * @param string Item type
+ * @param string Item target
+ * @param int Format (optional) Format type must be defined by the backend
+ * @return Return depends on format
+ */
+ public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) {
+ return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, 1, $includeCollections);
+ }
+
+ /**
+ * @brief Get the item of item type shared with the current user by source
+ * @param string Item type
+ * @param string Item source
+ * @param int Format (optional) Format type must be defined by the backend
+ * @return Return depends on format
+ */
+ public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) {
+ return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, $parameters, 1, $includeCollections, true);
+ }
+
+ /**
+ * @brief Get the item of item type shared by a link
+ * @param string Item type
+ * @param string Item source
+ * @param string Owner of link
+ * @return Item
+ */
+ public static function getItemSharedWithByLink($itemType, $itemSource, $uidOwner) {
+ return self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, null, 1);
+ }
+
+ /**
+ * @brief Get the item shared by a token
+ * @param string token
+ * @return Item
+ */
+ public static function getShareByToken($token) {
+ $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?',1);
+ $result = $query->execute(array($token));
+ if (\OC_DB::isError($result)) {
+ \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', token=' . $token, \OC_Log::ERROR);
+ }
+ return $result->fetchRow();
+ }
+
+ /**
+ * @brief Get the shared items of item type owned by the current user
+ * @param string Item type
+ * @param int Format (optional) Format type must be defined by the backend
+ * @param int Number of items to return (optional) Returns all by default
+ * @return Return depends on format
+ */
+ public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false) {
+ return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format, $parameters, $limit, $includeCollections);
+ }
+
+ /**
+ * @brief Get the shared item of item type owned by the current user
+ * @param string Item type
+ * @param string Item source
+ * @param int Format (optional) Format type must be defined by the backend
+ * @return Return depends on format
+ */
+ public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE, $parameters = null, $includeCollections = false) {
+ return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format, $parameters, -1, $includeCollections);
+ }
+
+ /**
+ * @brief Share an item with a user, group, or via private link
+ * @param string Item type
+ * @param string Item source
+ * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
+ * @param string User or group the item is being shared with
+ * @param int CRUDS permissions
+ * @return bool|string Returns true on success or false on failure, Returns token on success for links
+ */
+ public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions) {
+ $uidOwner = \OC_User::getUser();
+ $sharingPolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global');
+ // Verify share type and sharing conditions are met
+ if ($shareType === self::SHARE_TYPE_USER) {
+ if ($shareWith == $uidOwner) {
+ $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is the item owner';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ if (!\OC_User::userExists($shareWith)) {
+ $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' does not exist';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ if ($sharingPolicy == 'groups_only') {
+ $inGroup = array_intersect(\OC_Group::getUserGroups($uidOwner), \OC_Group::getUserGroups($shareWith));
+ if (empty($inGroup)) {
+ $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is not a member of any groups that '.$uidOwner.' is a member of';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ }
+ // Check if the item source is already shared with the user, either from the same owner or a different user
+ if ($checkExists = self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
+ // Only allow the same share to occur again if it is the same owner and is not a user share, this use case is for increasing permissions for a specific user
+ if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
+ $message = 'Sharing '.$itemSource.' failed, because this item is already shared with '.$shareWith;
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ }
+ } else if ($shareType === self::SHARE_TYPE_GROUP) {
+ if (!\OC_Group::groupExists($shareWith)) {
+ $message = 'Sharing '.$itemSource.' failed, because the group '.$shareWith.' does not exist';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ if ($sharingPolicy == 'groups_only' && !\OC_Group::inGroup($uidOwner, $shareWith)) {
+ $message = 'Sharing '.$itemSource.' failed, because '.$uidOwner.' is not a member of the group '.$shareWith;
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ // Check if the item source is already shared with the group, either from the same owner or a different user
+ // The check for each user in the group is done inside the put() function
+ if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_GROUP, $shareWith, null, self::FORMAT_NONE, null, 1, true, true)) {
+ // Only allow the same share to occur again if it is the same owner and is not a group share, this use case is for increasing permissions for a specific user
+ if ($checkExists['uid_owner'] != $uidOwner || $checkExists['share_type'] == $shareType) {
+ $message = 'Sharing '.$itemSource.' failed, because this item is already shared with '.$shareWith;
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ }
+ // Convert share with into an array with the keys group and users
+ $group = $shareWith;
+ $shareWith = array();
+ $shareWith['group'] = $group;
+ $shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner));
+ } else if ($shareType === self::SHARE_TYPE_LINK) {
+ if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
+ // when updating a link share
+ if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, null, 1)) {
+ // remember old token
+ $oldToken = $checkExists['token'];
+ //delete the old share
+ self::delete($checkExists['id']);
+ }
+
+ // Generate hash of password - same method as user passwords
+ if (isset($shareWith)) {
+ $forcePortable = (CRYPT_BLOWFISH != 1);
+ $hasher = new \PasswordHash(8, $forcePortable);
+ $shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', ''));
+ }
+
+ // Generate token
+ if (isset($oldToken)) {
+ $token = $oldToken;
+ } else {
+ $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH);
+ }
+ $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token);
+ if ($result) {
+ return $token;
+ } else {
+ return false;
+ }
+ }
+ $message = 'Sharing '.$itemSource.' failed, because sharing with links is not allowed';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ return false;
+// } else if ($shareType === self::SHARE_TYPE_CONTACT) {
+// if (!\OC_App::isEnabled('contacts')) {
+// $message = 'Sharing '.$itemSource.' failed, because the contacts app is not enabled';
+// \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+// return false;
+// }
+// $vcard = \OC_Contacts_App::getContactVCard($shareWith);
+// if (!isset($vcard)) {
+// $message = 'Sharing '.$itemSource.' failed, because the contact does not exist';
+// \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+// throw new \Exception($message);
+// }
+// $details = \OC_Contacts_VCard::structureContact($vcard);
+// // TODO Add ownCloud user to contacts vcard
+// if (!isset($details['EMAIL'])) {
+// $message = 'Sharing '.$itemSource.' failed, because no email address is associated with the contact';
+// \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+// throw new \Exception($message);
+// }
+// return self::shareItem($itemType, $itemSource, self::SHARE_TYPE_EMAIL, $details['EMAIL'], $permissions);
+ } else {
+ // Future share types need to include their own conditions
+ $message = 'Share type '.$shareType.' is not valid for '.$itemSource;
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ // If the item is a folder, scan through the folder looking for equivalent item types
+ if ($itemType == 'folder') {
+ $parentFolder = self::put('folder', $itemSource, $shareType, $shareWith, $uidOwner, $permissions, true);
+ if ($parentFolder && $files = \OC_Files::getDirectoryContent($itemSource)) {
+ for ($i = 0; $i < count($files); $i++) {
+ $name = substr($files[$i]['name'], strpos($files[$i]['name'], $itemSource) - strlen($itemSource));
+ if ($files[$i]['mimetype'] == 'httpd/unix-directory' && $children = \OC_Files::getDirectoryContent($name, '/')) {
+ // Continue scanning into child folders
+ array_push($files, $children);
+ } else {
+ // Check file extension for an equivalent item type to convert to
+ $extension = strtolower(substr($itemSource, strrpos($itemSource, '.') + 1));
+ foreach (self::$backends as $type => $backend) {
+ if (isset($backend->dependsOn) && $backend->dependsOn == 'file' && isset($backend->supportedFileExtensions) && in_array($extension, $backend->supportedFileExtensions)) {
+ $itemType = $type;
+ break;
+ }
+ }
+ // Pass on to put() to check if this item should be converted, the item won't be inserted into the database unless it can be converted
+ self::put($itemType, $name, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder);
+ }
+ }
+ return true;
+ }
+ return false;
+ } else {
+ // Put the item into the database
+ return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions);
+ }
+ }
+
+ /**
+ * @brief Unshare an item from a user, group, or delete a private link
+ * @param string Item type
+ * @param string Item source
+ * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
+ * @param string User or group the item is being shared with
+ * @return Returns true on success or false on failure
+ */
+ public static function unshare($itemType, $itemSource, $shareType, $shareWith) {
+ if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(), self::FORMAT_NONE, null, 1)) {
+ self::delete($item['id']);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @brief Unshare an item from all users, groups, and remove all links
+ * @param string Item type
+ * @param string Item source
+ * @return Returns true on success or false on failure
+ */
+ public static function unshareAll($itemType, $itemSource) {
+ if ($shares = self::getItemShared($itemType, $itemSource)) {
+ foreach ($shares as $share) {
+ self::delete($share['id']);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @brief Unshare an item shared with the current user
+ * @param string Item type
+ * @param string Item target
+ * @return Returns true on success or false on failure
+ *
+ * Unsharing from self is not allowed for items inside collections
+ *
+ */
+ public static function unshareFromSelf($itemType, $itemTarget) {
+ if ($item = self::getItemSharedWith($itemType, $itemTarget)) {
+ if ((int)$item['share_type'] === self::SHARE_TYPE_GROUP) {
+ // Insert an extra row for the group share and set permission to 0 to prevent it from showing up for the user
+ $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
+ $query->execute(array($item['item_type'], $item['item_source'], $item['item_target'], $item['id'], self::$shareTypeGroupUserUnique, \OC_User::getUser(), $item['uid_owner'], 0, $item['stime'], $item['file_source'], $item['file_target']));
+ \OC_DB::insertid('*PREFIX*share');
+ // Delete all reshares by this user of the group share
+ self::delete($item['id'], true, \OC_User::getUser());
+ } else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
+ // Set permission to 0 to prevent it from showing up for the user
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
+ $query->execute(array(0, $item['id']));
+ self::delete($item['id'], true);
+ } else {
+ self::delete($item['id']);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @brief Set the permissions of an item for a specific user or group
+ * @param string Item type
+ * @param string Item source
+ * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
+ * @param string User or group the item is being shared with
+ * @param int CRUDS permissions
+ * @return Returns true on success or false on failure
+ */
+ public static function setPermissions($itemType, $itemSource, $shareType, $shareWith, $permissions) {
+ if ($item = self::getItems($itemType, $itemSource, $shareType, $shareWith, \OC_User::getUser(), self::FORMAT_NONE, null, 1, false)) {
+ // Check if this item is a reshare and verify that the permissions granted don't exceed the parent shared item
+ if (isset($item['parent'])) {
+ $query = \OC_DB::prepare('SELECT `permissions` FROM `*PREFIX*share` WHERE `id` = ?', 1);
+ $result = $query->execute(array($item['parent']))->fetchRow();
+ if (~(int)$result['permissions'] & $permissions) {
+ $message = 'Setting permissions for '.$itemSource.' failed, because the permissions exceed permissions granted to '.\OC_User::getUser();
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ }
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = ? WHERE `id` = ?');
+ $query->execute(array($permissions, $item['id']));
+ // Check if permissions were removed
+ if ($item['permissions'] & ~$permissions) {
+ // If share permission is removed all reshares must be deleted
+ if (($item['permissions'] & PERMISSION_SHARE) && (~$permissions & PERMISSION_SHARE)) {
+ self::delete($item['id'], true);
+ } else {
+ $ids = array();
+ $parents = array($item['id']);
+ while (!empty($parents)) {
+ $parents = "'".implode("','", $parents)."'";
+ $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')');
+ $result = $query->execute();
+ // Reset parents array, only go through loop again if items are found that need permissions removed
+ $parents = array();
+ while ($item = $result->fetchRow()) {
+ // Check if permissions need to be removed
+ if ($item['permissions'] & ~$permissions) {
+ // Add to list of items that need permissions removed
+ $ids[] = $item['id'];
+ $parents[] = $item['id'];
+ }
+ }
+ }
+ // Remove the permissions for all reshares of this item
+ if (!empty($ids)) {
+ $ids = "'".implode("','", $ids)."'";
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `permissions` = `permissions` & ? WHERE `id` IN ('.$ids.')');
+ $query->execute(array($permissions));
+ }
+ }
+ }
+ return true;
+ }
+ $message = 'Setting permissions for '.$itemSource.' failed, because the item was not found';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+
+ public static function setExpirationDate($itemType, $itemSource, $date) {
+ if ($items = self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), self::FORMAT_NONE, null, -1, false)) {
+ if (!empty($items)) {
+ if ($date == '') {
+ $date = null;
+ } else {
+ $date = new \DateTime($date);
+ $date = date('Y-m-d H:i', $date->format('U') - $date->getOffset());
+ }
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `id` = ?');
+ foreach ($items as $item) {
+ $query->execute(array($date, $item['id']));
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @brief Get the backend class for the specified item type
+ * @param string Item type
+ * @return Sharing backend object
+ */
+ private static function getBackend($itemType) {
+ if (isset(self::$backends[$itemType])) {
+ return self::$backends[$itemType];
+ } else if (isset(self::$backendTypes[$itemType]['class'])) {
+ $class = self::$backendTypes[$itemType]['class'];
+ if (class_exists($class)) {
+ self::$backends[$itemType] = new $class;
+ if (!(self::$backends[$itemType] instanceof Share_Backend)) {
+ $message = 'Sharing backend '.$class.' must implement the interface OCP\Share_Backend';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ return self::$backends[$itemType];
+ } else {
+ $message = 'Sharing backend '.$class.' not found';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ }
+ $message = 'Sharing backend for '.$itemType.' not found';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+
+ /**
+ * @brief Get a list of collection item types for the specified item type
+ * @param string Item type
+ * @return array
+ */
+ private static function getCollectionItemTypes($itemType) {
+ $collectionTypes = array($itemType);
+ foreach (self::$backendTypes as $type => $backend) {
+ if (in_array($backend['collectionOf'], $collectionTypes)) {
+ $collectionTypes[] = $type;
+ }
+ }
+ if (!self::getBackend($itemType) instanceof Share_Backend_Collection) {
+ unset($collectionTypes[0]);
+ }
+ // Return array if collections were found or the item type is a collection itself - collections can be inside collections
+ if (count($collectionTypes) > 0) {
+ return $collectionTypes;
+ }
+ return false;
+ }
+
+ /**
+ * @brief Get shared items from the database
+ * @param string Item type
+ * @param string Item source or target (optional)
+ * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, SHARE_TYPE_LINK, $shareTypeUserAndGroups, or $shareTypeGroupUserUnique
+ * @param string User or group the item is being shared with
+ * @param string User that is the owner of shared items (optional)
+ * @param int Format to convert items to with formatItems()
+ * @param mixed Parameters to pass to formatItems()
+ * @param int Number of items to return, -1 to return all matches (optional)
+ * @param bool Include collection item types (optional)
+ * @return mixed
+ *
+ * See public functions getItem(s)... for parameter usage
+ *
+ */
+ private static function getItems($itemType, $item = null, $shareType = null, $shareWith = null, $uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1, $includeCollections = false, $itemShareWithBySource = false) {
+ if (!self::isEnabled()) {
+ if ($limit == 1 || (isset($uidOwner) && isset($item))) {
+ return false;
+ } else {
+ return array();
+ }
+ }
+ $backend = self::getBackend($itemType);
+ // Get filesystem root to add it to the file target and remove from the file source, match file_source with the file cache
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $root = \OC_Filesystem::getRoot();
+ $where = 'INNER JOIN `*PREFIX*fscache` ON `file_source` = `*PREFIX*fscache`.`id`';
+ if (!isset($item)) {
+ $where .= ' WHERE `file_target` IS NOT NULL';
+ }
+ $fileDependent = true;
+ $queryArgs = array();
+ } else {
+ $fileDependent = false;
+ $root = '';
+ if ($includeCollections && !isset($item) && ($collectionTypes = self::getCollectionItemTypes($itemType))) {
+ // If includeCollections is true, find collections of this item type, e.g. a music album contains songs
+ if (!in_array($itemType, $collectionTypes)) {
+ $itemTypes = array_merge(array($itemType), $collectionTypes);
+ } else {
+ $itemTypes = $collectionTypes;
+ }
+ $placeholders = join(',', array_fill(0, count($itemTypes), '?'));
+ $where .= ' WHERE `item_type` IN ('.$placeholders.'))';
+ $queryArgs = $itemTypes;
+ } else {
+ $where = ' WHERE `item_type` = ?';
+ $queryArgs = array($itemType);
+ }
+ }
+ if (isset($shareType)) {
+ // Include all user and group items
+ if ($shareType == self::$shareTypeUserAndGroups && isset($shareWith)) {
+ $where .= ' AND `share_type` IN (?,?,?)';
+ $queryArgs[] = self::SHARE_TYPE_USER;
+ $queryArgs[] = self::SHARE_TYPE_GROUP;
+ $queryArgs[] = self::$shareTypeGroupUserUnique;
+ $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith));
+ $placeholders = join(',', array_fill(0, count($userAndGroups), '?'));
+ $where .= ' AND `share_with` IN ('.$placeholders.')';
+ $queryArgs = array_merge($queryArgs, $userAndGroups);
+ // Don't include own group shares
+ $where .= ' AND `uid_owner` != ?';
+ $queryArgs[] = $shareWith;
+ } else {
+ $where .= ' AND `share_type` = ?';
+ $queryArgs[] = $shareType;
+ if (isset($shareWith)) {
+ $where .= ' AND `share_with` = ?';
+ $queryArgs[] = $shareWith;
+ }
+ }
+ }
+ if (isset($uidOwner)) {
+ $where .= ' AND `uid_owner` = ?';
+ $queryArgs[] = $uidOwner;
+ if (!isset($shareType)) {
+ // Prevent unique user targets for group shares from being selected
+ $where .= ' AND `share_type` != ?';
+ $queryArgs[] = self::$shareTypeGroupUserUnique;
+ }
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $column = 'file_source';
+ } else {
+ $column = 'item_source';
+ }
+ } else {
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $column = 'file_target';
+ } else {
+ $column = 'item_target';
+ }
+ }
+ if (isset($item)) {
+ if ($includeCollections && $collectionTypes = self::getCollectionItemTypes($itemType)) {
+ $where .= ' AND (';
+ } else {
+ $where .= ' AND';
+ }
+ // If looking for own shared items, check item_source else check item_target
+ if (isset($uidOwner) || $itemShareWithBySource) {
+ // If item type is a file, file source needs to be checked in case the item was converted
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $where .= ' `file_source` = ?';
+ $column = 'file_source';
+ } else {
+ $where .= ' `item_source` = ?';
+ $column = 'item_source';
+ }
+ } else {
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $where .= ' `file_target` = ?';
+ $item = \OC_Filesystem::normalizePath($item);
+ } else {
+ $where .= ' `item_target` = ?';
+ }
+ }
+ $queryArgs[] = $item;
+ if ($includeCollections && $collectionTypes) {
+ $placeholders = join(',', array_fill(0, count($collectionTypes), '?'));
+ $where .= ' OR `item_type` IN ('.$placeholders.'))';
+ $queryArgs = array_merge($queryArgs, $collectionTypes);
+ }
+ }
+ if ($limit != -1 && !$includeCollections) {
+ if ($shareType == self::$shareTypeUserAndGroups) {
+ // Make sure the unique user target is returned if it exists, unique targets should follow the group share in the database
+ // If the limit is not 1, the filtering can be done later
+ $where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
+ }
+ // The limit must be at least 3, because filtering needs to be done
+ if ($limit < 3) {
+ $queryLimit = 3;
+ } else {
+ $queryLimit = $limit;
+ }
+ } else {
+ $queryLimit = null;
+ }
+ // TODO Optimize selects
+ if ($format == self::FORMAT_STATUSES) {
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `file_source`, `path`, `expiration`';
+ } else {
+ $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `expiration`';
+ }
+ } else {
+ if (isset($uidOwner)) {
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`, `expiration`, `token`';
+ } else {
+ $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`, `stime`, `file_source`, `expiration`, `token`';
+ }
+ } else {
+ if ($fileDependent) {
+ if (($itemType == 'file' || $itemType == 'folder') && $format == \OC_Share_Backend_File::FORMAT_FILE_APP || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT) {
+ $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `uid_owner`, `share_type`, `share_with`, `file_source`, `path`, `file_target`, `permissions`, `expiration`, `name`, `ctime`, `mtime`, `mimetype`, `size`, `encrypted`, `versioned`, `writable`';
+ } else {
+ $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`';
+ }
+ } else {
+ $select = '*';
+ }
+ }
+ }
+ $root = strlen($root);
+ $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
+ $result = $query->execute($queryArgs);
+ if (\OC_DB::isError($result)) {
+ \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, \OC_Log::ERROR);
+ }
+ $items = array();
+ $targets = array();
+ while ($row = $result->fetchRow()) {
+ // Filter out duplicate group shares for users with unique targets
+ if ($row['share_type'] == self::$shareTypeGroupUserUnique && isset($items[$row['parent']])) {
+ $row['share_type'] = self::SHARE_TYPE_GROUP;
+ $row['share_with'] = $items[$row['parent']]['share_with'];
+ // Remove the parent group share
+ unset($items[$row['parent']]);
+ if ($row['permissions'] == 0) {
+ continue;
+ }
+ } else if (!isset($uidOwner)) {
+ // Check if the same target already exists
+ if (isset($targets[$row[$column]])) {
+ // Check if the same owner shared with the user twice through a group and user share - this is allowed
+ $id = $targets[$row[$column]];
+ if ($items[$id]['uid_owner'] == $row['uid_owner']) {
+ // Switch to group share type to ensure resharing conditions aren't bypassed
+ if ($items[$id]['share_type'] != self::SHARE_TYPE_GROUP) {
+ $items[$id]['share_type'] = self::SHARE_TYPE_GROUP;
+ $items[$id]['share_with'] = $row['share_with'];
+ }
+ // Switch ids if sharing permission is granted on only one share to ensure correct parent is used if resharing
+ if (~(int)$items[$id]['permissions'] & PERMISSION_SHARE && (int)$row['permissions'] & PERMISSION_SHARE) {
+ $items[$row['id']] = $items[$id];
+ unset($items[$id]);
+ $id = $row['id'];
+ }
+ // Combine the permissions for the item
+ $items[$id]['permissions'] |= (int)$row['permissions'];
+ continue;
+ }
+ } else {
+ $targets[$row[$column]] = $row['id'];
+ }
+ }
+ // Remove root from file source paths if retrieving own shared items
+ if (isset($uidOwner) && isset($row['path'])) {
+ if (isset($row['parent'])) {
+ $row['path'] = '/Shared/'.basename($row['path']);
+ } else {
+ $row['path'] = substr($row['path'], $root);
+ }
+ }
+ if (isset($row['expiration'])) {
+ $time = new \DateTime();
+ if ($row['expiration'] < date('Y-m-d H:i', $time->format('U') - $time->getOffset())) {
+ self::delete($row['id']);
+ continue;
+ }
+ }
+ $items[$row['id']] = $row;
+ }
+ if (!empty($items)) {
+ $collectionItems = array();
+ foreach ($items as &$row) {
+ // Return only the item instead of a 2-dimensional array
+ if ($limit == 1 && $row['item_type'] == $itemType && $row[$column] == $item) {
+ if ($format == self::FORMAT_NONE) {
+ return $row;
+ } else {
+ break;
+ }
+ }
+ // Check if this is a collection of the requested item type
+ if ($includeCollections && $collectionTypes && in_array($row['item_type'], $collectionTypes)) {
+ if (($collectionBackend = self::getBackend($row['item_type'])) && $collectionBackend instanceof Share_Backend_Collection) {
+ // Collections can be inside collections, check if the item is a collection
+ if (isset($item) && $row['item_type'] == $itemType && $row[$column] == $item) {
+ $collectionItems[] = $row;
+ } else {
+ $collection = array();
+ $collection['item_type'] = $row['item_type'];
+ if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
+ $collection['path'] = basename($row['path']);
+ }
+ $row['collection'] = $collection;
+ // Fetch all of the children sources
+ $children = $collectionBackend->getChildren($row[$column]);
+ foreach ($children as $child) {
+ $childItem = $row;
+ $childItem['item_type'] = $itemType;
+ if ($row['item_type'] != 'file' && $row['item_type'] != 'folder') {
+ $childItem['item_source'] = $child['source'];
+ $childItem['item_target'] = $child['target'];
+ }
+ if ($backend instanceof Share_Backend_File_Dependent) {
+ if ($row['item_type'] == 'file' || $row['item_type'] == 'folder') {
+ $childItem['file_source'] = $child['source'];
+ } else {
+ $childItem['file_source'] = \OC_FileCache::getId($child['file_path']);
+ }
+ $childItem['file_target'] = \OC_Filesystem::normalizePath($child['file_path']);
+ }
+ if (isset($item)) {
+ if ($childItem[$column] == $item) {
+ // Return only the item instead of a 2-dimensional array
+ if ($limit == 1) {
+ if ($format == self::FORMAT_NONE) {
+ return $childItem;
+ } else {
+ // Unset the items array and break out of both loops
+ $items = array();
+ $items[] = $childItem;
+ break 2;
+ }
+ } else {
+ $collectionItems[] = $childItem;
+ }
+ }
+ } else {
+ $collectionItems[] = $childItem;
+ }
+ }
+ }
+ }
+ // Remove collection item
+ unset($items[$row['id']]);
+ }
+ }
+ if (!empty($collectionItems)) {
+ $items = array_merge($items, $collectionItems);
+ }
+ if ($format == self::FORMAT_NONE) {
+ return $items;
+ } else if ($format == self::FORMAT_STATUSES) {
+ $statuses = array();
+ // Switch column to path for files and folders, used for determining statuses inside of folders
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $column = 'path';
+ }
+ foreach ($items as $item) {
+ if ($item['share_type'] == self::SHARE_TYPE_LINK) {
+ $statuses[$item[$column]] = true;
+ } else if (!isset($statuses[$item[$column]])) {
+ $statuses[$item[$column]] = false;
+ }
+ }
+ return $statuses;
+ } else {
+ return $backend->formatItems($items, $format, $parameters);
+ }
+ } else if ($limit == 1 || (isset($uidOwner) && isset($item))) {
+ return false;
+ }
+ return array();
+ }
+
+ /**
+ * @brief Put shared item into the database
+ * @param string Item type
+ * @param string Item source
+ * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
+ * @param string User or group the item is being shared with
+ * @param int CRUDS permissions
+ * @param bool|array Parent folder target (optional)
+ * @return bool Returns true on success or false on failure
+ */
+ private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder = null, $token = null) {
+ $backend = self::getBackend($itemType);
+ // Check if this is a reshare
+ if ($checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true)) {
+ // Check if attempting to share back to owner
+ if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) {
+ $message = 'Sharing '.$itemSource.' failed, because the user '.$shareWith.' is the original sharer';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ // Check if share permissions is granted
+ if ((int)$checkReshare['permissions'] & PERMISSION_SHARE) {
+ if (~(int)$checkReshare['permissions'] & $permissions) {
+ $message = 'Sharing '.$itemSource.' failed, because the permissions exceed permissions granted to '.$uidOwner;
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ } else {
+ // TODO Don't check if inside folder
+ $parent = $checkReshare['id'];
+ $itemSource = $checkReshare['item_source'];
+ $fileSource = $checkReshare['file_source'];
+ $suggestedItemTarget = $checkReshare['item_target'];
+ $suggestedFileTarget = $checkReshare['file_target'];
+ $filePath = $checkReshare['file_target'];
+ }
+ } else {
+ $message = 'Sharing '.$itemSource.' failed, because resharing is not allowed';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ } else {
+ $parent = null;
+ $suggestedItemTarget = null;
+ $suggestedFileTarget = null;
+ if (!$backend->isValidSource($itemSource, $uidOwner)) {
+ $message = 'Sharing '.$itemSource.' failed, because the sharing backend for '.$itemType.' could not find its source';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ $parent = null;
+ if ($backend instanceof Share_Backend_File_Dependent) {
+ $filePath = $backend->getFilePath($itemSource, $uidOwner);
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $fileSource = $itemSource;
+ } else {
+ $fileSource = \OC_FileCache::getId($filePath);
+ }
+ if ($fileSource == -1) {
+ $message = 'Sharing '.$itemSource.' failed, because the file could not be found in the file cache';
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+ } else {
+ $filePath = null;
+ $fileSource = null;
+ }
+ }
+ $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`, `token`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
+ // Share with a group
+ if ($shareType == self::SHARE_TYPE_GROUP) {
+ $groupItemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget);
+ if (isset($fileSource)) {
+ if ($parentFolder) {
+ if ($parentFolder === true) {
+ $groupFileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith['group'], $uidOwner, $suggestedFileTarget);
+ // Set group default file target for future use
+ $parentFolders[0]['folder'] = $groupFileTarget;
+ } else {
+ // Get group default file target
+ $groupFileTarget = $parentFolder[0]['folder'].$itemSource;
+ $parent = $parentFolder[0]['id'];
+ }
+ } else {
+ $groupFileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith['group'], $uidOwner, $suggestedFileTarget);
+ }
+ } else {
+ $groupFileTarget = null;
+ }
+ $query->execute(array($itemType, $itemSource, $groupItemTarget, $parent, $shareType, $shareWith['group'], $uidOwner, $permissions, time(), $fileSource, $groupFileTarget, $token));
+ // Save this id, any extra rows for this group share will need to reference it
+ $parent = \OC_DB::insertid('*PREFIX*share');
+ // Loop through all users of this group in case we need to add an extra row
+ foreach ($shareWith['users'] as $uid) {
+ $itemTarget = self::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedItemTarget, $parent);
+ if (isset($fileSource)) {
+ if ($parentFolder) {
+ if ($parentFolder === true) {
+ $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedFileTarget, $parent);
+ if ($fileTarget != $groupFileTarget) {
+ $parentFolders[$uid]['folder'] = $fileTarget;
+ }
+ } else if (isset($parentFolder[$uid])) {
+ $fileTarget = $parentFolder[$uid]['folder'].$itemSource;
+ $parent = $parentFolder[$uid]['id'];
+ }
+ } else {
+ $fileTarget = self::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, $uidOwner, $suggestedFileTarget, $parent);
+ }
+ } else {
+ $fileTarget = null;
+ }
+ \OC_Hook::emit('OCP\Share', 'post_shared', array(
+ 'itemType' => $itemType,
+ 'itemSource' => $itemSource,
+ 'itemTarget' => $itemTarget,
+ 'parent' => $parent,
+ 'shareType' => self::$shareTypeGroupUserUnique,
+ 'shareWith' => $uid,
+ 'uidOwner' => $uidOwner,
+ 'permissions' => $permissions,
+ 'fileSource' => $fileSource,
+ 'fileTarget' => $fileTarget,
+ 'id' => $parent,
+ 'token' => $token
+ ));
+ // Insert an extra row for the group share if the item or file target is unique for this user
+ if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) {
+ $query->execute(array($itemType, $itemSource, $itemTarget, $parent, self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), $fileSource, $fileTarget, $token));
+ $id = \OC_DB::insertid('*PREFIX*share');
+ }
+ }
+ if ($parentFolder === true) {
+ // Return parent folders to preserve file target paths for potential children
+ return $parentFolders;
+ }
+ } else {
+ $itemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedItemTarget);
+ if (isset($fileSource)) {
+ if ($parentFolder) {
+ if ($parentFolder === true) {
+ $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, $suggestedFileTarget);
+ $parentFolders['folder'] = $fileTarget;
+ } else {
+ $fileTarget = $parentFolder['folder'].$itemSource;
+ $parent = $parentFolder['id'];
+ }
+ } else {
+ $fileTarget = self::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, $suggestedFileTarget);
+ }
+ } else {
+ $fileTarget = null;
+ }
+ $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, $permissions, time(), $fileSource, $fileTarget, $token));
+ $id = \OC_DB::insertid('*PREFIX*share');
+ \OC_Hook::emit('OCP\Share', 'post_shared', array(
+ 'itemType' => $itemType,
+ 'itemSource' => $itemSource,
+ 'itemTarget' => $itemTarget,
+ 'parent' => $parent,
+ 'shareType' => $shareType,
+ 'shareWith' => $shareWith,
+ 'uidOwner' => $uidOwner,
+ 'permissions' => $permissions,
+ 'fileSource' => $fileSource,
+ 'fileTarget' => $fileTarget,
+ 'id' => $id,
+ 'token' => $token
+ ));
+ if ($parentFolder === true) {
+ $parentFolders['id'] = $id;
+ // Return parent folder to preserve file target paths for potential children
+ return $parentFolders;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @brief Generate a unique target for the item
+ * @param string Item type
+ * @param string Item source
+ * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
+ * @param string User or group the item is being shared with
+ * @param string The suggested target originating from a reshare (optional)
+ * @param int The id of the parent group share (optional)
+ * @return string Item target
+ */
+ private static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedTarget = null, $groupParent = null) {
+ $backend = self::getBackend($itemType);
+ if ($shareType == self::SHARE_TYPE_LINK) {
+ if (isset($suggestedTarget)) {
+ return $suggestedTarget;
+ }
+ return $backend->generateTarget($itemSource, false);
+ } else {
+ if ($itemType == 'file' || $itemType == 'folder') {
+ $column = 'file_target';
+ $columnSource = 'file_source';
+ } else {
+ $column = 'item_target';
+ $columnSource = 'item_source';
+ }
+ if ($shareType == self::SHARE_TYPE_USER) {
+ // Share with is a user, so set share type to user and groups
+ $shareType = self::$shareTypeUserAndGroups;
+ $userAndGroups = array_merge(array($shareWith), \OC_Group::getUserGroups($shareWith));
+ } else {
+ $userAndGroups = false;
+ }
+ $exclude = null;
+ // Backend has 3 opportunities to generate a unique target
+ for ($i = 0; $i < 2; $i++) {
+ // Check if suggested target exists first
+ if ($i == 0 && isset($suggestedTarget)) {
+ $target = $suggestedTarget;
+ } else {
+ if ($shareType == self::SHARE_TYPE_GROUP) {
+ $target = $backend->generateTarget($itemSource, false, $exclude);
+ } else {
+ $target = $backend->generateTarget($itemSource, $shareWith, $exclude);
+ }
+ if (is_array($exclude) && in_array($target, $exclude)) {
+ break;
+ }
+ }
+ // Check if target already exists
+ $checkTarget = self::getItems($itemType, $target, $shareType, $shareWith);
+ if (!empty($checkTarget)) {
+ foreach ($checkTarget as $item) {
+ // Skip item if it is the group parent row
+ if (isset($groupParent) && $item['id'] == $groupParent) {
+ if (count($checkTarget) == 1) {
+ return $target;
+ } else {
+ continue;
+ }
+ }
+ if ($item['uid_owner'] == $uidOwner) {
+ if ($itemType == 'file' || $itemType == 'folder') {
+ if ($item['file_source'] == \OC_FileCache::getId($itemSource)) {
+ return $target;
+ }
+ } else if ($item['item_source'] == $itemSource) {
+ return $target;
+ }
+ }
+ }
+ if (!isset($exclude)) {
+ $exclude = array();
+ }
+ // Find similar targets to improve backend's chances to generate a unqiue target
+ if ($userAndGroups) {
+ if ($column == 'file_target') {
+ $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` IN (\'file\', \'folder\') AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')');
+ $result = $checkTargets->execute(array(self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique));
+ } else {
+ $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\')');
+ $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique));
+ }
+ } else {
+ if ($column == 'file_target') {
+ $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` IN (\'file\', \'folder\') AND `share_type` = ? AND `share_with` = ?');
+ $result = $checkTargets->execute(array(self::SHARE_TYPE_GROUP, $shareWith));
+ } else {
+ $checkTargets = \OC_DB::prepare('SELECT `'.$column.'` FROM `*PREFIX*share` WHERE `item_type` = ? AND `share_type` = ? AND `share_with` = ?');
+ $result = $checkTargets->execute(array($itemType, self::SHARE_TYPE_GROUP, $shareWith));
+ }
+ }
+ while ($row = $result->fetchRow()) {
+ $exclude[] = $row[$column];
+ }
+ } else {
+ return $target;
+ }
+ }
+ }
+ $message = 'Sharing backend registered for '.$itemType.' did not generate a unique target for '.$itemSource;
+ \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
+ throw new \Exception($message);
+ }
+
+ /**
+ * @brief Delete all reshares of an item
+ * @param int Id of item to delete
+ * @param bool If true, exclude the parent from the delete (optional)
+ * @param string The user that the parent was shared with (optinal)
+ */
+ private static function delete($parent, $excludeParent = false, $uidOwner = null) {
+ $ids = array($parent);
+ $parents = array($parent);
+ while (!empty($parents)) {
+ $parents = "'".implode("','", $parents)."'";
+ // Check the owner on the first search of reshares, useful for finding and deleting the reshares by a single user of a group share
+ if (count($ids) == 1 && isset($uidOwner)) {
+ $query = \OC_DB::prepare('SELECT `id`, `uid_owner`, `item_type`, `item_target`, `parent` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') AND `uid_owner` = ?');
+ $result = $query->execute(array($uidOwner));
+ } else {
+ $query = \OC_DB::prepare('SELECT `id`, `item_type`, `item_target`, `parent`, `uid_owner` FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.')');
+ $result = $query->execute();
+ }
+ // Reset parents array, only go through loop again if items are found
+ $parents = array();
+ while ($item = $result->fetchRow()) {
+ // Search for a duplicate parent share, this occurs when an item is shared to the same user through a group and user or the same item is shared by different users
+ $userAndGroups = array_merge(array($item['uid_owner']), \OC_Group::getUserGroups($item['uid_owner']));
+ $query = \OC_DB::prepare('SELECT `id`, `permissions` FROM `*PREFIX*share` WHERE `item_type` = ? AND `item_target` = ? AND `share_type` IN (?,?,?) AND `share_with` IN (\''.implode('\',\'', $userAndGroups).'\') AND `uid_owner` != ? AND `id` != ?');
+ $duplicateParent = $query->execute(array($item['item_type'], $item['item_target'], self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, $item['uid_owner'], $item['parent']))->fetchRow();
+ if ($duplicateParent) {
+ // Change the parent to the other item id if share permission is granted
+ if ($duplicateParent['permissions'] & PERMISSION_SHARE) {
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` = ?');
+ $query->execute(array($duplicateParent['id'], $item['id']));
+ continue;
+ }
+ }
+ $ids[] = $item['id'];
+ $parents[] = $item['id'];
+ }
+ }
+ if ($excludeParent) {
+ unset($ids[0]);
+ }
+ if (!empty($ids)) {
+ $ids = "'".implode("','", $ids)."'";
+ $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$ids.')');
+ $query->execute();
+ }
+ }
+
+ /**
+ * Hook Listeners
+ */
+
+ public static function post_deleteUser($arguments) {
+ // Delete any items shared with the deleted user
+ $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `share_with` = ? AND `share_type` = ? OR `share_type` = ?');
+ $result = $query->execute(array($arguments['uid'], self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
+ // Delete any items the deleted user shared
+ $query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `uid_owner` = ?');
+ $result = $query->execute(array($arguments['uid']));
+ while ($item = $result->fetchRow()) {
+ self::delete($item['id']);
+ }
+ }
+
+ public static function post_addToGroup($arguments) {
+ // Find the group shares and check if the user needs a unique target
+ $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?');
+ $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid']));
+ $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
+ while ($item = $result->fetchRow()) {
+ if ($item['item_type'] == 'file' || $item['item_type'] == 'file') {
+ $itemTarget = null;
+ } else {
+ $itemTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, $arguments['uid'], $item['uid_owner'], $item['item_target'], $item['id']);
+ }
+ if (isset($item['file_source'])) {
+ $fileTarget = self::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, $arguments['uid'], $item['uid_owner'], $item['file_target'], $item['id']);
+ } else {
+ $fileTarget = null;
+ }
+ // Insert an extra row for the group share if the item or file target is unique for this user
+ if ($itemTarget != $item['item_target'] || $fileTarget != $item['file_target']) {
+ $query->execute(array($item['item_type'], $item['item_source'], $itemTarget, $item['id'], self::$shareTypeGroupUserUnique, $arguments['uid'], $item['uid_owner'], $item['permissions'], $item['stime'], $item['file_source'], $fileTarget));
+ \OC_DB::insertid('*PREFIX*share');
+ }
+ }
+ }
+
+ public static function post_removeFromGroup($arguments) {
+ // TODO Don't call if user deleted?
+ $query = \OC_DB::prepare('SELECT `id`, `share_type` FROM `*PREFIX*share` WHERE (`share_type` = ? AND `share_with` = ?) OR (`share_type` = ? AND `share_with` = ?)');
+ $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid'], self::$shareTypeGroupUserUnique, $arguments['uid']));
+ while ($item = $result->fetchRow()) {
+ if ($item['share_type'] == self::SHARE_TYPE_GROUP) {
+ // Delete all reshares by this user of the group share
+ self::delete($item['id'], true, $arguments['uid']);
+ } else {
+ self::delete($item['id']);
+ }
+ }
+ }
+
+ public static function post_deleteGroup($arguments) {
+ $query = \OC_DB::prepare('SELECT id FROM `*PREFIX*share` WHERE `share_type` = ? AND `share_with` = ?');
+ $result = $query->execute(array(self::SHARE_TYPE_GROUP, $arguments['gid']));
+ while ($item = $result->fetchRow()) {
+ self::delete($item['id']);
+ }
+ }
+
+}
+
+/**
+* Interface that apps must implement to share content.
+*/
+interface Share_Backend {
+
+ /**
+ * @brief Get the source of the item to be stored in the database
+ * @param string Item source
+ * @param string Owner of the item
+ * @return mixed|array|false Source
+ *
+ * Return an array if the item is file dependent, the array needs two keys: 'item' and 'file'
+ * Return false if the item does not exist for the user
+ *
+ * The formatItems() function will translate the source returned back into the item
+ */
+ public function isValidSource($itemSource, $uidOwner);
+
+ /**
+ * @brief Get a unique name of the item for the specified user
+ * @param string Item source
+ * @param string|false User the item is being shared with
+ * @param array|null List of similar item names already existing as shared items
+ * @return string Target name
+ *
+ * This function needs to verify that the user does not already have an item with this name.
+ * If it does generate a new name e.g. name_#
+ */
+ public function generateTarget($itemSource, $shareWith, $exclude = null);
+
+ /**
+ * @brief Converts the shared item sources back into the item in the specified format
+ * @param array Shared items
+ * @param int Format
+ * @return ?
+ *
+ * The items array is a 3-dimensional array with the item_source as the first key and the share id as the second key to an array with the share info.
+ * The key/value pairs included in the share info depend on the function originally called:
+ * If called by getItem(s)Shared: id, item_type, item, item_source, share_type, share_with, permissions, stime, file_source
+ * If called by getItem(s)SharedWith: id, item_type, item, item_source, item_target, share_type, share_with, permissions, stime, file_source, file_target
+ * This function allows the backend to control the output of shared items with custom formats.
+ * It is only called through calls to the public getItem(s)Shared(With) functions.
+ */
+ public function formatItems($items, $format, $parameters = null);
+
+}
+
+/**
+* Interface for share backends that share content that is dependent on files.
+* Extends the Share_Backend interface.
+*/
+interface Share_Backend_File_Dependent extends Share_Backend {
+
+ /**
+ * @brief Get the file path of the item
+ * @param
+ * @param
+ * @return
+ */
+ public function getFilePath($itemSource, $uidOwner);
+
+}
+
+/**
+* Interface for collections of of items implemented by another share backend.
+* Extends the Share_Backend interface.
+*/
+interface Share_Backend_Collection extends Share_Backend {
+
+ /**
+ * @brief Get the sources of the children of the item
+ * @param string Item source
+ * @return array Returns an array of children each inside an array with the keys: source, target, and file_path if applicable
+ */
+ public function getChildren($itemSource);
+
+}
diff --git a/lib/public/util.php b/lib/public/util.php
index 38da7e82171..7b5b1abbded 100644
--- a/lib/public/util.php
+++ b/lib/public/util.php
@@ -61,7 +61,7 @@ class Util {
*/
public static function sendMail( $toaddress, $toname, $subject, $mailtext, $fromaddress, $fromname, $html=0, $altbody='', $ccaddress='', $ccname='', $bcc='') {
// call the internal mail class
- \OC_MAIL::send( $toaddress, $toname, $subject, $mailtext, $fromaddress, $fromname, $html=0, $altbody='', $ccaddress='', $ccname='', $bcc='');
+ \OC_MAIL::send($toaddress, $toname, $subject, $mailtext, $fromaddress, $fromname, $html = 0, $altbody = '', $ccaddress = '', $ccname = '', $bcc = '');
}
/**
@@ -107,8 +107,8 @@ class Util {
* @param int timestamp $timestamp
* @param bool dateOnly option to ommit time from the result
*/
- public static function formatDate( $timestamp,$dateOnly=false) {
- return(\OC_Util::formatDate( $timestamp,$dateOnly ));
+ public static function formatDate( $timestamp, $dateOnly=false) {
+ return(\OC_Util::formatDate( $timestamp, $dateOnly ));
}
/**
diff --git a/lib/request.php b/lib/request.php
index 87262d98625..c975c84a711 100644..100755
--- a/lib/request.php
+++ b/lib/request.php
@@ -18,6 +18,9 @@ class OC_Request {
if(OC::$CLI) {
return 'localhost';
}
+ if(OC_Config::getValue('overwritehost', '')<>''){
+ return OC_Config::getValue('overwritehost');
+ }
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) {
$host = trim(array_pop(explode(",", $_SERVER['HTTP_X_FORWARDED_HOST'])));
@@ -40,6 +43,9 @@ class OC_Request {
* Returns the server protocol. It respects reverse proxy servers and load balancers
*/
public static function serverProtocol() {
+ if(OC_Config::getValue('overwriteprotocol', '')<>''){
+ return OC_Config::getValue('overwriteprotocol');
+ }
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
$proto = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']);
}else{
@@ -63,7 +69,7 @@ class OC_Request {
$path_info = substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME']));
// following is taken from Sabre_DAV_URLUtil::decodePathSegment
$path_info = rawurldecode($path_info);
- $encoding = mb_detect_encoding($path_info, array('UTF-8','ISO-8859-1'));
+ $encoding = mb_detect_encoding($path_info, array('UTF-8', 'ISO-8859-1'));
switch($encoding) {
@@ -98,7 +104,7 @@ class OC_Request {
$HTTP_ACCEPT_ENCODING = $_SERVER["HTTP_ACCEPT_ENCODING"];
if( strpos($HTTP_ACCEPT_ENCODING, 'x-gzip') !== false )
return 'x-gzip';
- else if( strpos($HTTP_ACCEPT_ENCODING,'gzip') !== false )
+ else if( strpos($HTTP_ACCEPT_ENCODING, 'gzip') !== false )
return 'gzip';
return false;
}
diff --git a/lib/route.php b/lib/route.php
new file mode 100644
index 00000000000..5901717c094
--- /dev/null
+++ b/lib/route.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+use Symfony\Component\Routing\Route;
+
+class OC_Route extends Route {
+ /**
+ * Specify the method when this route is to be used
+ *
+ * @param string $method HTTP method (uppercase)
+ */
+ public function method($method) {
+ $this->setRequirement('_method', strtoupper($method));
+ return $this;
+ }
+
+ /**
+ * Specify POST as the method to use with this route
+ */
+ public function post() {
+ $this->method('POST');
+ return $this;
+ }
+
+ /**
+ * Specify GET as the method to use with this route
+ */
+ public function get() {
+ $this->method('GET');
+ return $this;
+ }
+
+ /**
+ * Specify PUT as the method to use with this route
+ */
+ public function put() {
+ $this->method('PUT');
+ return $this;
+ }
+
+ /**
+ * Specify DELETE as the method to use with this route
+ */
+ public function delete() {
+ $this->method('DELETE');
+ return $this;
+ }
+
+ /**
+ * Defaults to use for this route
+ *
+ * @param array $defaults The defaults
+ */
+ public function defaults($defaults) {
+ $action = $this->getDefault('action');
+ $this->setDefaults($defaults);
+ if (isset($defaults['action'])) {
+ $action = $defaults['action'];
+ }
+ $this->action($action);
+ return $this;
+ }
+
+ /**
+ * Requirements for this route
+ *
+ * @param array $requirements The requirements
+ */
+ public function requirements($requirements) {
+ $method = $this->getRequirement('_method');
+ $this->setRequirements($requirements);
+ if (isset($requirements['_method'])) {
+ $method = $requirements['_method'];
+ }
+ if ($method) {
+ $this->method($method);
+ }
+ return $this;
+ }
+
+ /**
+ * The action to execute when this route matches
+ * @param string|callable $class the class or a callable
+ * @param string $function the function to use with the class
+ *
+ * This function is called with $class set to a callable or
+ * to the class with $function
+ */
+ public function action($class, $function = null) {
+ $action = array($class, $function);
+ if (is_null($function)) {
+ $action = $class;
+ }
+ $this->setDefault('action', $action);
+ return $this;
+ }
+
+ /**
+ * The action to execute when this route matches, includes a file like
+ * it is called directly
+ * @param $file
+ */
+ public function actionInclude($file) {
+ $function = create_function('$param',
+ 'unset($param["_route"]);'
+ .'$_GET=array_merge($_GET, $param);'
+ .'unset($param);'
+ .'require_once "'.$file.'";');
+ $this->action($function);
+ }
+}
diff --git a/lib/router.php b/lib/router.php
new file mode 100644
index 00000000000..8cb8fd4f33b
--- /dev/null
+++ b/lib/router.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+use Symfony\Component\Routing\Matcher\UrlMatcher;
+use Symfony\Component\Routing\Generator\UrlGenerator;
+use Symfony\Component\Routing\RequestContext;
+use Symfony\Component\Routing\RouteCollection;
+//use Symfony\Component\Routing\Route;
+
+class OC_Router {
+ protected $collections = array();
+ protected $collection = null;
+ protected $root = null;
+
+ protected $generator = null;
+ protected $routing_files;
+ protected $cache_key;
+
+ public function __construct() {
+ $baseUrl = OC_Helper::linkTo('', 'index.php');
+ $method = $_SERVER['REQUEST_METHOD'];
+ $host = OC_Request::serverHost();
+ $schema = OC_Request::serverProtocol();
+ $this->context = new RequestContext($baseUrl, $method, $host, $schema);
+ // TODO cache
+ $this->root = $this->getCollection('root');
+ }
+
+ public function getRoutingFiles() {
+ if (!isset($this->routing_files)) {
+ $this->routing_files = array();
+ foreach(OC_APP::getEnabledApps() as $app) {
+ $file = OC_App::getAppPath($app).'/appinfo/routes.php';
+ if(file_exists($file)) {
+ $this->routing_files[$app] = $file;
+ }
+ }
+ }
+ return $this->routing_files;
+ }
+
+ public function getCacheKey() {
+ if (!isset($this->cache_key)) {
+ $files = $this->getRoutingFiles();
+ $files[] = 'settings/routes.php';
+ $files[] = 'core/routes.php';
+ $this->cache_key = OC_Cache::generateCacheKeyFromFiles($files);
+ }
+ return $this->cache_key;
+ }
+
+ /**
+ * loads the api routes
+ */
+ public function loadRoutes() {
+ foreach($this->getRoutingFiles() as $app => $file) {
+ $this->useCollection($app);
+ require_once $file;
+ $collection = $this->getCollection($app);
+ $this->root->addCollection($collection, '/apps/'.$app);
+ }
+ $this->useCollection('root');
+ require_once 'settings/routes.php';
+ require_once 'core/routes.php';
+ }
+
+ protected function getCollection($name) {
+ if (!isset($this->collections[$name])) {
+ $this->collections[$name] = new RouteCollection();
+ }
+ return $this->collections[$name];
+ }
+
+ /**
+ * Sets the collection to use for adding routes
+ *
+ * @param string $name Name of the colletion to use.
+ */
+ public function useCollection($name) {
+ $this->collection = $this->getCollection($name);
+ }
+
+ /**
+ * Create a OC_Route.
+ *
+ * @param string $name Name of the route to create.
+ * @param string $pattern The pattern to match
+ * @param array $defaults An array of default parameter values
+ * @param array $requirements An array of requirements for parameters (regexes)
+ */
+ public function create($name, $pattern, array $defaults = array(), array $requirements = array()) {
+ $route = new OC_Route($pattern, $defaults, $requirements);
+ $this->collection->add($name, $route);
+ return $route;
+ }
+
+ /**
+ * Find the route matching $url.
+ *
+ * @param string $url The url to find
+ */
+ public function match($url) {
+ $matcher = new UrlMatcher($this->root, $this->context);
+ $parameters = $matcher->match($url);
+ if (isset($parameters['action'])) {
+ $action = $parameters['action'];
+ if (!is_callable($action)) {
+ var_dump($action);
+ throw new Exception('not a callable action');
+ }
+ unset($parameters['action']);
+ call_user_func($action, $parameters);
+ } elseif (isset($parameters['file'])) {
+ include $parameters['file'];
+ } else {
+ throw new Exception('no action available');
+ }
+ }
+
+ /**
+ * Get the url generator
+ *
+ */
+ public function getGenerator()
+ {
+ if (null !== $this->generator) {
+ return $this->generator;
+ }
+
+ return $this->generator = new UrlGenerator($this->root, $this->context);
+ }
+
+ /**
+ * Generate url based on $name and $parameters
+ *
+ * @param string $name Name of the route to use.
+ * @param array $parameters Parameters for the route
+ */
+ public function generate($name, $parameters = array(), $absolute = false)
+ {
+ return $this->getGenerator()->generate($name, $parameters, $absolute);
+ }
+
+ /**
+ * Generate JSON response for routing in javascript
+ */
+ public static function JSRoutes()
+ {
+ $router = OC::getRouter();
+
+ $etag = $router->getCacheKey();
+ OC_Response::enableCaching();
+ OC_Response::setETagHeader($etag);
+
+ $root = $router->getCollection('root');
+ $routes = array();
+ foreach($root->all() as $name => $route) {
+ $compiled_route = $route->compile();
+ $defaults = $route->getDefaults();
+ unset($defaults['action']);
+ $routes[$name] = array(
+ 'tokens' => $compiled_route->getTokens(),
+ 'defaults' => $defaults,
+ );
+ }
+ OCP\JSON::success ( array( 'data' => $routes ) );
+ }
+}
diff --git a/lib/search.php b/lib/search.php
index 0b6ad050024..3c3378ad13c 100644
--- a/lib/search.php
+++ b/lib/search.php
@@ -40,8 +40,8 @@ class OC_Search{
* register a new search provider to be used
* @param string $provider class name of a OC_Search_Provider
*/
- public static function registerProvider($class,$options=array()) {
- self::$registeredProviders[]=array('class'=>$class,'options'=>$options);
+ public static function registerProvider($class, $options=array()) {
+ self::$registeredProviders[]=array('class'=>$class, 'options'=>$options);
}
/**
diff --git a/lib/search/provider/file.php b/lib/search/provider/file.php
index 24832296c59..ea536ef77de 100644
--- a/lib/search/provider/file.php
+++ b/lib/search/provider/file.php
@@ -2,8 +2,9 @@
class OC_Search_Provider_File extends OC_Search_Provider{
function search($query) {
- $files=OC_FileCache::search($query,true);
+ $files=OC_FileCache::search($query, true);
$results=array();
+ $l=OC_L10N::get('lib');
foreach($files as $fileData) {
$path = $fileData['path'];
$mime = $fileData['mimetype'];
@@ -13,25 +14,25 @@ class OC_Search_Provider_File extends OC_Search_Provider{
$skip = false;
if($mime=='httpd/unix-directory') {
$link = OC_Helper::linkTo( 'files', 'index.php', array('dir' => $path));
- $type = 'Files';
+ $type = (string)$l->t('Files');
}else{
- $link = OC_Helper::linkTo( 'files', 'download.php', array('file' => $path));
+ $link = OC_Helper::linkToRoute( 'download', array('file' => $path));
$mimeBase = $fileData['mimepart'];
switch($mimeBase) {
case 'audio':
$skip = true;
break;
case 'text':
- $type = 'Text';
+ $type = (string)$l->t('Text');
break;
case 'image':
- $type = 'Images';
+ $type = (string)$l->t('Images');
break;
default:
if($mime=='application/xml') {
- $type = 'Text';
+ $type = (string)$l->t('Text');
}else{
- $type = 'Files';
+ $type = (string)$l->t('Files');
}
}
}
diff --git a/lib/search/result.php b/lib/search/result.php
index 63b5cfabce6..08beaea151c 100644
--- a/lib/search/result.php
+++ b/lib/search/result.php
@@ -15,7 +15,7 @@ class OC_Search_Result{
* @param string $link link for the result
* @param string $type the type of result as human readable string ('File', 'Music', etc)
*/
- public function __construct($name,$text,$link,$type) {
+ public function __construct($name, $text, $link, $type) {
$this->name=$name;
$this->text=$text;
$this->link=$link;
diff --git a/lib/setup.php b/lib/setup.php
index 16b9ec68df6..264cd55795e 100644
--- a/lib/setup.php
+++ b/lib/setup.php
@@ -1,38 +1,5 @@
<?php
-$hasSQLite = (is_callable('sqlite_open') or class_exists('SQLite3'));
-$hasMySQL = is_callable('mysql_connect');
-$hasPostgreSQL = is_callable('pg_connect');
-$hasOracle = is_callable('oci_connect');
-$datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data');
-$opts = array(
- 'hasSQLite' => $hasSQLite,
- 'hasMySQL' => $hasMySQL,
- 'hasPostgreSQL' => $hasPostgreSQL,
- 'hasOracle' => $hasOracle,
- 'directory' => $datadir,
- 'errors' => array(),
-);
-
-if(isset($_POST['install']) AND $_POST['install']=='true') {
- // We have to launch the installation process :
- $e = OC_Setup::install($_POST);
- $errors = array('errors' => $e);
-
- if(count($e) > 0) {
- //OC_Template::printGuestPage("", "error", array("errors" => $errors));
- $options = array_merge($_POST, $opts, $errors);
- OC_Template::printGuestPage("", "installation", $options);
- }
- else {
- header("Location: ".OC::$WEBROOT.'/');
- exit();
- }
-}
-else {
- OC_Template::printGuestPage("", "installation", $opts);
-}
-
class OC_Setup {
public static function install($options) {
$error = array();
@@ -63,6 +30,9 @@ class OC_Setup {
if(empty($options['dbname'])) {
$error[] = "$dbprettyname enter the database name.";
}
+ if(substr_count($options['dbname'], '.') >= 1) {
+ $error[] = "$dbprettyname you may not use dots in the database name";
+ }
if($dbtype != 'oci' && empty($options['dbhost'])) {
$error[] = "$dbprettyname set the database host.";
}
@@ -85,69 +55,27 @@ class OC_Setup {
//write the config file
OC_Config::setValue('datadirectory', $datadir);
OC_Config::setValue('dbtype', $dbtype);
- OC_Config::setValue('version',implode('.',OC_Util::getVersion()));
+ OC_Config::setValue('version', implode('.', OC_Util::getVersion()));
if($dbtype == 'mysql') {
$dbuser = $options['dbuser'];
$dbpass = $options['dbpass'];
$dbname = $options['dbname'];
$dbhost = $options['dbhost'];
$dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_';
+
OC_Config::setValue('dbname', $dbname);
OC_Config::setValue('dbhost', $dbhost);
OC_Config::setValue('dbtableprefix', $dbtableprefix);
- //check if the database user has admin right
- $connection = @mysql_connect($dbhost, $dbuser, $dbpass);
- if(!$connection) {
+ try {
+ self::setupMySQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username);
+ } catch (Exception $e) {
$error[] = array(
'error' => 'MySQL username and/or password not valid',
'hint' => 'You need to enter either an existing account or the administrator.'
);
return($error);
}
- else {
- $oldUser=OC_Config::getValue('dbuser', false);
-
- $query="SELECT user FROM mysql.user WHERE user='$dbuser'"; //this should be enough to check for admin rights in mysql
- if(mysql_query($query, $connection)) {
- //use the admin login data for the new database user
-
- //add prefix to the mysql user name to prevent collisions
- $dbusername=substr('oc_'.$username,0,16);
- if($dbusername!=$oldUser) {
- //hash the password so we don't need to store the admin config in the config file
- $dbpassword=md5(time().$password);
-
- self::createDBUser($dbusername, $dbpassword, $connection);
-
- OC_Config::setValue('dbuser', $dbusername);
- OC_Config::setValue('dbpassword', $dbpassword);
- }
-
- //create the database
- self::createDatabase($dbname, $dbusername, $connection);
- }
- else {
- if($dbuser!=$oldUser) {
- OC_Config::setValue('dbuser', $dbuser);
- OC_Config::setValue('dbpassword', $dbpass);
- }
-
- //create the database
- self::createDatabase($dbname, $dbuser, $connection);
- }
-
- //fill the database if needed
- $query="select count(*) from information_schema.tables where table_schema='$dbname' AND table_name = '{$dbtableprefix}users';";
- $result = mysql_query($query,$connection);
- if($result) {
- $row=mysql_fetch_row($result);
- }
- if(!$result or $row[0]==0) {
- OC_DB::createDbFromStructure('db_structure.xml');
- }
- mysql_close($connection);
- }
}
elseif($dbtype == 'pgsql') {
$dbuser = $options['dbuser'];
@@ -155,82 +83,20 @@ class OC_Setup {
$dbname = $options['dbname'];
$dbhost = $options['dbhost'];
$dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_';
- OC_CONFIG::setValue('dbname', $dbname);
- OC_CONFIG::setValue('dbhost', $dbhost);
- OC_CONFIG::setValue('dbtableprefix', $dbtableprefix);
-
- $e_host = addslashes($dbhost);
- $e_user = addslashes($dbuser);
- $e_password = addslashes($dbpass);
- //check if the database user has admin right
- $connection_string = "host='$e_host' dbname=postgres user='$e_user' password='$e_password'";
- $connection = @pg_connect($connection_string);
- if(!$connection) {
+
+ OC_Config::setValue('dbname', $dbname);
+ OC_Config::setValue('dbhost', $dbhost);
+ OC_Config::setValue('dbtableprefix', $dbtableprefix);
+
+ try {
+ self::setupPostgreSQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username);
+ } catch (Exception $e) {
$error[] = array(
'error' => 'PostgreSQL username and/or password not valid',
'hint' => 'You need to enter either an existing account or the administrator.'
);
return $error;
}
- else {
- $e_user = pg_escape_string($dbuser);
- //check for roles creation rights in postgresql
- $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'";
- $result = pg_query($connection, $query);
- if($result and pg_num_rows($result) > 0) {
- //use the admin login data for the new database user
-
- //add prefix to the postgresql user name to prevent collisions
- $dbusername='oc_'.$username;
- //create a new password so we don't need to store the admin config in the config file
- $dbpassword=md5(time());
-
- self::pg_createDBUser($dbusername, $dbpassword, $connection);
-
- OC_CONFIG::setValue('dbuser', $dbusername);
- OC_CONFIG::setValue('dbpassword', $dbpassword);
-
- //create the database
- self::pg_createDatabase($dbname, $dbusername, $connection);
- }
- else {
- OC_CONFIG::setValue('dbuser', $dbuser);
- OC_CONFIG::setValue('dbpassword', $dbpass);
-
- //create the database
- self::pg_createDatabase($dbname, $dbuser, $connection);
- }
-
- // the connection to dbname=postgres is not needed anymore
- pg_close($connection);
-
- // connect to the ownCloud database (dbname=$dbname) an check if it needs to be filled
- $dbuser = OC_CONFIG::getValue('dbuser');
- $dbpass = OC_CONFIG::getValue('dbpassword');
-
- $e_host = addslashes($dbhost);
- $e_dbname = addslashes($dbname);
- $e_user = addslashes($dbuser);
- $e_password = addslashes($dbpass);
-
- $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'";
- $connection = @pg_connect($connection_string);
- if(!$connection) {
- $error[] = array(
- 'error' => 'PostgreSQL username and/or password not valid',
- 'hint' => 'You need to enter either an existing account or the administrator.'
- );
- } else {
- $query = "select count(*) FROM pg_class WHERE relname='{$dbtableprefix}users' limit 1";
- $result = pg_query($connection, $query);
- if($result) {
- $row = pg_fetch_row($result);
- }
- if(!$result or $row[0]==0) {
- OC_DB::createDbFromStructure('db_structure.xml');
- }
- }
- }
}
elseif($dbtype == 'oci') {
$dbuser = $options['dbuser'];
@@ -239,116 +105,20 @@ class OC_Setup {
$dbtablespace = $options['dbtablespace'];
$dbhost = isset($options['dbhost'])?$options['dbhost']:'';
$dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_';
- OC_CONFIG::setValue('dbname', $dbname);
- OC_CONFIG::setValue('dbtablespace', $dbtablespace);
- OC_CONFIG::setValue('dbhost', $dbhost);
- OC_CONFIG::setValue('dbtableprefix', $dbtableprefix);
-
- $e_host = addslashes($dbhost);
- $e_dbname = addslashes($dbname);
- //check if the database user has admin right
- if ($e_host == '') {
- $easy_connect_string = $e_dbname; // use dbname as easy connect name
- } else {
- $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
- }
- $connection = @oci_connect($dbuser, $dbpass, $easy_connect_string);
- if(!$connection) {
- $e = oci_error();
+
+ OC_Config::setValue('dbname', $dbname);
+ OC_Config::setValue('dbtablespace', $dbtablespace);
+ OC_Config::setValue('dbhost', $dbhost);
+ OC_Config::setValue('dbtableprefix', $dbtableprefix);
+
+ try {
+ self::setupOCIDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $dbtablespace, $username);
+ } catch (Exception $e) {
$error[] = array(
'error' => 'Oracle username and/or password not valid',
'hint' => 'You need to enter either an existing account or the administrator.'
);
return $error;
- } else {
- //check for roles creation rights in oracle
-
- $query="SELECT count(*) FROM user_role_privs, role_sys_privs WHERE user_role_privs.granted_role = role_sys_privs.role AND privilege = 'CREATE ROLE'";
- $stmt = oci_parse($connection, $query);
- if (!$stmt) {
- $entry='DB Error: "'.oci_last_error($connection).'"<br />';
- $entry.='Offending command was: '.$query.'<br />';
- echo($entry);
- }
- $result = oci_execute($stmt);
- if($result) {
- $row = oci_fetch_row($stmt);
- }
- if($result and $row[0] > 0) {
- //use the admin login data for the new database user
-
- //add prefix to the oracle user name to prevent collisions
- $dbusername='oc_'.$username;
- //create a new password so we don't need to store the admin config in the config file
- $dbpassword=md5(time().$dbpass);
-
- //oracle passwords are treated as identifiers:
- // must start with aphanumeric char
- // needs to be shortened to 30 bytes, as the two " needed to escape the identifier count towards the identifier length.
- $dbpassword=substr($dbpassword, 0, 30);
-
- self::oci_createDBUser($dbusername, $dbpassword, $dbtablespace, $connection);
-
- OC_CONFIG::setValue('dbuser', $dbusername);
- OC_CONFIG::setValue('dbname', $dbusername);
- OC_CONFIG::setValue('dbpassword', $dbpassword);
-
- //create the database not neccessary, oracle implies user = schema
- //self::oci_createDatabase($dbname, $dbusername, $connection);
- } else {
-
- OC_CONFIG::setValue('dbuser', $dbuser);
- OC_CONFIG::setValue('dbname', $dbname);
- OC_CONFIG::setValue('dbpassword', $dbpass);
-
- //create the database not neccessary, oracle implies user = schema
- //self::oci_createDatabase($dbname, $dbuser, $connection);
- }
-
- //FIXME check tablespace exists: select * from user_tablespaces
-
- // the connection to dbname=oracle is not needed anymore
- oci_close($connection);
-
- // connect to the oracle database (schema=$dbuser) an check if the schema needs to be filled
- $dbuser = OC_CONFIG::getValue('dbuser');
- //$dbname = OC_CONFIG::getValue('dbname');
- $dbpass = OC_CONFIG::getValue('dbpassword');
-
- $e_host = addslashes($dbhost);
- $e_dbname = addslashes($dbname);
-
- if ($e_host == '') {
- $easy_connect_string = $e_dbname; // use dbname as easy connect name
- } else {
- $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
- }
- $connection = @oci_connect($dbuser, $dbpass, $easy_connect_string);
- if(!$connection) {
- $error[] = array(
- 'error' => 'Oracle username and/or password not valid',
- 'hint' => 'You need to enter either an existing account or the administrator.'
- );
- return $error;
- } else {
- $query = "SELECT count(*) FROM user_tables WHERE table_name = :un";
- $stmt = oci_parse($connection, $query);
- $un = $dbtableprefix.'users';
- oci_bind_by_name($stmt, ':un', $un);
- if (!$stmt) {
- $entry='DB Error: "'.oci_last_error($connection).'"<br />';
- $entry.='Offending command was: '.$query.'<br />';
- echo($entry);
- }
- $result = oci_execute($stmt);
-
- if($result) {
- $row = oci_fetch_row($stmt);
- }
- if(!$result or $row[0]==0) {
- OC_DB::createDbFromStructure('db_structure.xml');
- }
- }
}
}
else {
@@ -369,8 +139,8 @@ class OC_Setup {
}
if(count($error) == 0) {
- OC_Appconfig::setValue('core', 'installedat',microtime(true));
- OC_Appconfig::setValue('core', 'lastupdatedat',microtime(true));
+ OC_Appconfig::setValue('core', 'installedat', microtime(true));
+ OC_Appconfig::setValue('core', 'lastupdatedat', microtime(true));
OC_Group::createGroup('admin');
OC_Group::addToGroup($username, 'admin');
@@ -383,7 +153,7 @@ class OC_Setup {
if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) {
self::createHtaccess();
}
-
+
//and we are done
OC_Config::setValue('installed', true);
}
@@ -392,7 +162,56 @@ class OC_Setup {
return $error;
}
- public static function createDatabase($name,$user,$connection) {
+ private static function setupMySQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username) {
+ //check if the database user has admin right
+ $connection = @mysql_connect($dbhost, $dbuser, $dbpass);
+ if(!$connection) {
+ throw new Exception('MySQL username and/or password not valid');
+ }
+ $oldUser=OC_Config::getValue('dbuser', false);
+
+ $query="SELECT user FROM mysql.user WHERE user='$dbuser'"; //this should be enough to check for admin rights in mysql
+ if(mysql_query($query, $connection)) {
+ //use the admin login data for the new database user
+
+ //add prefix to the mysql user name to prevent collisions
+ $dbusername=substr('oc_'.$username, 0, 16);
+ if($dbusername!=$oldUser) {
+ //hash the password so we don't need to store the admin config in the config file
+ $dbpassword=md5(time().$dbpass);
+
+ self::createDBUser($dbusername, $dbpassword, $connection);
+
+ OC_Config::setValue('dbuser', $dbusername);
+ OC_Config::setValue('dbpassword', $dbpassword);
+ }
+
+ //create the database
+ self::createMySQLDatabase($dbname, $dbusername, $connection);
+ }
+ else {
+ if($dbuser!=$oldUser) {
+ OC_Config::setValue('dbuser', $dbuser);
+ OC_Config::setValue('dbpassword', $dbpass);
+ }
+
+ //create the database
+ self::createMySQLDatabase($dbname, $dbuser, $connection);
+ }
+
+ //fill the database if needed
+ $query="select count(*) from information_schema.tables where table_schema='$dbname' AND table_name = '{$dbtableprefix}users';";
+ $result = mysql_query($query, $connection);
+ if($result) {
+ $row=mysql_fetch_row($result);
+ }
+ if(!$result or $row[0]==0) {
+ OC_DB::createDbFromStructure('db_structure.xml');
+ }
+ mysql_close($connection);
+ }
+
+ private static function createMySQLDatabase($name, $user, $connection) {
//we cant use OC_BD functions here because we need to connect as the administrative user.
$query = "CREATE DATABASE IF NOT EXISTS `$name`";
$result = mysql_query($query, $connection);
@@ -405,7 +224,7 @@ class OC_Setup {
$result = mysql_query($query, $connection); //this query will fail if there aren't the right permissons, ignore the error
}
- private static function createDBUser($name,$password,$connection) {
+ private static function createDBUser($name, $password, $connection) {
// we need to create 2 accounts, one for global use and one for local user. if we don't specify the local one,
// the anonymous user would take precedence when there is one.
$query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'";
@@ -414,7 +233,73 @@ class OC_Setup {
$result = mysql_query($query, $connection);
}
- public static function pg_createDatabase($name,$user,$connection) {
+ private static function setupPostgreSQLDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $username) {
+ $e_host = addslashes($dbhost);
+ $e_user = addslashes($dbuser);
+ $e_password = addslashes($dbpass);
+
+ //check if the database user has admin rights
+ $connection_string = "host='$e_host' dbname=postgres user='$e_user' password='$e_password'";
+ $connection = @pg_connect($connection_string);
+ if(!$connection) {
+ throw new Exception('PostgreSQL username and/or password not valid');
+ }
+ $e_user = pg_escape_string($dbuser);
+ //check for roles creation rights in postgresql
+ $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'";
+ $result = pg_query($connection, $query);
+ if($result and pg_num_rows($result) > 0) {
+ //use the admin login data for the new database user
+
+ //add prefix to the postgresql user name to prevent collisions
+ $dbusername='oc_'.$username;
+ //create a new password so we don't need to store the admin config in the config file
+ $dbpassword=md5(time());
+
+ self::pg_createDBUser($dbusername, $dbpassword, $connection);
+
+ OC_Config::setValue('dbuser', $dbusername);
+ OC_Config::setValue('dbpassword', $dbpassword);
+
+ //create the database
+ self::pg_createDatabase($dbname, $dbusername, $connection);
+ }
+ else {
+ OC_Config::setValue('dbuser', $dbuser);
+ OC_Config::setValue('dbpassword', $dbpass);
+
+ //create the database
+ self::pg_createDatabase($dbname, $dbuser, $connection);
+ }
+
+ // the connection to dbname=postgres is not needed anymore
+ pg_close($connection);
+
+ // connect to the ownCloud database (dbname=$dbname) and check if it needs to be filled
+ $dbuser = OC_Config::getValue('dbuser');
+ $dbpass = OC_Config::getValue('dbpassword');
+
+ $e_host = addslashes($dbhost);
+ $e_dbname = addslashes($dbname);
+ $e_user = addslashes($dbuser);
+ $e_password = addslashes($dbpass);
+
+ $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'";
+ $connection = @pg_connect($connection_string);
+ if(!$connection) {
+ throw new Exception('PostgreSQL username and/or password not valid');
+ }
+ $query = "select count(*) FROM pg_class WHERE relname='{$dbtableprefix}users' limit 1";
+ $result = pg_query($connection, $query);
+ if($result) {
+ $row = pg_fetch_row($result);
+ }
+ if(!$result or $row[0]==0) {
+ OC_DB::createDbFromStructure('db_structure.xml');
+ }
+ }
+
+ private static function pg_createDatabase($name, $user, $connection) {
//we cant use OC_BD functions here because we need to connect as the administrative user.
$e_name = pg_escape_string($name);
$e_user = pg_escape_string($user);
@@ -439,7 +324,7 @@ class OC_Setup {
$result = pg_query($connection, $query);
}
- private static function pg_createDBUser($name,$password,$connection) {
+ private static function pg_createDBUser($name, $password, $connection) {
$e_name = pg_escape_string($name);
$e_password = pg_escape_string($password);
$query = "select * from pg_roles where rolname='$e_name';";
@@ -470,6 +355,106 @@ class OC_Setup {
}
}
}
+
+ private static function setupOCIDatabase($dbhost, $dbuser, $dbpass, $dbname, $dbtableprefix, $dbtablespace, $username) {
+ $e_host = addslashes($dbhost);
+ $e_dbname = addslashes($dbname);
+ //check if the database user has admin right
+ if ($e_host == '') {
+ $easy_connect_string = $e_dbname; // use dbname as easy connect name
+ } else {
+ $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
+ }
+ $connection = @oci_connect($dbuser, $dbpass, $easy_connect_string);
+ if(!$connection) {
+ $e = oci_error();
+ throw new Exception('Oracle username and/or password not valid');
+ }
+ //check for roles creation rights in oracle
+
+ $query="SELECT count(*) FROM user_role_privs, role_sys_privs WHERE user_role_privs.granted_role = role_sys_privs.role AND privilege = 'CREATE ROLE'";
+ $stmt = oci_parse($connection, $query);
+ if (!$stmt) {
+ $entry='DB Error: "'.oci_last_error($connection).'"<br />';
+ $entry.='Offending command was: '.$query.'<br />';
+ echo($entry);
+ }
+ $result = oci_execute($stmt);
+ if($result) {
+ $row = oci_fetch_row($stmt);
+ }
+ if($result and $row[0] > 0) {
+ //use the admin login data for the new database user
+
+ //add prefix to the oracle user name to prevent collisions
+ $dbusername='oc_'.$username;
+ //create a new password so we don't need to store the admin config in the config file
+ $dbpassword=md5(time().$dbpass);
+
+ //oracle passwords are treated as identifiers:
+ // must start with aphanumeric char
+ // needs to be shortened to 30 bytes, as the two " needed to escape the identifier count towards the identifier length.
+ $dbpassword=substr($dbpassword, 0, 30);
+
+ self::oci_createDBUser($dbusername, $dbpassword, $dbtablespace, $connection);
+
+ OC_Config::setValue('dbuser', $dbusername);
+ OC_Config::setValue('dbname', $dbusername);
+ OC_Config::setValue('dbpassword', $dbpassword);
+
+ //create the database not neccessary, oracle implies user = schema
+ //self::oci_createDatabase($dbname, $dbusername, $connection);
+ } else {
+
+ OC_Config::setValue('dbuser', $dbuser);
+ OC_Config::setValue('dbname', $dbname);
+ OC_Config::setValue('dbpassword', $dbpass);
+
+ //create the database not neccessary, oracle implies user = schema
+ //self::oci_createDatabase($dbname, $dbuser, $connection);
+ }
+
+ //FIXME check tablespace exists: select * from user_tablespaces
+
+ // the connection to dbname=oracle is not needed anymore
+ oci_close($connection);
+
+ // connect to the oracle database (schema=$dbuser) an check if the schema needs to be filled
+ $dbuser = OC_Config::getValue('dbuser');
+ //$dbname = OC_Config::getValue('dbname');
+ $dbpass = OC_Config::getValue('dbpassword');
+
+ $e_host = addslashes($dbhost);
+ $e_dbname = addslashes($dbname);
+
+ if ($e_host == '') {
+ $easy_connect_string = $e_dbname; // use dbname as easy connect name
+ } else {
+ $easy_connect_string = '//'.$e_host.'/'.$e_dbname;
+ }
+ $connection = @oci_connect($dbuser, $dbpass, $easy_connect_string);
+ if(!$connection) {
+ throw new Exception('Oracle username and/or password not valid');
+ }
+ $query = "SELECT count(*) FROM user_tables WHERE table_name = :un";
+ $stmt = oci_parse($connection, $query);
+ $un = $dbtableprefix.'users';
+ oci_bind_by_name($stmt, ':un', $un);
+ if (!$stmt) {
+ $entry='DB Error: "'.oci_last_error($connection).'"<br />';
+ $entry.='Offending command was: '.$query.'<br />';
+ echo($entry);
+ }
+ $result = oci_execute($stmt);
+
+ if($result) {
+ $row = oci_fetch_row($stmt);
+ }
+ if(!$result or $row[0]==0) {
+ OC_DB::createDbFromStructure('db_structure.xml');
+ }
+ }
+
/**
*
* @param String $name
@@ -548,7 +533,15 @@ class OC_Setup {
* create .htaccess files for apache hosts
*/
private static function createHtaccess() {
- $content = "ErrorDocument 403 ".OC::$WEBROOT."/core/templates/403.php\n";//custom 403 error page
+ $content = "<IfModule mod_fcgid.c>\n";
+ $content.= "<IfModule mod_setenvif.c>\n";
+ $content.= "<IfModule mod_headers.c>\n";
+ $content.= "SetEnvIfNoCase ^Authorization$ \"(.+)\" XAUTHORIZATION=$1\n";
+ $content.= "RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION\n";
+ $content.= "</IfModule>\n";
+ $content.= "</IfModule>\n";
+ $content.= "</IfModule>\n";
+ $content.= "ErrorDocument 403 ".OC::$WEBROOT."/core/templates/403.php\n";//custom 403 error page
$content.= "ErrorDocument 404 ".OC::$WEBROOT."/core/templates/404.php\n";//custom 404 error page
$content.= "<IfModule mod_php5.c>\n";
$content.= "php_value upload_max_filesize 512M\n";//upload limit
@@ -567,9 +560,17 @@ class OC_Setup {
$content.= "RewriteRule ^apps/([^/]*)/(.*\.(css|php))$ index.php?app=$1&getfile=$2 [QSA,L]\n";
$content.= "RewriteRule ^remote/(.*) remote.php [QSA,L]\n";
$content.= "</IfModule>\n";
+ $content.= "<IfModule mod_mime.c>\n";
+ $content.= "AddType image/svg+xml svg svgz\n";
+ $content.= "AddEncoding gzip svgz\n";
+ $content.= "</IfModule>\n";
$content.= "Options -Indexes\n";
@file_put_contents(OC::$SERVERROOT.'/.htaccess', $content); //supress errors in case we don't have permissions for it
+ self::protectDataDirectory();
+ }
+
+ public static function protectDataDirectory() {
$content = "deny from all\n";
$content.= "IndexIgnore *";
file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.htaccess', $content);
diff --git a/lib/streamwrappers.php b/lib/streamwrappers.php
index 1e5b19a11f0..981c280f0dd 100644
--- a/lib/streamwrappers.php
+++ b/lib/streamwrappers.php
@@ -5,8 +5,8 @@ class OC_FakeDirStream{
private $name;
private $index;
- public function dir_opendir($path,$options) {
- $this->name=substr($path,strlen('fakedir://'));
+ public function dir_opendir($path, $options) {
+ $this->name=substr($path, strlen('fakedir://'));
$this->index=0;
if(!isset(self::$dirs[$this->name])) {
self::$dirs[$this->name]=array();
@@ -223,9 +223,9 @@ class OC_CloseStreamWrapper{
private $source;
private static $open=array();
public function stream_open($path, $mode, $options, &$opened_path) {
- $path=substr($path,strlen('close://'));
+ $path=substr($path, strlen('close://'));
$this->path=$path;
- $this->source=fopen($path,$mode);
+ $this->source=fopen($path, $mode);
if(is_resource($this->source)) {
$this->meta=stream_get_meta_data($this->source);
}
@@ -234,7 +234,7 @@ class OC_CloseStreamWrapper{
}
public function stream_seek($offset, $whence=SEEK_SET) {
- fseek($this->source,$offset,$whence);
+ fseek($this->source, $offset, $whence);
}
public function stream_tell() {
@@ -242,23 +242,23 @@ class OC_CloseStreamWrapper{
}
public function stream_read($count) {
- return fread($this->source,$count);
+ return fread($this->source, $count);
}
public function stream_write($data) {
- return fwrite($this->source,$data);
+ return fwrite($this->source, $data);
}
- public function stream_set_option($option,$arg1,$arg2) {
+ public function stream_set_option($option, $arg1, $arg2) {
switch($option) {
case STREAM_OPTION_BLOCKING:
- stream_set_blocking($this->source,$arg1);
+ stream_set_blocking($this->source, $arg1);
break;
case STREAM_OPTION_READ_TIMEOUT:
- stream_set_timeout($this->source,$arg1,$arg2);
+ stream_set_timeout($this->source, $arg1, $arg2);
break;
case STREAM_OPTION_WRITE_BUFFER:
- stream_set_write_buffer($this->source,$arg1,$arg2);
+ stream_set_write_buffer($this->source, $arg1, $arg2);
}
}
@@ -267,7 +267,7 @@ class OC_CloseStreamWrapper{
}
public function stream_lock($mode) {
- flock($this->source,$mode);
+ flock($this->source, $mode);
}
public function stream_flush() {
@@ -279,7 +279,7 @@ class OC_CloseStreamWrapper{
}
public function url_stat($path) {
- $path=substr($path,strlen('close://'));
+ $path=substr($path, strlen('close://'));
if(file_exists($path)) {
return stat($path);
}else{
@@ -290,12 +290,12 @@ class OC_CloseStreamWrapper{
public function stream_close() {
fclose($this->source);
if(isset(self::$callBacks[$this->path])) {
- call_user_func(self::$callBacks[$this->path],$this->path);
+ call_user_func(self::$callBacks[$this->path], $this->path);
}
}
public function unlink($path) {
- $path=substr($path,strlen('close://'));
+ $path=substr($path, strlen('close://'));
return unlink($path);
}
}
diff --git a/lib/template.php b/lib/template.php
index 1c529932a30..04667d73a2c 100644
--- a/lib/template.php
+++ b/lib/template.php
@@ -22,6 +22,22 @@
*/
/**
+ * Prints an XSS escaped string
+ * @param string $string the string which will be escaped and printed
+ */
+function p($string) {
+ print(OC_Util::sanitizeHTML($string));
+}
+
+/**
+ * Prints an unescaped string
+ * @param string $string the string which will be printed as it is
+ */
+function print_unescaped($string) {
+ print($string);
+}
+
+/**
* @brief make OC_Helper::linkTo available as a simple function
* @param string $app app
* @param string $file file
@@ -69,7 +85,7 @@ function human_file_size( $bytes ) {
}
function simple_file_size($bytes) {
- $mbytes = round($bytes/(1024*1024),1);
+ $mbytes = round($bytes/(1024*1024), 1);
if($bytes == 0) { return '0'; }
else if($mbytes < 0.1) { return '&lt; 0.1'; }
else if($mbytes > 1000) { return '&gt; 1000'; }
@@ -86,14 +102,14 @@ function relative_modified_date($timestamp) {
if($timediff < 60) { return $l->t('seconds ago'); }
else if($timediff < 120) { return $l->t('1 minute ago'); }
- else if($timediff < 3600) { return $l->t('%d minutes ago',$diffminutes); }
- //else if($timediff < 7200) { return '1 hour ago'; }
- //else if($timediff < 86400) { return $diffhours.' hours ago'; }
+ else if($timediff < 3600) { return $l->t('%d minutes ago', $diffminutes); }
+ else if($timediff < 7200) { return $l->t('1 hour ago'); }
+ else if($timediff < 86400) { return $l->t('%d hours ago', $diffhours); }
else if((date('G')-$diffhours) > 0) { return $l->t('today'); }
else if((date('G')-$diffhours) > -24) { return $l->t('yesterday'); }
- else if($timediff < 2678400) { return $l->t('%d days ago',$diffdays); }
+ else if($timediff < 2678400) { return $l->t('%d days ago', $diffdays); }
else if($timediff < 5184000) { return $l->t('last month'); }
- else if((date('n')-$diffmonths) > 0) { return $l->t('months ago'); }
+ else if((date('n')-$diffmonths) > 0) { return $l->t('%d months ago', $diffmonths); }
else if($timediff < 63113852) { return $l->t('last year'); }
else { return $l->t('years ago'); }
}
@@ -156,7 +172,6 @@ class OC_Template{
$this->application = $app;
$this->vars = array();
$this->vars['requesttoken'] = OC_Util::callRegister();
- $this->vars['requestlifespan'] = OC_Util::$callLifespan;
$parts = explode('/', $app); // fix translation when app is something like core/lostpassword
$this->l10n = OC_L10N::get($parts[0]);
@@ -180,11 +195,11 @@ class OC_Template{
public static function detectFormfactor() {
// please add more useragent strings for other devices
if(isset($_SERVER['HTTP_USER_AGENT'])) {
- if(stripos($_SERVER['HTTP_USER_AGENT'],'ipad')>0) {
+ if(stripos($_SERVER['HTTP_USER_AGENT'], 'ipad')>0) {
$mode='tablet';
- }elseif(stripos($_SERVER['HTTP_USER_AGENT'],'iphone')>0) {
+ }elseif(stripos($_SERVER['HTTP_USER_AGENT'], 'iphone')>0) {
$mode='mobile';
- }elseif((stripos($_SERVER['HTTP_USER_AGENT'],'N9')>0) and (stripos($_SERVER['HTTP_USER_AGENT'],'nokia')>0)) {
+ }elseif((stripos($_SERVER['HTTP_USER_AGENT'], 'N9')>0) and (stripos($_SERVER['HTTP_USER_AGENT'], 'nokia')>0)) {
$mode='mobile';
}else{
$mode='default';
@@ -341,7 +356,7 @@ class OC_Template{
* @param string $text the text content for the element
*/
public function addHeader( $tag, $attributes, $text='') {
- $this->headers[]=array('tag'=>$tag,'attributes'=>$attributes,'text'=>$text);
+ $this->headers[]=array('tag'=>$tag,'attributes'=>$attributes, 'text'=>$text);
}
/**
@@ -375,13 +390,12 @@ class OC_Template{
$page = new OC_TemplateLayout($this->renderas);
if($this->renderas == 'user') {
$page->assign('requesttoken', $this->vars['requesttoken']);
- $page->assign('requestlifespan', $this->vars['requestlifespan']);
}
// Add custom headers
- $page->assign('headers',$this->headers, false);
+ $page->assign('headers', $this->headers, false);
foreach(OC_Util::$headers as $header) {
- $page->append('headers',$header);
+ $page->append('headers', $header);
}
$page->assign( "content", $data, false );
@@ -405,7 +419,7 @@ class OC_Template{
// Execute the template
ob_start();
- include( $this->template ); // <-- we have to use include because we pass $_!
+ include $this->template; // <-- we have to use include because we pass $_!
$data = ob_get_contents();
@ob_end_clean();
@@ -430,7 +444,7 @@ class OC_Template{
// Include
ob_start();
- include( $this->path.$file.'.php' );
+ include $this->path.$file.'.php';
$data = ob_get_contents();
@ob_end_clean();
@@ -482,4 +496,15 @@ class OC_Template{
}
return $content->printPage();
}
+
+ /**
+ * @brief Print a fatal error page and terminates the script
+ * @param string $error The error message to show
+ * @param string $hint An option hint message
+ */
+ public static function printErrorPage( $error_msg, $hint = '' ) {
+ $errors = array(array('error' => $error_msg, 'hint' => $hint));
+ OC_Template::printGuestPage("", "error", array("errors" => $errors));
+ die();
+ }
}
diff --git a/lib/templatelayout.php b/lib/templatelayout.php
index 4f26775b48e..1a0570a270d 100644
--- a/lib/templatelayout.php
+++ b/lib/templatelayout.php
@@ -12,10 +12,10 @@ class OC_TemplateLayout extends OC_Template {
if( $renderas == 'user' ) {
parent::__construct( 'core', 'layout.user' );
- if(in_array(OC_APP::getCurrentApp(),array('settings','admin','help'))!==false) {
- $this->assign('bodyid','body-settings', false);
+ if(in_array(OC_APP::getCurrentApp(), array('settings','admin', 'help'))!==false) {
+ $this->assign('bodyid', 'body-settings', false);
}else{
- $this->assign('bodyid','body-user', false);
+ $this->assign('bodyid', 'body-user', false);
}
// Add navigation entry
@@ -38,7 +38,7 @@ class OC_TemplateLayout extends OC_Template {
foreach(OC_App::getEnabledApps() as $app) {
$apps_paths[$app] = OC_App::getAppWebPath($app);
}
- $this->assign( 'apps_paths', str_replace('\\/', '/',json_encode($apps_paths)),false ); // Ugly unescape slashes waiting for better solution
+ $this->assign( 'apps_paths', str_replace('\\/', '/', json_encode($apps_paths)), false ); // Ugly unescape slashes waiting for better solution
if (OC_Config::getValue('installed', false) && !OC_AppConfig::getValue('core', 'remote_core.css', false)) {
OC_AppConfig::setValue('core', 'remote_core.css', '/core/minimizer.php');
@@ -49,7 +49,7 @@ class OC_TemplateLayout extends OC_Template {
$jsfiles = self::findJavascriptFiles(OC_Util::$scripts);
$this->assign('jsfiles', array(), false);
if (!empty(OC_Util::$core_scripts)) {
- $this->append( 'jsfiles', OC_Helper::linkToRemote('core.js', false));
+ $this->append( 'jsfiles', OC_Helper::linkToRemoteBase('core.js', false));
}
foreach($jsfiles as $info) {
$root = $info[0];
@@ -62,7 +62,7 @@ class OC_TemplateLayout extends OC_Template {
$cssfiles = self::findStylesheetFiles(OC_Util::$styles);
$this->assign('cssfiles', array());
if (!empty(OC_Util::$core_styles)) {
- $this->append( 'cssfiles', OC_Helper::linkToRemote('core.css', false));
+ $this->append( 'cssfiles', OC_Helper::linkToRemoteBase('core.css', false));
}
foreach($cssfiles as $info) {
$root = $info[0];
diff --git a/lib/updater.php b/lib/updater.php
index b3b289ef276..11081eded63 100644
--- a/lib/updater.php
+++ b/lib/updater.php
@@ -29,8 +29,8 @@ class OC_Updater{
* Check if a new version is available
*/
public static function check() {
- OC_Appconfig::setValue('core', 'lastupdatedat',microtime(true));
- if(OC_Appconfig::getValue('core', 'installedat','')=='') OC_Appconfig::setValue('core', 'installedat',microtime(true));
+ OC_Appconfig::setValue('core', 'lastupdatedat', microtime(true));
+ if(OC_Appconfig::getValue('core', 'installedat', '')=='') OC_Appconfig::setValue('core', 'installedat', microtime(true));
$updaterurl='http://apps.owncloud.com/updater.php';
$version=OC_Util::getVersion();
@@ -38,21 +38,21 @@ class OC_Updater{
$version['updated']=OC_Appconfig::getValue('core', 'lastupdatedat');
$version['updatechannel']='stable';
$version['edition']=OC_Util::getEditionString();
- $versionstring=implode('x',$version);
+ $versionstring=implode('x', $version);
//fetch xml data from updater
$url=$updaterurl.'?version='.$versionstring;
// set a sensible timeout of 10 sec to stay responsive even if the update server is down.
$ctx = stream_context_create(
- array(
- 'http' => array(
- 'timeout' => 10
- )
- )
- );
+ array(
+ 'http' => array(
+ 'timeout' => 10
+ )
+ )
+ );
$xml=@file_get_contents($url, 0, $ctx);
- if($xml==FALSE) {
+ if($xml==false) {
return array();
}
$data=@simplexml_load_string($xml);
@@ -72,7 +72,7 @@ class OC_Updater{
if(OC_Config::getValue('updatechecker', true)==true) {
$data=OC_Updater::check();
if(isset($data['version']) and $data['version']<>'') {
- $txt='<span style="color:#AA0000; font-weight:bold;">'.$l->t('%s is available. Get <a href="%s">more information</a>',array($data['versionstring'], $data['web'])).'</span>';
+ $txt='<span style="color:#AA0000; font-weight:bold;">'.$l->t('%s is available. Get <a href="%s">more information</a>', array($data['versionstring'], $data['web'])).'</span>';
}else{
$txt=$l->t('up to date');
}
diff --git a/lib/user.php b/lib/user.php
index 7de2a4b7fe6..31c93740d77 100644
--- a/lib/user.php
+++ b/lib/user.php
@@ -120,11 +120,11 @@ class OC_User {
* setup the configured backends in config.php
*/
public static function setupBackends() {
- $backends=OC_Config::getValue('user_backends',array());
+ $backends=OC_Config::getValue('user_backends', array());
foreach($backends as $i=>$config) {
$class=$config['class'];
$arguments=$config['arguments'];
- if(class_exists($class) and array_search($i,self::$_setupedBackends)===false) {
+ if(class_exists($class) and array_search($i, self::$_setupedBackends)===false) {
// make a reflection object
$reflectionObj = new ReflectionClass($class);
@@ -133,7 +133,7 @@ class OC_User {
self::useBackend($backend);
$_setupedBackends[]=$i;
}else{
- OC_Log::write('core','User backend '.$class.' not found.',OC_Log::ERROR);
+ OC_Log::write('core', 'User backend '.$class.' not found.', OC_Log::ERROR);
}
}
}
@@ -179,10 +179,10 @@ class OC_User {
if(!$backend->implementsActions(OC_USER_BACKEND_CREATE_USER))
continue;
- $backend->createUser($uid,$password);
+ $backend->createUser($uid, $password);
OC_Hook::emit( "OC_User", "post_createUser", array( "uid" => $uid, "password" => $password ));
- return true;
+ return self::userExists($uid);
}
}
return false;
@@ -204,12 +204,19 @@ class OC_User {
foreach(self::$_usedBackends as $backend) {
$backend->deleteUser($uid);
}
+ if (self::userExists($uid)) {
+ return false;
+ }
// We have to delete the user from all groups
foreach( OC_Group::getUserGroups( $uid ) as $i ) {
OC_Group::removeFromGroup( $uid, $i );
}
// Delete the user's keys in preferences
OC_Preferences::deleteUser($uid);
+
+ // Delete user files in /data/
+ OC_Helper::rmdirr(OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/'.$uid.'/');
+
// Emit and exit
OC_Hook::emit( "OC_User", "post_deleteUser", array( "uid" => $uid ));
return true;
@@ -325,10 +332,12 @@ class OC_User {
foreach(self::$_usedBackends as $backend) {
if($backend->implementsActions(OC_USER_BACKEND_SET_PASSWORD)) {
if($backend->userExists($uid)) {
- $success |= $backend->setPassword($uid,$password);
+ $success |= $backend->setPassword($uid, $password);
}
}
}
+ // invalidate all login cookies
+ OC_Preferences::deleteApp($uid, 'login_token');
OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password ));
return $success;
}
@@ -363,8 +372,7 @@ class OC_User {
* @param $password The password
* @returns string
*
- * Check if the password is correct without logging in the user
- * returns the user id or false
+ * returns the path to the users home directory
*/
public static function getHome($uid) {
foreach(self::$_usedBackends as $backend) {
@@ -472,9 +480,10 @@ class OC_User {
*/
public static function setMagicInCookie($username, $token) {
$secure_cookie = OC_Config::getValue("forcessl", false);
- setcookie("oc_username", $username, time()+60*60*24*15, '', '', $secure_cookie);
- setcookie("oc_token", $token, time()+60*60*24*15, '', '', $secure_cookie);
- setcookie("oc_remember_login", true, time()+60*60*24*15, '', '', $secure_cookie);
+ $expires = time() + OC_Config::getValue('remember_login_cookie_lifetime', 60*60*24*15);
+ setcookie("oc_username", $username, $expires, '', '', $secure_cookie);
+ setcookie("oc_token", $token, $expires, '', '', $secure_cookie, true);
+ setcookie("oc_remember_login", true, $expires, '', '', $secure_cookie);
}
/**
@@ -484,8 +493,8 @@ class OC_User {
unset($_COOKIE["oc_username"]);
unset($_COOKIE["oc_token"]);
unset($_COOKIE["oc_remember_login"]);
- setcookie("oc_username", NULL, -1);
- setcookie("oc_token", NULL, -1);
- setcookie("oc_remember_login", NULL, -1);
+ setcookie("oc_username", null, -1);
+ setcookie("oc_token", null, -1);
+ setcookie("oc_remember_login", null, -1);
}
}
diff --git a/lib/user/database.php b/lib/user/database.php
index 25e24fcf7e4..f33e338e2e4 100644
--- a/lib/user/database.php
+++ b/lib/user/database.php
@@ -48,7 +48,7 @@ class OC_User_Database extends OC_User_Backend {
if(!self::$hasher) {
//we don't want to use DES based crypt(), since it doesn't return a has with a recognisable prefix
$forcePortable=(CRYPT_BLOWFISH!=1);
- self::$hasher=new PasswordHash(8,$forcePortable);
+ self::$hasher=new PasswordHash(8, $forcePortable);
}
return self::$hasher;
@@ -137,7 +137,7 @@ class OC_User_Database extends OC_User_Backend {
}else{//old sha1 based hashing
if(sha1($password)==$storedHash) {
//upgrade to new hashing
- $this->setPassword($row['uid'],$password);
+ $this->setPassword($row['uid'], $password);
return $row['uid'];
}else{
return false;
@@ -155,7 +155,7 @@ class OC_User_Database extends OC_User_Backend {
* Get a list of all users.
*/
public function getUsers($search = '', $limit = null, $offset = null) {
- $query = OC_DB::prepare('SELECT `uid` FROM `*PREFIX*users` WHERE LOWER(`uid`) LIKE LOWER(?)',$limit,$offset);
+ $query = OC_DB::prepare('SELECT `uid` FROM `*PREFIX*users` WHERE LOWER(`uid`) LIKE LOWER(?)', $limit, $offset);
$result = $query->execute(array($search.'%'));
$users = array();
while ($row = $result->fetchRow()) {
@@ -172,7 +172,10 @@ class OC_User_Database extends OC_User_Backend {
public function userExists($uid) {
$query = OC_DB::prepare( 'SELECT * FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)' );
$result = $query->execute( array( $uid ));
-
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ return false;
+ }
return $result->numRows() > 0;
}
diff --git a/lib/user/http.php b/lib/user/http.php
index 2668341408d..944ede73a0b 100644
--- a/lib/user/http.php
+++ b/lib/user/http.php
@@ -40,7 +40,7 @@ class OC_User_HTTP extends OC_User_Backend {
if(isset($parts['query'])) {
$url.='?'.$parts['query'];
}
- return array($parts['user'],$url);
+ return array($parts['user'], $url);
}
@@ -50,7 +50,7 @@ class OC_User_HTTP extends OC_User_Backend {
* @return boolean
*/
private function matchUrl($url) {
- return ! is_null(parse_url($url,PHP_URL_USER));
+ return ! is_null(parse_url($url, PHP_URL_USER));
}
/**
@@ -66,7 +66,7 @@ class OC_User_HTTP extends OC_User_Backend {
if(!$this->matchUrl($uid)) {
return false;
}
- list($user,$url)=$this->parseUrl($uid);
+ list($user, $url)=$this->parseUrl($uid);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
diff --git a/lib/util.php b/lib/util.php
index afbea9a00cb..2ee3f0e4efb 100755
--- a/lib/util.php
+++ b/lib/util.php
@@ -24,6 +24,11 @@ class OC_Util {
$user = OC_User::getUser();
}
+ // load all filesystem apps before, so no setup-hook gets lost
+ if(!isset($RUNTIME_NOAPPS) || !$RUNTIME_NOAPPS) {
+ OC_App::loadApps(array('filesystem'));
+ }
+
// the filesystem will finish when $user is not empty,
// mark fs setup here to avoid doing the setup from loading
// OC_Filesystem
@@ -34,7 +39,7 @@ class OC_Util {
$CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
//first set up the local "root" storage
if(!self::$rootMounted) {
- OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY),'/');
+ OC_Filesystem::mount('OC_Filestorage_Local', array('datadir'=>$CONFIG_DATADIRECTORY), '/');
self::$rootMounted=true;
}
@@ -47,27 +52,13 @@ class OC_Util {
}
//jail the user into his "home" directory
OC_Filesystem::mount('OC_Filestorage_Local', array('datadir' => $user_root), $user);
- OC_Filesystem::init($user_dir);
+ OC_Filesystem::init($user_dir, $user);
$quotaProxy=new OC_FileProxy_Quota();
$fileOperationProxy = new OC_FileProxy_FileOperations();
OC_FileProxy::register($quotaProxy);
OC_FileProxy::register($fileOperationProxy);
// Load personal mount config
- if (is_file($user_root.'/mount.php')) {
- $mountConfig = include($user_root.'/mount.php');
- if (isset($mountConfig['user'][$user])) {
- foreach ($mountConfig['user'][$user] as $mountPoint => $options) {
- OC_Filesystem::mount($options['class'], $options['options'], $mountPoint);
- }
- }
-
- $mtime=filemtime($user_root.'/mount.php');
- $previousMTime=OC_Preferences::getValue($user,'files','mountconfigmtime',0);
- if($mtime>$previousMTime) {//mount config has changed, filecache needs to be updated
- OC_FileCache::triggerUpdate($user);
- OC_Preferences::setValue($user,'files','mountconfigmtime',$mtime);
- }
- }
+ self::loadUserMountPoints($user);
OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $user_dir));
}
}
@@ -77,13 +68,34 @@ class OC_Util {
self::$fsSetup=false;
}
+ public static function loadUserMountPoints($user) {
+ $user_dir = '/'.$user.'/files';
+ $user_root = OC_User::getHome($user);
+ $userdirectory = $user_root . '/files';
+ if (is_file($user_root.'/mount.php')) {
+ $mountConfig = include $user_root.'/mount.php';
+ if (isset($mountConfig['user'][$user])) {
+ foreach ($mountConfig['user'][$user] as $mountPoint => $options) {
+ OC_Filesystem::mount($options['class'], $options['options'], $mountPoint);
+ }
+ }
+
+ $mtime=filemtime($user_root.'/mount.php');
+ $previousMTime=OC_Preferences::getValue($user, 'files', 'mountconfigmtime', 0);
+ if($mtime>$previousMTime) {//mount config has changed, filecache needs to be updated
+ OC_FileCache::triggerUpdate($user);
+ OC_Preferences::setValue($user, 'files', 'mountconfigmtime', $mtime);
+ }
+ }
+ }
+
/**
* get the current installed version of ownCloud
* @return array
*/
public static function getVersion() {
// hint: We only can count up. So the internal version number of ownCloud 4.5 will be 4.90.0. This is not visible to the user
- return array(4,91,00);
+ return array(4, 91, 02);
}
/**
@@ -145,7 +157,7 @@ class OC_Util {
* @param string $text the text content for the element
*/
public static function addHeader( $tag, $attributes, $text='') {
- self::$headers[]=array('tag'=>$tag,'attributes'=>$attributes,'text'=>$text);
+ self::$headers[]=array('tag'=>$tag,'attributes'=>$attributes, 'text'=>$text);
}
/**
@@ -154,16 +166,16 @@ class OC_Util {
* @param int timestamp $timestamp
* @param bool dateOnly option to ommit time from the result
*/
- public static function formatDate( $timestamp,$dateOnly=false) {
+ public static function formatDate( $timestamp, $dateOnly=false) {
if(isset($_SESSION['timezone'])) {//adjust to clients timezone if we know it
$systemTimeZone = intval(date('O'));
- $systemTimeZone=(round($systemTimeZone/100,0)*60)+($systemTimeZone%100);
+ $systemTimeZone=(round($systemTimeZone/100, 0)*60)+($systemTimeZone%100);
$clientTimeZone=$_SESSION['timezone']*60;
$offset=$clientTimeZone-$systemTimeZone;
$timestamp=$timestamp+$offset*60;
}
- $timeformat=$dateOnly?'F j, Y':'F j, Y, H:i';
- return date($timeformat,$timestamp);
+ $l=OC_L10N::get('lib');
+ return $l->l($dateOnly ? 'date' : 'datetime', $timestamp);
}
/**
@@ -174,7 +186,7 @@ class OC_Util {
* @param string $url
* @return OC_Template
*/
- public static function getPageNavi($pagecount,$page,$url) {
+ public static function getPageNavi($pagecount, $page, $url) {
$pagelinkcount=8;
if ($pagecount>1) {
@@ -184,11 +196,11 @@ class OC_Util {
if($pagestop>$pagecount) $pagestop=$pagecount;
$tmpl = new OC_Template( '', 'part.pagenavi', '' );
- $tmpl->assign('page',$page);
- $tmpl->assign('pagecount',$pagecount);
- $tmpl->assign('pagestart',$pagestart);
- $tmpl->assign('pagestop',$pagestop);
- $tmpl->assign('url',$url);
+ $tmpl->assign('page', $page);
+ $tmpl->assign('pagecount', $pagecount);
+ $tmpl->assign('pagestart', $pagestart);
+ $tmpl->assign('pagestop', $pagestop);
+ $tmpl->assign('url', $url);
return $tmpl;
}
}
@@ -205,7 +217,7 @@ class OC_Util {
$web_server_restart= false;
//check for database drivers
if(!(is_callable('sqlite_open') or class_exists('SQLite3')) and !is_callable('mysql_connect') and !is_callable('pg_connect')) {
- $errors[]=array('error'=>'No database drivers (sqlite, mysql, or postgresql) installed.<br/>','hint'=>'');//TODO: sane hint
+ $errors[]=array('error'=>'No database drivers (sqlite, mysql, or postgresql) installed.<br/>', 'hint'=>'');//TODO: sane hint
$web_server_restart= true;
}
@@ -214,13 +226,13 @@ class OC_Util {
// Check if config folder is writable.
if(!is_writable(OC::$SERVERROOT."/config/") or !is_readable(OC::$SERVERROOT."/config/")) {
- $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");
+ $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");
}
// Check if there is a writable install folder.
if(OC_Config::getValue('appstoreenabled', true)) {
if( OC_App::getInstallPath() === null || !is_writable(OC_App::getInstallPath()) || !is_readable(OC_App::getInstallPath()) ) {
- $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
+ $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
in owncloud or disabling the appstore in the config file.");
}
}
@@ -229,24 +241,24 @@ class OC_Util {
//check for correct file permissions
if(!stristr(PHP_OS, 'WIN')) {
$permissionsModHint="Please change the permissions to 0770 so that the directory cannot be listed by other users.";
- $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)),-3);
- if(substr($prems,-1)!='0') {
- OC_Helper::chmodr($CONFIG_DATADIRECTORY,0770);
+ $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)), -3);
+ if(substr($prems, -1)!='0') {
+ OC_Helper::chmodr($CONFIG_DATADIRECTORY, 0770);
clearstatcache();
- $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)),-3);
- if(substr($prems,2,1)!='0') {
- $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') is readable for other users<br/>','hint'=>$permissionsModHint);
+ $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)), -3);
+ if(substr($prems, 2, 1)!='0') {
+ $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') is readable for other users<br/>', 'hint'=>$permissionsModHint);
}
}
if( OC_Config::getValue( "enablebackup", false )) {
$CONFIG_BACKUPDIRECTORY = OC_Config::getValue( "backupdirectory", OC::$SERVERROOT."/backup" );
- $prems=substr(decoct(@fileperms($CONFIG_BACKUPDIRECTORY)),-3);
- if(substr($prems,-1)!='0') {
- OC_Helper::chmodr($CONFIG_BACKUPDIRECTORY,0770);
+ $prems=substr(decoct(@fileperms($CONFIG_BACKUPDIRECTORY)), -3);
+ if(substr($prems, -1)!='0') {
+ OC_Helper::chmodr($CONFIG_BACKUPDIRECTORY, 0770);
clearstatcache();
- $prems=substr(decoct(@fileperms($CONFIG_BACKUPDIRECTORY)),-3);
- if(substr($prems,2,1)!='0') {
- $errors[]=array('error'=>'Data directory ('.$CONFIG_BACKUPDIRECTORY.') is readable for other users<br/>','hint'=>$permissionsModHint);
+ $prems=substr(decoct(@fileperms($CONFIG_BACKUPDIRECTORY)), -3);
+ if(substr($prems, 2, 1)!='0') {
+ $errors[]=array('error'=>'Data directory ('.$CONFIG_BACKUPDIRECTORY.') is readable for other users<br/>', 'hint'=>$permissionsModHint);
}
}
}
@@ -257,62 +269,67 @@ class OC_Util {
if(!is_dir($CONFIG_DATADIRECTORY)) {
$success=@mkdir($CONFIG_DATADIRECTORY);
if(!$success) {
- $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' ");
+ $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' ");
}
} else if(!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
- $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud<br/>','hint'=>$permissionsHint);
+ $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud<br/>', 'hint'=>$permissionsHint);
}
// check if all required php modules are present
if(!class_exists('ZipArchive')) {
- $errors[]=array('error'=>'PHP module zip not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
+ $errors[]=array('error'=>'PHP module zip not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.');
$web_server_restart= false;
}
if(!function_exists('mb_detect_encoding')) {
- $errors[]=array('error'=>'PHP module mb multibyte not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
+ $errors[]=array('error'=>'PHP module mb multibyte not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.');
$web_server_restart= false;
}
if(!function_exists('ctype_digit')) {
- $errors[]=array('error'=>'PHP module ctype is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
+ $errors[]=array('error'=>'PHP module ctype is not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.');
$web_server_restart= false;
}
if(!function_exists('json_encode')) {
- $errors[]=array('error'=>'PHP module JSON is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
+ $errors[]=array('error'=>'PHP module JSON is not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.');
$web_server_restart= false;
}
if(!function_exists('imagepng')) {
- $errors[]=array('error'=>'PHP module GD is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
+ $errors[]=array('error'=>'PHP module GD is not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.');
$web_server_restart= false;
}
if(!function_exists('gzencode')) {
- $errors[]=array('error'=>'PHP module zlib is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
+ $errors[]=array('error'=>'PHP module zlib is not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.');
+ $web_server_restart= false;
+ }
+ if(!function_exists('iconv')) {
+ $errors[]=array('error'=>'PHP module iconv is not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.');
$web_server_restart= false;
}
-
if(!function_exists('simplexml_load_string')) {
- $errors[]=array('error'=>'PHP module SimpleXML is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
+ $errors[]=array('error'=>'PHP module SimpleXML is not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.');
$web_server_restart= false;
}
if(floatval(phpversion())<5.3) {
- $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.');
+ $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.');
$web_server_restart= false;
}
if(!defined('PDO::ATTR_DRIVER_NAME')) {
- $errors[]=array('error'=>'PHP PDO module is not installed.<br/>','hint'=>'Please ask your server administrator to install the module.');
+ $errors[]=array('error'=>'PHP PDO module is not installed.<br/>', 'hint'=>'Please ask your server administrator to install the module.');
$web_server_restart= false;
}
if($web_server_restart) {
- $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.');
+ $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.');
}
return $errors;
}
- public static function displayLoginPage($display_lostpassword) {
+ public static function displayLoginPage($errors = array()) {
$parameters = array();
- $parameters['display_lostpassword'] = $display_lostpassword;
+ foreach( $errors as $key => $value ) {
+ $parameters[$value] = true;
+ }
if (!empty($_POST['user'])) {
$parameters["username"] =
OC_Util::sanitizeHTML($_POST['user']).'"';
@@ -359,6 +376,7 @@ class OC_Util {
public static function checkAdminUser() {
// Check if we are a user
self::checkLoggedIn();
+ self::verifyUser();
if( !OC_Group::inGroup( OC_User::getUser(), 'admin' )) {
header( 'Location: '.OC_Helper::linkToAbsolute( '', 'index.php' ));
exit();
@@ -372,7 +390,8 @@ class OC_Util {
public static function checkSubAdminUser() {
// Check if we are a user
self::checkLoggedIn();
- if(OC_Group::inGroup(OC_User::getUser(),'admin')) {
+ self::verifyUser();
+ if(OC_Group::inGroup(OC_User::getUser(), 'admin')) {
return true;
}
if(!OC_SubAdmin::isSubAdmin(OC_User::getUser())) {
@@ -383,6 +402,40 @@ class OC_Util {
}
/**
+ * Check if the user verified the login with his password in the last 15 minutes
+ * If not, the user will be shown a password verification page
+ */
+ public static function verifyUser() {
+ if(OC_Config::getValue('enhancedauth', false) === true) {
+ // Check password to set session
+ if(isset($_POST['password'])) {
+ if (OC_User::login(OC_User::getUser(), $_POST["password"] ) === true) {
+ $_SESSION['verifiedLogin']=time() + OC_Config::getValue('enhancedauthtime', 15 * 60);
+ }
+ }
+
+ // Check if the user verified his password
+ if(!isset($_SESSION['verifiedLogin']) OR $_SESSION['verifiedLogin'] < time()) {
+ OC_Template::printGuestPage("", "verify", array('username' => OC_User::getUser()));
+ exit();
+ }
+ }
+ }
+
+ /**
+ * Check if the user verified the login with his password
+ * @return bool
+ */
+ public static function isUserVerified() {
+ if(OC_Config::getValue('enhancedauth', false) === true) {
+ if(!isset($_SESSION['verifiedLogin']) OR $_SESSION['verifiedLogin'] < time()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* Redirect to the user default page
*/
public static function redirectToDefaultPage() {
@@ -411,26 +464,15 @@ class OC_Util {
* @return string
*/
public static function getInstanceId() {
- $id=OC_Config::getValue('instanceid',null);
+ $id=OC_Config::getValue('instanceid', null);
if(is_null($id)) {
$id=uniqid();
- OC_Config::setValue('instanceid',$id);
+ OC_Config::setValue('instanceid', $id);
}
return $id;
}
/**
- * @brief Static lifespan (in seconds) when a request token expires.
- * @see OC_Util::callRegister()
- * @see OC_Util::isCallRegistered()
- * @description
- * Also required for the client side to compute the piont in time when to
- * request a fresh token. The client will do so when nearly 97% of the
- * timespan coded here has expired.
- */
- public static $callLifespan = 3600; // 3600 secs = 1 hour
-
- /**
* @brief Register an get/post call. Important to prevent CSRF attacks.
* @todo Write howto: CSRF protection guide
* @return $token Generated token.
@@ -438,40 +480,25 @@ class OC_Util {
* Creates a 'request token' (random) and stores it inside the session.
* Ever subsequent (ajax) request must use such a valid token to succeed,
* otherwise the request will be denied as a protection against CSRF.
- * The tokens expire after a fixed lifespan.
- * @see OC_Util::$callLifespan
* @see OC_Util::isCallRegistered()
*/
public static function callRegister() {
- // generate a random token.
- $token = self::generate_random_bytes(20);
-
- // store the token together with a timestamp in the session.
- $_SESSION['requesttoken-'.$token]=time();
-
- // cleanup old tokens garbage collector
- // only run every 20th time so we don't waste cpu cycles
- if(rand(0,20)==0) {
- foreach($_SESSION as $key=>$value) {
- // search all tokens in the session
- if(substr($key,0,12)=='requesttoken') {
- // check if static lifespan has expired
- if($value+self::$callLifespan<time()) {
- // remove outdated tokens
- unset($_SESSION[$key]);
- }
- }
- }
+ // Check if a token exists
+ if(!isset($_SESSION['requesttoken'])) {
+ // No valid token found, generate a new one.
+ $requestToken = self::generate_random_bytes(20);
+ $_SESSION['requesttoken']=$requestToken;
+ } else {
+ // Valid token already exists, send it
+ $requestToken = $_SESSION['requesttoken'];
}
- // return the token
- return($token);
+ return($requestToken);
}
/**
* @brief Check an ajax get/post call if the request token is valid.
* @return boolean False if request token is not set or is invalid.
- * @see OC_Util::$callLifespan
- * @see OC_Util::calLRegister()
+ * @see OC_Util::callRegister()
*/
public static function isCallRegistered() {
if(isset($_GET['requesttoken'])) {
@@ -484,17 +511,14 @@ class OC_Util {
//no token found.
return false;
}
- if(isset($_SESSION['requesttoken-'.$token])) {
- $timestamp=$_SESSION['requesttoken-'.$token];
- // check if static lifespan has expired
- if($timestamp+self::$callLifespan<time()) {
- return false;
- }else{
- //token valid
- return true;
- }
- }else{
+
+ // Check if the token is valid
+ if($token !== $_SESSION['requesttoken']) {
+ // Not valid
return false;
+ } else {
+ // Valid token
+ return true;
}
}
@@ -518,7 +542,7 @@ class OC_Util {
* @return array with sanitized strings or a single sanitized string, depends on the input parameter.
*/
public static function sanitizeHTML( &$value ) {
- if (is_array($value) || is_object($value)) array_walk_recursive($value,'OC_Util::sanitizeHTML');
+ if (is_array($value) || is_object($value)) array_walk_recursive($value, 'OC_Util::sanitizeHTML');
else $value = htmlentities($value, ENT_QUOTES, 'UTF-8'); //Specify encoding for PHP<5.4
return $value;
}
@@ -534,6 +558,11 @@ class OC_Util {
// creating a test file
$testfile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$filename;
+
+ if(file_exists($testfile)) {// already running this test, possible recursive call
+ return false;
+ }
+
$fp = @fopen($testfile, 'w');
@fwrite($fp, $testcontent);
@fclose($fp);
@@ -555,30 +584,137 @@ class OC_Util {
}
}
- /*
- * @brief Generates random bytes with "openssl_random_pseudo_bytes" with a fallback for systems without openssl
- * Inspired by gorgo on php.net
- * @param Int with the length of the random
- * @return String with the random bytes
+
+ /**
+ * Check if the ownCloud server can connect to the internet
+ */
+ public static function isinternetconnectionworking() {
+
+ // try to connect to owncloud.org to see if http connections to the internet are possible.
+ $connected = @fsockopen("www.owncloud.org", 80);
+ if ($connected) {
+ fclose($connected);
+ return true;
+ }else{
+
+ // second try in case one server is down
+ $connected = @fsockopen("apps.owncloud.com", 80);
+ if ($connected) {
+ fclose($connected);
+ return true;
+ }else{
+ return false;
+ }
+
+ }
+
+ }
+
+ /**
+ * clear all levels of output buffering
+ */
+ public static function obEnd(){
+ while (ob_get_level()) {
+ ob_end_clean();
+ }
+ }
+
+
+ /**
+ * @brief Generates a cryptographical secure pseudorandom string
+ * @param Int with the length of the random string
+ * @return String
+ * Please also update secureRNG_available if you change something here
*/
public static function generate_random_bytes($length = 30) {
- if(function_exists('openssl_random_pseudo_bytes')) {
+
+ // Try to use openssl_random_pseudo_bytes
+ if(function_exists('openssl_random_pseudo_bytes')) {
$pseudo_byte = bin2hex(openssl_random_pseudo_bytes($length, $strong));
- if($strong == TRUE) {
+ if($strong == true) {
return substr($pseudo_byte, 0, $length); // Truncate it to match the length
}
}
- // fallback to mt_rand()
+ // Try to use /dev/urandom
+ $fp = @file_get_contents('/dev/urandom', false, null, 0, $length);
+ if ($fp !== false) {
+ $string = substr(bin2hex($fp), 0, $length);
+ return $string;
+ }
+
+ // Fallback to mt_rand()
$characters = '0123456789';
- $characters .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+ $characters .= 'abcdefghijklmnopqrstuvwxyz';
$charactersLength = strlen($characters)-1;
$pseudo_byte = "";
// Select some random characters
for ($i = 0; $i < $length; $i++) {
$pseudo_byte .= $characters[mt_rand(0, $charactersLength)];
- }
+ }
return $pseudo_byte;
}
+
+ /**
+ * @brief Checks if a secure random number generator is available
+ * @return bool
+ */
+ public static function secureRNG_available() {
+
+ // Check openssl_random_pseudo_bytes
+ if(function_exists('openssl_random_pseudo_bytes')) {
+ openssl_random_pseudo_bytes(1, $strong);
+ if($strong == true) {
+ return true;
+ }
+ }
+
+ // Check /dev/urandom
+ $fp = @file_get_contents('/dev/urandom', false, null, 0, 1);
+ if ($fp !== false) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @Brief Get file content via curl.
+ * @param string $url Url to get content
+ * @return string of the response or false on error
+ * This function get the content of a page via curl, if curl is enabled.
+ * If not, file_get_element is used.
+ */
+
+ public static function getUrlContent($url){
+
+ if (function_exists('curl_init')) {
+
+ $curl = curl_init();
+
+ curl_setopt($curl, CURLOPT_HEADER, 0);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
+ curl_setopt($curl, CURLOPT_URL, $url);
+ curl_setopt($curl, CURLOPT_USERAGENT, "ownCloud Server Crawler");
+ $data = curl_exec($curl);
+ curl_close($curl);
+
+ } else {
+
+ $ctx = stream_context_create(
+ array(
+ 'http' => array(
+ 'timeout' => 10
+ )
+ )
+ );
+ $data=@file_get_contents($url, 0, $ctx);
+
+ }
+
+ return $data;
+ }
+
}
diff --git a/lib/vcategories.php b/lib/vcategories.php
index 6b1d6a316f1..406a4eb1074 100644
--- a/lib/vcategories.php
+++ b/lib/vcategories.php
@@ -21,6 +21,7 @@
*
*/
+OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'post_deleteUser');
/**
* Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL.
@@ -28,50 +29,261 @@
* anything else that is either parsed from a vobject or that the user chooses
* to add.
* Category names are not case-sensitive, but will be saved with the case they
- * are entered in. If a user already has a category 'family' for an app, and
+ * are entered in. If a user already has a category 'family' for a type, and
* tries to add a category named 'Family' it will be silently ignored.
- * NOTE: There is a limitation in that the the configvalue field in the
- * preferences table is a varchar(255).
*/
class OC_VCategories {
- const PREF_CATEGORIES_LABEL = 'extra_categories';
+
/**
* Categories
*/
private $categories = array();
- private $app = null;
+ /**
+ * Used for storing objectid/categoryname pairs while rescanning.
+ */
+ private static $relations = array();
+
+ private $type = null;
private $user = null;
+ const CATEGORY_TABLE = '*PREFIX*vcategory';
+ const RELATION_TABLE = '*PREFIX*vcategory_to_object';
+
+ const CATEGORY_FAVORITE = '_$!<Favorite>!$_';
+
+ const FORMAT_LIST = 0;
+ const FORMAT_MAP = 1;
+
/**
* @brief Constructor.
- * @param $app The application identifier e.g. 'contacts' or 'calendar'.
+ * @param $type The type identifier e.g. 'contact' or 'event'.
* @param $user The user whos data the object will operate on. This
* parameter should normally be omitted but to make an app able to
* update categories for all users it is made possible to provide it.
* @param $defcategories An array of default categories to be used if none is stored.
*/
- public function __construct($app, $user=null, $defcategories=array()) {
- $this->app = $app;
+ public function __construct($type, $user=null, $defcategories=array()) {
+ $this->type = $type;
$this->user = is_null($user) ? OC_User::getUser() : $user;
- $categories = trim(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, ''));
- if ($categories) {
- $categories = @unserialize($categories);
+
+ $this->loadCategories();
+ OCP\Util::writeLog('core', __METHOD__ . ', categories: '
+ . print_r($this->categories, true),
+ OCP\Util::DEBUG
+ );
+
+ if($defcategories && count($this->categories) === 0) {
+ $this->addMulti($defcategories, true);
+ }
+ }
+
+ /**
+ * @brief Load categories from db.
+ */
+ private function loadCategories() {
+ $this->categories = array();
+ $result = null;
+ $sql = 'SELECT `id`, `category` FROM `' . self::CATEGORY_TABLE . '` '
+ . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`';
+ try {
+ $stmt = OCP\DB::prepare($sql);
+ $result = $stmt->execute(array($this->user, $this->type));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ }
+
+ if(!is_null($result)) {
+ while( $row = $result->fetchRow()) {
+ // The keys are prefixed because array_search wouldn't work otherwise :-/
+ $this->categories[$row['id']] = $row['category'];
+ }
+ }
+ OCP\Util::writeLog('core', __METHOD__.', categories: ' . print_r($this->categories, true),
+ OCP\Util::DEBUG);
+ }
+
+
+ /**
+ * @brief Check if any categories are saved for this type and user.
+ * @returns boolean.
+ * @param $type The type identifier e.g. 'contact' or 'event'.
+ * @param $user The user whos categories will be checked. If not set current user will be used.
+ */
+ public static function isEmpty($type, $user = null) {
+ $user = is_null($user) ? OC_User::getUser() : $user;
+ $sql = 'SELECT COUNT(*) FROM `' . self::CATEGORY_TABLE . '` '
+ . 'WHERE `uid` = ? AND `type` = ?';
+ try {
+ $stmt = OCP\DB::prepare($sql);
+ $result = $stmt->execute(array($user, $type));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ return false;
+ }
+ return ($result->numRows() == 0);
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ return false;
}
- $this->categories = is_array($categories) ? $categories : $defcategories;
}
/**
* @brief Get the categories for a specific user.
+ * @param
* @returns array containing the categories as strings.
*/
- public function categories() {
- //OC_Log::write('core','OC_VCategories::categories: '.print_r($this->categories, true), OC_Log::DEBUG);
+ public function categories($format = null) {
if(!$this->categories) {
return array();
}
- usort($this->categories, 'strnatcasecmp'); // usort to also renumber the keys
- return $this->categories;
+ $categories = array_values($this->categories);
+ uasort($categories, 'strnatcasecmp');
+ if($format == self::FORMAT_MAP) {
+ $catmap = array();
+ foreach($categories as $category) {
+ if($category !== self::CATEGORY_FAVORITE) {
+ $catmap[] = array(
+ 'id' => $this->array_searchi($category, $this->categories),
+ 'name' => $category
+ );
+ }
+ }
+ return $catmap;
+ }
+
+ // Don't add favorites to normal categories.
+ $favpos = array_search(self::CATEGORY_FAVORITE, $categories);
+ if($favpos !== false) {
+ return array_splice($categories, $favpos);
+ } else {
+ return $categories;
+ }
+ }
+
+ /**
+ * Get the a list if items belonging to $category.
+ *
+ * Throws an exception if the category could not be found.
+ *
+ * @param string|integer $category Category id or name.
+ * @returns array An array of object ids or false on error.
+ */
+ public function idsForCategory($category) {
+ $result = null;
+ if(is_numeric($category)) {
+ $catid = $category;
+ } elseif(is_string($category)) {
+ $catid = $this->array_searchi($category, $this->categories);
+ }
+ OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG);
+ if($catid === false) {
+ $l10n = OC_L10N::get('core');
+ throw new Exception(
+ $l10n->t('Could not find category "%s"', $category)
+ );
+ }
+
+ $ids = array();
+ $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE
+ . '` WHERE `categoryid` = ?';
+
+ try {
+ $stmt = OCP\DB::prepare($sql);
+ $result = $stmt->execute(array($catid));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ return false;
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ return false;
+ }
+
+ if(!is_null($result)) {
+ while( $row = $result->fetchRow()) {
+ $ids[] = (int)$row['objid'];
+ }
+ }
+
+ return $ids;
+ }
+
+ /**
+ * Get the a list if items belonging to $category.
+ *
+ * Throws an exception if the category could not be found.
+ *
+ * @param string|integer $category Category id or name.
+ * @param array $tableinfo Array in the form {'tablename' => table, 'fields' => ['field1', 'field2']}
+ * @param int $limit
+ * @param int $offset
+ *
+ * This generic method queries a table assuming that the id
+ * field is called 'id' and the table name provided is in
+ * the form '*PREFIX*table_name'.
+ *
+ * If the category name cannot be resolved an exception is thrown.
+ *
+ * TODO: Maybe add the getting permissions for objects?
+ *
+ * @returns array containing the resulting items or false on error.
+ */
+ public function itemsForCategory($category, $tableinfo, $limit = null, $offset = null) {
+ $result = null;
+ if(is_numeric($category)) {
+ $catid = $category;
+ } elseif(is_string($category)) {
+ $catid = $this->array_searchi($category, $this->categories);
+ }
+ OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG);
+ if($catid === false) {
+ $l10n = OC_L10N::get('core');
+ throw new Exception(
+ $l10n->t('Could not find category "%s"', $category)
+ );
+ }
+ $fields = '';
+ foreach($tableinfo['fields'] as $field) {
+ $fields .= '`' . $tableinfo['tablename'] . '`.`' . $field . '`,';
+ }
+ $fields = substr($fields, 0, -1);
+
+ $items = array();
+ $sql = 'SELECT `' . self::RELATION_TABLE . '`.`categoryid`, ' . $fields
+ . ' FROM `' . $tableinfo['tablename'] . '` JOIN `'
+ . self::RELATION_TABLE . '` ON `' . $tableinfo['tablename']
+ . '`.`id` = `' . self::RELATION_TABLE . '`.`objid` WHERE `'
+ . self::RELATION_TABLE . '`.`categoryid` = ?';
+
+ try {
+ $stmt = OCP\DB::prepare($sql, $limit, $offset);
+ $result = $stmt->execute(array($catid));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ return false;
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ return false;
+ }
+
+ if(!is_null($result)) {
+ while( $row = $result->fetchRow()) {
+ $items[] = $row;
+ }
+ }
+ //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG);
+ //OCP\Util::writeLog('core', __METHOD__.', sql: ' . $sql, OCP\Util::DEBUG);
+
+ return $items;
}
/**
@@ -84,22 +296,51 @@ class OC_VCategories {
}
/**
- * @brief Add a new category name.
+ * @brief Add a new category.
+ * @param $name A string with a name of the category
+ * @returns int the id of the added category or false if it already exists.
+ */
+ public function add($name) {
+ OCP\Util::writeLog('core', __METHOD__.', name: ' . $name, OCP\Util::DEBUG);
+ if($this->hasCategory($name)) {
+ OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', OCP\Util::DEBUG);
+ return false;
+ }
+ OCP\DB::insertIfNotExist(self::CATEGORY_TABLE,
+ array(
+ 'uid' => $this->user,
+ 'type' => $this->type,
+ 'category' => $name,
+ ));
+ $id = OCP\DB::insertid(self::CATEGORY_TABLE);
+ OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, OCP\Util::DEBUG);
+ $this->categories[$id] = $name;
+ return $id;
+ }
+
+ /**
+ * @brief Add a new category.
* @param $names A string with a name or an array of strings containing
* the name(s) of the categor(y|ies) to add.
* @param $sync bool When true, save the categories
+ * @param $id int Optional object id to add to this|these categor(y|ies)
* @returns bool Returns false on error.
*/
- public function add($names, $sync=false) {
+ public function addMulti($names, $sync=false, $id = null) {
if(!is_array($names)) {
$names = array($names);
}
$names = array_map('trim', $names);
$newones = array();
foreach($names as $name) {
- if(($this->in_arrayi($name, $this->categories) == false) && $name != '') {
+ if(($this->in_arrayi(
+ $name, $this->categories) == false) && $name != '') {
$newones[] = $name;
}
+ if(!is_null($id) ) {
+ // Insert $objectid, $categoryid pairs if not exist.
+ self::$relations[] = array('objid' => $id, 'category' => $name);
+ }
}
if(count($newones) > 0) {
$this->categories = array_merge($this->categories, $newones);
@@ -114,8 +355,8 @@ class OC_VCategories {
* @brief Extracts categories from a vobject and add the ones not already present.
* @param $vobject The instance of OC_VObject to load the categories from.
*/
- public function loadFromVObject($vobject, $sync=false) {
- $this->add($vobject->getAsArray('CATEGORIES'), $sync);
+ public function loadFromVObject($id, $vobject, $sync=false) {
+ $this->addMulti($vobject->getAsArray('CATEGORIES'), $sync, $id);
}
/**
@@ -128,23 +369,62 @@ class OC_VCategories {
* $result = $stmt->execute();
* $objects = array();
* if(!is_null($result)) {
- * while( $row = $result->fetchRow()) {
- * $objects[] = $row['carddata'];
+ * while( $row = $result->fetchRow()){
+ * $objects[] = array($row['id'], $row['carddata']);
* }
* }
* $categories->rescan($objects);
*/
public function rescan($objects, $sync=true, $reset=true) {
+
if($reset === true) {
+ $result = null;
+ // Find all objectid/categoryid pairs.
+ try {
+ $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` '
+ . 'WHERE `uid` = ? AND `type` = ?');
+ $result = $stmt->execute(array($this->user, $this->type));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ return false;
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ }
+
+ // And delete them.
+ if(!is_null($result)) {
+ $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
+ . 'WHERE `categoryid` = ? AND `type`= ?');
+ while( $row = $result->fetchRow()) {
+ $stmt->execute(array($row['id'], $this->type));
+ }
+ }
+ try {
+ $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` '
+ . 'WHERE `uid` = ? AND `type` = ?');
+ $result = $stmt->execute(array($this->user, $this->type));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ return;
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__ . ', exception: '
+ . $e->getMessage(), OCP\Util::ERROR);
+ return;
+ }
$this->categories = array();
}
+ // Parse all the VObjects
foreach($objects as $object) {
- //OC_Log::write('core','OC_VCategories::rescan: '.substr($object, 0, 100).'(...)', OC_Log::DEBUG);
- $vobject = OC_VObject::parse($object);
+ $vobject = OC_VObject::parse($object[1]);
if(!is_null($vobject)) {
- $this->loadFromVObject($vobject, $sync);
+ // Load the categories
+ $this->loadFromVObject($object[0], $vobject, $sync);
} else {
- OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.', '.substr($object, 0, 100).'(...)', OC_Log::DEBUG);
+ OC_Log::write('core', __METHOD__ . ', unable to parse. ID: ' . ', '
+ . substr($object, 0, 100) . '(...)', OC_Log::DEBUG);
}
}
$this->save();
@@ -155,16 +435,224 @@ class OC_VCategories {
*/
private function save() {
if(is_array($this->categories)) {
- usort($this->categories, 'strnatcasecmp'); // usort to also renumber the keys
- $escaped_categories = serialize($this->categories);
- OC_Preferences::setValue($this->user, $this->app, self::PREF_CATEGORIES_LABEL, $escaped_categories);
- OC_Log::write('core','OC_VCategories::save: '.print_r($this->categories, true), OC_Log::DEBUG);
+ foreach($this->categories as $category) {
+ OCP\DB::insertIfNotExist(self::CATEGORY_TABLE,
+ array(
+ 'uid' => $this->user,
+ 'type' => $this->type,
+ 'category' => $category,
+ ));
+ }
+ // reload categories to get the proper ids.
+ $this->loadCategories();
+ // Loop through temporarily cached objectid/categoryname pairs
+ // and save relations.
+ $categories = $this->categories;
+ // For some reason this is needed or array_search(i) will return 0..?
+ ksort($categories);
+ foreach(self::$relations as $relation) {
+ $catid = $this->array_searchi($relation['category'], $categories);
+ OC_Log::write('core', __METHOD__ . 'catid, ' . $relation['category'] . ' ' . $catid, OC_Log::DEBUG);
+ if($catid) {
+ OCP\DB::insertIfNotExist(self::RELATION_TABLE,
+ array(
+ 'objid' => $relation['objid'],
+ 'categoryid' => $catid,
+ 'type' => $this->type,
+ ));
+ }
+ }
+ self::$relations = array(); // reset
} else {
- OC_Log::write('core','OC_VCategories::save: $this->categories is not an array! '.print_r($this->categories, true), OC_Log::ERROR);
+ OC_Log::write('core', __METHOD__.', $this->categories is not an array! '
+ . print_r($this->categories, true), OC_Log::ERROR);
}
}
/**
+ * @brief Delete categories and category/object relations for a user.
+ * For hooking up on post_deleteUser
+ * @param string $uid The user id for which entries should be purged.
+ */
+ public static function post_deleteUser($arguments) {
+ // Find all objectid/categoryid pairs.
+ $result = null;
+ try {
+ $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` '
+ . 'WHERE `uid` = ?');
+ $result = $stmt->execute(array($arguments['uid']));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ }
+
+ if(!is_null($result)) {
+ try {
+ $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
+ . 'WHERE `categoryid` = ?');
+ while( $row = $result->fetchRow()) {
+ try {
+ $stmt->execute(array($row['id']));
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ }
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ }
+ }
+ try {
+ $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` '
+ . 'WHERE `uid` = ? AND');
+ $result = $stmt->execute(array($arguments['uid']));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__ . ', exception: '
+ . $e->getMessage(), OCP\Util::ERROR);
+ }
+ }
+
+ /**
+ * @brief Delete category/object relations from the db
+ * @param int $id The id of the object
+ * @param string $type The type of object (event/contact/task/journal).
+ * Defaults to the type set in the instance
+ * @returns boolean Returns false on error.
+ */
+ public function purgeObject($id, $type = null) {
+ $type = is_null($type) ? $this->type : $type;
+ try {
+ $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
+ . 'WHERE `objid` = ? AND `type`= ?');
+ $result = $stmt->execute(array($id, $type));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ return false;
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get favorites for an object type
+ *
+ * @param string $type The type of object (event/contact/task/journal).
+ * Defaults to the type set in the instance
+ * @returns array An array of object ids.
+ */
+ public function getFavorites($type = null) {
+ $type = is_null($type) ? $this->type : $type;
+
+ try {
+ return $this->idsForCategory(self::CATEGORY_FAVORITE);
+ } catch(Exception $e) {
+ // No favorites
+ return array();
+ }
+ }
+
+ /**
+ * Add an object to favorites
+ *
+ * @param int $objid The id of the object
+ * @param string $type The type of object (event/contact/task/journal).
+ * Defaults to the type set in the instance
+ * @returns boolean
+ */
+ public function addToFavorites($objid, $type = null) {
+ $type = is_null($type) ? $this->type : $type;
+ if(!$this->hasCategory(self::CATEGORY_FAVORITE)) {
+ $this->add(self::CATEGORY_FAVORITE, true);
+ }
+ return $this->addToCategory($objid, self::CATEGORY_FAVORITE, $type);
+ }
+
+ /**
+ * Remove an object from favorites
+ *
+ * @param int $objid The id of the object
+ * @param string $type The type of object (event/contact/task/journal).
+ * Defaults to the type set in the instance
+ * @returns boolean
+ */
+ public function removeFromFavorites($objid, $type = null) {
+ $type = is_null($type) ? $this->type : $type;
+ return $this->removeFromCategory($objid, self::CATEGORY_FAVORITE, $type);
+ }
+
+ /**
+ * @brief Creates a category/object relation.
+ * @param int $objid The id of the object
+ * @param int|string $category The id or name of the category
+ * @param string $type The type of object (event/contact/task/journal).
+ * Defaults to the type set in the instance
+ * @returns boolean Returns false on database error.
+ */
+ public function addToCategory($objid, $category, $type = null) {
+ $type = is_null($type) ? $this->type : $type;
+ if(is_string($category) && !is_numeric($category)) {
+ if(!$this->hasCategory($category)) {
+ $this->add($category, true);
+ }
+ $categoryid = $this->array_searchi($category, $this->categories);
+ } else {
+ $categoryid = $category;
+ }
+ try {
+ OCP\DB::insertIfNotExist(self::RELATION_TABLE,
+ array(
+ 'objid' => $objid,
+ 'categoryid' => $categoryid,
+ 'type' => $type,
+ ));
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @brief Delete single category/object relation from the db
+ * @param int $objid The id of the object
+ * @param int|string $category The id or name of the category
+ * @param string $type The type of object (event/contact/task/journal).
+ * Defaults to the type set in the instance
+ * @returns boolean
+ */
+ public function removeFromCategory($objid, $category, $type = null) {
+ $type = is_null($type) ? $this->type : $type;
+ $categoryid = (is_string($category) && !is_numeric($category))
+ ? $this->array_searchi($category, $this->categories)
+ : $category;
+ try {
+ $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
+ . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?';
+ OCP\Util::writeLog('core', __METHOD__.', sql: ' . $objid . ' ' . $categoryid . ' ' . $type,
+ OCP\Util::DEBUG);
+ $stmt = OCP\DB::prepare($sql);
+ $stmt->execute(array($objid, $categoryid, $type));
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ return false;
+ }
+ return true;
+ }
+
+ /**
* @brief Delete categories from the db and from all the vobject supplied
* @param $names An array of categories to delete
* @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table.
@@ -173,37 +661,87 @@ class OC_VCategories {
if(!is_array($names)) {
$names = array($names);
}
- OC_Log::write('core','OC_VCategories::delete, before: '.print_r($this->categories, true), OC_Log::DEBUG);
+
+ OC_Log::write('core', __METHOD__ . ', before: '
+ . print_r($this->categories, true), OC_Log::DEBUG);
foreach($names as $name) {
- OC_Log::write('core','OC_VCategories::delete: '.$name, OC_Log::DEBUG);
+ $id = null;
+ OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG);
if($this->hasCategory($name)) {
- //OC_Log::write('core','OC_VCategories::delete: '.$name.' got it', OC_Log::DEBUG);
- unset($this->categories[$this->array_searchi($name, $this->categories)]);
+ $id = $this->array_searchi($name, $this->categories);
+ unset($this->categories[$id]);
+ }
+ try {
+ $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` WHERE '
+ . '`uid` = ? AND `type` = ? AND `category` = ?');
+ $result = $stmt->execute(array($this->user, $this->type, $name));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__ . ', exception: '
+ . $e->getMessage(), OCP\Util::ERROR);
+ }
+ if(!is_null($id) && $id !== false) {
+ try {
+ $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
+ . 'WHERE `categoryid` = ?';
+ $stmt = OCP\DB::prepare($sql);
+ $result = $stmt->execute(array($id));
+ if (OC_DB::isError($result)) {
+ OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR);
+ }
+ } catch(Exception $e) {
+ OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
+ OCP\Util::ERROR);
+ return false;
+ }
}
}
- $this->save();
- OC_Log::write('core','OC_VCategories::delete, after: '.print_r($this->categories, true), OC_Log::DEBUG);
+ OC_Log::write('core', __METHOD__.', after: '
+ . print_r($this->categories, true), OC_Log::DEBUG);
if(!is_null($objects)) {
foreach($objects as $key=>&$value) {
$vobject = OC_VObject::parse($value[1]);
if(!is_null($vobject)) {
- $categories = $vobject->getAsArray('CATEGORIES');
- //OC_Log::write('core','OC_VCategories::delete, before: '.$key.': '.print_r($categories, true), OC_Log::DEBUG);
+ $object = null;
+ $componentname = '';
+ if (isset($vobject->VEVENT)) {
+ $object = $vobject->VEVENT;
+ $componentname = 'VEVENT';
+ } else
+ if (isset($vobject->VTODO)) {
+ $object = $vobject->VTODO;
+ $componentname = 'VTODO';
+ } else
+ if (isset($vobject->VJOURNAL)) {
+ $object = $vobject->VJOURNAL;
+ $componentname = 'VJOURNAL';
+ } else {
+ $object = $vobject;
+ }
+ $categories = $object->getAsArray('CATEGORIES');
foreach($names as $name) {
$idx = $this->array_searchi($name, $categories);
- //OC_Log::write('core','OC_VCategories::delete, loop: '.$name.', '.print_r($idx, true), OC_Log::DEBUG);
if($idx !== false) {
- OC_Log::write('core','OC_VCategories::delete, unsetting: '.$categories[$this->array_searchi($name, $categories)], OC_Log::DEBUG);
+ OC_Log::write('core', __METHOD__
+ .', unsetting: '
+ . $categories[$this->array_searchi($name, $categories)],
+ OC_Log::DEBUG);
unset($categories[$this->array_searchi($name, $categories)]);
- //unset($categories[$idx]);
}
}
- //OC_Log::write('core','OC_VCategories::delete, after: '.$key.': '.print_r($categories, true), OC_Log::DEBUG);
- $vobject->setString('CATEGORIES', implode(',', $categories));
+
+ $object->setString('CATEGORIES', implode(',', $categories));
+ if($vobject !== $object) {
+ $vobject[$componentname] = $object;
+ }
$value[1] = $vobject->serialize();
$objects[$key] = $value;
} else {
- OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 50).'(...)', OC_Log::DEBUG);
+ OC_Log::write('core', __METHOD__
+ .', unable to parse. ID: ' . $value[0] . ', '
+ . substr($value[1], 0, 50) . '(...)', OC_Log::DEBUG);
}
}
}
@@ -222,7 +760,7 @@ class OC_VCategories {
if(!is_array($haystack)) {
return false;
}
- return array_search(strtolower($needle),array_map('strtolower',$haystack));
+ return array_search(strtolower($needle), array_map('strtolower', $haystack));
}
-
}
+
diff --git a/lib/vobject.php b/lib/vobject.php
index b5a04b4bf65..267176ebc07 100644
--- a/lib/vobject.php
+++ b/lib/vobject.php
@@ -24,11 +24,11 @@
* This class provides a streamlined interface to the Sabre VObject classes
*/
class OC_VObject{
- /** @var Sabre_VObject_Component */
+ /** @var Sabre\VObject\Component */
protected $vobject;
/**
- * @returns Sabre_VObject_Component
+ * @returns Sabre\VObject\Component
*/
public function getVObject() {
return $this->vobject;
@@ -41,9 +41,9 @@ class OC_VObject{
*/
public static function parse($data) {
try {
- Sabre_VObject_Property::$classMap['LAST-MODIFIED'] = 'Sabre_VObject_Property_DateTime';
- $vobject = Sabre_VObject_Reader::read($data);
- if ($vobject instanceof Sabre_VObject_Component) {
+ Sabre\VObject\Property::$classMap['LAST-MODIFIED'] = 'Sabre\VObject\Property\DateTime';
+ $vobject = Sabre\VObject\Reader::read($data);
+ if ($vobject instanceof Sabre\VObject\Component) {
$vobject = new OC_VObject($vobject);
}
return $vobject;
@@ -62,7 +62,7 @@ class OC_VObject{
foreach($value as &$i ) {
$i = implode("\\\\;", explode(';', $i));
}
- return implode(';',$value);
+ return implode(';', $value);
}
/**
@@ -71,15 +71,15 @@ class OC_VObject{
* @return array
*/
public static function unescapeSemicolons($value) {
- $array = explode(';',$value);
+ $array = explode(';', $value);
for($i=0;$i<count($array);$i++) {
- if(substr($array[$i],-2,2)=="\\\\") {
+ if(substr($array[$i], -2, 2)=="\\\\") {
if(isset($array[$i+1])) {
- $array[$i] = substr($array[$i],0,count($array[$i])-2).';'.$array[$i+1];
+ $array[$i] = substr($array[$i], 0, count($array[$i])-2).';'.$array[$i+1];
unset($array[$i+1]);
}
else{
- $array[$i] = substr($array[$i],0,count($array[$i])-2).';';
+ $array[$i] = substr($array[$i], 0, count($array[$i])-2).';';
}
$i = $i - 1;
}
@@ -89,13 +89,13 @@ class OC_VObject{
/**
* Constuctor
- * @param Sabre_VObject_Component or string
+ * @param Sabre\VObject\Component or string
*/
public function __construct($vobject_or_name) {
if (is_object($vobject_or_name)) {
$this->vobject = $vobject_or_name;
} else {
- $this->vobject = new Sabre_VObject_Component($vobject_or_name);
+ $this->vobject = new Sabre\VObject\Component($vobject_or_name);
}
}
@@ -117,9 +117,9 @@ class OC_VObject{
if(is_array($value)) {
$value = OC_VObject::escapeSemicolons($value);
}
- $property = new Sabre_VObject_Property( $name, $value );
+ $property = new Sabre\VObject\Property( $name, $value );
foreach($parameters as $name => $value) {
- $property->parameters[] = new Sabre_VObject_Parameter($name, $value);
+ $property->parameters[] = new Sabre\VObject\Parameter($name, $value);
}
$this->vobject->add($property);
@@ -127,8 +127,8 @@ class OC_VObject{
}
public function setUID() {
- $uid = substr(md5(rand().time()),0,10);
- $this->vobject->add('UID',$uid);
+ $uid = substr(md5(rand().time()), 0, 10);
+ $this->vobject->add('UID', $uid);
}
public function setString($name, $string) {
@@ -150,12 +150,12 @@ class OC_VObject{
* @param int $dateType
* @return void
*/
- public function setDateTime($name, $datetime, $dateType=Sabre_VObject_Property_DateTime::LOCALTZ) {
+ public function setDateTime($name, $datetime, $dateType=Sabre\VObject\Property\DateTime::LOCALTZ) {
if ($datetime == 'now') {
$datetime = new DateTime();
}
if ($datetime instanceof DateTime) {
- $datetime_element = new Sabre_VObject_Property_DateTime($name);
+ $datetime_element = new Sabre\VObject\Property\DateTime($name);
$datetime_element->setDateTime($datetime, $dateType);
$this->vobject->__set($name, $datetime_element);
}else{
@@ -183,7 +183,7 @@ class OC_VObject{
return $this->vobject->children;
}
$return = $this->vobject->__get($name);
- if ($return instanceof Sabre_VObject_Component) {
+ if ($return instanceof Sabre\VObject\Component) {
$return = new OC_VObject($return);
}
return $return;
@@ -201,7 +201,7 @@ class OC_VObject{
return $this->vobject->__isset($name);
}
- public function __call($function,$arguments) {
+ public function __call($function, $arguments) {
return call_user_func_array(array($this->vobject, $function), $arguments);
}
}