fix image text
[pear] / File.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4 /**
5  * File
6  *
7  * PHP versions 4 and 5
8  *
9  * LICENSE: This source file is subject to version 3.0 of the PHP license
10  * that is available through the world-wide-web at the following URI:
11  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
12  * the PHP License and are unable to obtain it through the web, please
13  * send a note to license@php.net so we can mail you a copy immediately.
14  *
15  * @category    File
16  * @package     File
17  * @author      Richard Heyes <richard@php.net>
18  * @author      Tal Peer <tal@php.net>
19  * @author      Michael Wallner <mike@php.net>
20  * @copyright   2002-2005 The Authors
21  * @license     http://www.php.net/license/3_0.txt  PHP License 3.0
22  * @version     CVS: $Id: File.php,v 1.38 2007/03/24 16:38:56 dufuz Exp $
23  * @link        http://pear.php.net/package/File
24  */
25
26 /**
27  * Requires PEAR
28  */
29 require_once 'PEAR.php';
30
31 /**
32  * The default number of bytes for reading
33  */
34 if (!defined('FILE_DEFAULT_READSIZE')) {
35     define('FILE_DEFAULT_READSIZE', 1024, true);
36 }
37
38 /**
39  * The maximum number of bytes for reading lines
40  */
41 if (!defined('FILE_MAX_LINE_READSIZE')) {
42     define('FILE_MAX_LINE_READSIZE', 40960, true);
43 }
44
45 /**
46  * Whether file locks should block
47  */
48 if (!defined('FILE_LOCKS_BLOCK')) {
49     define('FILE_LOCKS_BLOCK', true, true);
50 }
51
52 /**
53  * Mode to use for reading from files
54  */
55 define('FILE_MODE_READ', 'rb', true);
56
57 /**
58  * Mode to use for truncating files, then writing
59  */
60 define('FILE_MODE_WRITE', 'wb', true);
61
62 /**
63  * Mode to use for appending to files
64  */
65 define('FILE_MODE_APPEND', 'ab', true);
66
67 /**
68  * Use this when a shared (read) lock is required
69  */
70 define('FILE_LOCK_SHARED', LOCK_SH | (FILE_LOCKS_BLOCK ? 0 : LOCK_NB), true);
71
72 /**
73  * Use this when an exclusive (write) lock is required
74  */
75 define('FILE_LOCK_EXCLUSIVE', LOCK_EX | (FILE_LOCKS_BLOCK ? 0 : LOCK_NB), true);
76
77 /**
78  * Class for handling files
79  *
80  * A class with common functions for writing,
81  * reading and handling files and directories
82  *
83  * @author  Richard Heyes <richard@php.net>
84  * @author  Tal Peer <tal@php.net>
85  * @author  Michael Wallner <mike@php.net>
86  * @access  public
87  * @package File
88  *
89  * @static
90  */
91 class File extends PEAR
92 {
93     /**
94      * Destructor
95      *
96      * Unlocks any locked file pointers and closes all filepointers
97      *
98      * @access private
99      */
100     function _File()
101     {
102         File::closeAll();
103     }
104
105     /**
106      * Handles file pointers. If a file pointer needs to be opened,
107      * it will be. If it already exists (based on filename and mode)
108      * then the existing one will be returned.
109      *
110      * @access  private
111      * @param   string  $filename Filename to be used
112      * @param   string  $mode Mode to open the file in
113      * @param   mixed   $lock Type of lock to use
114      * @return  mixed   PEAR_Error on error or file pointer resource on success
115      */
116     function _getFilePointer($filename, $mode, $lock = false)
117     {
118         $filePointers = &PEAR::getStaticProperty('File', 'filePointers');
119
120         // Win32 is case-insensitive
121         if (OS_WINDOWS) {
122             $filename = strtolower($filename);
123         }
124
125         // check if file pointer already exists
126         if (!isset($filePointers[$filename][$mode]) ||
127             !is_resource($filePointers[$filename][$mode])) {
128
129             // check if we can open the file in the desired mode
130             switch ($mode)
131             {
132                 case FILE_MODE_READ:
133                     if (!preg_match('/^.+(?<!file):\/\//i', $filename) &&
134                         !file_exists($filename)) {
135                         return PEAR::raiseError("File does not exist: $filename");
136                     }
137                 break;
138
139                 case FILE_MODE_APPEND:
140                 case FILE_MODE_WRITE:
141                     if (file_exists($filename)) {
142                         if (!is_writable($filename)) {
143                             return PEAR::raiseError("File is not writable: $filename");
144                         }
145                     } elseif (!is_writable($dir = dirname($filename))) {
146                         return PEAR::raiseError("Cannot create file in directory: $dir");
147                     }
148                 break;
149
150                 default:
151                     return PEAR::raiseError("Invalid access mode: $mode");
152             }
153
154             // open file
155             $filePointers[$filename][$mode] = @fopen($filename, $mode);
156             if (!is_resource($filePointers[$filename][$mode])) {
157                 return PEAR::raiseError('Failed to open file: ' . $filename);
158             }
159         }
160
161         // lock file
162         if ($lock) {
163             $lock = $mode == FILE_MODE_READ ? FILE_LOCK_SHARED : FILE_LOCK_EXCLUSIVE;
164             $locks = &PEAR::getStaticProperty('File', 'locks');
165             if (@flock($filePointers[$filename][$mode], $lock)) {
166                 $locks[] = &$filePointers[$filename][$mode];
167             } elseif (FILE_LOCKS_BLOCK) {
168                 return PEAR::raiseError("File already locked: $filename");
169             } else {
170                 return PEAR::raiseError("Could not lock file: $filename");
171             }
172         }
173
174         return $filePointers[$filename][$mode];
175     }
176
177     /**
178      * Reads an entire file and returns it.
179      * Uses file_get_contents if available.
180      *
181      * @access  public
182      * @param   string  $filename Name of file to read from
183      * @param   mixed   $lock Type of lock to use
184      * @return  mixed   PEAR_Error if an error has occured or a string with the contents of the the file
185      */
186     function readAll($filename, $lock = false)
187     {
188         if (false === $file = @file_get_contents($filename)) {
189             return PEAR::raiseError("Cannot read file: $filename");
190         }
191         return $file;
192     }
193
194     /**
195      * Returns a specified number of bytes of a file.
196      * Defaults to FILE_DEFAULT_READSIZE.  If $size is 0, all file will be read.
197      *
198      * @access  public
199      * @param   string  $filename Name of file to read from
200      * @param   integer $size Bytes to read
201      * @param   mixed   $lock Type of lock to use
202      * @return  mixed   PEAR_Error on error or a string which contains the data read
203      *                  Will also return false upon EOF
204      */
205     function read($filename, $size = FILE_DEFAULT_READSIZE, $lock = false)
206     {
207         static $filePointers;
208
209         if ($size == 0) {
210             return File::readAll($filename, $lock);
211         }
212
213         if (!isset($filePointers[$filename]) ||
214             !is_resource($filePointers[$filename])) {
215             $fp = File::_getFilePointer($filename, FILE_MODE_READ, $lock);
216             if (PEAR::isError($fp)) {
217                 return $fp;
218             }
219
220             $filePointers[$filename] = $fp;
221         } else {
222             $fp = $filePointers[$filename];
223         }
224
225         return !feof($fp) ? fread($fp, $size) : false;
226     }
227
228     /**
229      * Writes the given data to the given filename.
230      * Defaults to no lock, append mode.
231      *
232      * @access  public
233      * @param   string  $filename Name of file to write to
234      * @param   string  $data Data to write to file
235      * @param   string  $mode Mode to open file in
236      * @param   mixed   $lock Type of lock to use
237      * @return  mixed   PEAR_Error on error or number of bytes written to file.
238      */
239     function write($filename, $data, $mode = FILE_MODE_APPEND, $lock = false)
240     {
241         $fp = File::_getFilePointer($filename, $mode, $lock);
242         if (PEAR::isError($fp)) {
243             return $fp;
244         }
245
246         if (false === $bytes = @fwrite($fp, $data, strlen($data))) {
247             return PEAR::raiseError("Cannot write data: '$data' to file: '$filename'");
248         }
249
250         return $bytes;
251     }
252
253     /**
254      * Reads and returns a single character from given filename
255      *
256      * @access  public
257      * @param   string  $filename Name of file to read from
258      * @param   mixed   $lock Type of lock to use
259      * @return  mixed   PEAR_Error on error or one character of the specified file
260      */
261     function readChar($filename, $lock = false)
262     {
263         return File::read($filename, 1, $lock);
264     }
265
266     /**
267      * Writes a single character to a file
268      *
269      * @access  public
270      * @param   string  $filename Name of file to write to
271      * @param   string  $char Character to write
272      * @param   string  $mode Mode to use when writing
273      * @param   mixed   $lock Type of lock to use
274      * @return  mixed   PEAR_Error on error, or 1 on success
275      */
276     function writeChar($filename, $char, $mode = FILE_MODE_APPEND, $lock = false)
277     {
278         $fp = File::_getFilePointer($filename, $mode, $lock);
279         if (PEAR::isError($fp)) {
280             return $fp;
281         }
282
283         if (false === @fwrite($fp, $char, 1)) {
284             return PEAR::raiseError("Cannot write data: '$data' to file: '$filename'");
285         }
286
287         return 1;
288     }
289
290     /**
291      * Returns a line of the file (without trailing CRLF).
292      * Maximum read line length is FILE_MAX_LINE_READSIZE.
293      *
294      * @access  public
295      * @param   string  $filename Name of file to read from
296      * @param   boolean $lock Whether file should be locked
297      * @return  mixed   PEAR_Error on error or a string containing the line read from file
298      */
299     function readLine($filename, $lock = false)
300     {
301         static $filePointers; // Used to prevent unnecessary calls to _getFilePointer()
302
303         if (!isset($filePointers[$filename]) ||
304             !is_resource($filePointers[$filename])) {
305             $fp = File::_getFilePointer($filename, FILE_MODE_READ, $lock);
306             if (PEAR::isError($fp)) {
307                 return $fp;
308             }
309
310             $filePointers[$filename] = $fp;
311         } else {
312             $fp = $filePointers[$filename];
313         }
314
315         if (feof($fp)) {
316             return false;
317         }
318
319         return rtrim(fgets($fp, FILE_MAX_LINE_READSIZE), "\r\n");
320     }
321
322     /**
323      * Writes a single line, appending a LF (by default)
324      *
325      * @access  public
326      * @param   string  $filename Name of file to write to
327      * @param   string  $line Line of data to be written to file
328      * @param   string  $mode Write mode, can be either FILE_MODE_WRITE or FILE_MODE_APPEND
329      * @param   string  $crlf The CRLF your system is using. UNIX = \n Windows = \r\n Mac = \r
330      * @param   mixed   $lock Whether to lock the file
331      * @return  mixed   PEAR_Error on error or number of bytes written to file (including appended crlf)
332      */
333     function writeLine($filename, $line, $mode = FILE_MODE_APPEND, $crlf = "\n", $lock = false)
334     {
335         $fp = File::_getFilePointer($filename, $mode, $lock);
336         if (PEAR::isError($fp)) {
337             return $fp;
338         }
339
340         if (false === $bytes = fwrite($fp, $line . $crlf)) {
341             return PEAR::raiseError("Cannot write data: '$data' to file: '$file'");
342         }
343
344         return $bytes;
345     }
346
347     /**
348      * This rewinds a filepointer to the start of a file
349      *
350      * @access  public
351      * @param   string  $filename The filename
352      * @param   string  $mode Mode the file was opened in
353      * @return  mixed   PEAR Error on error, true on success
354      */
355     function rewind($filename, $mode)
356     {
357         $fp = File::_getFilePointer($filename, $mode);
358         if (PEAR::isError($fp)) {
359             return $fp;
360         }
361
362         if (!@rewind($fp)) {
363             return PEAR::raiseError("Cannot rewind file: $filename");
364         }
365
366         return true;
367     }
368
369     /**
370      * Closes all open file pointers
371      *
372      * @access  public
373      * @return  void
374      */
375     function closeAll()
376     {
377         $locks = &PEAR::getStaticProperty('File', 'locks');
378         $filePointers = &PEAR::getStaticProperty('File', 'filePointers');
379
380         // unlock files
381         for ($i = 0, $c = count($locks); $i < $c; $i++) {
382             is_resource($locks[$i]) and @flock($locks[$i], LOCK_UN);
383         }
384
385         // close files
386         if (!empty($filePointers)) {
387             foreach ($filePointers as $fname => $modes) {
388                 foreach (array_keys($modes) as $mode) {
389                     if (is_resource($filePointers[$fname][$mode])) {
390                         @fclose($filePointers[$fname][$mode]);
391                     }
392                     unset($filePointers[$fname][$mode]);
393                 }
394             }
395         }
396     }
397
398     /**
399      * This closes an open file pointer
400      *
401      * @access  public
402      * @param   string  $filename The filename that was opened
403      * @param   string  $mode Mode the file was opened in
404      * @return  mixed   PEAR Error on error, true otherwise
405      */
406     function close($filename, $mode)
407     {
408         $filePointers = &PEAR::getStaticProperty('File', 'filePointers');
409
410         if (OS_WINDOWS) {
411             $filename = strToLower($filename);
412         }
413
414         if (!isset($filePointers[$filename][$mode])) {
415             return true;
416         }
417
418         $fp = $filePointers[$filename][$mode];
419         unset($filePointers[$filename][$mode]);
420
421         if (is_resource($fp)) {
422             // unlock file
423             @flock($fp, LOCK_UN);
424             // close file
425             if (!@fclose($fp)) {
426                 return PEAR::raiseError("Cannot close file: $filename");
427             }
428         }
429
430         return true;
431     }
432
433     /**
434      * This unlocks a locked file pointer.
435      *
436      * @access  public
437      * @param   string  $filename The filename that was opened
438      * @param   string  $mode Mode the file was opened in
439      * @return  mixed   PEAR Error on error, true otherwise
440      */
441     function unlock($filename, $mode)
442     {
443         $fp = File::_getFilePointer($filename, $mode);
444         if (PEAR::isError($fp)) {
445             return $fp;
446         }
447
448         if (!@flock($fp, LOCK_UN)) {
449             return PEAR::raiseError("Cacnnot unlock file: $filename");
450         }
451
452         return true;
453     }
454
455     /**
456      * @deprecated
457      */
458     function stripTrailingSeparators($path, $separator = DIRECTORY_SEPARATOR)
459     {
460         if ($path === $separator) {
461             return $path;
462         }
463         return rtrim($path, $separator);
464     }
465
466     /**
467      * @deprecated
468      */
469     function stripLeadingSeparators($path, $separator = DIRECTORY_SEPARATOR)
470     {
471         if ($path === $separator) {
472             return $path;
473         }
474         return ltrim($path, $separator);
475     }
476
477     /**
478      * @deprecated Use File_Util::buildPath() instead.
479      */
480     function buildPath($parts, $separator = DIRECTORY_SEPARATOR)
481     {
482         require_once 'File/Util.php';
483         return File_Util::buildPath($parts, $separator);
484     }
485
486     /**
487      * @deprecated Use File_Util::skipRoot() instead.
488      */
489     function skipRoot($path)
490     {
491         require_once 'File/Util.php';
492         return File_Util::skipRoot($path);
493     }
494
495     /**
496      * @deprecated Use File_Util::tmpDir() instead.
497      */
498     function getTempDir()
499     {
500         require_once 'File/Util.php';
501         return File_Util::tmpDir();
502     }
503
504     /**
505      * @deprecated Use File_Util::tmpFile() instead.
506      */
507     function getTempFile($dirname = null)
508     {
509         require_once 'File/Util.php';
510         return File_Util::tmpFile($dirname);
511     }
512
513     /**
514      * @deprecated Use File_Util::isAbsolute() instead.
515      */
516     function isAbsolute($path)
517     {
518         require_once 'File/Util.php';
519         return File_Util::isAbsolute($path);
520     }
521
522     /**
523      * @deprecated Use File_Util::relativePath() instead.
524      */
525     function relativePath($path, $root, $separator = DIRECTORY_SEPARATOR)
526     {
527         require_once 'File/Util.php';
528         return File_Util::relativePath($path, $root, $separator);
529     }
530
531     /**
532      * @deprecated Use File_Util::realpath() instead.
533      */
534     function realpath($path, $separator = DIRECTORY_SEPARATOR)
535     {
536         require_once 'File/Util.php';
537         return File_Util::realpath($path, $separator);
538     }
539 }
540
541 PEAR::registerShutdownFunc(array('File', '_File'));
542
543 ?>