a few changes required to use sqlfs as base of a versioning stream wrapper (EPL only)

This commit is contained in:
Ralf Becker 2010-02-07 06:19:56 +00:00
parent b75f5f9828
commit c99c79cd32

View File

@ -7,7 +7,7 @@
* @package api
* @subpackage vfs
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008-9 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @version $Id$
*/
@ -30,7 +30,6 @@
* The stream wrapper interface is according to the docu on php.net
*
* @link http://www.php.net/manual/en/function.stream-wrapper-register.php
* @ToDo versioning
*/
class sqlfs_stream_wrapper implements iface_stream_wrapper
{
@ -80,10 +79,6 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*/
const LOG_LEVEL = 1;
/**
* We do versioning AND store the content in the db, NOT YET IMPLEMENTED
*/
const VERSIONING = 0;
/**
* We store the content in the DB (no versioning)
*/
@ -142,13 +137,13 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*
* @var array $path => info-array pairs
*/
static private $stat_cache = array();
static protected $stat_cache = array();
/**
* Reference to the PDO object we use
*
* @var PDO
*/
static private $pdo;
static protected $pdo;
/**
* Array with filenames of dir opened with dir_opendir
*
@ -174,10 +169,13 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* - STREAM_USE_PATH If path is relative, search for the resource using the include_path.
* - STREAM_REPORT_ERRORS If this flag is set, you are responsible for raising errors using trigger_error() during opening of the stream.
* If this flag is not set, you should not raise any errors.
* @param string $opened_path full path of the file/resource, if the open was successfull and STREAM_USE_PATH was set
* @param string &$opened_path full path of the file/resource, if the open was successfull and STREAM_USE_PATH was set
* @param array $overwrite_new=null if set create new file with values overwriten by the given ones
* @param string $class=__CLASS__ class to use to call static methods, eg url_stat (workaround for no late static binding in php < 5.3)
* @todo remove $class parameter and use static::url_stat() once we require PHP5.3!
* @return boolean true if the ressource was opened successful, otherwise false
*/
function stream_open ( $url, $mode, $options, &$opened_path )
function stream_open ( $url, $mode, $options, &$opened_path, array $overwrite_new=null, $class=__CLASS__ )
{
if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url,$mode,$options)");
@ -188,17 +186,17 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
$this->opened_path = $path;
$this->opened_mode = $mode = str_replace('b','',$mode); // we are always binary, like every Linux system
$this->opened_stream = null;
if (!($stat = self::url_stat($path,STREAM_URL_STAT_QUIET)) || $mode[0] == 'x') // file not found or file should NOT exist
if (!is_null($overwrite_new) || !($stat = call_user_func(array($class,'url_stat'),$path,STREAM_URL_STAT_QUIET)) || $mode[0] == 'x') // file not found or file should NOT exist
{
if ($mode[0] == 'r' || // does $mode require the file to exist (r,r+)
$mode[0] == 'x' || // or file should not exist, but does
!($dir_stat=self::url_stat($dir,STREAM_URL_STAT_QUIET)) || // or parent dir does not exist create it
!($dir_stat=call_user_func(array($class,'url_stat'),$dir,STREAM_URL_STAT_QUIET)) || // or parent dir does not exist create it
!egw_vfs::check_access($dir,egw_vfs::WRITABLE,$dir_stat)) // or we are not allowed to create it
{
self::_remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$mode,$options) file does not exist or can not be created!");
if (!($options & STREAM_URL_STAT_QUIET))
if (($options & STREAM_REPORT_ERRORS))
{
trigger_error(__METHOD__."($url,$mode,$options) file does not exist or can not be created!",E_USER_WARNING);
}
@ -206,8 +204,8 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
return false;
}
// new file --> create it in the DB
$query = 'INSERT INTO '.self::TABLE.' (fs_name,fs_dir,fs_mode,fs_uid,fs_gid,fs_created,fs_modified,fs_creator,fs_mime,fs_size'.
') VALUES (:fs_name,:fs_dir,:fs_mode,:fs_uid,:fs_gid,:fs_created,:fs_modified,:fs_creator,:fs_mime,:fs_size)';
$query = 'INSERT INTO '.self::TABLE.' (fs_name,fs_dir,fs_mode,fs_uid,fs_gid,fs_created,fs_modified,fs_creator,fs_mime,fs_size,fs_active'.
') VALUES (:fs_name,:fs_dir,:fs_mode,:fs_uid,:fs_gid,:fs_created,:fs_modified,:fs_creator,:fs_mime,:fs_size,:fs_active)';
if (self::LOG_LEVEL > 2) $query = '/* '.__METHOD__.': '.__LINE__.' */ '.$query;
$stmt = self::$pdo->prepare($query);
$values = array(
@ -224,7 +222,9 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
'fs_creator' => egw_vfs::$user,
'fs_mime' => 'application/octet-stream', // required NOT NULL!
'fs_size' => 0,
'fs_active' => self::_pdo_boolean(true),
);
if ($overwrite_new) $values = array_merge($values,$overwrite_new);
if (!$stmt->execute($values) || !($this->opened_fs_id = self::$pdo->lastInsertId('egw_sqlfs_fs_id_seq')))
{
$this->opened_stream = $this->opened_path = $this->opened_mode = null;
@ -252,7 +252,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
self::_remove_password($url);
$op = $mode == 'r' ? 'read' : 'edited';
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$mode,$options) file can not be $op!");
if (!($options & STREAM_URL_STAT_QUIET))
if (($options & STREAM_REPORT_ERRORS))
{
trigger_error(__METHOD__."($url,$mode,$options) file can not be $op!",E_USER_WARNING);
}
@ -644,7 +644,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
{
self::_remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$mode,$options) already exist!");
if (!($options & STREAM_URL_STAT_QUIET))
if (!($options & STREAM_REPORT_ERRORS))
{
//throw new Exception(__METHOD__."('$url',$mode,$options) already exist!");
trigger_error(__METHOD__."('$url',$mode,$options) already exist!",E_USER_WARNING);
@ -670,7 +670,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
{
self::_remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."('$url',$mode,$options) permission denied!");
if (!($options & STREAM_URL_STAT_QUIET))
if (!($options & STREAM_REPORT_ERRORS))
{
trigger_error(__METHOD__."('$url',$mode,$options) permission denied!",E_USER_WARNING);
}
@ -717,7 +717,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
$err_msg = __METHOD__."($url,$options) ".(!$stat ? 'not found!' :
($stat['mime'] != self::DIR_MIME_TYPE ? 'not a directory!' : 'permission denied!'));
if (self::LOG_LEVEL) error_log($err_msg);
if (!($options & STREAM_URL_STAT_QUIET))
if (!($options & STREAM_REPORT_ERRORS))
{
trigger_error($err_msg,E_USER_WARNING);
}
@ -729,7 +729,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
{
self::_remove_password($url);
if (self::LOG_LEVEL) error_log(__METHOD__."($url,$options) dir is not empty!");
if (!($options & STREAM_URL_STAT_QUIET))
if (!($options & STREAM_REPORT_ERRORS))
{
trigger_error(__METHOD__."('$url',$options) dir is not empty!",E_USER_WARNING);
}
@ -932,7 +932,8 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
}
$this->opened_dir = array();
$query = 'SELECT fs_id,fs_name,fs_mode,fs_uid,fs_gid,fs_size,fs_mime,fs_created,fs_modified'.self::$extra_columns.
' FROM '.self::TABLE." WHERE fs_dir=? ORDER BY fs_mime='httpd/unix-directory' DESC, fs_name ASC";
' FROM '.self::TABLE.' WHERE fs_dir=? AND fs_active='.self::_pdo_boolean(true).
" ORDER BY fs_mime='httpd/unix-directory' DESC, fs_name ASC";
//if (self::LOG_LEVEL > 2) $query = '/* '.__METHOD__.': '.__LINE__.' */ '.$query;
if (self::LOG_LEVEL > 2) $query = '/* '.__METHOD__."($url,$options)".' */ '.$query;
@ -1005,7 +1006,8 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
self::_pdo();
}
$base_query = 'SELECT fs_id,fs_name,fs_mode,fs_uid,fs_gid,fs_size,fs_mime,fs_created,fs_modified'.self::$extra_columns.
' FROM '.self::TABLE.' WHERE fs_name'.self::$case_sensitive_equal.'? AND fs_dir=';
' FROM '.self::TABLE.' WHERE fs_active='.self::_pdo_boolean(true).
' AND fs_name'.self::$case_sensitive_equal.'? AND fs_dir=';
$parts = explode('/',$path);
// if we have extendes acl access to the url, we dont need and can NOT include the sql for the readable check
@ -1035,7 +1037,8 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
// we also store negatives (all methods creating new files/dirs have to unset the stat-cache!)
return self::$stat_cache[$path] = false;
}
$query = 'SELECT fs_id FROM '.self::TABLE.' WHERE fs_dir=('.$query.') AND fs_name'.self::$case_sensitive_equal.self::$pdo->quote($name);
$query = 'SELECT fs_id FROM '.self::TABLE.' WHERE fs_dir=('.$query.') AND fs_active='.
self::_pdo_boolean(true).' AND fs_name'.self::$case_sensitive_equal.self::$pdo->quote($name);
// if we are not root AND have no extended acl access, we need to make sure the user has the right to tranverse all parent directories (read-rights)
if (!egw_vfs::$is_root && !$eacl_access)
@ -1078,7 +1081,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*
* @return string
*/
private function _sql_readable()
protected function _sql_readable()
{
static $sql_read_acl;
@ -1243,7 +1246,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* Read the extended acl via acl::get_grants('sqlfs')
*
*/
private static function _read_extended_acl()
static protected function _read_extended_acl()
{
if ((self::$extended_acl = $GLOBALS['egw']->session->appsession('extended_acl',self::EACL_APPNAME)) != false)
{
@ -1445,7 +1448,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* @param array $info
* @return array
*/
static private function _vfsinfo2stat($info)
static protected function _vfsinfo2stat($info)
{
$stat = array(
'ino' => $info['fs_id'],
@ -1480,7 +1483,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*
* @return PDO
*/
static private function _pdo()
static protected function _pdo()
{
$egw_db = isset($GLOBALS['egw_setup']) ? $GLOBALS['egw_setup']->db : $GLOBALS['egw']->db;
@ -1522,7 +1525,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
self::$pdo = new PDO($dsn,$egw_db->User,'$egw_db->Password');
}
// set client charset of the connection
$charset = $GLOBALS['egw']->translation->charset();
$charset = translation::charset();
switch(self::$pdo_type)
{
case 'mysql':
@ -1545,7 +1548,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
* @param mixed $time
* @return string Y-m-d H:i:s
*/
static private function _pdo_timestamp($time)
static protected function _pdo_timestamp($time)
{
if (is_numeric($time))
{
@ -1553,6 +1556,21 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
}
return $time;
}
/**
* Just a little abstration 'til I know how to organise stuff like that with PDO
*
* @param boolean $val
* @return string '1' or '0' for mysql, 'true' or 'false' for everyone else
*/
static protected function _pdo_boolean($val)
{
if (self::$pdo_type == 'mysql')
{
return $val ? '1' : '0';
}
return $val ? 'true' : 'false';
}
/**
* Maximum value for a single hash element (should be 10^N): 10, 100 (default), 1000, ...
@ -1612,7 +1630,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper
*
* @param string &$url
*/
static private function _remove_password(&$url)
static protected function _remove_password(&$url)
{
$parts = parse_url($url);