source: trunk/phpgwapi/inc/class.vfs_shared.inc.php @ 2

Revision 2, 38.8 KB checked in by niltonneto, 17 years ago (diff)

Removida todas as tags usadas pelo CVS ($Id, $Source).
Primeira versão no CVS externo.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1<?php
2  /**************************************************************************\
3  * eGroupWare API - VFS base class                                          *
4  * This file written by Jason Wies (Zone) <zone@phpgroupware.org>           *
5  * This class handles file/dir access for eGroupWare                        *
6  * Copyright (C) 2001 Jason Wies                                            *
7  * -------------------------------------------------------------------------*
8  * This library is part of the eGroupWare API                               *
9  * http://www.egroupware.org/api                                            *
10  * ------------------------------------------------------------------------ *
11  * This library is free software; you can redistribute it and/or modify it  *
12  * under the terms of the GNU Lesser General Public License as published by *
13  * the Free Software Foundation; either version 2.1 of the License,         *
14  * or any later version.                                                    *
15  * This library is distributed in the hope that it will be useful, but      *
16  * WITHOUT ANY WARRANTY; without even the implied warranty of               *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     *
18  * See the GNU Lesser General Public License for more details.              *
19  * You should have received a copy of the GNU Lesser General Public License *
20  * along with this library; if not, write to the Free Software Foundation,  *
21  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA            *
22  \**************************************************************************/
23
24
25        /* Relative defines.  Used mainly by getabsolutepath () */
26        define ('RELATIVE_ROOT', 1);
27        define ('RELATIVE_USER', 2);
28        define ('RELATIVE_CURR_USER', 4);
29        define ('RELATIVE_USER_APP', 8);
30        define ('RELATIVE_PATH', 16);
31        define ('RELATIVE_NONE', 32);
32        define ('RELATIVE_CURRENT', 64);
33        define ('VFS_REAL', 1024);
34        define ('RELATIVE_ALL', RELATIVE_PATH);
35
36        /* These are used in calls to add_journal (), and allow journal messages to be more standard */
37        define ('VFS_OPERATION_CREATED', 1);
38        define ('VFS_OPERATION_EDITED', 2);
39        define ('VFS_OPERATION_EDITED_COMMENT', 4);
40        define ('VFS_OPERATION_COPIED', 8);
41        define ('VFS_OPERATION_MOVED', 16);
42        define ('VFS_OPERATION_DELETED', 32);
43
44        /*!
45         * @class path_class
46         * @abstract helper class for path_parts
47         */
48        class path_class
49        {
50                var $mask;
51                var $outside;
52                var $fake_full_path;
53                var $fake_leading_dirs;
54                var $fake_extra_path;
55                var $fake_name;
56                var $real_full_path;
57                var $real_leading_dirs;
58                var $real_extra_path;
59                var $real_name;
60                var $fake_full_path_clean;
61                var $fake_leading_dirs_clean;
62                var $fake_extra_path_clean;
63                var $fake_name_clean;
64                var $real_full_path_clean;
65                var $real_leading_dirs_clean;
66                var $real_extra_path_clean;
67                var $real_name_clean;
68        }
69
70        /*!
71         * @class vfs_shared
72         * @abstract Base class for Virtual File System classes
73         * @author Zone
74         */
75        class vfs_shared
76        {
77                /*
78                 * All VFS classes must have some form of 'linked directories'.
79                 * Linked directories allow an otherwise disparate "real" directory
80                 * to be linked into the "virtual" filesystem.  See make_link().
81                 */
82                var $linked_dirs = array ();
83
84                /*
85                 * All VFS classes need to support the access control in some form
86                 * (see acl_check()).  There are times when applications will need
87                 * to explictly disable access checking, for example when creating a
88                 * user's home directory for the first time or when the admin is
89                 * performing maintanence.  When override_acl is set, any access
90                 * checks must return True.
91                 */
92                var $override_acl = 0;
93
94                /*
95                 * The current relativity.  See set_relative() and get_relative().
96                 */
97                var $relative;
98
99                /*
100                 * Implementation dependant 'base real directory'.  It is not required
101                 * that derived classes use $basedir, but some of the shared functions
102                 * below rely on it, so those functions will need to be overload if
103                 * basedir isn't appropriate for a particular backend.
104                 */
105                var $basedir;
106
107                /*
108                 * Fake base directory.  Only the administrator should change this.
109                 */
110                var $fakebase = '/home';
111
112                /*
113                 * All derived classes must store certain information about each
114                 * location.  The attributes in the 'attributes' array represent
115                 * the minimum attributes that must be stored.  Derived classes
116                 * should add to this array any custom attributes.
117                 *
118                 * Not all of the attributes below are appropriate for all backends.
119                 * Those that don't apply can be replaced by dummy values, ie. '' or 0.
120                 */
121                var $attributes = array(
122                        'file_id',      /* Integer.  Unique to each location */
123                        'owner_id',     /* phpGW account_id of owner */
124                        'createdby_id', /* phpGW account_id of creator */
125                        'modifiedby_id',/* phpGW account_id of who last modified */
126                        'created',      /* Datetime created, in SQL format */
127                        'modified',     /* Datetime last modified, in SQL format */
128                        'size',         /* Size in bytes */
129                        'mime_type',    /* Mime type.  'Directory' for directories */
130                        'comment',      /* User-supplied comment.  Can be empty */
131                        'app',          /* Name of phpGW application responsible for location */
132                        'directory',    /* Directory location is in */
133                        'name',         /* Name of file/directory */
134                        'link_directory',       /* Directory location is linked to, if any */
135                        'link_name',            /* Name location is linked to, if any */
136                        'version',      /* Version of file.  May be 0 */
137                );
138
139                /*!
140                 * @function vfs_shared
141                 * @abstract constructor
142                 * @description All derived classes should call this function in their
143                 *              constructor ($this->vfs_shared())
144                 */
145                function vfs_shared ()
146                {
147                }
148
149                /*
150                 * Definitions for functions that every derived
151                 * class must have, and suggestions for private functions
152                 * to completement the public ones.  The prototypes for
153                 * the public functions need to be uniform for all
154                 * classes.  Of course, each derived class should overload these
155                 * functions with their own version.
156                 */
157
158                /*
159                 * Journal functions.
160                 *
161                 * See also: VFS_OPERATION_* defines
162                 *
163                 * Overview:
164                 * Each action performed on a location
165                 * should be recorded, in both machine and human
166                 * readable format.
167                 *
168                 * PRIVATE functions (suggested examples only, not mandatory):
169                 *
170                 * add_journal - Add journal entry
171                 * flush_journal - Clear all journal entries for a location
172                 *
173                 * PUBLIC functions (mandatory):
174                 *
175                 * get_journal - Get journal entries for a location
176                 */
177
178                /* Private, suggestions only */
179                function add_journal ($data) {}
180                function flush_journal ($data) {}
181
182                /*!
183                 * @function get_journal
184                 * @abstract Get journal entries for a location
185                 * @required string     Path to location
186                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
187                 * @optional type       [0|1|2]
188                 *                              0 = any journal entries
189                 *                              1 = current journal entries
190                 *                              2 = deleted journal entries
191                 * @result Array of arrays of journal entries
192                 *         The keys will vary depending on the implementation,
193                 *         with most attributes in this->attributes being valid,
194                 *         and these keys being mandatory:
195                 *              created - Datetime in SQL format that journal entry
196                 *                        was entered
197                 *              comment - Human readable comment describing the action
198                 *              version - May be 0 if the derived class does not support
199                 *                        versioning
200                 */
201                function get_journal ($data) { return array(array()); }
202
203                /*
204                 * Access checking functions.
205                 *
206                 * Overview:
207                 * Each derived class should have some kind of
208                 * user and group access control.  This will
209                 * usually be based directly on the ACL class.
210                 *
211                 * If $this->override_acl is set, acl_check()
212                 * must always return True.
213                 *
214                 * PUBLIC functions (mandatory):
215                 *
216                 * acl_check() - Check access for a user to a given
217                 */
218
219                /*!
220                 * @function acl_check
221                 * @abstract Check access for a user to a given location
222                 * @discussion If $this->override_acl is set, always return True
223                 * @required string     Path to location
224                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
225                 * @required operation  Operation to check access for.  Any combination
226                 *                      of the PHPGW_ACL_* defines, for example:
227                 *                      PHPGW_ACL_READ
228                 *                      PHPGW_ACL_READ|PHPGW_ACL_WRITE
229                 * @optional owner_id   phpGW ID to check access for.
230                 *                      Default: $GLOBALS['phpgw_info']['user']['account_id']
231                 * @optional must_exist If set, string must exist, and acl_check() must
232                 *                      return False if it doesn't.  If must_exist isn't
233                 *                      passed, and string doesn't exist, check the owner_id's
234                 *                      access to the parent directory, if it exists.
235                 * @result Boolean.  True if access is ok, False otherwise.
236                 */
237                function acl_check ($data) { return True; }
238
239                /*
240                 * Operations functions.
241                 *
242                 * Overview:
243                 * These functions perform basic file operations.
244                 *
245                 * PUBLIC functions (mandatory):
246                 *
247                 * read - Retreive file contents
248                 *
249                 * write - Store file contents
250                 *
251                 * touch - Create a file if it doesn't exist.
252                 *         Optionally, update the modified time and
253                 *         modified user if the file exists.
254                 *
255                 * cp - Copy location
256                 *
257                 * mv - Move location
258                 *
259                 * rm - Delete location
260                 *
261                 * mkdir - Create directory
262                 */
263
264                /*!
265                 * @function read
266                 * @abstract Retreive file contents
267                 * @required string     Path to location
268                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
269                 * @result String.  Contents of 'string', or False on error.
270                 */
271                function read ($data) { return False; }
272
273                 /*!
274                @function view
275                @abstract Views the specified file (does not return!)
276                @param string filename
277                @param relatives Relativity array
278                @result None (doesnt return)
279                @discussion By default this function just reads the file and
280                outputs it too the browser, after setting the content-type header
281                appropriately.  For some other VFS implementations though, there
282                may be some more sensible way of viewing the file.
283                */
284                 function view($data)
285                 {
286                       
287                        $default_values = array
288                                (
289                                        'relatives'     => array (RELATIVE_CURRENT)
290                                );
291                        $data = array_merge ($this->default_values ($data, $default_values), $data);
292 
293                        $GLOBALS['phpgw_info']['flags']['noheader'] = true;
294                        $GLOBALS['phpgw_info']['flags']['nonavbar'] = true;
295                        $GLOBALS['phpgw_info']['flags']['noappheader'] = true;
296                        $GLOBALS['phpgw_info']['flags']['noappfooter'] = true;
297                        $ls_array = $this->ls (array (
298                                        'string'        =>  $data['string'],
299                                        'relatives'     => $data['relatives'],
300                                        'checksubdirs'  => False,
301                                        'nofiles'       => True
302                                )
303                        );
304               
305                        if ($ls_array[0]['mime_type'])
306                        {
307                                $mime_type = $ls_array[0]['mime_type'];
308                        }
309                        elseif ($GLOBALS['settings']['viewtextplain'])
310                        {
311                                $mime_type = 'text/plain';
312                        }
313               
314                        header('Content-type: ' . $mime_type);
315                        echo $this->read (array (
316                                        'string'        =>  $data['string'],
317                                        'relatives'     => $data['relatives'],
318                                )
319                        );             
320                        exit();
321                 }
322               
323                /*!
324                 * @function write
325                 * @abstract Store file contents
326                 * @required string     Path to location
327                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
328                 * @result Boolean.  True on success, False otherwise.
329                 */
330                function write ($data) { return False; }
331
332                /*!
333                 * @function touch
334                 * @abstract Create a file if it doesn't exist.
335                 *           Optionally, update the modified time and
336                 *           modified user if the file exists.
337                 * @required string     Path to location
338                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
339                 * @result Boolean.  True on success, False otherwise.
340                 */
341                function touch ($data) { return False; }
342
343                /*!
344                 * @function cp
345                 * @abstract Copy location
346                 * @required from       Path to location to copy from
347                 * @required to         Path to location to copy to
348                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT, RELATIVE_CURRENT)
349                 * @result Boolean.  True on success, False otherwise.
350                 */
351                function cp ($data) { return False; }
352
353                /*!
354                 * @function mv
355                 * @abstract Move location
356                 * @required from       Path to location to move from
357                 * @required to         Path to location to move to
358                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT, RELATIVE_CURRENT)
359                 * @result Boolean.  True on success, False otherwise.
360                 */
361                function mv ($data) { return False; }
362
363                /*!
364                 * @function rm
365                 * @abstract Delete location
366                 * @required string     Path to location
367                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
368                 * @result Boolean.  True on success, False otherwise.
369                 */
370                function rm ($data) { return False; }
371
372                /*!
373                 * @function mkdir
374                 * @abstract Create directory
375                 * @required string     Path to location
376                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
377                 * @result Boolean.  True on success, False otherwise.
378                 */
379                function mkdir ($data) { return False; }
380
381                /*
382                 * Information functions.
383                 *
384                 * Overview:
385                 * These functions set or return information about locations.
386                 *
387                 * PUBLIC functions (mandatory):
388                 *
389                 * set_attributes - Set attributes for a location
390                 *
391                 * file_exists - Check if a location (file or directory) exists
392                 *
393                 * get_size - Determine size of location
394                 *
395                 * ls - Return detailed information for location(s)
396                 */
397
398                /*!
399                 * @function set_attributes
400                 * @abstract Set attributes for a location
401                 * @discussion Valid attributes are listed in vfs->attributes,
402                 *             which may be extended by each derived class
403                 * @required string     Path to location
404                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
405                 * @optional attributes Keyed array of attributes.  Key is attribute
406                 *                      name, value is attribute value.
407                 * @result Boolean.  True on success, False otherwise.
408                 */
409                 function set_attributes ($data) { return False; }
410
411                /*!
412                 * @function file_exists
413                 * @abstract Check if a location (file or directory) exists
414                 * @required string     Path to location
415                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
416                 * @result Boolean.  True if file exists, False otherwise.
417                 */
418                function file_exists ($data) { return False; }
419
420                /*!
421                 * @function get_size
422                 * @abstract Determine size of location
423                 * @required string     Path to location
424                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
425                 * @optional checksubdirs       Boolean.  If set, include the size of
426                 *                              all subdirectories recursively.
427                 * @result Integer.  Size of location in bytes.
428                 */
429                function get_size ($data) { return 0; }
430
431                /*!
432                 * @function ls
433                 * @abstract Return detailed information for location(s)
434                 * @required string     Path to location
435                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
436                 * @optional checksubdirs       Boolean.  If set, return information for all
437                 *                              subdirectories recursively.
438                 * @optional mime       String.  Only return information for locations with MIME type
439                 *                      specified.  VFS classes must recogize these special types:
440                 *                              "Directory" - Location is a directory
441                 *                              " " - Location doesn't not have a MIME type
442                 * @optional nofiles    Boolean.  If set and 'string' is a directory, return
443                 *                      information about the directory, not the files in it.
444                 * @result Array of arrays of file information.
445                 *         Keys may vary depending on the implementation, but must include
446                 *         at least those attributes listed in $this->attributes.
447                 */
448                function ls ($data) { return array(array()); }
449
450                /*
451                 * Linked directory functions.
452                 *
453                 * Overview:
454                 * One 'special' feature that VFS classes must support
455                 * is linking an otherwise unrelated 'real' directory into
456                 * the virtual filesystem.  For a traditional filesystem, this
457                 * might mean linking /var/specialdir in the real filesystem to
458                 * /home/user/specialdir in the VFS.  For networked filesystems,
459                 * this might mean linking 'another.host.com/dir' to
460                 * 'this.host.com/home/user/somedir'.
461                 *
462                 * This is a feature that will be used mostly be administrators,
463                 * in order to present a consistent view to users.  Each VFS class
464                 * will almost certainly need a new interface for the administrator
465                 * to use to make links, but the concept is the same across all the
466                 * VFS backends.
467                 *
468                 * Note that by using $this->linked_dirs in conjunction with
469                 * $this->path_parts(), you can keep the implementation of linked
470                 * directories very isolated in your code.
471                 *
472                 * PUBLIC functions (mandatory):
473                 *
474                 * make_link - Create a real to virtual directory link
475                 */
476
477                /*!
478                 * @function make_link
479                 * @abstract Create a real to virtual directory link
480                 * @required rdir       Real directory to make link from/to
481                 * @required vdir       Virtual directory to make link to/from
482                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT, RELATIVE_CURRENT)
483                 * @result Boolean.  True on success, False otherwise.
484                 */
485                function make_link ($data) { return False; }
486
487                /*
488                 * Miscellaneous functions.
489                 *
490                 * PUBLIC functions (mandatory):
491                 *
492                 * update_real - Ensure that information about a location is
493                 *               up-to-date
494                 */
495
496                /*!
497                 * @function update_real
498                 * @abstract Ensure that information about a location is up-to-date
499                 * @discussion Some VFS backends store information about locations
500                 *             in a secondary location, for example in a database
501                 *             or in a cache file.  update_real() can be called to
502                 *             ensure that the information in the secondary location
503                 *             is up-to-date.
504                 * @required string     Path to location
505                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
506                 * @result Boolean.  True on success, False otherwise.
507                 */
508                function update_real ($data) { return False; }
509 
510                /*
511                 * SHARED FUNCTIONS
512                 *
513                 * The rest of the functions in this file are shared between
514                 * all derived VFS classes.
515                 *
516                 * Derived classes can overload any of these functions if they
517                 * see it fit to do so, as long as the prototypes and return
518                 * values are the same for public functions, and the function
519                 * accomplishes the same goal.
520                 *
521                 * PRIVATE functions:
522                 *
523                 * securitycheck - Check if location string is ok to use in VFS functions
524                 *
525                 * sanitize - Remove any possible security problems from a location
526                 *            string (i.e. remove leading '..')
527                 *
528                 * clean_string - Clean location string.  This function is used if
529                 *                any special characters need to be escaped or removed
530                 *                before accessing a database, network protocol, etc.
531                 *                The default is to escape characters before doing an SQL
532                 *                query.
533                 *
534                 * getabsolutepath - Translate a location string depending on the
535                 *                   relativity.  This is the only function that is
536                 *                   directly concerned with relativity.
537                 *
538                 * get_ext_mime_type - Return MIME type based on file extension
539                 *
540                 * PUBLIC functions (mandatory):
541                 *
542                 * set_relative - Sets the current relativity, the relativity used
543                 *                when RELATIVE_CURRENT is passed to a function
544                 *
545                 * get_relative - Return the current relativity
546                 *
547                 * path_parts - Return information about the component parts of a location string
548                 *
549                 * cd - Change current directory.  This function is used to store the
550                 *      current directory in a standard way, so that it may be accessed
551                 *      throughout phpGroupWare to provide a consistent view for the user.
552                 *
553                 * pwd - Return current directory
554                 *
555                 * copy - Alias for cp
556                 *
557                 * move - Alias for mv
558                 *
559                 * delete - Alias for rm
560                 *
561                 * dir - Alias for ls
562                 *
563                 * command_line - Process and run a Unix-sytle command line
564                 */
565
566                /* PRIVATE functions */
567
568                /*!
569                 * @function securitycheck
570                 * @abstract Check if location string is ok to use in VFS functions
571                 * @discussion Checks for basic violations such as ..
572                 *             If securitycheck () fails, run your string through $this->sanitize ()
573                 * @required string     Path to location
574                 * @result Boolean.  True if string is ok, False otherwise.
575                 */
576                function securitycheck ($data)
577                {
578                        if (!is_array ($data))
579                        {
580                                $data = array ();
581                        }
582
583                        if (substr ($data['string'], 0, 1) == "\\" || strstr ($data['string'], "..") || strstr ($data['string'], "\\..") || strstr ($data['string'], ".\\."))
584                        {
585                                return False;
586                        }
587                        else
588                        {
589                                return True;
590                        }
591                }
592
593                /*!
594                 * @function sanitize
595                 * @abstract Remove any possible security problems from a location
596                 *           string (i.e. remove leading '..')
597                 * @discussion You should not pass all filenames through sanitize ()
598                 *             unless you plan on rejecting .files.  Instead, pass
599                 *             the name through securitycheck () first, and if it fails,
600                 *             pass it through sanitize.
601                 * @required string     Path to location
602                 * @result String. 'string' with any security problems fixed.
603                 */
604                function sanitize ($data)
605                {
606                        if (!is_array ($data))
607                        {
608                                $data = array ();
609                        }
610
611                        /* We use path_parts () just to parse the string, not translate paths */
612                        $p = $this->path_parts (array(
613                                        'string' => $data['string'],
614                                        'relatives' => array (RELATIVE_NONE)
615                                )
616                        );
617
618                        return (ereg_replace ("^\.+", '', $p->fake_name));
619                }
620
621                /*!
622                 * @function clean_string
623                 * @abstract Clean location string.  This function is used if
624                 *           any special characters need to be escaped or removed
625                 *           before accessing a database, network protocol, etc.
626                 *           The default is to escape characters before doing an SQL
627                 *           query.
628                 * @required string     Location string to clean
629                 * @result String.  Cleaned version of 'string'.
630                 */
631                function clean_string ($data)
632                {
633                        if (!is_array ($data))
634                        {
635                                $data = array ();
636                        }
637
638                        $string = $GLOBALS['phpgw']->db->db_addslashes ($data['string']);
639
640                        return $string;
641                }
642
643                /*!
644                 * @function getabsolutepath
645                 * @abstract Translate a location string depending on the
646                 *           relativity. This is the only function that is
647                 *           directly concerned with relativity.
648                 * @optional string     Path to location, relative to mask[0].
649                 *                      Defaults to empty string.
650                 * @optional mask       Relativity array (default: RELATIVE_CURRENT)
651                 * @optional fake       Boolean.  If set, returns the 'fake' path,
652                 *                      i.e. /home/user/dir/file.  This is not always
653                 *                      possible,  use path_parts() instead.
654                 * @result String. Full fake or real path, or False on error.
655                 */
656                function getabsolutepath ($data)
657                {
658                        if (!is_array ($data))
659                        {
660                                $data = array ();
661                        }
662
663                        $default_values = array
664                                (
665                                        'string'        => False,
666                                        'mask'  => array (RELATIVE_CURRENT),
667                                        'fake'  => True
668                                );
669
670                        $data = array_merge ($this->default_values ($data, $default_values), $data);
671
672                        $currentdir = $this->pwd (False);
673
674                        /* If they supply just VFS_REAL, we assume they want current relativity */
675                        if ($data['mask'][0] == VFS_REAL)
676                        {
677                                $data['mask'][0] |= RELATIVE_CURRENT;
678                        }
679
680                        if (!$this->securitycheck (array(
681                                        'string'        => $data['string']
682                                ))
683                        )
684                        {
685                                return False;
686                        }
687
688                        if ($data['mask'][0] & RELATIVE_NONE)
689                        {
690                                return $data['string'];
691                        }
692
693                        if ($data['fake'])
694                        {
695                                $sep = '/';
696                        }
697                        else
698                        {
699                                $sep = SEP;
700                        }
701
702                        /* if RELATIVE_CURRENT, retrieve the current mask */
703                        if ($data['mask'][0] & RELATIVE_CURRENT)
704                        {
705                                $mask = $data['mask'][0];
706                                /* Respect any additional masks by re-adding them after retrieving the current mask*/
707                                $data['mask'][0] = $this->get_relative () + ($mask - RELATIVE_CURRENT);
708                        }
709
710                        if ($data['fake'])
711                        {
712                                $basedir = "/";
713                        }
714                        else
715                        {
716                                $basedir = $this->basedir . $sep;
717
718                                /* This allows all requests to use /'s */
719                                $data['string'] = preg_replace ("|/|", $sep, $data['string']);
720                        }
721
722                        if (($data['mask'][0] & RELATIVE_PATH) && $currentdir)
723                        {
724                                $basedir = $basedir . $currentdir . $sep;
725                        }
726                        elseif (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP))
727                        {
728                                $basedir = $basedir . $this->fakebase . $sep;
729                        }
730
731                        if ($data['mask'][0] & RELATIVE_CURR_USER)
732                        {
733                                $basedir = $basedir . $this->working_lid . $sep;
734                        }
735
736                        if (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP))
737                        {
738                                $basedir = $basedir . $GLOBALS['phpgw_info']['user']['account_lid'] . $sep;
739                        }
740
741                        if ($data['mask'][0] & RELATIVE_USER_APP)
742                        {
743                                $basedir = $basedir . "." . $GLOBALS['phpgw_info']['flags']['currentapp'] . $sep;
744                        }
745
746                        /* Don't add string if it's a /, just for aesthetics */
747                        if ($data['string'] && $data['string'] != $sep)
748                        {
749                                $basedir = $basedir . $data['string'];
750                        }
751
752                        /* Let's not return // */
753                        while (ereg ($sep . $sep, $basedir))
754                        {
755                                $basedir = ereg_replace ($sep . $sep, $sep, $basedir);
756                        }
757
758                        $basedir = ereg_replace ($sep . '$', '', $basedir);
759
760                        return $basedir;
761                }
762
763                /*!
764                 * @function get_ext_mime_type
765                 * @abstract Return MIME type based on file extension
766                 * @description Internal use only.  Applications should call vfs->file_type ()
767                 * @author skeeter
768                 * @required string     Real path to file, with or without leading paths
769                 * @result String.  MIME type based on file extension.
770                 */
771                function get_ext_mime_type ($data)
772                {
773                        if (!is_array ($data))
774                        {
775                                $data = array ();
776                        }
777
778                        $file=basename($data['string']);
779                        $mimefile=PHPGW_API_INC.'/phpgw_mime.types';
780                        $fp=fopen($mimefile,'r');
781                        $contents = explode("\n",fread($fp,filesize($mimefile)));
782                        fclose($fp);
783
784                        $parts=explode('.',strtolower($file));
785                        $ext=$parts[(sizeof($parts)-1)];
786
787                        for($i=0;$i<sizeof($contents);$i++)
788                        {
789                                if (!ereg("^#",$contents[$i]))
790                                {
791                                        $line=split("[[:space:]]+", $contents[$i]);
792                                        if (sizeof($line) >= 2)
793                                        {
794                                                for($j=1;$j<sizeof($line);$j++)
795                                                {
796                                                        if($line[$j] == $ext)
797                                                        {
798                                                                return $line[0];
799                                                        }
800                                                }
801                                        }
802                                }
803                        }
804
805                        return '';
806                }
807
808                /* PUBLIC functions (mandatory) */
809
810                /*!
811                 * @function set_relative
812                 * @abstract Sets the current relativity, the relativity used
813                 *           when RELATIVE_CURRENT is passed to a function
814                 * @optional mask       Relative bitmask.  If not set, relativity
815                 *                      will be returned to the default.
816                 * @result Void
817                 */
818                function set_relative ($data)
819                {
820                        if (!is_array ($data))
821                        {
822                                $data = array ();
823                        }
824
825                        if (!$data['mask'])
826                        {
827                                unset ($this->relative);
828                        }
829                        else
830                        {
831                                $this->relative = $data['mask'];
832                        }
833                }
834
835                /*!
836                 * @function get_relative
837                 * @abstract Return the current relativity
838                 * @discussion Returns relativity bitmask, or the default
839                 *             of "completely relative" if unset
840                 * @result Integer.  One of the RELATIVE_* defines.
841                 */
842                function get_relative ()
843                {
844                        if (isset ($this->relative) && $this->relative)
845                        {
846                                return $this->relative;
847                        }
848                        else
849                        {
850                                return RELATIVE_ALL;
851                        }
852                }
853
854                /*!
855                 * @function path_parts
856                 * @abstract Return information about the component parts of a location string
857                 * @discussion Most VFS functions call path_parts() with their 'string' and
858                 *             'relatives' arguments before doing their work, in order to
859                 *             determine the file/directory to work on.
860                 * @required string     Path to location
861                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
862                 * @optional object     If set, return an object instead of an array
863                 * @optional nolinks    Don't check for linked directories (made with
864                 *                      make_link()).  Used internally to prevent recursion.
865                 * @result Array or object.  Contains the fake and real component parts of the path.
866                 * @discussion Returned values are:
867                 *              mask
868                 *              outside
869                 *              fake_full_path
870                 *              fake_leading_dirs
871                 *              fake_extra_path         BROKEN
872                 *              fake_name
873                 *              real_full_path
874                 *              real_leading_dirs
875                 *              real_extra_path         BROKEN
876                 *              real_name
877                 *              fake_full_path_clean
878                 *              fake_leading_dirs_clean
879                 *              fake_extra_path_clean   BROKEN
880                 *              fake_name_clean
881                 *              real_full_path_clean
882                 *              real_leading_dirs_clean
883                 *              real_extra_path_clean   BROKEN
884                 *              real_name_clean
885                 *      "clean" values are run through vfs->clean_string () and
886                 *      are safe for use in SQL queries that use key='value'
887                 *      They should be used ONLY for SQL queries, so are used
888                 *      mostly internally
889                 *      mask is either RELATIVE_NONE or RELATIVE_NONE|VFS_REAL,
890                 *      and is used internally
891                 *      outside is boolean, True if 'relatives' contains VFS_REAL
892                 */
893                function path_parts ($data)
894                {
895                        if (!is_array ($data))
896                        {
897                                $data = array ();
898                        }
899
900                        $default_values = array
901                                (
902                                        'relatives'     => array (RELATIVE_CURRENT),
903                                        'object'        => True,
904                                        'nolinks'       => False
905                                );
906
907                        $data = array_merge ($this->default_values ($data, $default_values), $data);
908
909                        $sep = SEP;
910
911                        $rarray['mask'] = RELATIVE_NONE;
912
913                        if (!($data['relatives'][0] & VFS_REAL))
914                        {
915                                $rarray['outside'] = False;
916                                $fake = True;
917                        }
918                        else
919                        {
920                                $rarray['outside'] = True;
921                                $rarray['mask'] |= VFS_REAL;
922                        }
923
924                        $string = $this->getabsolutepath (array(
925                                        'string'        => $data['string'],
926                                        'mask'  => array ($data['relatives'][0]),
927                                        'fake'  => $fake
928                                )
929                        );
930
931                        if ($fake)
932                        {
933                                $base_sep = '/';
934                                $base = '/';
935
936                                $opp_base = $this->basedir . $sep;
937
938                                $rarray['fake_full_path'] = $string;
939                        }
940                        else
941                        {
942                                $base_sep = $sep;
943                                if (substr($string,0,strlen($this->basedir)+1) == $this->basedir . $sep)
944                                {
945                                        $base = $this->basedir . $sep;
946                                }
947                                else
948                                {
949                                        $base = $sep;
950                                }
951
952                                $opp_base = '/';
953
954                                $rarray['real_full_path'] = $string;
955                        }
956
957                        /* This is needed because of substr's handling of negative lengths */
958                        $baselen = strlen ($base);
959                        $lastslashpos = @strrpos ($string, $base_sep);
960                        $length = $lastslashpos < $baselen ? 0 : $lastslashpos - $baselen;
961
962                        $extra_path = $rarray['fake_extra_path'] = $rarray['real_extra_path'] = substr ($string, strlen ($base), $length);
963                        if($string[1] != ':')
964                        {
965                                $name = $rarray['fake_name'] = $rarray['real_name'] = substr ($string, @strrpos ($string, $base_sep) + 1);
966                        }
967                        else
968                        {
969                                $name = $rarray['fake_name'] = $rarray['real_name'] = $string;
970                        }
971
972                        if ($fake)
973                        {
974                                $rarray['real_extra_path'] ? $dispsep = $sep : $dispsep = '';
975                                $rarray['real_full_path'] = $opp_base . $rarray['real_extra_path'] . $dispsep . $rarray['real_name'];
976                                if ($extra_path)
977                                {
978                                        $rarray['fake_leading_dirs'] = $base . $extra_path;
979                                        $rarray['real_leading_dirs'] = $opp_base . $extra_path;
980                                }
981                                elseif (@strrpos ($rarray['fake_full_path'], $sep) == 0)
982                                {
983                                        /* If there is only one $sep in the path, we don't want to strip it off */
984                                        $rarray['fake_leading_dirs'] = $sep;
985                                        $rarray['real_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1);
986                                }
987                                else
988                                {
989                                        /* These strip the ending / */
990                                        $rarray['fake_leading_dirs'] = substr ($base, 0, strlen ($base) - 1);
991                                        $rarray['real_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1);
992                                }
993                        }
994                        else
995                        {
996                                if($rarray['fake_name'][1] != ':')
997                                {
998                                        $rarray['fake_full_path'] = $opp_base . $rarray['fake_extra_path'] . '/' . $rarray['fake_name'];
999                                }
1000                                else
1001                                {
1002                                        $rarray['fake_full_path'] = $rarray['fake_name'];
1003                                }
1004                                if ($extra_path)
1005                                {
1006                                        $rarray['fake_leading_dirs'] = $opp_base . $extra_path;
1007                                        $rarray['real_leading_dirs'] = $base . $extra_path;
1008                                }
1009                                else
1010                                {
1011                                        $rarray['fake_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1);
1012                                        $rarray['real_leading_dirs'] = substr ($base, 0, strlen ($base) - 1);
1013                                }
1014                        }
1015
1016                        /* We check for linked dirs made with make_link ().  This could be better, but it works */
1017                        if (!$data['nolinks'])
1018                        {
1019                                reset ($this->linked_dirs);
1020                                while (list ($num, $link_info) = each ($this->linked_dirs))
1021                                {
1022                                        if (ereg ("^$link_info[directory]/$link_info[name](/|$)", $rarray['fake_full_path']))
1023                                        {
1024                                                $rarray['real_full_path'] = ereg_replace ("^$this->basedir", '', $rarray['real_full_path']);
1025                                                $rarray['real_full_path'] = ereg_replace ("^$link_info[directory]" . SEP . "$link_info[name]", $link_info['link_directory'] . SEP . $link_info['link_name'], $rarray['real_full_path']);
1026
1027                                                $p = $this->path_parts (array(
1028                                                                'string'        => $rarray['real_full_path'],
1029                                                                'relatives'     => array (RELATIVE_NONE|VFS_REAL),
1030                                                                'nolinks'       => True
1031                                                        )
1032                                                );
1033
1034                                                $rarray['real_leading_dirs'] = $p->real_leading_dirs;
1035                                                $rarray['real_extra_path'] = $p->real_extra_path;
1036                                                $rarray['real_name'] = $p->real_name;
1037                                        }
1038                                }
1039                        }
1040
1041                        /*
1042                           We have to count it before because new keys will be added,
1043                           which would create an endless loop
1044                        */
1045                        $count = count ($rarray);
1046                        reset ($rarray);
1047                        for ($i = 0; (list ($key, $value) = each ($rarray)) && $i != $count; $i++)
1048                        {
1049                                $rarray[$key . '_clean'] = $this->clean_string (array ('string' => $value));
1050                        }
1051
1052                        if ($data['object'])
1053                        {
1054                                $robject = new path_class;
1055
1056                                reset ($rarray);
1057                                while (list ($key, $value) = each ($rarray))
1058                                {
1059                                        $robject->$key = $value;
1060                                }
1061                        }
1062
1063                        /*
1064                        echo "<br>fake_full_path: $rarray[fake_full_path]
1065                                <br>fake_leading_dirs: $rarray[fake_leading_dirs]
1066                                <br>fake_extra_path: $rarray[fake_extra_path]
1067                                <br>fake_name: $rarray[fake_name]
1068                                <br>real_full_path: $rarray[real_full_path]
1069                                <br>real_leading_dirs: $rarray[real_leading_dirs]
1070                                <br>real_extra_path: $rarray[real_extra_path]
1071                                <br>real_name: $rarray[real_name]";
1072                        */
1073
1074                        if ($data['object'])
1075                        {
1076                                return ($robject);
1077                        }
1078                        else
1079                        {
1080                                return ($rarray);
1081                        }
1082                }
1083
1084                /*!
1085                 * @function cd
1086                 * @abstract Change current directory.  This function is used to store the
1087                 *           current directory in a standard way, so that it may be accessed
1088                 *           throughout phpGroupWare to provide a consistent view for the user.
1089                 * @discussion To cd to the root '/', use:
1090                 *              cd (array(
1091                 *                      'string' => '/',
1092                 *                      'relative' => False,
1093                 *                      'relatives' => array (RELATIVE_NONE)
1094                 *              ));
1095                 * @optional string     Directory location to cd into.  Default is '/'.
1096                 * @optional relative   If set, add target to current path.
1097                 *                      Else, pass 'relative' as mask to getabsolutepath()
1098                 *                      Default is True.
1099                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
1100                 */
1101                function cd ($data = '')
1102                {
1103                        if (!is_array ($data))
1104                        {
1105                                $noargs = 1;
1106                                $data = array ();
1107                        }
1108
1109                        $default_values = array
1110                                (
1111                                        'string'        => '/',
1112                                        'relative'      => True,
1113                                        'relatives'     => array (RELATIVE_CURRENT)
1114                                );
1115
1116                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1117
1118                        if ($data['relatives'][0] & VFS_REAL)
1119                        {
1120                                $sep = SEP;
1121                        }
1122                        else
1123                        {
1124                                $sep = '/';
1125                        }
1126
1127                        if ($data['relative'] == 'relative' || $data['relative'] == True)
1128                        {
1129                                /* if 'string' is "/" and 'relative' is set, we cd to the user/group home dir */
1130                                if ($data['string'] == '/')
1131                                {
1132                                        $data['relatives'][0] = RELATIVE_USER;
1133                                        $basedir = $this->getabsolutepath (array(
1134                                                        'string'        => False,
1135                                                        'mask'  => array ($data['relatives'][0]),
1136                                                        'fake'  => True
1137                                                )
1138                                        );
1139                                }
1140                                else
1141                                {
1142                                        $currentdir = $GLOBALS['phpgw']->session->appsession('vfs','');
1143                                        $basedir = $this->getabsolutepath (array(
1144                                                        'string'        => $currentdir . $sep . $data['string'],
1145                                                        'mask'  => array ($data['relatives'][0]),
1146                                                        'fake'  => True
1147                                                )
1148                                        );
1149                                }
1150                        }
1151                        else
1152                        {
1153                                $basedir = $this->getabsolutepath (array(
1154                                                'string'        => $data['string'],
1155                                                'mask'  => array ($data['relatives'][0])
1156                                        )
1157                                );
1158                        }
1159
1160                        $GLOBALS['phpgw']->session->appsession('vfs','',$basedir);
1161
1162                        return True;
1163                }
1164
1165                /*!
1166                 * @function pwd
1167                 * @abstract Return current directory
1168                 * @optional full       If set, return full fake path, else just
1169                 *                      the extra dirs (False strips the leading /).
1170                 *                      Default is True.
1171                 * @result String.  The current directory.
1172                 */
1173                function pwd ($data = '')
1174                {
1175                        if (!is_array ($data))
1176                        {
1177                                $data = array ();
1178                        }
1179
1180                        $default_values = array
1181                                (
1182                                        'full'  => True
1183                                );
1184
1185                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1186
1187                        $currentdir = $GLOBALS['phpgw']->session->appsession('vfs','');
1188
1189                        if (!$data['full'])
1190                        {
1191                                $currentdir = ereg_replace ("^/", '', $currentdir);
1192                        }
1193
1194                        if ($currentdir == '' && $data['full'])
1195                        {
1196                                $currentdir = '/';
1197                        }
1198
1199                        $currentdir = trim ($currentdir);
1200
1201                        return $currentdir;
1202                }
1203
1204                /*!
1205                 * @function copy
1206                 * @abstract shortcut to cp
1207                 */
1208                function copy ($data)
1209                {
1210                        return $this->cp ($data);
1211                }
1212
1213                /*!
1214                 * @function move
1215                 * @abstract shortcut to mv
1216                 */
1217                function move ($data)
1218                {
1219                        return $this->mv ($data);
1220                }
1221
1222                /*!
1223                 * @function delete
1224                 * @abstract shortcut to rm
1225                 */
1226                function delete ($data)
1227                {
1228                        return $this->rm ($data);
1229                }
1230
1231                /*!
1232                 * @function dir
1233                 * @abstract shortcut to ls
1234                 */
1235                function dir ($data)
1236                {
1237                        return $this->ls ($data);
1238                }
1239
1240                /*!
1241                 * @function command_line
1242                 * @abstract Process and run a Unix-sytle command line
1243                 * @discussion EXPERIMENTAL.  DANGEROUS.  DO NOT USE THIS UNLESS YOU
1244                 *             KNOW WHAT YOU'RE DOING!
1245                 *             This is mostly working, but the command parser needs
1246                 *             to be improved to take files with spaces into
1247                 *             consideration (those should be in "").
1248                 * @required command_line       Unix-style command line with one of the
1249                 *                              commands in the $args array
1250                 * @result The return value of the actual VFS call
1251                 */
1252                function command_line ($data)
1253                {
1254                        if (!is_array ($data))
1255                        {
1256                                $data = array ();
1257                        }
1258
1259                        $args = array
1260                        (
1261                                array ('name'   => 'mv', 'params'       => 2),
1262                                array ('name'   => 'cp', 'params'       => 2),
1263                                array ('name'   => 'rm', 'params'       => 1),
1264                                array ('name'   => 'ls', 'params'       => -1),
1265                                array ('name'   => 'du', 'params'       => 1, 'func'    => get_size),
1266                                array ('name'   => 'cd', 'params'       => 1),
1267                                array ('name'   => 'pwd', 'params'      => 0),
1268                                array ('name'   => 'cat', 'params'      => 1, 'func'    => read),
1269                                array ('name'   => 'file', 'params'     => 1, 'func'    => file_type),
1270                                array ('name'   => 'mkdir', 'params'    => 1),
1271                                array ('name'   => 'touch', 'params'    => 1)
1272                        );
1273
1274                        if (!$first_space = strpos ($data['command_line'], ' '))
1275                        {
1276                                $first_space = strlen ($data['command_line']);
1277                        }
1278                        if ((!$last_space = strrpos ($data['command_line'], ' ')) || ($last_space == $first_space))
1279                        {
1280                                $last_space = strlen ($data['command_line']) + 1;
1281                        }
1282                        $argv[0] = substr ($data['command_line'], 0, $first_space);
1283                        if (strlen ($argv[0]) != strlen ($data['command_line']))
1284                        {
1285                                $argv[1] = substr ($data['command_line'], $first_space + 1, $last_space - ($first_space + 1));
1286                                if ((strlen ($argv[0]) + 1 + strlen ($argv[1])) != strlen ($data['command_line']))
1287                                {
1288                                        $argv[2] = substr ($data['command_line'], $last_space + 1);
1289                                }
1290                        }
1291                        $argc = count ($argv);
1292
1293                        reset ($args);
1294                        while (list (,$arg_info) = each ($args))
1295                        {
1296                                if ($arg_info['name'] == $argv[0])
1297                                {
1298                                        $command_ok = 1;
1299                                        if (($argc == ($arg_info['params'] + 1)) || ($arg_info['params'] == -1))
1300                                        {
1301                                                $param_count_ok = 1;
1302                                        }
1303                                        break;
1304                                }
1305                        }
1306
1307                        if (!$command_ok)
1308                        {
1309//                              return E_VFS_BAD_COMMAND;
1310                                return False;
1311                        }
1312                        if (!$param_count_ok)
1313                        {
1314//                              return E_VFS_BAD_PARAM_COUNT;
1315                                return False;
1316                        }
1317
1318                        for ($i = 1; $i != ($arg_info['params'] + 1); $i++)
1319                        {
1320                                if (substr ($argv[$i], 0, 1) == "/")
1321                                {
1322                                        $relatives[] = RELATIVE_NONE;
1323                                }
1324                                else
1325                                {
1326                                        $relatives[] = RELATIVE_ALL;
1327                                }
1328                        }
1329
1330                        $func = $arg_info['func'] ? $arg_info['func'] : $arg_info['name'];
1331
1332                        if (!$argv[2])
1333                        {
1334                                $rv = $this->$func (array(
1335                                                'string'        => $argv[1],
1336                                                'relatives'     => $relatives
1337                                        )
1338                                );
1339                        }
1340                        else
1341                        {
1342                                $rv = $this->$func (array(
1343                                                'from'  => $argv[1],
1344                                                'to'    => $argv[2],
1345                                                'relatives'     => $relatives
1346                                        )
1347                                );
1348                        }
1349
1350                        return ($rv);
1351                }
1352
1353                /* Helper functions, not public */
1354
1355                function default_values ($data, $default_values)
1356                {
1357                        for ($i = 0; list ($key, $value) = each ($default_values); $i++)
1358                        {
1359                                if (!isset ($data[$key]))
1360                                {
1361                                        $data[$key] = $value;
1362                                }
1363                        }
1364
1365                        return $data;
1366                }
1367        }
1368
1369?>
Note: See TracBrowser for help on using the repository browser.