From 26d79b1eca7092bac5f3e5b2c2f16d4a6849b2e8 Mon Sep 17 00:00:00 2001 From: wbond Date: Wed, 16 Dec 2009 07:03:54 +0000 Subject: [PATCH] BackwardsCompatibilityBreak - Renamed fFile::getFilename() to fFile::getName(), fFile::getFilesize() to fFile::getSize(), fFile::getDirectory() to fFile::getParent(), fDirectory::getFilesize() to fDirectory::getSize(). Added fDirectory::getName(), fDirectory::move() and fFile::move(). --- classes/fDirectory.php | 108 +++++++++++++++++++++-------- classes/fFile.php | 153 +++++++++++++++++++++++++---------------- classes/fORMFile.php | 7 +- 3 files changed, 176 insertions(+), 92 deletions(-) diff --git a/classes/fDirectory.php b/classes/fDirectory.php index 154d78a4..3e3666a6 100644 --- a/classes/fDirectory.php +++ b/classes/fDirectory.php @@ -9,7 +9,8 @@ * @package Flourish * @link http://flourishlib.com/fDirectory * - * @version 1.0.0b7 + * @version 1.0.0b8 + * @changes 1.0.0b8 Backwards Compatibility Break - renamed ::getFilesize() to ::getSize(), added ::move() [wb, 2009-12-16] * @changes 1.0.0b7 Fixed ::__construct() to throw an fValidationException when the directory does not exist [wb, 2009-08-21] * @changes 1.0.0b6 Fixed a bug where deleting a directory would prevent any future operations in the same script execution on a file or directory with the same path [wb, 2009-08-20] * @changes 1.0.0b5 Added the ability to skip checks in ::__construct() for better performance in conjunction with fFilesystem::createObject() [wb, 2009-08-06] @@ -211,31 +212,13 @@ public function delete() /** - * Gets the disk usage of the directory and all files and folders contained within + * Gets the name of the directory * - * This method may return incorrect results if files over 2GB exist and the - * server uses a 32 bit operating system - * - * @param boolean $format If the filesize should be formatted for human readability - * @param integer $decimal_places The number of decimal places to format to (if enabled) - * @return integer|string If formatted, a string with filesize in b/kb/mb/gb/tb, otherwise an integer + * @return string The name of the directory */ - public function getFilesize($format=FALSE, $decimal_places=1) + public function getName() { - $this->tossIfException(); - - $size = 0; - - $children = $this->scan(); - foreach ($children as $child) { - $size += $child->getFilesize(); - } - - if (!$format) { - return $size; - } - - return fFilesystem::formatFilesize($size, $decimal_places); + return fFilesystem::getPathInfo($this->directory, 'basename'); } @@ -256,7 +239,7 @@ public function getParent() ); } - return new fDirectory(); + return new fDirectory($dirname); } @@ -280,6 +263,35 @@ public function getPath($translate_to_web_path=FALSE) } + /** + * Gets the disk usage of the directory and all files and folders contained within + * + * This method may return incorrect results if files over 2GB exist and the + * server uses a 32 bit operating system + * + * @param boolean $format If the filesize should be formatted for human readability + * @param integer $decimal_places The number of decimal places to format to (if enabled) + * @return integer|string If formatted, a string with filesize in b/kb/mb/gb/tb, otherwise an integer + */ + public function getSize($format=FALSE, $decimal_places=1) + { + $this->tossIfException(); + + $size = 0; + + $children = $this->scan(); + foreach ($children as $child) { + $size += $child->getSize(); + } + + if (!$format) { + return $size; + } + + return fFilesystem::formatFilesize($size, $decimal_places); + } + + /** * Check to see if the current directory is writable * @@ -294,14 +306,47 @@ public function isWritable() /** - * Renames the current directory, overwriting any existing file/directory + * Moves the current directory into a different directory + * + * Please note that ::rename() will rename a directory in its current + * parent directory or rename it into a different parent directory. + * + * If the current directory's name already exists in the new parent + * directory and the overwrite flag is set to false, the name will be + * changed to a unique name. + * + * This operation will be reverted if a filesystem transaction is in + * progress and is later rolled back. + * + * @throws fValidationException When the new parent directory passed is not a directory, is not readable or is a sub-directory of this directory + * + * @param fDirectory|string $new_parent_directory The directory to move this directory into + * @param boolean $overwrite If the current filename already exists in the new directory, `TRUE` will cause the file to be overwritten, `FALSE` will cause the new filename to change + * @return fDirectory The directory object, to allow for method chaining + */ + public function move($new_parent_directory, $overwrite) + { + if (!$new_parent_directory instanceof fDirectory) { + $new_parent_directory = new fDirectory($new_parent_directory); + } + + if (strpos($new_parent_directory->getPath(), $this->getPath()) === 0) { + throw new fValidationException('It is not possible to move a directory into one of its sub-directories'); + } + + return $this->rename($new_parent_directory->getPath() . $this->getName(), $overwrite); + } + + + /** + * Renames the current directory * * This operation will NOT be performed until the filesystem transaction * has been committed, if a transaction is in progress. Any non-Flourish * code (PHP or system) will still see this directory (and all contained * files/dirs) as existing with the old paths until that point. * - * @param string $new_dirname The new full path to the directory + * @param string $new_dirname The new full path to the directory or a new name in the current parent directory * @param boolean $overwrite If the new dirname already exists, TRUE will cause the file to be overwritten, FALSE will cause the new filename to change * @return void */ @@ -316,6 +361,11 @@ public function rename($new_dirname, $overwrite) ); } + // If the dirname does not contain any folder traversal, rename the dir in the current parent directory + if (preg_match('#^[^/\\\\]+$#D', $new_dirname)) { + $new_dirname = $this->getParent()->getPath() . $new_dirname; + } + $info = fFilesystem::getPathInfo($new_dirname); if (!file_exists($info['dirname'])) { @@ -325,9 +375,6 @@ public function rename($new_dirname, $overwrite) ); } - // Make the dirname absolute - $new_dirname = fDirectory::makeCanonical(realpath($new_dirname)); - if (file_exists($new_dirname)) { if (!is_writable($new_dirname)) { throw new fEnvironmentException( @@ -350,6 +397,9 @@ public function rename($new_dirname, $overwrite) rename($this->directory, $new_dirname); + // Make the dirname absolute + $new_dirname = fDirectory::makeCanonical(realpath($new_dirname)); + // Allow filesystem transactions if (fFilesystem::isInsideTransaction()) { fFilesystem::rename($this->directory, $new_dirname); diff --git a/classes/fFile.php b/classes/fFile.php index 40b37e85..72c1a37b 100644 --- a/classes/fFile.php +++ b/classes/fFile.php @@ -9,7 +9,8 @@ * @package Flourish * @link http://flourishlib.com/fFile * - * @version 1.0.0b26 + * @version 1.0.0b27 + * @changes 1.0.0b27 Backwards Compatibility Break - renamed ::getFilename() to ::getName(), ::getFilesize() to ::getSize(), ::getDirectory() to ::getParent(), added ::move() [wb, 2009-12-16] * @changes 1.0.0b26 ::getDirectory(), ::getFilename() and ::getPath() now all work even if the file has been deleted [wb, 2009-10-22] * @changes 1.0.0b25 Fixed ::__construct() to throw an fValidationException when the file does not exist [wb, 2009-08-21] * @changes 1.0.0b24 Fixed a bug where deleting a file would prevent any future operations in the same script execution on a file or directory with the same path [wb, 2009-08-20] @@ -466,7 +467,7 @@ public function __clone() { $this->tossIfException(); - $directory = $this->getDirectory(); + $directory = $this->getParent(); if (!$directory->isWritable()) { throw new fEnvironmentException( @@ -475,7 +476,7 @@ public function __clone() ); } - $file = fFilesystem::makeUniqueName($directory->getPath() . $this->getFilename()); + $file = fFilesystem::makeUniqueName($directory->getPath() . $this->getName()); copy($this->getPath(), $file); chmod($file, fileperms($this->getPath())); @@ -575,7 +576,7 @@ public function __sleep() public function __toString() { try { - return $this->getFilename(); + return $this->getName(); } catch (Exception $e) { return ''; } @@ -645,7 +646,7 @@ public function delete() return; } - if (!$this->getDirectory()->isWritable()) { + if (!$this->getParent()->isWritable()) { throw new fEnvironmentException( 'The file, %s, can not be deleted because the directory containing it is not writable', $this->file @@ -686,14 +687,14 @@ public function duplicate($new_directory=NULL, $overwrite=NULL) $this->tossIfException(); if ($new_directory === NULL) { - $new_directory = $this->getDirectory(); + $new_directory = $this->getParent(); } if (!is_object($new_directory)) { $new_directory = new fDirectory($new_directory); } - $new_filename = $new_directory->getPath() . $this->getFilename(); + $new_filename = $new_directory->getPath() . $this->getName(); $check_dir_permissions = FALSE; @@ -706,7 +707,7 @@ public function duplicate($new_directory=NULL, $overwrite=NULL) throw new fEnvironmentException( 'The new directory specified, %1$s, already contains a file with the name %2$s, but it is not writable', $new_directory->getPath(), - $this->getFilename() + $this->getName() ); } @@ -738,53 +739,6 @@ public function duplicate($new_directory=NULL, $overwrite=NULL) } - /** - * Gets the directory the file is located in - * - * @return fDirectory The directory containing the file - */ - public function getDirectory() - { - return new fDirectory(fFilesystem::getPathInfo($this->file, 'dirname')); - } - - - /** - * Gets the filename (i.e. does not include the directory) - * - * @return string The filename of the file - */ - public function getFilename() - { - // For some reason PHP calls the filename the basename, where filename is the filename minus the extension - return fFilesystem::getPathInfo($this->file, 'basename'); - } - - - /** - * Gets the size of the file - * - * The return value may be incorrect for files over 2GB on 32-bit OSes. - * - * @param boolean $format If the filesize should be formatted for human readability - * @param integer $decimal_places The number of decimal places to format to (if enabled) - * @return integer|string If formatted a string with filesize in b/kb/mb/gb/tb, otherwise an integer - */ - public function getFilesize($format=FALSE, $decimal_places=1) - { - $this->tossIfException(); - - // This technique can overcome signed integer limit - $size = sprintf("%u", filesize($this->file)); - - if (!$format) { - return $size; - } - - return fFilesystem::formatFilesize($size, $decimal_places); - } - - /** * Gets the file's mime type * @@ -887,6 +841,29 @@ public function getMTime() } + /** + * Gets the filename (i.e. does not include the directory) + * + * @return string The filename of the file + */ + public function getName() + { + // For some reason PHP calls the filename the basename, where filename is the filename minus the extension + return fFilesystem::getPathInfo($this->file, 'basename'); + } + + + /** + * Gets the directory the file is located in + * + * @return fDirectory The directory containing the file + */ + public function getParent() + { + return new fDirectory(fFilesystem::getPathInfo($this->file, 'dirname')); + } + + /** * Gets the file's current path (directory and filename) * @@ -905,6 +882,30 @@ public function getPath($translate_to_web_path=FALSE) } + /** + * Gets the size of the file + * + * The return value may be incorrect for files over 2GB on 32-bit OSes. + * + * @param boolean $format If the filesize should be formatted for human readability + * @param integer $decimal_places The number of decimal places to format to (if enabled) + * @return integer|string If formatted a string with filesize in b/kb/mb/gb/tb, otherwise an integer + */ + public function getSize($format=FALSE, $decimal_places=1) + { + $this->tossIfException(); + + // This technique can overcome signed integer limit + $size = sprintf("%u", filesize($this->file)); + + if (!$format) { + return $size; + } + + return fFilesystem::formatFilesize($size, $decimal_places); + } + + /** * Check to see if the current file is writable * @@ -941,6 +942,35 @@ public function key() } + /** + * Moves the current file to a different directory + * + * Please note that ::rename() will rename a file in its directory or rename + * it into a different directory. + * + * If the current file's filename already exists in the new directory and + * the overwrite flag is set to false, the filename will be changed to a + * unique name. + * + * This operation will be reverted if a filesystem transaction is in + * progress and is later rolled back. + * + * @throws fValidationException When the directory passed is not a directory or is not readable + * + * @param fDirectory|string $new_directory The directory to move this file into + * @param boolean $overwrite If the current filename already exists in the new directory, `TRUE` will cause the file to be overwritten, `FALSE` will cause the new filename to change + * @return fFile The file object, to allow for method chaining + */ + public function move($new_directory, $overwrite) + { + if (!$new_directory instanceof fDirectory) { + $new_directory = new fDirectory($new_directory); + } + + return $this->rename($new_directory->getPath() . $this->getName(), $overwrite); + } + + /** * Advances to the next line in the file (required by iterator interface) * @@ -971,7 +1001,10 @@ public function next() * Prints the contents of the file * * This method is primarily intended for when PHP is used to control access - * to files. + * to files. + * + * Be sure to turn off output buffering and close the session, if open, to + * prevent performance issues. * * @param boolean $headers If HTTP headers for the file should be included * @param mixed $filename Present the file as an attachment instead of just outputting type headers - if a string is passed, that will be used for the filename, if `TRUE` is passed, the current filename will be used @@ -994,11 +1027,11 @@ public function output($headers, $filename=NULL) if ($headers) { if ($filename !== NULL) { - if ($filename === TRUE) { $filename = $this->getFilename(); } + if ($filename === TRUE) { $filename = $this->getName(); } header('Content-Disposition: attachment; filename="' . $filename . '"'); } header('Cache-Control: '); - header('Content-Length: ' . $this->getFilesize()); + header('Content-Length: ' . $this->getSize()); header('Content-Type: ' . $this->getMimeType()); header('Expires: '); header('Last-Modified: ' . $this->getMTime()->format('D, d M Y H:i:s')); @@ -1047,7 +1080,7 @@ public function rename($new_filename, $overwrite) { $this->tossIfException(); - if (!$this->getDirectory()->isWritable()) { + if (!$this->getParent()->isWritable()) { throw new fEnvironmentException( 'The file, %s, can not be renamed because the directory containing it is not writable', $this->file @@ -1056,7 +1089,7 @@ public function rename($new_filename, $overwrite) // If the filename does not contain any folder traversal, rename the file in the current directory if (preg_match('#^[^/\\\\]+$#D', $new_filename)) { - $new_filename = $this->getDirectory()->getPath() . $new_filename; + $new_filename = $this->getParent()->getPath() . $new_filename; } $info = fFilesystem::getPathInfo($new_filename); diff --git a/classes/fORMFile.php b/classes/fORMFile.php index 61cefc3f..fcb13554 100644 --- a/classes/fORMFile.php +++ b/classes/fORMFile.php @@ -9,7 +9,8 @@ * @package Flourish * @link http://flourishlib.com/fORMFile * - * @version 1.0.0b17 + * @version 1.0.0b18 + * @changes 1.0.0b18 Updated code for the new fFile API [wb, 2009-12-16] * @changes 1.0.0b17 Updated code for the new fORMDatabase and fORMSchema APIs [wb, 2009-10-28] * @changes 1.0.0b16 fImage method calls for file upload columns will no longer cause notices due to a missing image type [wb, 2009-09-09] * @changes 1.0.0b15 ::addFImageMethodCall() no longer requires column be an image upload column, inheritance to an image column now only happens for fImage objects [wb, 2009-07-29] @@ -570,7 +571,7 @@ static public function moveFromTemp($object, &$values, &$old_values, &$related_r } // If the file is in a temp dir, move it out - if (strpos($value->getDirectory()->getPath(), self::TEMP_DIRECTORY) !== FALSE) { + if (strpos($value->getParent()->getPath(), self::TEMP_DIRECTORY) !== FALSE) { $new_filename = str_replace(self::TEMP_DIRECTORY, '', $value->getPath()); $new_filename = fFilesystem::makeUniqueName($new_filename); $value->rename($new_filename, FALSE); @@ -902,7 +903,7 @@ static public function replicate($class, $column, $value) } // If the file we are replicating is in the temp dir, the copy can live there too - if (strpos($value->getDirectory()->getPath(), self::TEMP_DIRECTORY) !== FALSE) { + if (strpos($value->getParent()->getPath(), self::TEMP_DIRECTORY) !== FALSE) { $value = clone $value; // Otherwise, the copy of the file must be placed in the temp dir so it is properly cleaned up