| // | Tal Peer | // +----------------------------------------------------------------------+ /* * Example 1: * $stdin = File::readAll('php://stdin'); * * Example 2: * while ($data = File::read('/blaat/bar')) { * // Code... * } */ require_once('PEAR.php'); /** * The default number of bytes for reading * @const FILE_DEFAULT_READSIZE */ define('FILE_DEFAULT_READSIZE', 1024, true); /** * Mode to use for reading from files * @const FILE_MODE_READ */ define('FILE_MODE_READ', 'rb', true); /** * Mode to use for truncating files, then writing * @const FILE_MODE_WRITE */ define('FILE_MODE_WRITE', 'wb', true); /** * Mode to use for appending to files * @const FILE_MODE_APPEND */ define('FILE_MODE_APPEND', 'ab', true); /** * Use this when a shared (read) lock is required * @const FILE_LOCK_SHARED */ define('FILE_LOCK_SHARED', LOCK_SH, true); /** * Use this when an exclusive (write) lock is required * @const FILE_LOCK_EXCLUSIVE */ define('FILE_LOCK_EXCLUSIVE', LOCK_EX, true); /** * Class for handling files * * A class with common functions for writing, * reading and handling files and directories * * * @author Richard Heyes * @author Tal Peer * @access public * @version 0.9 * @package File */ class File extends PEAR { /** * Destructor * * Unlocks any locked file pointers and closes all filepointers * @access private */ function _File() { $locks = &PEAR::getStaticProperty('File', 'locks'); $filePointers = &PEAR::getStaticProperty('File', 'filePointers'); for ($i = 0; $i < count($locks); $i++) { flock($this->locks[$i], LOCK_UN); } if (!empty($filePointers)) { foreach ($filePointers as $fname => $value) { foreach ($value as $mode => $value) { @fclose($filePointers[$fname][$mode]); } } } } /** * Handles file pointers. If a file pointer needs to be opened, * it will be. If it already exists (based on filename and mode) * then the existing one will be returned. * * @access private * @param string $filename Filename to be used * @param string $mode Mode to open the file in * @param mixed $lock Type of lock to use * @return mixed PEAR_Error on error and file pointer resource on success */ function &_getFilePointer($filename, $mode, $lock = false) { $filePointers = &PEAR::getStaticProperty('File', 'filePointers'); // Need to open first... if (!isset($filePointers[$filename][$mode]) OR !is_resource($filePointers[$filename][$mode])) { // Check it exists if (FILE_MODE_READ == $mode AND !preg_match('/^(http|https|ftp|php):\/\//i', $filename) AND !file_exists($filename)) { return PEAR::raiseError('File does not exist: ' . $filename); // Writeable? } elseif ( (FILE_MODE_WRITE == $mode OR FILE_MODE_APPEND == $mode) AND !file_exists($filename) AND !is_writeable(dirname($filename))) { return PEAR::raiseError('Could not create file: ' . $filename); } elseif ( (FILE_MODE_WRITE == $mode OR FILE_MODE_APPEND == $mode) AND !is_writeable(dirname($filename))) { return PEAR::raiseError('File is not writeable: ' . $filename); } $filePointers[$filename][$mode] = @fopen($filename, $mode); if (false === $filePointers[$filename][$mode]) { return PEAR::raiseError('Failed to open file: ' . $filename); } } // Lock it? if ($lock) { $locks = &PEAR::getStaticProperty('File', 'locks'); if (flock($filePointers[$filename][$mode], $lock)) { $this->locks[] = &$filePointers[$filename][$mode]; } } return $filePointers[$filename][$mode]; } /** * Reads an entire file and returns it. * * @access public * @param string $filename Name of file to read from * @param mixed $lock Type of lock to use * @return mixed PEAR_Error if an error has occured or a string with the contents of the the file */ function readAll($filename, $lock = false) { $file = ''; while (($tmp = File::read($filename, FILE_DEFAULT_READSIZE, $lock)) !== FALSE) { if (PEAR::isError($tmp)) { return $tmp; } $file .= $tmp; } return $file; } /** * Returns a specified number of bytes of a file. Defaults to 1024. * * @access public * @param string $filename Name of file to read from * @param integer $size Bytes to read * @param mixed $lock Type of lock to use * @return mixed PEAR_Error on error or a string which contains the data read * Will also return false upon EOF */ function read($filename, $size = FILE_DEFAULT_READSIZE, $lock = false) { static $filePointers; // Used to prevent unnecessary calls to _getFilePointer() if (0 == $size) { return File::readAll($filename); } if (!isset($filePointers[$filename]) OR !is_resource($filePointers[$filename])) { if (PEAR::isError($fp = &File::_getFilePointer($filename, FILE_MODE_READ, $lock))) { return $fp; } $filePointers[$filename] = &$fp; } else { $fp = &$filePointers[$filename]; } return !feof($fp) ? fread($fp, $size) : false; } /** * Writes the given data to the given filename. Defaults to no lock, append mode. * * @access public * @param string $filename Name of file to write to * @param string $data Data to write to file * @param string $mode Mode to open file in * @param mixed $lock Type of lock to use * @return mixed PEAR_Error on error or number of bytes written to file. */ function write($filename, $data, $mode = FILE_MODE_APPEND, $lock = false) { if (!PEAR::isError($fp = &File::_getFilePointer($filename, $mode, $lock))) { if (($bytes = fwrite($fp, $data, strlen($data))) == -1) { return PEAR::raiseError(sprintf('fwrite() call failed to write data: "%s" to file: "%s"', $data, $filename)); } else { return $bytes; } } return $fp; } /** * Reads and returns a single character from given filename * * @access public * @param string $filename Name of file to read from * @param mixed $lock Type of lock to use * @return mixed PEAR_Error on error or one character of the specified file */ function readChar($filename, $lock = false) { return File::read($filename, 1, $lock); } /** * Writes a single character to a file * * @access public * @param string $filename Name of file to write to * @param string $char Character to write * @param string $mode Mode to use when writing * @param mixed $lock Type of lock to use * @return mixed PEAR_Error on error, or 1 on success */ function writeChar($filename, $char, $mode = FILE_MODE_APPEND, $lock = false) { if (!PEAR::isError($fp = &File::_getFilePointer($filename, $mode, $lock))) { if (fwrite($fp, $char, 1) == -1) { return PEAR::raiseError(sprintf('fwrite() call failed to write data: "%s" to file: "%s"', $data, $filename)); } else { return 1; } } return $fp; } /** * Returns a line of the file * * @access public * @param string $filename Name of file to read from * @param boolean $lock Type of lock to use * @return mixed PEAR_Error on error or a string containing the line read from file */ function readLine($filename, $lock = false) { static $filePointers; // Used to prevent unnecessary calls to _getFilePointer() if (!isset($filePointers[$filename]) OR !is_resource($filePointers[$filename])) { if (PEAR::isError($fp = &File::_getFilePointer($filename, FILE_MODE_READ, $lock))) { return $fp; } $filePointers[$filename] = &$fp; } else { $fp = &$filePointers[$filename]; } if (feof($fp)) { return false; } $fileString = ''; while (($fileChar = fgetc($fp)) != "\n" AND !feof($fp)) { $fileString .= $fileChar; } return substr($fileString, -1) == "\r" ? substr($fileString, 0, -1) : $fileString; } /** * Writes a single line, appending a LF (by default) * * @access public * @param string $filename Name of file to write to * @param string $line Line of data to be written to file * @param string $mode Write mode, can be either FILE_MODE_WRITE or FILE_MODE_APPEND * @param string $crlf The CRLF your system is using. UNIX = \n Windows = \r\n Mac = \r * @param mixed $lock Type of lock to use * @return mixed PEAR_Error on error or number of bytes written to file (including appended crlf) */ function writeLine($filename, $line, $mode = FILE_MODE_APPEND, $crlf = "\n", $lock = false) { if(!PEAR::isError($fp = &File::_getFilePointer($filename, $mode, $lock))){ if (($bytes = fwrite($fp, $line . $crlf)) == -1) { return PEAR::raiseError(sprintf('fwrite() call failed to write data: "%s" to file: "%s"', $data, $filename)); } else { return $bytes; } } return $fp; } /** * This rewinds a filepointer to the start of a file * * @access public * @param string $filename The filename * @param string $mode Mode the file was opened in * @return mixed PEAR Error on error, true on success */ function rewind($filename, $mode) { if (!PEAR::isError($fp = &File::_getFilePointer($filename, $mode))) { return rewind($fp) ? true : PEAR::raiseError('Failed to rewind file: ' . $filename); } return $fp; } /** * This closes an open file pointer * * @access public * @param string $filename The filename that was opened * @param string $mode Mode the file was opened in * @return mixed PEAR Error on error, true otherwise */ function close($filename, $mode) { if (!PEAR::isError($fp = &File::_getFilePointer($filename, $mode))) { $filePointers = &PEAR::getStaticProperty('File', 'filePointers'); unset($filePointers[$filename][$mode]); return fclose($fp) ? true : PEAR::raiseError('Failed to close file: ' . $filename); } return $fp; } /** * This unlocks a locked file pointer. * * @access public * @param string $filename The filename that was opened * @param string $mode Mode the file was opened in * @return mixed PEAR Error on error, true otherwise */ function unlock($filename, $mode) { if (!PEAR::isError($fp = &FILE::_getFilePointer($filename, $mode))) { return flock($fp, LOCK_UN) ? true : PEAR::raiseError('Failed to unlock file: ' . $filename); } return $fp; } /** * Returns a string path built from the array $pathParts. Where a join occurs * multiple separators are removed. Joins using the optional separator, defaulting * to the PHP DIRECTORY_SEPARATOR constant. * * @access public * @param array $parts Array containing the parts to be joined * @param string $separator The system directory seperator */ function buildPath($parts, $separator = DIRECTORY_SEPARATOR) { for ($i = 0; $i < count($parts); $i++) { if (0 == $i) { $parts[$i] = File::stripTrailingSeparators($parts[$i], $separator); } elseif(count($parts) - 1 == $i) { $parts[$i] = File::stripLeadingSeparators($parts[$i], $separator); } else { $parts[$i] = File::stripTrailingSeparators($parts[$i], $separator); $parts[$i] = File::stripLeadingSeparators($parts[$i], $separator); } } return implode($separator, $parts); } /** * Strips trailing separators from the given path * * @access public * @param string $path Path to use * @param string $separator Separator to look for * @return string Resulting path */ function stripTrailingSeparators($path, $separator = DIRECTORY_SEPARATOR) { while (substr($path, -1) == $separator) { $path = substr($path, 0, -1); } return $path; } /** * Strips leading separators from the given path * * @access public * @param string $path Path to use * @param string $separator Separator to look for * @return string Resulting path */ function stripLeadingSeparators($path, $separator = DIRECTORY_SEPARATOR) { while (substr($path, 0, 1) == $separator) { $path = substr($path, 1); } return $path; } /** * Returns a path without leading / or C:\. If this is not * present the path is returned as is. * * @access public * @param string $path The path to be processed * @return string The processed path or the path as is */ function skipRoot($path) { if (File::isAbsolute($path)) { if (DIRECTORY_SEPARATOR == "/") { return substr($path,1); } elseif(DIRECTORY_SEPARATOR == "\\") { return substr($path, 3); } } else { return $path; } } /** * Returns the temp directory according to either the TMP, TMPDIR, or TEMP env * variables. If these are not set it will also check for the existence of * /tmp, %WINDIR%\temp * * @access public * @return string The system tmp directory */ function getTempDir() { if (OS_WINDOWS){ if (isset($_ENV['TEMP'])) { return $_ENV['TEMP']; } if (isset($_ENV['TMP'])) { return $_ENV['TMP']; } if (isset($_ENV['windir'])) { return $_ENV['windir'] . '\temp'; } return $_ENV['SystemRoot'] . '\temp'; } if (isset($_ENV['TMPDIR'])) { return $_ENV['TMPDIR']; } return '/tmp'; } /** * Returns a temporary filename using tempnam() and the above getTmpDir() function. * * @access public * @param string $dirname Optional directory name for the tmp file * @return string Filename and path of the tmp file */ function getTempFile($dirname = NULL) { if (is_null($dirname)) { $dirname = File::getTempDir(); } return tempnam($dirname, 'temp.'); } /** * Returns boolean based on whether given path is absolute or not. * * @access public * @param string $path Given path * @return boolean True if the path is absolute, false if it is not */ function isAbsolute($path) { if (preg_match("/\.\./", $path)) { return false; } if (DIRECTORY_SEPARATOR == '/' AND (substr($path, 0, 1) == '/' OR substr($path, 0, 1) == '~')) { return true; } elseif(DIRECTORY_SEPARATOR == '\\' AND preg_match('/^[a-z]:\\\/i', $path)) { return true; } return false; } } PEAR::registerShutdownFunc(array('File', '_File')); ?>