2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
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.
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
29 require_once 'PEAR.php';
32 * The default number of bytes for reading
34 if (!defined('FILE_DEFAULT_READSIZE')) {
35 define('FILE_DEFAULT_READSIZE', 1024, true);
39 * The maximum number of bytes for reading lines
41 if (!defined('FILE_MAX_LINE_READSIZE')) {
42 define('FILE_MAX_LINE_READSIZE', 40960, true);
46 * Whether file locks should block
48 if (!defined('FILE_LOCKS_BLOCK')) {
49 define('FILE_LOCKS_BLOCK', true, true);
53 * Mode to use for reading from files
55 define('FILE_MODE_READ', 'rb', true);
58 * Mode to use for truncating files, then writing
60 define('FILE_MODE_WRITE', 'wb', true);
63 * Mode to use for appending to files
65 define('FILE_MODE_APPEND', 'ab', true);
68 * Use this when a shared (read) lock is required
70 define('FILE_LOCK_SHARED', LOCK_SH | (FILE_LOCKS_BLOCK ? 0 : LOCK_NB), true);
73 * Use this when an exclusive (write) lock is required
75 define('FILE_LOCK_EXCLUSIVE', LOCK_EX | (FILE_LOCKS_BLOCK ? 0 : LOCK_NB), true);
78 * Class for handling files
80 * A class with common functions for writing,
81 * reading and handling files and directories
83 * @author Richard Heyes <richard@php.net>
84 * @author Tal Peer <tal@php.net>
85 * @author Michael Wallner <mike@php.net>
91 class File extends PEAR
96 * Unlocks any locked file pointers and closes all filepointers
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.
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
116 function _getFilePointer($filename, $mode, $lock = false)
118 $filePointers = &PEAR::getStaticProperty('File', 'filePointers');
120 // Win32 is case-insensitive
122 $filename = strtolower($filename);
125 // check if file pointer already exists
126 if (!isset($filePointers[$filename][$mode]) ||
127 !is_resource($filePointers[$filename][$mode])) {
129 // check if we can open the file in the desired mode
133 if (!preg_match('/^.+(?<!file):\/\//i', $filename) &&
134 !file_exists($filename)) {
135 return PEAR::raiseError("File does not exist: $filename");
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");
145 } elseif (!is_writable($dir = dirname($filename))) {
146 return PEAR::raiseError("Cannot create file in directory: $dir");
151 return PEAR::raiseError("Invalid access mode: $mode");
155 $filePointers[$filename][$mode] = @fopen($filename, $mode);
156 if (!is_resource($filePointers[$filename][$mode])) {
157 return PEAR::raiseError('Failed to open file: ' . $filename);
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");
170 return PEAR::raiseError("Could not lock file: $filename");
174 return $filePointers[$filename][$mode];
178 * Reads an entire file and returns it.
179 * Uses file_get_contents if available.
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
186 function readAll($filename, $lock = false)
188 if (false === $file = @file_get_contents($filename)) {
189 return PEAR::raiseError("Cannot read file: $filename");
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.
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
205 function read($filename, $size = FILE_DEFAULT_READSIZE, $lock = false)
207 static $filePointers;
210 return File::readAll($filename, $lock);
213 if (!isset($filePointers[$filename]) ||
214 !is_resource($filePointers[$filename])) {
215 $fp = File::_getFilePointer($filename, FILE_MODE_READ, $lock);
216 if (PEAR::isError($fp)) {
220 $filePointers[$filename] = $fp;
222 $fp = $filePointers[$filename];
225 return !feof($fp) ? fread($fp, $size) : false;
229 * Writes the given data to the given filename.
230 * Defaults to no lock, append mode.
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.
239 function write($filename, $data, $mode = FILE_MODE_APPEND, $lock = false)
241 $fp = File::_getFilePointer($filename, $mode, $lock);
242 if (PEAR::isError($fp)) {
246 if (false === $bytes = @fwrite($fp, $data, strlen($data))) {
247 return PEAR::raiseError("Cannot write data: '$data' to file: '$filename'");
254 * Reads and returns a single character from given filename
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
261 function readChar($filename, $lock = false)
263 return File::read($filename, 1, $lock);
267 * Writes a single character to a file
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
276 function writeChar($filename, $char, $mode = FILE_MODE_APPEND, $lock = false)
278 $fp = File::_getFilePointer($filename, $mode, $lock);
279 if (PEAR::isError($fp)) {
283 if (false === @fwrite($fp, $char, 1)) {
284 return PEAR::raiseError("Cannot write data: '$data' to file: '$filename'");
291 * Returns a line of the file (without trailing CRLF).
292 * Maximum read line length is FILE_MAX_LINE_READSIZE.
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
299 function readLine($filename, $lock = false)
301 static $filePointers; // Used to prevent unnecessary calls to _getFilePointer()
303 if (!isset($filePointers[$filename]) ||
304 !is_resource($filePointers[$filename])) {
305 $fp = File::_getFilePointer($filename, FILE_MODE_READ, $lock);
306 if (PEAR::isError($fp)) {
310 $filePointers[$filename] = $fp;
312 $fp = $filePointers[$filename];
319 return rtrim(fgets($fp, FILE_MAX_LINE_READSIZE), "\r\n");
323 * Writes a single line, appending a LF (by default)
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)
333 function writeLine($filename, $line, $mode = FILE_MODE_APPEND, $crlf = "\n", $lock = false)
335 $fp = File::_getFilePointer($filename, $mode, $lock);
336 if (PEAR::isError($fp)) {
340 if (false === $bytes = fwrite($fp, $line . $crlf)) {
341 return PEAR::raiseError("Cannot write data: '$data' to file: '$file'");
348 * This rewinds a filepointer to the start of a file
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
355 function rewind($filename, $mode)
357 $fp = File::_getFilePointer($filename, $mode);
358 if (PEAR::isError($fp)) {
363 return PEAR::raiseError("Cannot rewind file: $filename");
370 * Closes all open file pointers
377 $locks = &PEAR::getStaticProperty('File', 'locks');
378 $filePointers = &PEAR::getStaticProperty('File', 'filePointers');
381 for ($i = 0, $c = count($locks); $i < $c; $i++) {
382 is_resource($locks[$i]) and @flock($locks[$i], LOCK_UN);
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]);
392 unset($filePointers[$fname][$mode]);
399 * This closes an open file pointer
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
406 function close($filename, $mode)
408 $filePointers = &PEAR::getStaticProperty('File', 'filePointers');
411 $filename = strToLower($filename);
414 if (!isset($filePointers[$filename][$mode])) {
418 $fp = $filePointers[$filename][$mode];
419 unset($filePointers[$filename][$mode]);
421 if (is_resource($fp)) {
423 @flock($fp, LOCK_UN);
426 return PEAR::raiseError("Cannot close file: $filename");
434 * This unlocks a locked file pointer.
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
441 function unlock($filename, $mode)
443 $fp = File::_getFilePointer($filename, $mode);
444 if (PEAR::isError($fp)) {
448 if (!@flock($fp, LOCK_UN)) {
449 return PEAR::raiseError("Cacnnot unlock file: $filename");
458 function stripTrailingSeparators($path, $separator = DIRECTORY_SEPARATOR)
460 if ($path === $separator) {
463 return rtrim($path, $separator);
469 function stripLeadingSeparators($path, $separator = DIRECTORY_SEPARATOR)
471 if ($path === $separator) {
474 return ltrim($path, $separator);
478 * @deprecated Use File_Util::buildPath() instead.
480 function buildPath($parts, $separator = DIRECTORY_SEPARATOR)
482 require_once 'File/Util.php';
483 return File_Util::buildPath($parts, $separator);
487 * @deprecated Use File_Util::skipRoot() instead.
489 function skipRoot($path)
491 require_once 'File/Util.php';
492 return File_Util::skipRoot($path);
496 * @deprecated Use File_Util::tmpDir() instead.
498 function getTempDir()
500 require_once 'File/Util.php';
501 return File_Util::tmpDir();
505 * @deprecated Use File_Util::tmpFile() instead.
507 function getTempFile($dirname = null)
509 require_once 'File/Util.php';
510 return File_Util::tmpFile($dirname);
514 * @deprecated Use File_Util::isAbsolute() instead.
516 function isAbsolute($path)
518 require_once 'File/Util.php';
519 return File_Util::isAbsolute($path);
523 * @deprecated Use File_Util::relativePath() instead.
525 function relativePath($path, $root, $separator = DIRECTORY_SEPARATOR)
527 require_once 'File/Util.php';
528 return File_Util::relativePath($path, $root, $separator);
532 * @deprecated Use File_Util::realpath() instead.
534 function realpath($path, $separator = DIRECTORY_SEPARATOR)
536 require_once 'File/Util.php';
537 return File_Util::realpath($path, $separator);
541 PEAR::registerShutdownFunc(array('File', '_File'));