mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-24 15:48:55 +01:00
* Filemanager/Admin: ability to check virtual filesystem (Admin >> Check virtual filesystem) and some code to prefent double creation of directories
This commit is contained in:
commit
8848953385
172
admin/inc/class.admin_prefs_sidebox_hooks.inc.php
Normal file
172
admin/inc/class.admin_prefs_sidebox_hooks.inc.php
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EGroupware Admin: Hooks
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @author Stefan Becker <StefanBecker-AT-outdoor-training.de>
|
||||||
|
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||||
|
* @package admin
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static hooks for admin application
|
||||||
|
*/
|
||||||
|
class admin_prefs_sidebox_hooks
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Functions callable via menuaction
|
||||||
|
*
|
||||||
|
* @var unknown_type
|
||||||
|
*/
|
||||||
|
var $public_functions = array(
|
||||||
|
'register_all_hooks' => True,
|
||||||
|
'fsck' => true,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hooks to build projectmanager's sidebox-menu plus the admin and preferences sections
|
||||||
|
*
|
||||||
|
* @param string/array $args hook args
|
||||||
|
*/
|
||||||
|
static function all_hooks($args)
|
||||||
|
{
|
||||||
|
if (!isset($_GET['menuaction']) && substr($_SERVER['PHP_SELF'],-16) == '/admin/index.php')
|
||||||
|
{
|
||||||
|
admin_statistics::check();
|
||||||
|
}
|
||||||
|
$appname = 'admin';
|
||||||
|
$location = is_array($args) ? $args['location'] : $args;
|
||||||
|
|
||||||
|
if ($GLOBALS['egw_info']['user']['apps']['admin'] && $location != 'admins')
|
||||||
|
{
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('site_config_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['Site Configuration'] = egw::link('/index.php','menuaction=admin.uiconfig.index&appname=admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disabled it, til it does something useful
|
||||||
|
if (! $GLOBALS['egw']->acl->check('peer_server_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['Peer Servers'] = egw::link('/index.php','menuaction=admin.uiserver.list_servers');
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (! $GLOBALS['egw']->acl->check('account_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['User Accounts'] = egw::link('/index.php','menuaction=admin.uiaccounts.list_users');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('group_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['User Groups'] = egw::link('/index.php','menuaction=admin.uiaccounts.list_groups');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('applications_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['Applications'] = egw::link('/index.php','menuaction=admin.admin_applications.index');
|
||||||
|
}
|
||||||
|
if (! $GLOBALS['egw']->acl->check('global_categories_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['Global Categories'] = egw::link('/index.php','menuaction=admin.admin_categories.index&appname=phpgw');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$GLOBALS['egw']->acl->check('mainscreen_message_access',1,'admin') || !$GLOBALS['egw']->acl->check('mainscreen_message_access',2,'admin'))
|
||||||
|
{
|
||||||
|
$file['Change Main Screen Message'] = egw::link('/index.php','menuaction=admin.uimainscreen.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('current_sessions_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['View Sessions'] = egw::link('/index.php','menuaction=admin.uicurrentsessions.list_sessions');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('access_log_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['View Access Log'] = egw::link('/index.php','menuaction=admin.admin_accesslog.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('error_log_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['View Error Log'] = egw::link('/index.php','menuaction=admin.uilog.list_log');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('applications_access',16,'admin'))
|
||||||
|
{
|
||||||
|
$file['Find and Register all Application Hooks'] = egw::link('/index.php','menuaction=admin.admin_prefs_sidebox_hooks.register_all_hooks');
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (! $GLOBALS['egw']->acl->check('applications_access',16,'admin'))
|
||||||
|
{
|
||||||
|
$file['Check virtual filesystem'] = egw::link('/index.php','menuaction=admin.admin_prefs_sidebox_hooks.fsck');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('asyncservice_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['Asynchronous timed services'] = egw::link('/index.php','menuaction=admin.uiasyncservice.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('db_backup_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['DB backup and restore'] = egw::link('/index.php','menuaction=admin.admin_db_backup.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $GLOBALS['egw']->acl->check('info_access',1,'admin'))
|
||||||
|
{
|
||||||
|
$file['phpInfo'] = "javascript:openwindow('" . egw::link('/admin/phpinfo.php') . "')"; //egw::link('/admin/phpinfo.php');
|
||||||
|
}
|
||||||
|
$file['Admin queue and history'] = egw::link('/index.php','menuaction=admin.admin_cmds.index');
|
||||||
|
$file['Remote administration instances'] = egw::link('/index.php','menuaction=admin.admin_cmds.remotes');
|
||||||
|
|
||||||
|
$file['Submit statistic information'] = egw::link('/index.php','menuaction=admin.admin_statistics.submit');
|
||||||
|
|
||||||
|
if ($location == 'admin')
|
||||||
|
{
|
||||||
|
display_section($appname,$file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
display_sidebox($appname,lang('Admin'),$file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register all hooks
|
||||||
|
*/
|
||||||
|
function register_all_hooks()
|
||||||
|
{
|
||||||
|
if ($GLOBALS['egw']->acl->check('applications_access',16,'admin'))
|
||||||
|
{
|
||||||
|
$GLOBALS['egw']->redirect_link('/index.php');
|
||||||
|
}
|
||||||
|
$GLOBALS['egw']->hooks->register_all_hooks();
|
||||||
|
|
||||||
|
if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited
|
||||||
|
{
|
||||||
|
$GLOBALS['egw']->invalidate_session_cache(); // in case with cache the egw_info array in the session
|
||||||
|
}
|
||||||
|
$GLOBALS['egw']->redirect_link('/admin/index.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run fsck on sqlfs
|
||||||
|
*/
|
||||||
|
function fsck()
|
||||||
|
{
|
||||||
|
$check_only = !isset($_POST['fix']);
|
||||||
|
|
||||||
|
if (!($msgs = sqlfs_utils::fsck($check_only)))
|
||||||
|
{
|
||||||
|
$msgs = lang('Filesystem check reported no problems.');
|
||||||
|
}
|
||||||
|
$content = '<p>'.implode("</p>\n<p>", (array)$msgs)."</p>\n";
|
||||||
|
|
||||||
|
$content .= html::form('<p>'.($check_only&&is_array($msgs)?html::submit_button('fix', lang('Fix reported problems')):'').
|
||||||
|
html::submit_button('cancel', lang('Cancel'), "window.location.href='".egw::link('/admin/index.php')."'; return false;").'</p>',
|
||||||
|
'',egw::link('/index.php',array('menuaction'=>'admin.admin_prefs_sidebox_hooks.fsck')));
|
||||||
|
|
||||||
|
$GLOBALS['egw']->framework->render($content, lang('Admin').' - '.lang('Check virtual filesystem'), true);
|
||||||
|
}
|
||||||
|
}
|
@ -111,6 +111,8 @@ change password for %1 admin de Ändern des Passworts für %1
|
|||||||
check acl for entries of not (longer) existing accounts admin de Prüfe ACL Einträge auf Bezüge zu nicht (mehr) existierenden Benutzerkonten
|
check acl for entries of not (longer) existing accounts admin de Prüfe ACL Einträge auf Bezüge zu nicht (mehr) existierenden Benutzerkonten
|
||||||
check ip address of all sessions admin de IP-Adresse für alle Sessions überprüfen
|
check ip address of all sessions admin de IP-Adresse für alle Sessions überprüfen
|
||||||
check items to <b>%1</b> to %2 for %3 admin de Durch Abhaken %3 in %2 <b>%1</b>
|
check items to <b>%1</b> to %2 for %3 admin de Durch Abhaken %3 in %2 <b>%1</b>
|
||||||
|
check virtual filesystem admin de Virtuelles Dateisystem überprüfen
|
||||||
|
children admin de Kinder
|
||||||
click to select a color admin de Anclicken um eine Farbe auszuwählen
|
click to select a color admin de Anclicken um eine Farbe auszuwählen
|
||||||
color admin de Farbe
|
color admin de Farbe
|
||||||
command scheduled to run at %1 admin de Ausführung des Befehls eingeplant am/um %1
|
command scheduled to run at %1 admin de Ausführung des Befehls eingeplant am/um %1
|
||||||
@ -251,6 +253,7 @@ false admin de Falsch
|
|||||||
field '%1' already exists !!! admin de Feld '%1' existiert bereits !!!
|
field '%1' already exists !!! admin de Feld '%1' existiert bereits !!!
|
||||||
file space admin de Speicherplatz
|
file space admin de Speicherplatz
|
||||||
file space must be an integer admin de Speicherplatz muss eine Zahl sein
|
file space must be an integer admin de Speicherplatz muss eine Zahl sein
|
||||||
|
filesystem check reported no problems. admin de Überprüfung des Dateisystem ergab keine Probleme.
|
||||||
find and register all application hooks admin de Suchen und registrieren der "Hooks" aller Anwendungen
|
find and register all application hooks admin de Suchen und registrieren der "Hooks" aller Anwendungen
|
||||||
for the times above admin de für die oben angegebenen Zeiten
|
for the times above admin de für die oben angegebenen Zeiten
|
||||||
for the times below (empty values count as '*', all empty = every minute) admin de für die darunter angegebenen Zeiten (leere Felder zählen als "*", alles leer = jede Minute)
|
for the times below (empty values count as '*', all empty = every minute) admin de für die darunter angegebenen Zeiten (leere Felder zählen als "*", alles leer = jede Minute)
|
||||||
|
@ -113,6 +113,8 @@ change password for %1 admin en change password for %1
|
|||||||
check acl for entries of not (longer) existing accounts admin en Check ACL for entries of not (longer) existing accounts
|
check acl for entries of not (longer) existing accounts admin en Check ACL for entries of not (longer) existing accounts
|
||||||
check ip address of all sessions admin en Check IP address of all sessions
|
check ip address of all sessions admin en Check IP address of all sessions
|
||||||
check items to <b>%1</b> to %2 for %3 admin en Check items to <b>%1</b> to %2 for %3
|
check items to <b>%1</b> to %2 for %3 admin en Check items to <b>%1</b> to %2 for %3
|
||||||
|
check virtual filesystem admin en Check virtual filesystem
|
||||||
|
children admin en Children
|
||||||
click to select a color admin en Click to select a color
|
click to select a color admin en Click to select a color
|
||||||
color admin en Color
|
color admin en Color
|
||||||
command scheduled to run at %1 admin en Command scheduled to run at %1
|
command scheduled to run at %1 admin en Command scheduled to run at %1
|
||||||
@ -253,14 +255,18 @@ false admin en false
|
|||||||
field '%1' already exists !!! admin en Field '%1' already exists !!!
|
field '%1' already exists !!! admin en Field '%1' already exists !!!
|
||||||
file space admin en File space
|
file space admin en File space
|
||||||
file space must be an integer admin en File space must be an integer
|
file space must be an integer admin en File space must be an integer
|
||||||
find and register all application hooks admin en Find and Register all Application Hooks
|
filesystem check reported no problems. admin en Filesystem check reported no problems.
|
||||||
for the times above admin en for the times above
|
find and register all application hooks admin en Find and register all application hooks
|
||||||
for the times below (empty values count as '*', all empty = every minute) admin en for the times below (empty values count as '*', all empty = every minute)
|
for the times above admin en For the times above
|
||||||
force selectbox admin en Force Selectbox
|
for the times below (empty values count as '*', all empty = every minute) admin en For the times below: empty values count as '*', all empty = every minute.
|
||||||
forward also to admin en forward also to
|
force password strength (1-5, default empty: no check against rules for a strong password)? admin en Set required password strength. 1 = weak, up to 5 = very strong. Default = empty, no password strength checked
|
||||||
forward emails to admin en forward emails to
|
force selectbox admin en Force select box
|
||||||
forward only admin en forward only
|
force users to change their password regularily?(empty for no,number for after that number of days admin en Set recurrent forced password change. Set a number of days. Empty = No
|
||||||
global categories common en Global Categories
|
forward also to admin en Forward also to
|
||||||
|
forward emails to admin en Forward emails to
|
||||||
|
forward only admin en Forward only
|
||||||
|
full name admin en Full name
|
||||||
|
global categories common en Global categories
|
||||||
go directly to admin menu, returning here the next time you click on administration. admin en Go directly to admin menu, returning here the next time you click on administration.
|
go directly to admin menu, returning here the next time you click on administration. admin en Go directly to admin menu, returning here the next time you click on administration.
|
||||||
governmental: incl. state or municipal authorities or services admin en Governmental: incl. state or municipal authorities or services
|
governmental: incl. state or municipal authorities or services admin en Governmental: incl. state or municipal authorities or services
|
||||||
grant admin en Grant
|
grant admin en Grant
|
||||||
|
@ -267,7 +267,7 @@ switch($cmd)
|
|||||||
}
|
}
|
||||||
die("\n/ NOT mounted with 'storage=db' --> no need to convert!\n\n");
|
die("\n/ NOT mounted with 'storage=db' --> no need to convert!\n\n");
|
||||||
}
|
}
|
||||||
$num_files = sqlfs_stream_wrapper::migrate_db2fs(); // throws exception on error
|
$num_files = sqlfs_utils::migrate_db2fs(); // throws exception on error
|
||||||
echo "\n$num_files files migrated from DB to filesystem.\n";
|
echo "\n$num_files files migrated from DB to filesystem.\n";
|
||||||
$new_url = preg_replace('/storage=db&?/','',$fstab['/']);
|
$new_url = preg_replace('/storage=db&?/','',$fstab['/']);
|
||||||
if (substr($new_url,-1) == '?') $new_url = substr($new_url,0,-1);
|
if (substr($new_url,-1) == '?') $new_url = substr($new_url,0,-1);
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* eGroupWare API: VFS - new DB based VFS stream wrapper
|
* EGroupware API: VFS - new DB based VFS stream wrapper
|
||||||
*
|
*
|
||||||
* @link http://www.egroupware.org
|
* @link http://www.egroupware.org
|
||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
* @package api
|
* @package api
|
||||||
* @subpackage vfs
|
* @subpackage vfs
|
||||||
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||||
* @copyright (c) 2008-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
* @copyright (c) 2008-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -700,7 +700,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
unset(self::$stat_cache[$path]);
|
unset(self::$stat_cache[$path]);
|
||||||
$stmt = self::$pdo->prepare('INSERT INTO '.self::TABLE.' (fs_name,fs_dir,fs_mode,fs_uid,fs_gid,fs_size,fs_mime,fs_created,fs_modified,fs_creator'.
|
$stmt = self::$pdo->prepare('INSERT INTO '.self::TABLE.' (fs_name,fs_dir,fs_mode,fs_uid,fs_gid,fs_size,fs_mime,fs_created,fs_modified,fs_creator'.
|
||||||
') VALUES (:fs_name,:fs_dir,:fs_mode,:fs_uid,:fs_gid,:fs_size,:fs_mime,:fs_created,:fs_modified,:fs_creator)');
|
') VALUES (:fs_name,:fs_dir,:fs_mode,:fs_uid,:fs_gid,:fs_size,:fs_mime,:fs_created,:fs_modified,:fs_creator)');
|
||||||
return $stmt->execute(array(
|
if (($ok = $stmt->execute(array(
|
||||||
'fs_name' => egw_vfs::basename($path),
|
'fs_name' => egw_vfs::basename($path),
|
||||||
'fs_dir' => $parent['ino'],
|
'fs_dir' => $parent['ino'],
|
||||||
'fs_mode' => $parent['mode'],
|
'fs_mode' => $parent['mode'],
|
||||||
@ -711,7 +711,25 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
'fs_created' => self::_pdo_timestamp(time()),
|
'fs_created' => self::_pdo_timestamp(time()),
|
||||||
'fs_modified' => self::_pdo_timestamp(time()),
|
'fs_modified' => self::_pdo_timestamp(time()),
|
||||||
'fs_creator' => egw_vfs::$user,
|
'fs_creator' => egw_vfs::$user,
|
||||||
));
|
))))
|
||||||
|
{
|
||||||
|
// check if some other process created the directory parallel to us (sqlfs would gives SQL errors later!)
|
||||||
|
$new_fs_id = self::$pdo->lastInsertId('egw_sqlfs_fs_id_seq');
|
||||||
|
|
||||||
|
unset($stmt); // free statement object, on some installs a new prepare fails otherwise!
|
||||||
|
|
||||||
|
$stmt = self::$pdo->prepare($q='SELECT COUNT(*) FROM '.self::TABLE.
|
||||||
|
' WHERE fs_dir=:fs_dir AND fs_active=:fs_active AND fs_name'.self::$case_sensitive_equal.':fs_name');
|
||||||
|
if ($stmt->execute(array(
|
||||||
|
'fs_dir' => $parent['ino'],
|
||||||
|
'fs_active' => self::_pdo_boolean(true),
|
||||||
|
'fs_name' => egw_vfs::basename($path),
|
||||||
|
)) && $stmt->fetchColumn() > 1) // if there's more then one --> remove our new dir
|
||||||
|
{
|
||||||
|
self::$pdo->query('DELETE FROM '.self::TABLE.' WHERE fs_id='.$new_fs_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1794,80 +1812,6 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
|
|||||||
if (self::LOG_LEVEL > 1) foreach((array)$props as $k => $v) error_log(__METHOD__."($path_ids,$ns) $k => ".array2string($v));
|
if (self::LOG_LEVEL > 1) foreach((array)$props as $k => $v) error_log(__METHOD__."($path_ids,$ns) $k => ".array2string($v));
|
||||||
return $props;
|
return $props;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Migrate SQLFS content from DB to filesystem
|
|
||||||
*
|
|
||||||
* @param boolean $debug true to echo a message for each copied file
|
|
||||||
*/
|
|
||||||
static function migrate_db2fs($debug=false)
|
|
||||||
{
|
|
||||||
if (!is_object(self::$pdo))
|
|
||||||
{
|
|
||||||
self::_pdo();
|
|
||||||
}
|
|
||||||
$query = 'SELECT fs_id,fs_name,fs_size,fs_content'.
|
|
||||||
' FROM '.self::TABLE.' WHERE fs_content IS NOT NULL';
|
|
||||||
|
|
||||||
$stmt = self::$pdo->prepare($query);
|
|
||||||
$stmt->bindColumn(1,$fs_id);
|
|
||||||
$stmt->bindColumn(2,$fs_name);
|
|
||||||
$stmt->bindColumn(3,$fs_size);
|
|
||||||
$stmt->bindColumn(4,$fs_content,PDO::PARAM_LOB);
|
|
||||||
|
|
||||||
if ($stmt->execute())
|
|
||||||
{
|
|
||||||
foreach($stmt as $row)
|
|
||||||
{
|
|
||||||
// hack to work around a current php bug (http://bugs.php.net/bug.php?id=40913)
|
|
||||||
// PDOStatement::bindColumn(,,PDO::PARAM_LOB) is not working for MySQL, content is returned as string :-(
|
|
||||||
if (is_string($fs_content))
|
|
||||||
{
|
|
||||||
$name = md5($fs_name.$fs_id);
|
|
||||||
$GLOBALS[$name] =& $fs_content;
|
|
||||||
require_once(EGW_API_INC.'/class.global_stream_wrapper.inc.php');
|
|
||||||
$content = fopen('global://'.$name,'r');
|
|
||||||
if (!$content) echo "fopen('global://$name','w' failed, strlen(\$GLOBALS['$name'])=".strlen($GLOBALS[$name]).", \$GLOBALS['$name']=".substr($GLOBALS['$name'],0,100)."...\n";
|
|
||||||
unset($GLOBALS[$name]); // unset it, so it does not use up memory, once the stream is closed
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$content = $fs_content;
|
|
||||||
}
|
|
||||||
if (!is_resource($content))
|
|
||||||
{
|
|
||||||
throw new egw_exception_assertion_failed(__METHOD__."(): fs_id=$fs_id ($fs_name, $fs_size bytes) content is NO resource! ".array2string($content));
|
|
||||||
}
|
|
||||||
$filename = self::_fs_path($fs_id);
|
|
||||||
if (!file_exists($fs_dir=egw_vfs::dirname($filename)))
|
|
||||||
{
|
|
||||||
self::mkdir_recursive($fs_dir,0700,true);
|
|
||||||
}
|
|
||||||
if (!($dest = fopen($filename,'w')))
|
|
||||||
{
|
|
||||||
throw new egw_exception_assertion_failed(__METHOD__."(): fopen($filename,'w') failed!");
|
|
||||||
}
|
|
||||||
if (($bytes = stream_copy_to_stream($content,$dest)) != $fs_size)
|
|
||||||
{
|
|
||||||
throw new egw_exception_assertion_failed(__METHOD__."(): fs_id=$fs_id ($fs_name) $bytes bytes copied != size of $fs_size bytes!");
|
|
||||||
}
|
|
||||||
if ($debug) echo "$fs_id: $fs_name: $bytes bytes copied to fs\n";
|
|
||||||
fclose($dest);
|
|
||||||
fclose($content); unset($content);
|
|
||||||
|
|
||||||
++$n;
|
|
||||||
}
|
|
||||||
unset($stmt);
|
|
||||||
|
|
||||||
if ($n) // delete all content in DB, if there was some AND no error (exception thrown!)
|
|
||||||
{
|
|
||||||
$query = 'UPDATE '.self::TABLE.' SET fs_content=NULL WHERE fs_content IS NOT NULL';
|
|
||||||
$stmt = self::$pdo->prepare($query);
|
|
||||||
$stmt->execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $n;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_register_wrapper(sqlfs_stream_wrapper::SCHEME ,'sqlfs_stream_wrapper');
|
stream_register_wrapper(sqlfs_stream_wrapper::SCHEME ,'sqlfs_stream_wrapper');
|
||||||
|
352
phpgwapi/inc/class.sqlfs_utils.inc.php
Normal file
352
phpgwapi/inc/class.sqlfs_utils.inc.php
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EGroupware API: sqlfs stream wrapper utilities: migration db-fs, fsck
|
||||||
|
*
|
||||||
|
* @link http://www.egroupware.org
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @package api
|
||||||
|
* @subpackage vfs
|
||||||
|
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||||
|
* @copyright (c) 2008-12 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once 'class.iface_stream_wrapper.inc.php';
|
||||||
|
require_once 'class.sqlfs_stream_wrapper.inc.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sqlfs stream wrapper utilities: migration db-fs, fsck
|
||||||
|
*/
|
||||||
|
class sqlfs_utils extends sqlfs_stream_wrapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Migrate SQLFS content from DB to filesystem
|
||||||
|
*
|
||||||
|
* @param boolean $debug true to echo a message for each copied file
|
||||||
|
*/
|
||||||
|
static function migrate_db2fs($debug=false)
|
||||||
|
{
|
||||||
|
if (!is_object(self::$pdo))
|
||||||
|
{
|
||||||
|
self::_pdo();
|
||||||
|
}
|
||||||
|
$query = 'SELECT fs_id,fs_name,fs_size,fs_content'.
|
||||||
|
' FROM '.self::TABLE.' WHERE fs_content IS NOT NULL';
|
||||||
|
|
||||||
|
$stmt = self::$pdo->prepare($query);
|
||||||
|
$stmt->bindColumn(1,$fs_id);
|
||||||
|
$stmt->bindColumn(2,$fs_name);
|
||||||
|
$stmt->bindColumn(3,$fs_size);
|
||||||
|
$stmt->bindColumn(4,$fs_content,PDO::PARAM_LOB);
|
||||||
|
|
||||||
|
if ($stmt->execute())
|
||||||
|
{
|
||||||
|
foreach($stmt as $row)
|
||||||
|
{
|
||||||
|
// hack to work around a current php bug (http://bugs.php.net/bug.php?id=40913)
|
||||||
|
// PDOStatement::bindColumn(,,PDO::PARAM_LOB) is not working for MySQL, content is returned as string :-(
|
||||||
|
if (is_string($fs_content))
|
||||||
|
{
|
||||||
|
$name = md5($fs_name.$fs_id);
|
||||||
|
$GLOBALS[$name] =& $fs_content;
|
||||||
|
require_once(EGW_API_INC.'/class.global_stream_wrapper.inc.php');
|
||||||
|
$content = fopen('global://'.$name,'r');
|
||||||
|
if (!$content) echo "fopen('global://$name','w' failed, strlen(\$GLOBALS['$name'])=".strlen($GLOBALS[$name]).", \$GLOBALS['$name']=".substr($GLOBALS['$name'],0,100)."...\n";
|
||||||
|
unset($GLOBALS[$name]); // unset it, so it does not use up memory, once the stream is closed
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$content = $fs_content;
|
||||||
|
}
|
||||||
|
if (!is_resource($content))
|
||||||
|
{
|
||||||
|
throw new egw_exception_assertion_failed(__METHOD__."(): fs_id=$fs_id ($fs_name, $fs_size bytes) content is NO resource! ".array2string($content));
|
||||||
|
}
|
||||||
|
$filename = self::_fs_path($fs_id);
|
||||||
|
if (!file_exists($fs_dir=egw_vfs::dirname($filename)))
|
||||||
|
{
|
||||||
|
self::mkdir_recursive($fs_dir,0700,true);
|
||||||
|
}
|
||||||
|
if (!($dest = fopen($filename,'w')))
|
||||||
|
{
|
||||||
|
throw new egw_exception_assertion_failed(__METHOD__."(): fopen($filename,'w') failed!");
|
||||||
|
}
|
||||||
|
if (($bytes = stream_copy_to_stream($content,$dest)) != $fs_size)
|
||||||
|
{
|
||||||
|
throw new egw_exception_assertion_failed(__METHOD__."(): fs_id=$fs_id ($fs_name) $bytes bytes copied != size of $fs_size bytes!");
|
||||||
|
}
|
||||||
|
if ($debug) echo "$fs_id: $fs_name: $bytes bytes copied to fs\n";
|
||||||
|
fclose($dest);
|
||||||
|
fclose($content); unset($content);
|
||||||
|
|
||||||
|
++$n;
|
||||||
|
}
|
||||||
|
unset($stmt);
|
||||||
|
|
||||||
|
if ($n) // delete all content in DB, if there was some AND no error (exception thrown!)
|
||||||
|
{
|
||||||
|
$query = 'UPDATE '.self::TABLE.' SET fs_content=NULL WHERE fs_content IS NOT NULL';
|
||||||
|
$stmt = self::$pdo->prepare($query);
|
||||||
|
$stmt->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check and optionaly fix corruption in sqlfs
|
||||||
|
*
|
||||||
|
* @param boolean $check_only=true
|
||||||
|
* @return array with messages / found problems
|
||||||
|
*/
|
||||||
|
public static function fsck($check_only=true)
|
||||||
|
{
|
||||||
|
if (!is_object(self::$pdo))
|
||||||
|
{
|
||||||
|
self::_pdo();
|
||||||
|
}
|
||||||
|
$msgs = self::fsck_fix_multiple_active($check_only);
|
||||||
|
$msgs = array_merge($msgs, self::fsck_fix_unconnected($check_only));
|
||||||
|
$msgs = array_merge($msgs, self::fsck_fix_no_content($check_only));
|
||||||
|
|
||||||
|
return $msgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check and optionally remove files without content part in physical filesystem
|
||||||
|
*
|
||||||
|
* @param boolean $check_only=true
|
||||||
|
* @return array with messages / found problems
|
||||||
|
*/
|
||||||
|
private static function fsck_fix_no_content($check_only=true)
|
||||||
|
{
|
||||||
|
$msgs = array();
|
||||||
|
|
||||||
|
foreach(self::$pdo->query('SELECT fs_id FROM '.self::TABLE.
|
||||||
|
" WHERE fs_mime!='httpd/unix-directory' AND fs_content IS NULL AND fs_link IS NULL") as $row)
|
||||||
|
{
|
||||||
|
if (!file_exists($phy_path=self::_fs_path($row['fs_id'])))
|
||||||
|
{
|
||||||
|
egw_vfs::$is_root = true;
|
||||||
|
$path = self::id2path($row['fs_id']);
|
||||||
|
if ($check_only)
|
||||||
|
{
|
||||||
|
$msgs[] = lang('File %1 has no content in physical filesystem %2!',
|
||||||
|
$path.' (#'.$row['fs_id'].')',$phy_path);
|
||||||
|
}
|
||||||
|
elseif (self::unlink($path.'?storage=db')) // storage=db to not try to delete not existing phy. file
|
||||||
|
{
|
||||||
|
$msgs[] = lang('File %1 has no content in physical filesystem %2 --> file removed!',$path,$phy_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$msgs[] = lang('File %1 has no content in physical filesystem %2 --> failed to remove file!',
|
||||||
|
$path.' (#'.$row['fs_id'].')',$phy_path);
|
||||||
|
}
|
||||||
|
egw_vfs::$is_root = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($check_only && $msgs)
|
||||||
|
{
|
||||||
|
$msgs[] = lang('Files without content in physical filesystem will be removed.');
|
||||||
|
}
|
||||||
|
return $msgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of lost+found directory for unconnected nodes
|
||||||
|
*/
|
||||||
|
const LOST_N_FOUND = '/lost+found';
|
||||||
|
const LOST_N_FOUND_MOD = 070;
|
||||||
|
const LOST_N_FOUND_GRP = 'Admins';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check and optionally fix unconnected nodes - parent directory does not (longer) exists:
|
||||||
|
*
|
||||||
|
* SELECT fs.*
|
||||||
|
* FROM egw_sqlfs fs
|
||||||
|
* LEFT JOIN egw_sqlfs dir ON dir.fs_id=fs.fs_dir
|
||||||
|
* WHERE fs.fs_id > 1 && dir.fs_id IS NULL
|
||||||
|
*
|
||||||
|
* @param boolean $check_only=true
|
||||||
|
* @return array with messages / found problems
|
||||||
|
*/
|
||||||
|
private static function fsck_fix_unconnected($check_only=true)
|
||||||
|
{
|
||||||
|
$msgs = array();
|
||||||
|
foreach(self::$pdo->query('SELECT fs.* FROM '.self::TABLE.' fs'.
|
||||||
|
' LEFT JOIN '.self::TABLE.' dir ON dir.fs_id=fs.fs_dir'.
|
||||||
|
' WHERE fs.fs_id > 1 && dir.fs_id IS NULL') as $row)
|
||||||
|
{
|
||||||
|
if ($check_only)
|
||||||
|
{
|
||||||
|
$msgs[] = lang('Found unconnected %1 %2!',
|
||||||
|
mime_magic::mime2label($row['fs_mime']),
|
||||||
|
egw_vfs::decodePath($row['fs_name']).' (#'.$row['fs_id'].')');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!isset($lostnfound))
|
||||||
|
{
|
||||||
|
// check if we already have /lost+found, create it if not
|
||||||
|
if (!($lostnfound = self::url_stat(self::LOST_N_FOUND, STREAM_URL_STAT_QUIET)))
|
||||||
|
{
|
||||||
|
egw_vfs::$is_root = true;
|
||||||
|
if (!self::mkdir(self::LOST_N_FOUND, self::LOST_N_FOUND_MOD, 0) ||
|
||||||
|
!(!($admins = $GLOBALS['egw']->accounts->name2id(self::LOST_N_FOUND_GRP)) ||
|
||||||
|
self::chgrp(self::LOST_N_FOUND, $admins) && self::chmod(self::LOST_N_FOUND,self::LOST_N_FOUND_MOD)) ||
|
||||||
|
!($lostnfound = self::url_stat(self::LOST_N_FOUND, STREAM_URL_STAT_QUIET)))
|
||||||
|
{
|
||||||
|
$msgs[] = lang("Can't create directory %1 to connect found unconnected nodes to it!",self::LOST_N_FOUND);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$msgs[] = lang('Successful created new directory %1 for unconnected nods.',self::LOST_N_FOUND);
|
||||||
|
}
|
||||||
|
egw_vfs::$is_root = false;
|
||||||
|
if (!$lostnfound) break;
|
||||||
|
}
|
||||||
|
$stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_dir=:fs_dir WHERE fs_id=:fs_id');
|
||||||
|
}
|
||||||
|
if ($stmt->execute(array(
|
||||||
|
'fs_dir' => $lostnfound['ino'],
|
||||||
|
'fs_id' => $row['fs_id'],
|
||||||
|
)))
|
||||||
|
{
|
||||||
|
$msgs[] = lang('Moved unconnected %1 %2 to %3.',
|
||||||
|
mime_magic::mime2label($row['fs_mime']),
|
||||||
|
egw_vfs::decodePath($row['fs_name']).' (#'.$row['fs_id'].')',
|
||||||
|
self::LOST_N_FOUND);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$msgs[] = lang('Faild to move unconnected %1 %2 to %3!',
|
||||||
|
mime_magic::mime2label($row['fs_mime']), egw_vfs::decodePath($row['fs_name']), self::LOST_N_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($check_only && $msgs)
|
||||||
|
{
|
||||||
|
$msgs[] = lang('Unconnected nodes will be moved to %1.',self::LOST_N_FOUND);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return $msgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check and optionally fix multiple active files and directories with identical path
|
||||||
|
*
|
||||||
|
* @param boolean $check_only=true
|
||||||
|
* @return array with messages / found problems
|
||||||
|
*/
|
||||||
|
private static function fsck_fix_multiple_active($check_only=true)
|
||||||
|
{
|
||||||
|
$msgs = array();
|
||||||
|
foreach(self::$pdo->query('SELECT fs_dir,fs_name,COUNT(*) FROM '.self::TABLE.
|
||||||
|
' WHERE fs_active='.self::_pdo_boolean(true).
|
||||||
|
' GROUP BY fs_dir,fs_name'.
|
||||||
|
' HAVING COUNT(*) > 1') as $row)
|
||||||
|
{
|
||||||
|
if (!isset($stmt))
|
||||||
|
{
|
||||||
|
$stmt = self::$pdo->prepare('SELECT *,(SELECT COUNT(*) FROM '.self::TABLE.' sub WHERE sub.fs_dir=fs.fs_id) AS children'.
|
||||||
|
' FROM '.self::TABLE.' fs'.
|
||||||
|
' WHERE fs.fs_dir=:fs_dir AND fs.fs_active='.self::_pdo_boolean(true).' AND fs.fs_name'.self::$case_sensitive_equal.':fs_name'.
|
||||||
|
" ORDER BY fs.fs_mime='httpd/unix-directory' DESC,children DESC,fs.fs_modified DESC");
|
||||||
|
$inactivate_stmt = self::$pdo->prepare('UPDATE '.self::TABLE.
|
||||||
|
' SET fs_active='.self::_pdo_boolean(false).
|
||||||
|
' WHERE fs_dir=:fs_dir AND fs_active='.self::_pdo_boolean(true).
|
||||||
|
' AND fs_name'.self::$case_sensitive_equal.':fs_name AND fs_id!=:fs_id');
|
||||||
|
}
|
||||||
|
//$msgs[] = array2string($row);
|
||||||
|
$cnt = 0;
|
||||||
|
$stmt->execute(array(
|
||||||
|
'fs_dir' => $row['fs_dir'],
|
||||||
|
'fs_name' => $row['fs_name'],
|
||||||
|
));
|
||||||
|
foreach($stmt as $entry)
|
||||||
|
{
|
||||||
|
if ($entry['fs_mime'] == 'httpd/unix-directory')
|
||||||
|
{
|
||||||
|
if (!$n)
|
||||||
|
{
|
||||||
|
$dir = $entry; // directory to keep
|
||||||
|
$msgs[] = lang('%1 directories %2 found!', $row[2], self::id2path($entry['fs_id']));
|
||||||
|
if ($check_only) break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($entry['children'])
|
||||||
|
{
|
||||||
|
$msgs[] = lang('Moved %1 children from directory fs_id=%2 to %3',
|
||||||
|
$children = self::$pdo->exec('UPDATE '.self::TABLE.' SET fs_dir='.(int)$dir['fs_id'].
|
||||||
|
' WHERE fs_dir='.(int)$entry['fs_id']),
|
||||||
|
$entry['fs_id'], $dir['fs_id']);
|
||||||
|
|
||||||
|
$dir['children'] += $children;
|
||||||
|
}
|
||||||
|
self::$pdo->query('DELETE FROM '.self::TABLE.' WHERE fs_id='.(int)$entry['fs_id']);
|
||||||
|
$msgs[] = lang('Removed (now) empty directory fs_id=%1',$entry['fs_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (isset($dir)) // file and directory with same name exist!
|
||||||
|
{
|
||||||
|
if (!$check_only)
|
||||||
|
{
|
||||||
|
$inactivate_stmt->execute(array(
|
||||||
|
'fs_dir' => $row['fs_dir'],
|
||||||
|
'fs_name' => $row['fs_name'],
|
||||||
|
'fs_id' => $dir['fs_id'],
|
||||||
|
));
|
||||||
|
$cnt = $inactivate_stmt->rowCount();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cnt = ucfirst(lang('none of %1', $row[2]-1));
|
||||||
|
}
|
||||||
|
$msgs[] = lang('%1 active file(s) with same name as directory inactivated!',$cnt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else // newest file --> set for all other fs_active=false
|
||||||
|
{
|
||||||
|
if (!$check_only)
|
||||||
|
{
|
||||||
|
$inactivate_stmt->execute(array(
|
||||||
|
'fs_dir' => $row['fs_dir'],
|
||||||
|
'fs_name' => $row['fs_name'],
|
||||||
|
'fs_id' => $entry['fs_id'],
|
||||||
|
));
|
||||||
|
$cnt = $inactivate_stmt->rowCount();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$cnt = lang('none of %1', $row[2]-1);
|
||||||
|
}
|
||||||
|
$msgs[] = lang('More then one active file %1 found, inactivating %2 older revisions!',
|
||||||
|
self::id2path($entry['fs_id']), $cnt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($dir);
|
||||||
|
if ($cnt && !isset($inactivate_msg_added))
|
||||||
|
{
|
||||||
|
$msgs[] = lang('To examine or reinstate inactived files, you might need to turn versioning on.');
|
||||||
|
$inactivate_msg_added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $msgs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fsck testcode, if this file is called via it's URL (you need to uncomment it!)
|
||||||
|
/*if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__)
|
||||||
|
{
|
||||||
|
$GLOBALS['egw_info'] = array(
|
||||||
|
'flags' => array(
|
||||||
|
'currentapp' => 'admin',
|
||||||
|
'nonavbar' => true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
include_once '../../header.inc.php';
|
||||||
|
|
||||||
|
$msgs = sqlfs_utils::fsck(!isset($_GET['check_only']) || $_GET['check_only']);
|
||||||
|
echo '<p>'.implode("</p>\n<p>", (array)$msgs)."</p>\n";
|
||||||
|
}*/
|
Loading…
Reference in New Issue
Block a user