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

Revision 7655, 39.0 KB checked in by douglasz, 11 years ago (diff)

Ticket #3236 - Melhorias de performance no codigo do Expresso.

  • 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_all
422                * @abstract Determine size of location
423                * @owner_id string      uid owner
424                */
425               
426                function get_size_all($owner_id) { return 0; }
427               
428                /*!
429                 * @function get_size
430                 * @abstract Determine size of location
431                 * @required string     Path to location
432                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
433                 * @optional checksubdirs       Boolean.  If set, include the size of
434                 *                              all subdirectories recursively.
435                 * @result Integer.  Size of location in bytes.
436                 */
437                function get_size ($data) { return 0; }
438
439                /*!
440                 * @function ls
441                 * @abstract Return detailed information for location(s)
442                 * @required string     Path to location
443                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
444                 * @optional checksubdirs       Boolean.  If set, return information for all
445                 *                              subdirectories recursively.
446                 * @optional mime       String.  Only return information for locations with MIME type
447                 *                      specified.  VFS classes must recogize these special types:
448                 *                              "Directory" - Location is a directory
449                 *                              " " - Location doesn't not have a MIME type
450                 * @optional nofiles    Boolean.  If set and 'string' is a directory, return
451                 *                      information about the directory, not the files in it.
452                 * @result Array of arrays of file information.
453                 *         Keys may vary depending on the implementation, but must include
454                 *         at least those attributes listed in $this->attributes.
455                 */
456                function ls ($data) { return array(array()); }
457
458                /*
459                 * Linked directory functions.
460                 *
461                 * Overview:
462                 * One 'special' feature that VFS classes must support
463                 * is linking an otherwise unrelated 'real' directory into
464                 * the virtual filesystem.  For a traditional filesystem, this
465                 * might mean linking /var/specialdir in the real filesystem to
466                 * /home/user/specialdir in the VFS.  For networked filesystems,
467                 * this might mean linking 'another.host.com/dir' to
468                 * 'this.host.com/home/user/somedir'.
469                 *
470                 * This is a feature that will be used mostly be administrators,
471                 * in order to present a consistent view to users.  Each VFS class
472                 * will almost certainly need a new interface for the administrator
473                 * to use to make links, but the concept is the same across all the
474                 * VFS backends.
475                 *
476                 * Note that by using $this->linked_dirs in conjunction with
477                 * $this->path_parts(), you can keep the implementation of linked
478                 * directories very isolated in your code.
479                 *
480                 * PUBLIC functions (mandatory):
481                 *
482                 * make_link - Create a real to virtual directory link
483                 */
484
485                /*!
486                 * @function make_link
487                 * @abstract Create a real to virtual directory link
488                 * @required rdir       Real directory to make link from/to
489                 * @required vdir       Virtual directory to make link to/from
490                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT, RELATIVE_CURRENT)
491                 * @result Boolean.  True on success, False otherwise.
492                 */
493                function make_link ($data) { return False; }
494
495                /*
496                 * Miscellaneous functions.
497                 *
498                 * PUBLIC functions (mandatory):
499                 *
500                 * update_real - Ensure that information about a location is
501                 *               up-to-date
502                 */
503
504                /*!
505                 * @function update_real
506                 * @abstract Ensure that information about a location is up-to-date
507                 * @discussion Some VFS backends store information about locations
508                 *             in a secondary location, for example in a database
509                 *             or in a cache file.  update_real() can be called to
510                 *             ensure that the information in the secondary location
511                 *             is up-to-date.
512                 * @required string     Path to location
513                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
514                 * @result Boolean.  True on success, False otherwise.
515                 */
516                function update_real ($data) { return False; }
517 
518                /*
519                 * SHARED FUNCTIONS
520                 *
521                 * The rest of the functions in this file are shared between
522                 * all derived VFS classes.
523                 *
524                 * Derived classes can overload any of these functions if they
525                 * see it fit to do so, as long as the prototypes and return
526                 * values are the same for public functions, and the function
527                 * accomplishes the same goal.
528                 *
529                 * PRIVATE functions:
530                 *
531                 * securitycheck - Check if location string is ok to use in VFS functions
532                 *
533                 * sanitize - Remove any possible security problems from a location
534                 *            string (i.e. remove leading '..')
535                 *
536                 * clean_string - Clean location string.  This function is used if
537                 *                any special characters need to be escaped or removed
538                 *                before accessing a database, network protocol, etc.
539                 *                The default is to escape characters before doing an SQL
540                 *                query.
541                 *
542                 * getabsolutepath - Translate a location string depending on the
543                 *                   relativity.  This is the only function that is
544                 *                   directly concerned with relativity.
545                 *
546                 * get_ext_mime_type - Return MIME type based on file extension
547                 *
548                 * PUBLIC functions (mandatory):
549                 *
550                 * set_relative - Sets the current relativity, the relativity used
551                 *                when RELATIVE_CURRENT is passed to a function
552                 *
553                 * get_relative - Return the current relativity
554                 *
555                 * path_parts - Return information about the component parts of a location string
556                 *
557                 * cd - Change current directory.  This function is used to store the
558                 *      current directory in a standard way, so that it may be accessed
559                 *      throughout phpGroupWare to provide a consistent view for the user.
560                 *
561                 * pwd - Return current directory
562                 *
563                 * copy - Alias for cp
564                 *
565                 * move - Alias for mv
566                 *
567                 * delete - Alias for rm
568                 *
569                 * dir - Alias for ls
570                 *
571                 * command_line - Process and run a Unix-sytle command line
572                 */
573
574                /* PRIVATE functions */
575
576                /*!
577                 * @function securitycheck
578                 * @abstract Check if location string is ok to use in VFS functions
579                 * @discussion Checks for basic violations such as ..
580                 *             If securitycheck () fails, run your string through $this->sanitize ()
581                 * @required string     Path to location
582                 * @result Boolean.  True if string is ok, False otherwise.
583                 */
584                function securitycheck ($data)
585                {
586                        if (!is_array ($data))
587                        {
588                                $data = array ();
589                        }
590
591                        if (substr ($data['string'], 0, 1) == "\\" || strstr ($data['string'], "..") || strstr ($data['string'], "\\..") || strstr ($data['string'], ".\\."))
592                        {
593                                return False;
594                        }
595                        else
596                        {
597                                return True;
598                        }
599                }
600
601                /*!
602                 * @function sanitize
603                 * @abstract Remove any possible security problems from a location
604                 *           string (i.e. remove leading '..')
605                 * @discussion You should not pass all filenames through sanitize ()
606                 *             unless you plan on rejecting .files.  Instead, pass
607                 *             the name through securitycheck () first, and if it fails,
608                 *             pass it through sanitize.
609                 * @required string     Path to location
610                 * @result String. 'string' with any security problems fixed.
611                 */
612                function sanitize ($data)
613                {
614                        if (!is_array ($data))
615                        {
616                                $data = array ();
617                        }
618
619                        /* We use path_parts () just to parse the string, not translate paths */
620                        $p = $this->path_parts (array(
621                                        'string' => $data['string'],
622                                        'relatives' => array (RELATIVE_NONE)
623                                )
624                        );
625
626                        return (preg_replace('/^\.+/', '', $p->fake_name));
627                }
628
629                /*!
630                 * @function clean_string
631                 * @abstract Clean location string.  This function is used if
632                 *           any special characters need to be escaped or removed
633                 *           before accessing a database, network protocol, etc.
634                 *           The default is to escape characters before doing an SQL
635                 *           query.
636                 * @required string     Location string to clean
637                 * @result String.  Cleaned version of 'string'.
638                 */
639                function clean_string ($data)
640                {
641                        if (!is_array ($data))
642                        {
643                                $data = array ();
644                        }
645
646                        $string = $GLOBALS['phpgw']->db->db_addslashes ($data['string']);
647
648                        return $string;
649                }
650
651                /*!
652                 * @function getabsolutepath
653                 * @abstract Translate a location string depending on the
654                 *           relativity. This is the only function that is
655                 *           directly concerned with relativity.
656                 * @optional string     Path to location, relative to mask[0].
657                 *                      Defaults to empty string.
658                 * @optional mask       Relativity array (default: RELATIVE_CURRENT)
659                 * @optional fake       Boolean.  If set, returns the 'fake' path,
660                 *                      i.e. /home/user/dir/file.  This is not always
661                 *                      possible,  use path_parts() instead.
662                 * @result String. Full fake or real path, or False on error.
663                 */
664                function getabsolutepath ($data)
665                {
666                        if (!is_array ($data))
667                        {
668                                $data = array ();
669                        }
670
671                        $default_values = array
672                                (
673                                        'string'        => False,
674                                        'mask'  => array (RELATIVE_CURRENT),
675                                        'fake'  => True
676                                );
677
678                        $data = array_merge ($this->default_values ($data, $default_values), $data);
679
680                        $currentdir = $this->pwd (False);
681
682                        /* If they supply just VFS_REAL, we assume they want current relativity */
683                        if ($data['mask'][0] == VFS_REAL)
684                        {
685                                $data['mask'][0] |= RELATIVE_CURRENT;
686                        }
687
688                        if (!$this->securitycheck (array(
689                                        'string'        => $data['string']
690                                ))
691                        )
692                        {
693                                return False;
694                        }
695
696                        if ($data['mask'][0] & RELATIVE_NONE)
697                        {
698                                return $data['string'];
699                        }
700
701                        if ($data['fake'])
702                        {
703                                $sep = '/';
704                        }
705                        else
706                        {
707                                $sep = SEP;
708                        }
709
710                        /* if RELATIVE_CURRENT, retrieve the current mask */
711                        if ($data['mask'][0] & RELATIVE_CURRENT)
712                        {
713                                $mask = $data['mask'][0];
714                                /* Respect any additional masks by re-adding them after retrieving the current mask*/
715                                $data['mask'][0] = $this->get_relative () + ($mask - RELATIVE_CURRENT);
716                        }
717
718                        if ($data['fake'])
719                        {
720                                $basedir = "/";
721                        }
722                        else
723                        {
724                                $basedir = $this->basedir . $sep;
725
726                                /* This allows all requests to use /'s */
727                                $data['string'] = preg_replace ("|/|", $sep, $data['string']);
728                        }
729
730                        if (($data['mask'][0] & RELATIVE_PATH) && $currentdir)
731                        {
732                                $basedir = $basedir . $currentdir . $sep;
733                        }
734                        elseif (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP))
735                        {
736                                $basedir = $basedir . $this->fakebase . $sep;
737                        }
738
739                        if ($data['mask'][0] & RELATIVE_CURR_USER)
740                        {
741                                $basedir = $basedir . $this->working_lid . $sep;
742                        }
743
744                        if (($data['mask'][0] & RELATIVE_USER) || ($data['mask'][0] & RELATIVE_USER_APP))
745                        {
746                                $basedir = $basedir . $GLOBALS['phpgw_info']['user']['account_lid'] . $sep;
747                        }
748
749                        if ($data['mask'][0] & RELATIVE_USER_APP)
750                        {
751                                $basedir = $basedir . "." . $GLOBALS['phpgw_info']['flags']['currentapp'] . $sep;
752                        }
753
754                        /* Don't add string if it's a /, just for aesthetics */
755                        if ($data['string'] && $data['string'] != $sep)
756                        {
757                                $basedir = $basedir . $data['string'];
758                        }
759
760                        /* Let's not return // */
761                        while (preg_match("/$sep"."$sep/", $basedir))
762                        {
763                                $basedir = preg_replace("/$sep"."$sep/", $sep, $basedir);
764                        }
765
766                        $basedir = preg_replace("/$sep$/", '', $basedir);
767
768                        return $basedir;
769                }
770
771                /*!
772                 * @function get_ext_mime_type
773                 * @abstract Return MIME type based on file extension
774                 * @description Internal use only.  Applications should call vfs->file_type ()
775                 * @author skeeter
776                 * @required string     Real path to file, with or without leading paths
777                 * @result String.  MIME type based on file extension.
778                 */
779                function get_ext_mime_type ($data)
780                {
781                        if (!is_array ($data))
782                        {
783                                $data = array ();
784                        }
785
786                        $file=basename($data['string']);
787                        $mimefile=PHPGW_API_INC.'/phpgw_mime.types';
788                        $fp=fopen($mimefile,'r');
789                        $contents = explode("\n",fread($fp,filesize($mimefile)));
790                        fclose($fp);
791
792                        $parts=explode('.',strtolower($file));
793                        $ext=$parts[(sizeof($parts)-1)];
794
795                        for($i=0;$i<sizeof($contents);++$i)
796                        {
797                                if (!preg_match('/^#/',$contents[$i]))
798                                {
799                                        $line=preg_split('/[[:space:]]+/', $contents[$i]);
800                                        if (sizeof($line) >= 2)
801                                        {
802                                                for($j=1;$j<sizeof($line);++$j)
803                                                {
804                                                        if($line[$j] == $ext)
805                                                        {
806                                                                return $line[0];
807                                                        }
808                                                }
809                                        }
810                                }
811                        }
812
813                        return '';
814                }
815
816                /* PUBLIC functions (mandatory) */
817
818                /*!
819                 * @function set_relative
820                 * @abstract Sets the current relativity, the relativity used
821                 *           when RELATIVE_CURRENT is passed to a function
822                 * @optional mask       Relative bitmask.  If not set, relativity
823                 *                      will be returned to the default.
824                 * @result Void
825                 */
826                function set_relative ($data)
827                {
828                        if (!is_array ($data))
829                        {
830                                $data = array ();
831                        }
832
833                        if (!$data['mask'])
834                        {
835                                unset ($this->relative);
836                        }
837                        else
838                        {
839                                $this->relative = $data['mask'];
840                        }
841                }
842
843                /*!
844                 * @function get_relative
845                 * @abstract Return the current relativity
846                 * @discussion Returns relativity bitmask, or the default
847                 *             of "completely relative" if unset
848                 * @result Integer.  One of the RELATIVE_* defines.
849                 */
850                function get_relative ()
851                {
852                        if (isset ($this->relative) && $this->relative)
853                        {
854                                return $this->relative;
855                        }
856                        else
857                        {
858                                return RELATIVE_ALL;
859                        }
860                }
861
862                /*!
863                 * @function path_parts
864                 * @abstract Return information about the component parts of a location string
865                 * @discussion Most VFS functions call path_parts() with their 'string' and
866                 *             'relatives' arguments before doing their work, in order to
867                 *             determine the file/directory to work on.
868                 * @required string     Path to location
869                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
870                 * @optional object     If set, return an object instead of an array
871                 * @optional nolinks    Don't check for linked directories (made with
872                 *                      make_link()).  Used internally to prevent recursion.
873                 * @result Array or object.  Contains the fake and real component parts of the path.
874                 * @discussion Returned values are:
875                 *              mask
876                 *              outside
877                 *              fake_full_path
878                 *              fake_leading_dirs
879                 *              fake_extra_path         BROKEN
880                 *              fake_name
881                 *              real_full_path
882                 *              real_leading_dirs
883                 *              real_extra_path         BROKEN
884                 *              real_name
885                 *              fake_full_path_clean
886                 *              fake_leading_dirs_clean
887                 *              fake_extra_path_clean   BROKEN
888                 *              fake_name_clean
889                 *              real_full_path_clean
890                 *              real_leading_dirs_clean
891                 *              real_extra_path_clean   BROKEN
892                 *              real_name_clean
893                 *      "clean" values are run through vfs->clean_string () and
894                 *      are safe for use in SQL queries that use key='value'
895                 *      They should be used ONLY for SQL queries, so are used
896                 *      mostly internally
897                 *      mask is either RELATIVE_NONE or RELATIVE_NONE|VFS_REAL,
898                 *      and is used internally
899                 *      outside is boolean, True if 'relatives' contains VFS_REAL
900                 */
901                function path_parts ($data)
902                {
903                        if (!is_array ($data))
904                        {
905                                $data = array ();
906                        }
907
908                        $default_values = array
909                                (
910                                        'relatives'     => array (RELATIVE_CURRENT),
911                                        'object'        => True,
912                                        'nolinks'       => False
913                                );
914
915                        $data = array_merge ($this->default_values ($data, $default_values), $data);
916
917                        $sep = SEP;
918
919                        $rarray['mask'] = RELATIVE_NONE;
920
921                        if (!($data['relatives'][0] & VFS_REAL))
922                        {
923                                $rarray['outside'] = False;
924                                $fake = True;
925                        }
926                        else
927                        {
928                                $rarray['outside'] = True;
929                                $rarray['mask'] |= VFS_REAL;
930                        }
931
932                        $string = $this->getabsolutepath (array(
933                                        'string'        => $data['string'],
934                                        'mask'  => array ($data['relatives'][0]),
935                                        'fake'  => $fake
936                                )
937                        );
938
939                        if ($fake)
940                        {
941                                $base_sep = '/';
942                                $base = '/';
943
944                                $opp_base = $this->basedir . $sep;
945
946                                $rarray['fake_full_path'] = $string;
947                        }
948                        else
949                        {
950                                $base_sep = $sep;
951                                if (substr($string,0,strlen($this->basedir)+1) == $this->basedir . $sep)
952                                {
953                                        $base = $this->basedir . $sep;
954                                }
955                                else
956                                {
957                                        $base = $sep;
958                                }
959
960                                $opp_base = '/';
961
962                                $rarray['real_full_path'] = $string;
963                        }
964
965                        /* This is needed because of substr's handling of negative lengths */
966                        $baselen = strlen ($base);
967                        $lastslashpos = @strrpos ($string, $base_sep);
968                        $length = $lastslashpos < $baselen ? 0 : $lastslashpos - $baselen;
969
970                        $extra_path = $rarray['fake_extra_path'] = $rarray['real_extra_path'] = substr ($string, strlen ($base), $length);
971                        if($string[1] != ':')
972                        {
973                                $name = $rarray['fake_name'] = $rarray['real_name'] = substr ($string, @strrpos ($string, $base_sep) + 1);
974                        }
975                        else
976                        {
977                                $name = $rarray['fake_name'] = $rarray['real_name'] = $string;
978                        }
979
980                        if ($fake)
981                        {
982                                $rarray['real_extra_path'] ? $dispsep = $sep : $dispsep = '';
983                                $rarray['real_full_path'] = $opp_base . $rarray['real_extra_path'] . $dispsep . $rarray['real_name'];
984                                if ($extra_path)
985                                {
986                                        $rarray['fake_leading_dirs'] = $base . $extra_path;
987                                        $rarray['real_leading_dirs'] = $opp_base . $extra_path;
988                                }
989                                elseif (@strrpos ($rarray['fake_full_path'], $sep) == 0)
990                                {
991                                        /* If there is only one $sep in the path, we don't want to strip it off */
992                                        $rarray['fake_leading_dirs'] = $sep;
993                                        $rarray['real_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1);
994                                }
995                                else
996                                {
997                                        /* These strip the ending / */
998                                        $rarray['fake_leading_dirs'] = substr ($base, 0, strlen ($base) - 1);
999                                        $rarray['real_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1);
1000                                }
1001                        }
1002                        else
1003                        {
1004                                if($rarray['fake_name'][1] != ':')
1005                                {
1006                                        $rarray['fake_full_path'] = $opp_base . $rarray['fake_extra_path'] . '/' . $rarray['fake_name'];
1007                                }
1008                                else
1009                                {
1010                                        $rarray['fake_full_path'] = $rarray['fake_name'];
1011                                }
1012                                if ($extra_path)
1013                                {
1014                                        $rarray['fake_leading_dirs'] = $opp_base . $extra_path;
1015                                        $rarray['real_leading_dirs'] = $base . $extra_path;
1016                                }
1017                                else
1018                                {
1019                                        $rarray['fake_leading_dirs'] = substr ($opp_base, 0, strlen ($opp_base) - 1);
1020                                        $rarray['real_leading_dirs'] = substr ($base, 0, strlen ($base) - 1);
1021                                }
1022                        }
1023
1024                        /* We check for linked dirs made with make_link ().  This could be better, but it works */
1025                        if (!$data['nolinks'])
1026                        {
1027                                reset ($this->linked_dirs);
1028                                while (list ($num, $link_info) = each ($this->linked_dirs))
1029                                {
1030                                        if (preg_match("/^$link_info[directory]\/$link_info[name](\/|$)/", $rarray['fake_full_path']))
1031                                        {
1032                                                $rarray['real_full_path'] = preg_replace("/^$this->basedir/", '', $rarray['real_full_path']);
1033                                                $rarray['real_full_path'] = preg_replace("/^$link_info[directory]" . SEP . "$link_info[name]/", $link_info['link_directory'] . SEP . $link_info['link_name'], $rarray['real_full_path']);
1034
1035                                                $p = $this->path_parts (array(
1036                                                                'string'        => $rarray['real_full_path'],
1037                                                                'relatives'     => array (RELATIVE_NONE|VFS_REAL),
1038                                                                'nolinks'       => True
1039                                                        )
1040                                                );
1041
1042                                                $rarray['real_leading_dirs'] = $p->real_leading_dirs;
1043                                                $rarray['real_extra_path'] = $p->real_extra_path;
1044                                                $rarray['real_name'] = $p->real_name;
1045                                        }
1046                                }
1047                        }
1048
1049                        /*
1050                           We have to count it before because new keys will be added,
1051                           which would create an endless loop
1052                        */
1053                        $count = count ($rarray);
1054                        reset ($rarray);
1055                        for ($i = 0; (list ($key, $value) = each ($rarray)) && $i != $count; ++$i)
1056                        {
1057                                $rarray[$key . '_clean'] = $this->clean_string (array ('string' => $value));
1058                        }
1059
1060                        if ($data['object'])
1061                        {
1062                                $robject = new path_class;
1063
1064                                reset ($rarray);
1065                                while (list ($key, $value) = each ($rarray))
1066                                {
1067                                        $robject->$key = $value;
1068                                }
1069                        }
1070
1071                        /*
1072                        echo "<br>fake_full_path: $rarray[fake_full_path]
1073                                <br>fake_leading_dirs: $rarray[fake_leading_dirs]
1074                                <br>fake_extra_path: $rarray[fake_extra_path]
1075                                <br>fake_name: $rarray[fake_name]
1076                                <br>real_full_path: $rarray[real_full_path]
1077                                <br>real_leading_dirs: $rarray[real_leading_dirs]
1078                                <br>real_extra_path: $rarray[real_extra_path]
1079                                <br>real_name: $rarray[real_name]";
1080                        */
1081
1082                        if ($data['object'])
1083                        {
1084                                return ($robject);
1085                        }
1086                        else
1087                        {
1088                                return ($rarray);
1089                        }
1090                }
1091
1092                /*!
1093                 * @function cd
1094                 * @abstract Change current directory.  This function is used to store the
1095                 *           current directory in a standard way, so that it may be accessed
1096                 *           throughout phpGroupWare to provide a consistent view for the user.
1097                 * @discussion To cd to the root '/', use:
1098                 *              cd (array(
1099                 *                      'string' => '/',
1100                 *                      'relative' => False,
1101                 *                      'relatives' => array (RELATIVE_NONE)
1102                 *              ));
1103                 * @optional string     Directory location to cd into.  Default is '/'.
1104                 * @optional relative   If set, add target to current path.
1105                 *                      Else, pass 'relative' as mask to getabsolutepath()
1106                 *                      Default is True.
1107                 * @optional relatives  Relativity array (default: RELATIVE_CURRENT)
1108                 */
1109                function cd ($data = '')
1110                {
1111                        if (!is_array ($data))
1112                        {
1113                                $noargs = 1;
1114                                $data = array ();
1115                        }
1116
1117                        $default_values = array
1118                                (
1119                                        'string'        => '/',
1120                                        'relative'      => True,
1121                                        'relatives'     => array (RELATIVE_CURRENT)
1122                                );
1123
1124                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1125
1126                        if ($data['relatives'][0] & VFS_REAL)
1127                        {
1128                                $sep = SEP;
1129                        }
1130                        else
1131                        {
1132                                $sep = '/';
1133                        }
1134
1135                        if ($data['relative'] == 'relative' || $data['relative'] == True)
1136                        {
1137                                /* if 'string' is "/" and 'relative' is set, we cd to the user/group home dir */
1138                                if ($data['string'] == '/')
1139                                {
1140                                        $data['relatives'][0] = RELATIVE_USER;
1141                                        $basedir = $this->getabsolutepath (array(
1142                                                        'string'        => False,
1143                                                        'mask'  => array ($data['relatives'][0]),
1144                                                        'fake'  => True
1145                                                )
1146                                        );
1147                                }
1148                                else
1149                                {
1150                                        $currentdir = $GLOBALS['phpgw']->session->appsession('vfs','');
1151                                        $basedir = $this->getabsolutepath (array(
1152                                                        'string'        => $currentdir . $sep . $data['string'],
1153                                                        'mask'  => array ($data['relatives'][0]),
1154                                                        'fake'  => True
1155                                                )
1156                                        );
1157                                }
1158                        }
1159                        else
1160                        {
1161                                $basedir = $this->getabsolutepath (array(
1162                                                'string'        => $data['string'],
1163                                                'mask'  => array ($data['relatives'][0])
1164                                        )
1165                                );
1166                        }
1167
1168                        $GLOBALS['phpgw']->session->appsession('vfs','',$basedir);
1169
1170                        return True;
1171                }
1172
1173                /*!
1174                 * @function pwd
1175                 * @abstract Return current directory
1176                 * @optional full       If set, return full fake path, else just
1177                 *                      the extra dirs (False strips the leading /).
1178                 *                      Default is True.
1179                 * @result String.  The current directory.
1180                 */
1181                function pwd ($data = '')
1182                {
1183                        if (!is_array ($data))
1184                        {
1185                                $data = array ();
1186                        }
1187
1188                        $default_values = array
1189                                (
1190                                        'full'  => True
1191                                );
1192
1193                        $data = array_merge ($this->default_values ($data, $default_values), $data);
1194
1195                        $currentdir = $GLOBALS['phpgw']->session->appsession('vfs','');
1196
1197                        if (!$data['full'])
1198                        {
1199                                $currentdir = preg_replace('/^\//', '', $currentdir);
1200                        }
1201
1202                        if ($currentdir == '' && $data['full'])
1203                        {
1204                                $currentdir = '/';
1205                        }
1206
1207                        $currentdir = trim ($currentdir);
1208
1209                        return $currentdir;
1210                }
1211
1212                /*!
1213                 * @function copy
1214                 * @abstract shortcut to cp
1215                 */
1216                function copy ($data)
1217                {
1218                        return $this->cp ($data);
1219                }
1220
1221                /*!
1222                 * @function move
1223                 * @abstract shortcut to mv
1224                 */
1225                function move ($data)
1226                {
1227                        return $this->mv ($data);
1228                }
1229
1230                /*!
1231                 * @function delete
1232                 * @abstract shortcut to rm
1233                 */
1234                function delete ($data)
1235                {
1236                        return $this->rm ($data);
1237                }
1238
1239                /*!
1240                 * @function dir
1241                 * @abstract shortcut to ls
1242                 */
1243                function dir ($data)
1244                {
1245                        return $this->ls ($data);
1246                }
1247
1248                /*!
1249                 * @function command_line
1250                 * @abstract Process and run a Unix-sytle command line
1251                 * @discussion EXPERIMENTAL.  DANGEROUS.  DO NOT USE THIS UNLESS YOU
1252                 *             KNOW WHAT YOU'RE DOING!
1253                 *             This is mostly working, but the command parser needs
1254                 *             to be improved to take files with spaces into
1255                 *             consideration (those should be in "").
1256                 * @required command_line       Unix-style command line with one of the
1257                 *                              commands in the $args array
1258                 * @result The return value of the actual VFS call
1259                 */
1260                function command_line ($data)
1261                {
1262                        if (!is_array ($data))
1263                        {
1264                                $data = array ();
1265                        }
1266
1267                        $args = array
1268                        (
1269                                array ('name'   => 'mv', 'params'       => 2),
1270                                array ('name'   => 'cp', 'params'       => 2),
1271                                array ('name'   => 'rm', 'params'       => 1),
1272                                array ('name'   => 'ls', 'params'       => -1),
1273                                array ('name'   => 'du', 'params'       => 1, 'func'    => get_size),
1274                                array ('name'   => 'cd', 'params'       => 1),
1275                                array ('name'   => 'pwd', 'params'      => 0),
1276                                array ('name'   => 'cat', 'params'      => 1, 'func'    => read),
1277                                array ('name'   => 'file', 'params'     => 1, 'func'    => file_type),
1278                                array ('name'   => 'mkdir', 'params'    => 1),
1279                                array ('name'   => 'touch', 'params'    => 1)
1280                        );
1281
1282                        if (!$first_space = strpos ($data['command_line'], ' '))
1283                        {
1284                                $first_space = strlen ($data['command_line']);
1285                        }
1286                        if ((!$last_space = strrpos ($data['command_line'], ' ')) || ($last_space == $first_space))
1287                        {
1288                                $last_space = strlen ($data['command_line']) + 1;
1289                        }
1290                        $argv[0] = substr ($data['command_line'], 0, $first_space);
1291                        if (strlen ($argv[0]) != strlen ($data['command_line']))
1292                        {
1293                                $argv[1] = substr ($data['command_line'], $first_space + 1, $last_space - ($first_space + 1));
1294                                if ((strlen ($argv[0]) + 1 + strlen ($argv[1])) != strlen ($data['command_line']))
1295                                {
1296                                        $argv[2] = substr ($data['command_line'], $last_space + 1);
1297                                }
1298                        }
1299                        $argc = count ($argv);
1300
1301                        reset ($args);
1302                        while (list (,$arg_info) = each ($args))
1303                        {
1304                                if ($arg_info['name'] == $argv[0])
1305                                {
1306                                        $command_ok = 1;
1307                                        if (($argc == ($arg_info['params'] + 1)) || ($arg_info['params'] == -1))
1308                                        {
1309                                                $param_count_ok = 1;
1310                                        }
1311                                        break;
1312                                }
1313                        }
1314
1315                        if (!$command_ok)
1316                        {
1317//                              return E_VFS_BAD_COMMAND;
1318                                return False;
1319                        }
1320                        if (!$param_count_ok)
1321                        {
1322//                              return E_VFS_BAD_PARAM_COUNT;
1323                                return False;
1324                        }
1325
1326                        for ($i = 1; $i != ($arg_info['params'] + 1); ++$i)
1327                        {
1328                                if (substr ($argv[$i], 0, 1) == "/")
1329                                {
1330                                        $relatives[] = RELATIVE_NONE;
1331                                }
1332                                else
1333                                {
1334                                        $relatives[] = RELATIVE_ALL;
1335                                }
1336                        }
1337
1338                        $func = $arg_info['func'] ? $arg_info['func'] : $arg_info['name'];
1339
1340                        if (!$argv[2])
1341                        {
1342                                $rv = $this->$func (array(
1343                                                'string'        => $argv[1],
1344                                                'relatives'     => $relatives
1345                                        )
1346                                );
1347                        }
1348                        else
1349                        {
1350                                $rv = $this->$func (array(
1351                                                'from'  => $argv[1],
1352                                                'to'    => $argv[2],
1353                                                'relatives'     => $relatives
1354                                        )
1355                                );
1356                        }
1357
1358                        return ($rv);
1359                }
1360
1361                /* Helper functions, not public */
1362
1363                function default_values ($data, $default_values)
1364                {
1365                        for ($i = 0; list ($key, $value) = each ($default_values); ++$i)
1366                        {
1367                                if (!isset ($data[$key]))
1368                                {
1369                                        $data[$key] = $value;
1370                                }
1371                        }
1372
1373                        return $data;
1374                }
1375        }
1376
1377?>
Note: See TracBrowser for help on using the repository browser.