<!doctype linuxdoc system>

<article>
<!-- LyX 1.1 created this file. For more info see http://www.lyx.org/ -->
<title>
phpgwapi - VFS Class
</title>
<author>
Jason Wies
</author>
<date>
June 2001, February 2002
</date>
<abstract>
The VFS, or Virtual File System, handles all file system activity
 for phpGroupWare.
</abstract>
<sect>
Introduction and Purpose<label id="sec:introduction" >
<p>
The latest version of the VFS for phpGroupWare combines actual
 file system manipulation with fully integrated database support.
 It features nearly transparent handling of files and directories,
 as well as files inside and outside the virtual root. This document
 is intended to provide API and application developers with a guide
 to incorporating the VFS into their work.
</p>
<sect>
Basics<label id="sec:basics" >
<sect1>
Prerequisites<label id="sec:prerequisites" >
<p>
You must explicitly enable the VFS class. To do this, set 'enable_vfs_class'
 to True in &dollar;GLOBALS&lsqb;'phpgw_info'&rsqb;&lsqb;'flags'&rsqb;.
 An example:
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw_info'&rsqb;&lsqb;'flags'&rsqb; = array(
     'currentapp' =&gt; 'phpwebhosting',
     'noheader' =&gt; False,
     'noappheader' =&gt; False,
     'enable_vfs_class' =&gt; True,
     'enable_browser_class' =&gt; True
);
</verb>
</p><sect1>
Concepts<label id="sec:concepts" >
<p>
The VFS in located in phpgwapi/inc/class.vfs_sql.inc.php. You
 can look over it, but I don't suggest trying to understand how it
 works. It isn't necessary to know its internals to use it, but you
 may find the inline comments helpful. The basic things to keep in
 mind:
</p>
<p>
<itemize>
 <item>
Files and directories are synonymous in almost all cases
</itemize>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;mv (array(
     'from' =&gt; 'file1',
     'to' =&gt; 'dir/file2'
));

&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;mv (array(
     'from' =&gt; 'dir1',
     'to' =&gt; 'dir/dir1'
));

&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;rm (array(
     'string' =&gt; 'file'
));

&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;rm (array(
     'string' =&gt; 'dir'
));
</verb>
</p><p>
All work as you would except them to. The major exception is:
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;touch (array(
     'string' =&gt; 'file'
));
</verb>
</p><p>
vs.
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;mkdir (array(
     'string' =&gt; 'dir'
));

</verb>
<p>
<itemize>
 <item>
Users and groups are synonymous
</itemize>
</p><p>
As far as the actual paths are concerned, users and groups are
 the same. /home/username works the same as /home/groupname.
</p>
<p>
<itemize>
 <item>
You should never have to know the real paths of files
</itemize>
</p><p>
One of the VFS's responsibilities is to translate paths for you.
 While you certainly <em>can</em> operate using full paths, it is much simpler
 to use the virtual paths. For example, instead of using:
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;cp (array(
     'from' =&gt; '/var/www/phpgroupware/files/home/user/file1',
     'to' =&gt; '/var/www/phpgroupware/files/home/user/file2',
     'relatives' =&gt; array(
          RELATIVE_NONE|VFS_REAL,
          RELATIVE_NONE|VFS_REAL
     )
));
</verb>
</p><p>
you might use
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;cp (array(
     'from' =&gt; '/home/user/file1',
     'to' =&gt; '/home/user/file2',
     'relatives' =&gt; array(
          RELATIVE_NONE,
          RELATIVE_NONE
     )
));
</verb>
</p><p>
(We'll get to the RELATIVE's in a minute.)
</p>
<p>
Site administrators should be able to move their files dir around
 on their system and know that everything will continue to work smoothly.
</p>
<p>
<itemize>
 <item>
Relativity is <em>vital</em>
</itemize>
</p><p>
Relativity is a new feature in the VFS, and its importance cannot
 be stressed enough. It will make your life much easier, especially
 for file system intensive applications, but it will take some getting
 used to. If something doesn't work right the first time, chances
 are great it has to do with incorrect relativity settings. We will
 deal with relativity in depth in the Relativity section.
</p>
<sect>
Basic Functions<label id="sec:basic_functions" >
<p>
These are two functions you'll need to know before we get into
 relativity.
</p>
<sect1>
path_parts ()<label id="sec:path_parts" >
<p>
The job of path_parts () is to translate any given file location
 into its many component parts for any relativity. The values passed
 to path_parts () are:
</p>
<p>
<verb>
string
relatives
object
</verb>
</p><p>
'string' is the path you want to translate, 'relatives' is the
 standard relativity array, and 'object' specifies how you would like
 the return value: if 'object' is True, an object will be returned;
 if 'object' is False, an array will be returned. I think you'll find
 the object easier to deal with, and we'll be using it throughout
 this document. The most important returned values (but not all) for
 path_parts () are:
</p>
<p>
<verb>
fake_full_path
fake_leading_dirs
fake_extra_path
fake_name
real_full_path
real_leading_dirs
real_extra_path
real_name
</verb>
</p><p>
Just like you would think, fake_full_path contains the full virtual
 path of 'string', and real_full_path contains the full real path
 of 'string'. The fake_name and real_name variables should always
 be the same, and contain the final file or directory name. The leading_dirs
 contain everything except the name, and the extra_path is everything
 from the / before "home" to the end of the leading_dirs. To better
 illustrate, here is an example:
</p>
<p>
<verb>
&dollar;p = &dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;path_parts (array(
     'string' =&gt; '/home/jason/dir/file',
     'relatives' =&gt; array(
         RELATIVE_NONE
     )
));
</verb>
<p>
<itemize>
 <item>
&dollar;p-&gt;fake_full_path - /home/jason/dir/file
 <item>
&dollar;p-&gt;fake_leading_dirs - /home/jason/dir
 <item>
&dollar;p-&gt;fake_extra_path - home/jason/dir
 <item>
&dollar;p-&gt;fake_name - file
 <item>
&dollar;p-&gt;real_full_path - /var/www/phpgroupware/files/home/jason/dir/file
 <item>
&dollar;p-&gt;real_leading_dirs - /var/www/phpgroupware/files/home/jason/dir
 
 <item>
&dollar;p-&gt;real_extra_path - home/jason/dir
 <item>
&dollar;p-&gt;real_name - file
</itemize>
</p><p>
As you can see, path_parts () is a very useful function and will
 save you from doing those darn substr ()'s yourself. For those of
 you used to the prior VFS, note that <em>getabsolutepath () is depreciated</em>.
 getabsolutepath () still exists (albeit in a much different form),
 and is responsible for some of the path translation, but it is an
 <em>internal</em> function only. Applications should only use path_parts ().
 We have shown you how to use path_parts () so you can experiment
 with it using different paths and relativities as we explore relativity.
</p>
<sect1>
cd ()<label id="sec:cd" >
<p>
Part of the overall goal for the VFS in phpGroupWare is to give
 the user a seamless experience during their session. For example,
 if they upload a file using a file manager to the directory /home/my_group/project1,
 and then go to download an email attachment, the default directory
 will be /home/my_group/project1. This is accomplished using the cd
 () function. Examples: 
</p>
<p>
<verb>
/* cd to their home directory */
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;cd (array(
     'string' =&gt; '/'
));

/* cd to /home/jason/dir */
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;cd (array(
     'string' =&gt; '/home/jason/dir',
     'relative' =&gt; False,
     'relatives' =&gt; array(
          RELATIVE_NONE
     )
));

/* When following the above, cd's to /home/jason/dir/dir2 */
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;cd (array(
     'string' =&gt; 'dir2',
     'relative' =&gt; True
));
</verb>
</p><p>
If 'relative' is True, the 'string' is simply appended to the
 current path. If you want to know what the current path is, use &dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;pwd
 ().
</p>
<p>
Now you're ready for relativity.
</p>
<sect>
Relativity<label id="sec:relativity" >
<p>
Ok, just one last thing before we get into relativity. You will
 notice throughout the examples the use of &dollar;fakebase. &dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;fakebase
 is by default '/home'. The old VFS was hard-coded to use '/home',
 but the naming choice for this is now up to administrators. See the
 <ref id="sec:fakebase" name="Fakebase directory (changing /home)" > section for more information. Throughout the rest of this document,
 you will see &dollar;fakebase used in calls to the VFS, and /home
 used in actual paths. <em>You should always use &dollar;fakebase when
 making applications. </em>I suggest doing &dollar;fakebase = &dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;fakebase;
 right off the bat to keep things neater.
</p>
<sect1>
What is it and how does it work?
<p>
One of the design challenges for a Virtual File System is to
 try to figure out whether the calling application is referring to
 a file inside or outside the virtual root, and if inside, exactly
 where. To solve this problem, the phpGroupWare VFS uses RELATIVE
 defines that are used in bitmasks passed to each function. The result
 is that any set of different relativities can be used in combination
 with each other. Let's look at a few examples. Say you want to move
 'logo.png' from the user's home directory to the current directory.
 
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;mv (array(
    'from' =&gt; 'logo.png',
    'to' =&gt; 'logo.png',
    'relatives' =&gt; array(
          RELATIVE_USER,
          RELATIVE_ALL
     )
));
</verb>
</p><p>
RELATIVE_USER means relative to the user's home directory. RELATIVE_ALL
 means relative to the current directory, as set by cd () and as reported
 by pwd (). So if the current directory was "&dollar;fakebase/my_group/project1",
 the call to mv () would be processed as:
</p>
<p>
<verb>
MOVE "&dollar;fakebase/jason/logo.png" TO "&dollar;fakebase/my_group/project1/logo.png"
</verb>
</p><p>
and the actual file system call would be:
</p>
<p>
<verb>
rename ('/var/www/phpgroupware/files/home/jason/logo.php', '/var/www/phpgroupware/files/home/my_group/project1/logo.png');
</verb>
</p><p>
Those used to the old VFS will note that you do not have to translate
 the path beforehand. Let's look at another example. Suppose you were
 moving an email attachment stored in phpGroupWare's temporary directory
 to the 'attachments' directory within the user's home directory (we're
 assuming the attachments directory exists). Note that the temporary
 directory is <em>outside</em> the virtual root.
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;mv (array(
     'from' =&gt; &dollar;GLOBALS&lsqb;'phpgw_info'&rsqb;&lsqb;'server'&rsqb;&lsqb;'temp_dir'&rsqb; . '/' . &dollar;randomdir . '/' . &dollar;randomfile,
     'to' =&gt; 'attachments/actual_name.ext',
     'relatives' =&gt; array(
          RELATIVE_NONE|VFS_REAL,
          RELATIVE_USER
     )
));
</verb>
</p><p>
&dollar;randomdir and &dollar;randomfile are what the directory
 and file might be called before they are given a proper name by the
 user, which is actual_name.ext in this example. RELATIVE_NONE is
 the define for using full path names. However, RELATIVE_NONE is still
 relative to the virtual root, so we pass along VFS_REAL as well,
 to say that the file is <em>outside</em> the virtual root, somewhere else
 in the file system. Once again, RELATIVE_USER means relative to the
 user's home directory. So the actual file system call might look
 like this (keep in mind that &dollar;randomdir and &dollar;randomfile
 are just random strings):
</p>
<p>
<verb>
rename ('/var/www/phpgroupware/tmp/0ak5adftgh7/jX42sC9M', '/var/www/phpgroupware/files/home/jason/attachments/actual_name.ext');
</verb>
</p><p>
Of course you don't have to know that, nor should you be concerned
 with it; you can take it for granted that the VFS will translate
 the paths correctly. Let's take a look at one more example, this
 time using the RELATIVE_USER_APP define. RELATIVE_USER_APP is used
 to store quasi-hidden application files, similar to the Unix convention
 of &tilde;/.appname. It simply appends .appname to the user's home
 directory. For example, if you were making an HTML editor application
 named 'htmledit', and wanted to keep a backup file in case something
 goes wrong, you could use RELATIVE_USER_APP to store it:
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;write (array(
     'string' =&gt; 'file.name&tilde;',
     'relatives' =&gt; array(
          RELATIVE_USER_APP
     ),
     'content' =&gt; &dollar;contents
));
</verb>
</p><p>
This assumes that &tilde;/.htmledit exists of course. The backup
 file "file.name&tilde;" would then be written in &dollar;fakebase/jason/.htmledit/file.name&tilde;.
 Note that storing files like this might not be as good of a solution
 as storing them in the temporary directory or in the database. But
 it is there in case you need it.
</p>
<sect1>
Complete List<label id="sec:relatives_complete_list" >
<p>
Here is the complete list of RELATIVE defines, and what they
 do:
</p>
<p>
<descrip>
 <tag>
RELATIVE_ROOT</tag>Don't translate the path at all. Just prepends
 a /. You'll probably want to use RELATIVE_NONE though, which handles
 both virtual and real files.
 <tag>
RELATIVE_USER</tag>User's home directory
 <tag>
RELATIVE_CURR_USER</tag>Current user's home directory. If the
 current directory is &dollar;fakebase/my_group/project1, this will
 return is &dollar;fakebase/my_group
 <tag>
RELATIVE_USER_APP</tag>Append .appname to the user's home directory,
 where appname is the current application's appname
 <tag>
RELATIVE_PATH</tag>DO NOT USE. Relative to the current directory,
 used in RELATIVE_ALL
 <tag>
RELATIVE_NONE</tag>Not relative to anything. Use this with VFS_REAL
 for files outside the virtual root. Note that using RELATIVE_NONE
 by itself still means relative to the virtual root
 <tag>
RELATIVE_CURRENT</tag>An alias for the currently set RELATIVE
 define, or RELATIVE_ALL if none is set (see the Defaults section)
 <tag>
VFS_REAL</tag>File is outside of the virtual root. Usually used
 with RELATIVE_NONE
 <tag>
RELATIVE_ALL</tag>Relative to the current directory. Use RELATIVE_ALL<em>
 </em>instead of RELATIVE_PATH
</descrip>
</p><sect1>
Defaults<label id="sec:relatives_defaults" >
<p>
You might be thinking to yourself that passing along RELATIVE
 defines with every VFS call is overkill, especially if your application
 always uses the same relativity. The default RELATIVE define for
 all VFS calls is RELATIVE_CURRENT. RELATIVE_CURRENT itself defaults
 to RELATIVE_ALL (relative to the current path), <em>unless</em> your application
 sets a specific relativity. If your application requires most of
 the work to be done outside of the virtual root, you may wish to
 set RELATIVE_CURRENT to RELATIVE_NONE|VFS_REAL. set_relative () is
 the function to do this. For example:
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;set_relative (array(
     'mask' =&gt; RELATIVE_NONE|VFS_REAL
));

&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;read (array(
     'string' =&gt; '/etc/passwd'
));

&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;cp (array(
     'from' =&gt; '/usr/include/stdio.h',
     'to' =&gt; '/tmp/stdio.h'
));

&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;cp (array(
     'from' =&gt; '/usr/share/pixmaps/yes.xpm',
     'to' =&gt; 'icons/yes.xpm',
     'relatives' =&gt; array(
          RELATIVE_CURRENT,
          RELATIVE_USER
     )
));
</verb>
</p><p>
You should notice that no relativity array is needed in the other
 calls that refer to files outside the virtual root, but one is needed
 for calls that include files inside the virtual root. Any RELATIVE
 define can be set as the default and works in the same fashion. To
 retrieve the currently set define, use get_relative (). Note that
 the relativity is reset after each page request; that is, it's good
 only for the life of the current page loading, and is not stored
 in session management.
</p>
<sect>
Function reference<label id="sec:function_reference" >
<p>
To view the function reference for the VFS, use the doc/inlinedocparser.php
 script that comes with phpGroupWare, ie <url url="http://localhost/doc/inlinedocparser.php?fn=class.vfs_sql.inc.php" name="http://localhost/doc/inlinedocparser.php?fn=class.vfs_sql.inc.php">.
</p>
<sect>
Notes<label id="sec:notes" >
<sect1>
Database<label id="sec:database" >
<p>
Data about the files and directories within the virtual root
 is kept in the SQL database. Currently, this information includes:
</p>
<p>
<itemize>
 <item>
File ID (used internally, primary key for table)
 <item>
Owner ID (phpGW account_id)
 <item>
Created by ID (phpGW account_id)
 <item>
Modified by ID (phpGW account_id)
 <item>
Created (date)
 <item>
Modified (date)
 <item>
Size (bytes)
 <item>
MIME type
 <item>
Deleteable (Y/N/Other?)
 <item>
Comment
 <item>
App (appname of application that created the file)
 <item>
Directory (directory the file or directory is in)
 <item>
Name (name of file or directory)
 <item>
Link directory (if the file or directory is linked, what the
 actual directory is)
 <item>
Link name (if the file or directory is linked, what the actual
 name is)
 <item>
Version (numeric version of the file)
</itemize>
</p><p>
The internal names of these (the database column names) are stored
 in the &dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;attributes
 array, which is useful for loops, and is guaranteed to be up-to-date.
</p>
<p>
Note that no information is kept about files outside the virtual
 root. If a file is moved outside, all records of it are deleted from
 the database (other than the journaling records). If a file is moved
 into the virtual root, some information, specifically MIME-type,
 is not always stored in the database. The vital information has defaults:
 owner is based on where the file is being stored; size is correctly
 read; deleteable is set to Y.
</p>
<sect1>
ACL support<label id="sec:acl_support" >
<p>
ACL support is built into the VFS. vfs-&gt;acl_check () does
 the actual checking, and is called from all VFS functions as needed.
 If the file or directory sent to acl_check () doesn't exist, the
 permissions for the parent directory are used to determine access.
 ACL checking can be overridden at any time by setting vfs-&gt;override_acl.
 For example:
</p>
<p>
<verb>
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;override_acl = 1;
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;mkdir (array(
     'string' =&gt; &dollar;GLOBALS&lsqb;'fakebase'&rsqb;. '/' . &dollar;group_array&lsqb;'account_name'&rsqb;,
     'relatives' =&gt; array(
          RELATIVE_NONE
     )
));
&dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;override_acl = 0;
</verb>
</p><sect1>
Function aliases<label id="sec:function_aliases" >
<p>
You might have noticed there are some functions that just pass
 the arguments on to other functions. These are provided in part because
 of legacy and in part for convenience. You can use either. Here is
 the list (alias -&gt; actual):
</p>
<p>
<itemize>
 <item>
copy -&gt; cp
 <item>
move -&gt; rm
 <item>
delete -&gt; rm
 <item>
dir -&gt; ls
</itemize>
</p><sect1>
Fakebase directory (changing /home)<label id="sec:fakebase" >
<p>
The old VFS was hard-coded to use '/home' as the fake base directory,
 even though the user never saw it. With the new system, crafty administrators
 may wish to change '/home' to something else, say '/users' or '/public_html'.
 The fake base directory name is stored in &dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;fakebase,
 and changing it will transparently change it throughout the VFS and
 all applications. However, this must be done <em>before</em> any data is in
 the VFS database. If you wish to change it afterwords, you'll have
 to manually update the database, replacing the old value with the
 new value. <em>Application programmers need to recognize that /home is
 not absolute, and use &dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;fakebase
 instead</em>. I suggest setting &dollar;fakebase = &dollar;GLOBALS&lsqb;'phpgw'&rsqb;-&gt;vfs-&gt;fakebase;
 right off the bat to keep things neater.
</p>
<sect>
About this Document
<sect1>
Copyright and License
<p>
Copyright (c) 2001, 2002 Jason Wies
</p>
<p>
Permission is granted to copy, distribute and/or modify this
 document under the terms of the GNU Free Documentation License, Version
 1.1 or any later version published by the Free Software Foundation;
 with no Invarient Sections, with no Front-Cover Texts, and no Back-Cover
 Texts.
</p>
<p>
A copy of the license is available at <url url="http://www.gnu.org/copyleft/fdl.html" name="http://www.gnu.org/copyleft/fdl.html">.
</p>
<sect1>
History
<p>
Original document released in June 2001 by Jason Wies.
</p>
<p>
Updated February 2002 to include arrayized parameters, single
 quotes, and GLOBALS.
</p>
<sect1>
Contributing
<p>
Contributions are always welcome. Please send to the current
 maintainer, Jason Wies, <url url="mailto:zone@phpgroupware.org" name="zone@phpgroupware.org">.
</p>


</article>
