Package home | Report new bug | New search | Development Roadmap Status: Open | Feedback | All | Closed Since Version 1.4.1

Request #1542 Feature Request: adding some utility methods
Submitted: 2004-06-02 06:23 UTC Modified: 2004-12-16 09:55 UTC
From: mike Assigned: mike
Status: Closed Package: File
PHP Version: Irrelevant OS: N/A
Roadmaps: (Not assigned)    
Subscription  


 [2004-06-02 06:23 UTC] mike
Description: ------------ Here's the patch - if someone could review/integrate it: Adds: File::realPath($path) File::relativePath($path) File::pathInRoot($path, $inPath) File::deltree($path) Index: File.php =================================================================== RCS file: /repository/pear/File/File.php,v retrieving revision 1.24 diff -u -r1.24 File.php --- File.php 28 Jan 2003 11:19:27 -0000 1.24 +++ File.php 2 Jun 2004 11:26:23 -0000 @@ -529,6 +529,140 @@ return false; } + + /** + * Real Path + * + * This method works with non-existant paths. + * + * @static + * @access public + * @return string Returns the built path. + * @param string $path + */ + function realPath($path) + { + if (empty($path)) { + return null; + } + + $drive = ''; + if (DIRECTORY_SEPARATOR == '\\') { + $path = preg_replace('/[\\\\\/]/', DIRECTORY_SEPARATOR, $path); + if (preg_match('/([a-zA-Z]\:)(.*)/', $path, $matches)) { + $drive = $matches[1]; + $path = $matches[2]; + } else { + $cwd = getcwd(); + $drive = substr($cwd, 0, 2); + if ($path{0} !== DIRECTORY_SEPARATOR) { + $path = substr($cwd, 3) . DIRECTORY_SEPARATOR . $path; + } + } + } else { + if ($path{0} !== DIRECTORY_SEPARATOR) { + $cwd = getcwd(); + $path = $cwd . DIRECTORY_SEPARATOR . File::relativePath($path, $cwd); + } + } + + $dirStack = array(); + foreach (explode(DIRECTORY_SEPARATOR, $path) as $dir) { + if ($dir === '' || $dir == '.') { + continue; + } + if ($dir == '..') { + array_pop($dirStack); + } else { + $dirStack[] = $dir; + } + } + + return $drive . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $dirStack); + } + + /** + * Relative Path + * + * Get path relative to another path. + * + * @static + * @access public + * @return string Returns the realtive path. + * @param string $path + * @param string $root + */ + function relativePath($path, $root) + { + $dirs = explode(DIRECTORY_SEPARATOR, File::realPath($path)); + $comp = explode(DIRECTORY_SEPARATOR, File::realPath($root)); + + foreach ($comp as $i => $part) { + if (isset($dirs[$i]) && $part == $dirs[$i]) { + unset($dirs[$i], $comp[$i]); + } else { + break; + } + } + + return + str_repeat('..' . DIRECTORY_SEPARATOR, count($comp)) . + implode(DIRECTORY_SEPARATOR, $dirs); + } + + /** + * Path In Path + * + * Check if path is within another path. + * + * @access public + * @return bool Retrurns true if path is above $inPath. + * @param string $path + */ + function pathInRoot($path, $inPath, $caseSensitivity = OS_UNIX) + { + return false !== $caseSensitivity ? + strstr(File::realPath($path), File::realPath($inPath)) : + stristr(File::realPath($path), File::realPath($inPath)); + } + + /** + * Deltree + * + * Delete a directory tree. + * + * @static + * @access public + * @return mixed Returns true on success or PEAR_Error on failure. + * @param string $path + */ + function deltree($path) + { + $d = Dir($path); + while ($file = $d->read()) { + if ($file == '.' || $file == '..') { + continue; + } + + $fullpath = $path . DIRECTORY_SEPARATOR .$file; + + if (is_dir($fullpath)) { + if (is_a($e = File::deltree($fullpath), 'PEAR_Error')) { + return $e; + } + } else { + if (!@unlink($fullpath)) { + return PEAR::raiseError("unlink($fullpath) failed: $php_errormsg"); + } + } + } + $d->close(); + + if (!@rmdir($path)) { + return PEAR::raiseError("rmdir($path) failed: $php_errormsg"); + } + return true; + } } PEAR::registerShutdownFunc(array('File', '_File'));

Comments

 [2004-06-02 06:53 UTC] tacker
Another Method to be added. Adds: File::readReverse($filename, $limit = 0, $crlf = "\n", $readbytes = FILE_DEFAULT_READSIZE) ? tests/numbered_test.csv ? tests/readreverse.php Index: File.php =================================================================== RCS file: /repository/pear/File/File.php,v retrieving revision 1.24 diff -u -3 -p -u -r1.24 File.php --- File.php 28 Jan 2003 11:19:27 -0000 1.24 +++ File.php 2 Jun 2004 11:59:44 -0000 @@ -529,8 +529,125 @@ class File extends PEAR return false; } + + /** + * Returns an array of the files lines, starting + * from the end of the file + * + * @access public + * @param string $filename The file to read + * @param int $limit Limit the number of read rows to $limit + * @param string $crlf The CRLF your system is using. UNIX = \n Windows = \r\n Mac = \r + * @param int $readbytes Amount of bytes to read per loop + * @return mixed Array on success, Pear Error otherwise + */ + function readReverse($filename, $limit = 0, $crlf = "\n", $readbytes = FILE_DEFAULT_READSIZE) + { + // check if file exists + if(!is_file($filename)) return PEAR::raiseError(sprintf('Not a file: "%s"', $filename)); + // Try to open the file + if(!$fp = fopen($filename, 'r')) return PEAR::raiseError(sprintf('Failed to open file: "%s"', $filename)); + // Get a shared lock on the file + if(!flock($fp, FILE_LOCK_SHARED)) return PEAR::raiseError(sprintf('Failed to get a shared lock on file: "%s"', $filename)); + // Go the the end of the file + fseek($fp, -1, SEEK_END); + // Get the file's size + $filesize = ftell($fp); + // Is an empty file? + if($filesize == 0) { // Yes, it is + // Unlock and close it + flock($fp, LOCK_UN); + fclose($fp); + // return an empty array + return array(); + } + // Set $readbytes to $filesize, if $filesize is smaller than $readbytes + if($filesize < $readbytes) $readbytes = $filesize; + // This stores the number of found lines + $nLinesFound = 0; + // Now start to read in the file + // This is done by moving the filepointer backwards until the + // beginning of the file is reached + // In every cycle $readbytes bytes are read from the file + $currpos = $filesize; + while($currpos >= 0) { + // next fp position - move back $readbytes + $newpos = $currpos - $readbytes; + // if the new position is negative (would be before the + // beginning of the file) set it to zero and read only + // the remaining amount of bytes + if($newpos < 0) { + $readbytes += $newpos; + $newpos = 0; + } + // Move the fp to the new positions + fseek($fp, $newpos); + // Update current position + $currpos = $newpos; + // If current position is zero, we have reached the + // file's beginning -> end the which loop after this run + if($currpos == 0) $currpos = -1; + // read a 'block' of data + $block = fread($fp, $readbytes); + // append part of line from previous block if there is one + if(isset($saveLinePart)) { + $block .= $saveLinePart; + // Free the store + unset($saveLinePart); + } + // check if we have at least one line-break + if(strpos($block, $crlf) === false) { + // if this is the first row append $saveForNext + if($currpos == -1) { + $block .= $saveForNext; + } else { + // if not save this block and do next cycle + $saveLinePart = $block; + continue; + } + } + // extract the lines by splitting it by the linebreak + $lines = explode($crlf, $block); + // first row wille be returned as a string -> enclose in array + if(is_string($lines)) { + $lines = array($lines); + } + + // walk the lines + while($line = array_pop($lines) or !is_null($line)) { + // This is the last line of the block -> keep it for the next block + if(count($lines) == 0) { + $saveForNext = $line; + break; + } + // Is there a leftover from the previous block? + if(isset($saveForNext)) { + // Append it + $line .= $saveForNext; + // Empty the storage + unset($saveForNext); + } + // add to return values + $return[] = $line; + // Increase the counter for found lines + $nLinesFound++; + // Already found enough lines? + if($limit > 0 and $nLinesFound >= $limit) break 2; + } + } + // If we have reached the beginning of the file there + // will be data left in $saveForNext -> append it + if(isset($saveForNext)) $return[] = $saveForNext; + + // Unlock and close the file + flock($fp, LOCK_UN); + fclose($fp); + // Return the lines + if(!isset($return)) return array(); + return $return; + } } PEAR::registerShutdownFunc(array('File', '_File')); -?> +?> \ No newline at end of file
 [2004-06-02 07:07 UTC] tacker
The files for my patch are there: http://www.tacker.org/transfer/PEAR_File/File.tgz
 [2004-07-20 11:45 UTC] jausions
See System::rm() for deleting tree. Maybe it would be good to have that referenced in the File package doc. -Philippe
 [2004-12-16 09:55 UTC] mike
This bug has been fixed in CVS. In case this was a documentation problem, the fix will show up at the end of next Sunday (CET) on pear.php.net. In case this was a pear.php.net website problem, the change will show up on the website in short time. Thank you for the report, and for helping us make PEAR better.