Ticket #219: File.php
| File File.php, 28.3 KB (added by hans, 4 years ago) |
|---|
| Line | |
|---|---|
| 1 | <?php |
| 2 | /* |
| 3 | * $Id: File.php 313 2007-11-17 04:20:58Z hans $ |
| 4 | * |
| 5 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 6 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 7 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 8 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 9 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 10 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 11 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 12 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 13 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 14 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 15 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 16 | * |
| 17 | * This software consists of voluntary contributions made by many individuals |
| 18 | * and is licensed under the LGPL. For more information please see |
| 19 | * <http://phing.info>. |
| 20 | */ |
| 21 | |
| 22 | namespace phing::system::io; |
| 23 | use phing::system::io::FileSystem; |
| 24 | use phing::system::lang::NullPointerException; |
| 25 | |
| 26 | /** |
| 27 | * An representation of file and directory pathnames. |
| 28 | * |
| 29 | * @package phing.system.io |
| 30 | */ |
| 31 | class File { |
| 32 | |
| 33 | /** |
| 34 | * Separator string, static, obtained from FileSystem. |
| 35 | * @see FileSystem::getSeparator() |
| 36 | */ |
| 37 | public static $separator; |
| 38 | |
| 39 | /** |
| 40 | * Path separator string, static, obtained from FileSystem (; or :) |
| 41 | * @see FileSystem::getSeparator() |
| 42 | */ |
| 43 | public static $pathSeparator; |
| 44 | |
| 45 | /** |
| 46 | * This abstract pathname's normalized pathname string. A normalized |
| 47 | * pathname string uses the default name-separator character and does not |
| 48 | * contain any duplicate or redundant separators. |
| 49 | * @var string |
| 50 | */ |
| 51 | private $path; |
| 52 | |
| 53 | /** |
| 54 | * The length of this abstract pathname's prefix, or zero if it has no prefix. |
| 55 | * @var int |
| 56 | */ |
| 57 | private $prefixLength = 0; |
| 58 | |
| 59 | /** |
| 60 | * Create a new File object. |
| 61 | * |
| 62 | * This method supports sevarl valid signatures: |
| 63 | * new File(File parent, string filename) |
| 64 | * new File(string filename) |
| 65 | * new File(string parent, string filename) |
| 66 | */ |
| 67 | function __construct($arg1, $arg2 = null) { |
| 68 | |
| 69 | if (self::$separator === null || self::$pathSeparator === null) { |
| 70 | $fs = FileSystem::getFileSystem(); |
| 71 | self::$separator = $fs->getSeparator(); |
| 72 | self::$pathSeparator = $fs->getPathSeparator(); |
| 73 | } |
| 74 | |
| 75 | /* simulate constructor overloading */ |
| 76 | if ($arg1 instanceof File && is_string($arg2)) { |
| 77 | $this->__constructFileParentStringChild($arg1, $arg2); |
| 78 | } elseif (is_string($arg1) && ($arg2 === null)) { |
| 79 | $this->__constructPathname($arg1); |
| 80 | } elseif(is_string($arg1) && is_string($arg2)) { |
| 81 | $this->__constructStringParentStringChild($arg1, $arg2); |
| 82 | } else { |
| 83 | if ($arg1 === null) { |
| 84 | throw new NullPointerException("Argument1 to function must not be null"); |
| 85 | } |
| 86 | $this->path = (string) $arg1; |
| 87 | $this->prefixLength = (int) $arg2; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | /** |
| 92 | * Private overloaded constructor when passed a File parent path and string child path. |
| 93 | * @param File $parent The parent path |
| 94 | * @param string $child (optional) The child path |
| 95 | */ |
| 96 | private function __constructFileParentStringChild(File $parent, $child) { |
| 97 | // obtain ref to the filesystem layer |
| 98 | $fs = FileSystem::getFileSystem(); |
| 99 | |
| 100 | if ($child === null) { |
| 101 | throw new NullPointerException("Argument to function must not be null"); |
| 102 | } |
| 103 | |
| 104 | if ($parent !== null) { |
| 105 | if ($parent->getPath() === "") { |
| 106 | $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child)); |
| 107 | } else { |
| 108 | $this->path = $fs->resolve($parent->getPath(), $fs->normalize($child)); |
| 109 | } |
| 110 | } else { |
| 111 | $this->path = $fs->normalize($child); |
| 112 | } |
| 113 | $this->prefixLength = $fs->prefixLength($this->path); |
| 114 | } |
| 115 | |
| 116 | /** |
| 117 | * Private constructor when passed a single path string. |
| 118 | * |
| 119 | * @param string $pathname |
| 120 | */ |
| 121 | private function __constructPathname($pathname) { |
| 122 | // obtain ref to the filesystem layer |
| 123 | $fs = FileSystem::getFileSystem(); |
| 124 | |
| 125 | if ($pathname === null) { |
| 126 | throw new NullPointerException("Argument to function must not be null"); |
| 127 | } |
| 128 | |
| 129 | $this->path = (string) $fs->normalize($pathname); |
| 130 | $this->prefixLength = (int) $fs->prefixLength($this->path); |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * Private overloaded constructor when passed a string parent path and child paths. |
| 135 | * @param string $parent The parent path |
| 136 | * @param string $child (optional) The child path |
| 137 | */ |
| 138 | private function __constructStringParentStringChild($parent, $child) { |
| 139 | // obtain ref to the filesystem layer |
| 140 | $fs = FileSystem::getFileSystem(); |
| 141 | |
| 142 | if ($child === null) { |
| 143 | throw new NullPointerException("Argument to function must not be null"); |
| 144 | } |
| 145 | if ($parent !== null) { |
| 146 | if ($parent === "") { |
| 147 | $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child)); |
| 148 | } else { |
| 149 | $this->path = $fs->resolve($fs->normalize($parent), $fs->normalize($child)); |
| 150 | } |
| 151 | } else { |
| 152 | $this->path = (string) $fs->normalize($child); |
| 153 | } |
| 154 | $this->prefixLength = (int) $fs->prefixLength($this->path); |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * Returns the length of this abstract pathname's prefix. |
| 159 | * @return int |
| 160 | */ |
| 161 | function getPrefixLength() { |
| 162 | return (int) $this->prefixLength; |
| 163 | } |
| 164 | |
| 165 | /* -- Path-component accessors -- */ |
| 166 | |
| 167 | /** |
| 168 | * Returns the name of the file or directory denoted by this abstract |
| 169 | * pathname. This is just the last name in the pathname's name |
| 170 | * sequence. If the pathname's name sequence is empty, then the empty |
| 171 | * string is returned. |
| 172 | * |
| 173 | * @return string The name of the file or directory. |
| 174 | */ |
| 175 | public function getName() { |
| 176 | // that's a lastIndexOf |
| 177 | $index = ((($res = strrpos($this->path, self::$separator)) === false) ? -1 : $res); |
| 178 | if ($index < $this->prefixLength) { |
| 179 | return substr($this->path, $this->prefixLength); |
| 180 | } |
| 181 | return substr($this->path, $index + 1); |
| 182 | } |
| 183 | |
| 184 | /** |
| 185 | * Returns the pathname string of this abstract pathname's parent, or |
| 186 | * null if this pathname does not name a parent directory. |
| 187 | * |
| 188 | * The parent of an abstract pathname consists of the pathname's prefix, |
| 189 | * if any, and each name in the pathname's name sequence except for the last. |
| 190 | * If the name sequence is empty then the pathname does not name a parent |
| 191 | * directory. |
| 192 | * |
| 193 | * @return string The pathname string of the parent directory. |
| 194 | */ |
| 195 | public function getParent() { |
| 196 | // that's a lastIndexOf |
| 197 | $index = ((($res = strrpos($this->path, self::$separator)) === false) ? -1 : $res); |
| 198 | if ($index < $this->prefixLength) { |
| 199 | if (($this->prefixLength > 0) && (strlen($this->path > $this->prefixLength))) { |
| 200 | return substr($this->path, 0, $this->prefixLength); |
| 201 | } |
| 202 | return null; |
| 203 | } |
| 204 | return substr($this->path, 0, $index); |
| 205 | } |
| 206 | |
| 207 | /** |
| 208 | * Returns the parent directory as File object. |
| 209 | * |
| 210 | * @return File A File of the parent directory for this file. |
| 211 | */ |
| 212 | public function getParentFile() { |
| 213 | $p = $this->getParent(); |
| 214 | if ($p === null) { |
| 215 | return null; |
| 216 | } |
| 217 | return new File((string) $p, (int) $this->prefixLength); |
| 218 | } |
| 219 | |
| 220 | /** |
| 221 | * Converts this abstract pathname into a pathname string. The resulting |
| 222 | * string uses the default name-separator character to separate the names |
| 223 | * in the name sequence. |
| 224 | * |
| 225 | * @return string The string form of this abstract pathname |
| 226 | */ |
| 227 | public function getPath() { |
| 228 | return (string) $this->path; |
| 229 | } |
| 230 | |
| 231 | /** |
| 232 | * Tests whether this abstract pathname is absolute. The definition of |
| 233 | * absolute pathname is system dependent. On UNIX systems, a pathname is |
| 234 | * absolute if its prefix is "/". On Win32 systems, a pathname is absolute |
| 235 | * if its prefix is a drive specifier followed by "\\", or if its prefix |
| 236 | * is "\\". |
| 237 | * |
| 238 | * @return boolean true if this abstract pathname is absolute, false otherwise |
| 239 | */ |
| 240 | public function isAbsolute() { |
| 241 | return ($this->prefixLength !== 0); |
| 242 | } |
| 243 | |
| 244 | /** |
| 245 | * Returns the absolute pathname string of this abstract pathname. |
| 246 | * |
| 247 | * If this abstract pathname is already absolute, then the pathname |
| 248 | * string is simply returned as if by the getPath method. |
| 249 | * If this abstract pathname is the empty abstract pathname then |
| 250 | * the pathname string of the current user directory, which is named by the |
| 251 | * system property user.dir, is returned. Otherwise this |
| 252 | * pathname is resolved in a system-dependent way. On UNIX systems, a |
| 253 | * relative pathname is made absolute by resolving it against the current |
| 254 | * user directory. On Win32 systems, a relative pathname is made absolute |
| 255 | * by resolving it against the current directory of the drive named by the |
| 256 | * pathname, if any; if not, it is resolved against the current user |
| 257 | * directory. |
| 258 | * |
| 259 | * @return string The absolute pathname of this file/directory. |
| 260 | * @see isAbsolute() |
| 261 | */ |
| 262 | public function getAbsolutePath() { |
| 263 | $fs = FileSystem::getFileSystem(); |
| 264 | return $fs->resolveFile($this); |
| 265 | } |
| 266 | |
| 267 | /** |
| 268 | * Returns a File object containing abs path to this file/dir. |
| 269 | * |
| 270 | * @see getAbsolutePath() |
| 271 | * @return File A File object containing the absolute path to this file/dir. |
| 272 | */ |
| 273 | public function getAbsoluteFile() { |
| 274 | return new File((string) $this->getAbsolutePath()); |
| 275 | } |
| 276 | |
| 277 | /** |
| 278 | * Returns the canonical pathname string of this abstract pathname. |
| 279 | * |
| 280 | * A canonical pathname is both absolute and unique. The precise |
| 281 | * definition of canonical form is system-dependent. This method first |
| 282 | * converts this pathname to absolute form if necessary, as if by invoking the |
| 283 | * getAbsolutePath() method, and then maps it to its unique form in a |
| 284 | * system-dependent way. This typically involves removing redundant names |
| 285 | * such as "." and .. from the pathname, resolving symbolic links |
| 286 | * (on UNIX platforms), and converting drive letters to a standard case |
| 287 | * (on Win32 platforms). |
| 288 | * |
| 289 | * Every pathname that denotes an existing file or directory has a |
| 290 | * unique canonical form. Every pathname that denotes a nonexistent file |
| 291 | * or directory also has a unique canonical form. The canonical form of |
| 292 | * the pathname of a nonexistent file or directory may be different from |
| 293 | * the canonical form of the same pathname after the file or directory is |
| 294 | * created. Similarly, the canonical form of the pathname of an existing |
| 295 | * file or directory may be different from the canonical form of the same |
| 296 | * pathname after the file or directory is deleted. |
| 297 | * |
| 298 | * @return string The canonical path to this file/dir. |
| 299 | */ |
| 300 | public function getCanonicalPath() { |
| 301 | $fs = FileSystem::getFileSystem(); |
| 302 | return $fs->canonicalize($this->path); |
| 303 | } |
| 304 | |
| 305 | /** |
| 306 | * Returns the canonical form of this abstract pathname. |
| 307 | * |
| 308 | * @see getCanonicalPath() |
| 309 | * @return File The canonical File to tihs file/dir. |
| 310 | */ |
| 311 | public function getCanonicalFile() { |
| 312 | return new File($this->getCanonicalPath()); |
| 313 | } |
| 314 | |
| 315 | /** |
| 316 | * Normalizes the directory separators in the path and adds a trailing '/' to directories. |
| 317 | * |
| 318 | * @param string $path |
| 319 | * @param boolean $isDirectory |
| 320 | * @return string |
| 321 | */ |
| 322 | private function _slashify($path, $isDirectory) { |
| 323 | $p = (string) $path; |
| 324 | |
| 325 | if (self::$separator !== '/') { |
| 326 | $p = str_replace(self::$separator, '/', $p); |
| 327 | } |
| 328 | |
| 329 | if (!StringHelper::startsWith('/', $p)) { |
| 330 | $p = '/'.$p; |
| 331 | } |
| 332 | |
| 333 | if (!StringHelper::endsWith('/', $p) && $isDirectory) { |
| 334 | $p = $p.'/'; |
| 335 | } |
| 336 | |
| 337 | return $p; |
| 338 | } |
| 339 | |
| 340 | /* -- Attribute accessors -- */ |
| 341 | |
| 342 | /** |
| 343 | * Tests whether the application can read the file denoted by this |
| 344 | * abstract pathname. |
| 345 | * |
| 346 | * @return boolean Whether file/dir can be read by application. |
| 347 | */ |
| 348 | public function canRead() { |
| 349 | $fs = FileSystem::getFileSystem(); |
| 350 | |
| 351 | if ($fs->checkAccess($this)) { |
| 352 | return (boolean) @is_readable($this->getAbsolutePath()); |
| 353 | } |
| 354 | return false; |
| 355 | } |
| 356 | |
| 357 | /** |
| 358 | * Tests whether the application can modify to the file denoted by this |
| 359 | * abstract pathname. |
| 360 | * |
| 361 | * @return boolean Whether file/dir can be written to. |
| 362 | * |
| 363 | */ |
| 364 | public function canWrite() { |
| 365 | $fs = FileSystem::getFileSystem(); |
| 366 | return $fs->checkAccess($this, true); |
| 367 | } |
| 368 | |
| 369 | /** |
| 370 | * Tests whether the file denoted by this abstract pathname exists. |
| 371 | * |
| 372 | * @return boolean Whether file/dir exists. |
| 373 | */ |
| 374 | public function exists() { |
| 375 | clearstatcache(); |
| 376 | if ($this->isFile()) { |
| 377 | return @file_exists($this->path); |
| 378 | } else { |
| 379 | return @is_dir($this->path); |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | /** |
| 384 | * Tests whether the path represented by this object corresponds to a directory. |
| 385 | * |
| 386 | * @return boolean Whether path represented is a directory. |
| 387 | */ |
| 388 | public function isDirectory() { |
| 389 | clearstatcache(); |
| 390 | $fs = FileSystem::getFileSystem(); |
| 391 | if ($fs->checkAccess($this) !== true) { |
| 392 | throw new IOException("No read access to ".$this->path); |
| 393 | } |
| 394 | return @is_dir($this->path); |
| 395 | } |
| 396 | |
| 397 | /** |
| 398 | * Tests whether the path represented by this object corresponds to a normal file. |
| 399 | * |
| 400 | * @return boolean Whether path represents a file. |
| 401 | */ |
| 402 | public function isFile() { |
| 403 | clearstatcache(); |
| 404 | //$fs = FileSystem::getFileSystem(); |
| 405 | return @is_file($this->path); |
| 406 | } |
| 407 | |
| 408 | /** |
| 409 | * Tests whether the path represented by this object is a hidden file. |
| 410 | * |
| 411 | * @return boolean Whether file/dir is hidden. |
| 412 | */ |
| 413 | public function isHidden() { |
| 414 | $fs = FileSystem::getFileSystem(); |
| 415 | if ($fs->checkAccess($this) !== true) { |
| 416 | throw new IOException("No read access to ".$this->path); |
| 417 | } |
| 418 | return (($fs->getBooleanAttributes($this) & $fs->BA_HIDDEN) !== 0); |
| 419 | } |
| 420 | |
| 421 | /** |
| 422 | * Returns the time that the file denoted by this abstract pathname was |
| 423 | * last modified. |
| 424 | * |
| 425 | * @return int A integer value representing the time the file was |
| 426 | * last modified, measured in milliseconds since the epoch |
| 427 | * (00:00:00 GMT, January 1, 1970), or 0 if the |
| 428 | * file does not exist or if an I/O error occurs |
| 429 | */ |
| 430 | public function lastModified() { |
| 431 | $fs = FileSystem::getFileSystem(); |
| 432 | if ($fs->checkAccess($this) !== true) { |
| 433 | throw new IOException("No read access to " . $this->path); |
| 434 | } |
| 435 | return $fs->getLastModifiedTime($this); |
| 436 | } |
| 437 | |
| 438 | /** |
| 439 | * Returns the length of the file denoted by this abstract pathname. |
| 440 | * The return value is unspecified if this pathname denotes a directory. |
| 441 | * |
| 442 | * @return int The length, in bytes, of the file denoted by this abstract |
| 443 | * pathname, or 0 if the file does not exist |
| 444 | * @throws IOException - if file cannot be read |
| 445 | */ |
| 446 | public function length() { |
| 447 | $fs = FileSystem::getFileSystem(); |
| 448 | if ($fs->checkAccess($this) !== true) { |
| 449 | throw new IOException("No read access to ".$this->path."\n"); |
| 450 | } |
| 451 | return $fs->getLength($this); |
| 452 | } |
| 453 | |
| 454 | /** |
| 455 | * Convenience method for returning the contents of this file as a string. |
| 456 | * This method uses file_get_contents() to read file in an optimized way. |
| 457 | * @return string |
| 458 | * @throws IOException - if file cannot be read |
| 459 | */ |
| 460 | public function contents() { |
| 461 | if (!$this->canRead() || !$this->isFile()) { |
| 462 | throw new IOException("Cannot read file contents!"); |
| 463 | } |
| 464 | return file_get_contents($this->getAbsolutePath()); |
| 465 | } |
| 466 | |
| 467 | /* -- File operations -- */ |
| 468 | |
| 469 | /** |
| 470 | * Atomically creates a new, empty file named by this abstract pathname if |
| 471 | * and only if a file with this name does not yet exist. The check for the |
| 472 | * existence of the file and the creation of the file if it does not exist |
| 473 | * are a single operation that is atomic with respect to all other |
| 474 | * filesystem activities that might affect the file. |
| 475 | * |
| 476 | * @return true if the named file does not exist and was |
| 477 | * successfully created; <code>false</code> if the named file |
| 478 | * already exists |
| 479 | * @throws IOException if file can't be created |
| 480 | */ |
| 481 | public function createNewFile($parents=true, $mode=0777) { |
| 482 | $file = FileSystem::getFileSystem()->createNewFile($this->path); |
| 483 | return $file; |
| 484 | } |
| 485 | |
| 486 | /** |
| 487 | * Deletes the file or directory denoted by this abstract pathname. If |
| 488 | * this pathname denotes a directory, then the directory must be empty in |
| 489 | * order to be deleted. |
| 490 | * |
| 491 | * @return true if and only if the file or directory is |
| 492 | * successfully deleted; false otherwise |
| 493 | */ |
| 494 | public function delete() { |
| 495 | $fs = FileSystem::getFileSystem(); |
| 496 | if ($fs->canDelete($this) !== true) { |
| 497 | throw new IOException("Cannot delete " . $this->path . "\n"); |
| 498 | } |
| 499 | return $fs->delete($this); |
| 500 | } |
| 501 | |
| 502 | /** |
| 503 | * Requests that the file or directory denoted by this abstract pathname |
| 504 | * be deleted when php terminates. Deletion will be attempted only for |
| 505 | * normal termination of php and if and if only Phing::shutdown() is |
| 506 | * called. |
| 507 | * |
| 508 | * Once deletion has been requested, it is not possible to cancel the |
| 509 | * request. This method should therefore be used with care. |
| 510 | * |
| 511 | */ |
| 512 | public function deleteOnExit() { |
| 513 | $fs = FileSystem::getFileSystem(); |
| 514 | $fs->deleteOnExit($this); |
| 515 | } |
| 516 | |
| 517 | /** |
| 518 | * Return an array of names for contents of directory represented by this object. |
| 519 | * |
| 520 | * If this abstract pathname does not denote a directory, then this |
| 521 | * method returns null. |
| 522 | * |
| 523 | * @return array string[] An array of file and directory names |
| 524 | */ |
| 525 | public function listDir($filter = null) { |
| 526 | $fs = FileSystem::getFileSystem(); |
| 527 | return $fs->lister($this, $filter); |
| 528 | } |
| 529 | |
| 530 | /** |
| 531 | * Return an array of File objects for contents of directory represented by this object. |
| 532 | * |
| 533 | * @param unknown_type $filter |
| 534 | * @return array File[] |
| 535 | */ |
| 536 | public function listFiles($filter = null) { |
| 537 | $ss = $this->listDir($filter); |
| 538 | if ($ss === null) { |
| 539 | return null; |
| 540 | } |
| 541 | $n = count($ss); |
| 542 | $fs = array(); |
| 543 | for ($i = 0; $i < $n; $i++) { |
| 544 | $fs[$i] = new File((string)$this->path, (string)$ss[$i]); |
| 545 | } |
| 546 | return $fs; |
| 547 | } |
| 548 | |
| 549 | /** |
| 550 | * Creates the directory named by this abstract pathname, including any |
| 551 | * necessary but nonexistent parent directories. Note that if this |
| 552 | * operation fails it may have succeeded in creating some of the necessary |
| 553 | * parent directories. |
| 554 | * |
| 555 | * @return true if and only if the directory was created, |
| 556 | * along with all necessary parent directories; false |
| 557 | * otherwise |
| 558 | * @throws IOException |
| 559 | */ |
| 560 | public function mkdirs() { |
| 561 | if ($this->exists()) { |
| 562 | return false; |
| 563 | } |
| 564 | try { |
| 565 | if ($this->mkdir()) { |
| 566 | return true; |
| 567 | } |
| 568 | } catch (IOException $ioe) { |
| 569 | // IOException from mkdir() means that directory propbably didn't exist. |
| 570 | } |
| 571 | $parentFile = $this->getParentFile(); |
| 572 | return (($parentFile !== null) && ($parentFile->mkdirs() && $this->mkdir())); |
| 573 | } |
| 574 | |
| 575 | /** |
| 576 | * Creates the directory named by this abstract pathname. |
| 577 | * |
| 578 | * @return true if and only if the directory was created; false otherwise |
| 579 | * @throws IOException - If no write access |
| 580 | */ |
| 581 | public function mkdir() { |
| 582 | $fs = FileSystem::getFileSystem(); |
| 583 | |
| 584 | if ($fs->checkAccess(new File($this->path), true) !== true) { |
| 585 | throw new IOException("No write access to " . $this->getPath()); |
| 586 | } |
| 587 | return $fs->createDirectory($this); |
| 588 | } |
| 589 | |
| 590 | /** |
| 591 | * Renames the file denoted by this abstract pathname. |
| 592 | * |
| 593 | * @param destFile The new abstract pathname for the named file |
| 594 | * @return true if and only if the renaming succeeded; false otherwise |
| 595 | */ |
| 596 | public function renameTo(File $destFile) { |
| 597 | $fs = FileSystem::getFileSystem(); |
| 598 | if ($fs->checkAccess($this) !== true) { |
| 599 | throw new IOException("No write access to ".$this->getPath()); |
| 600 | } |
| 601 | return $fs->rename($this, $destFile); |
| 602 | } |
| 603 | |
| 604 | /** |
| 605 | * Simple-copies file denoted by this abstract pathname into another |
| 606 | * File |
| 607 | * |
| 608 | * @param File $destFile The new abstract pathname for the named file |
| 609 | * @return true if and only if the renaming succeeded; false otherwise |
| 610 | */ |
| 611 | public function copyTo(File $destFile) { |
| 612 | $fs = FileSystem::getFileSystem(); |
| 613 | |
| 614 | if ($fs->checkAccess($this) !== true) { |
| 615 | throw new IOException("No read access to ".$this->getPath()."\n"); |
| 616 | } |
| 617 | |
| 618 | if ($fs->checkAccess($destFile, true) !== true) { |
| 619 | throw new IOException("File::copyTo() No write access to ".$destFile->getPath()); |
| 620 | } |
| 621 | return $fs->copy($this, $destFile); |
| 622 | } |
| 623 | |
| 624 | /** |
| 625 | * Sets the last-modified time of the file or directory named by this |
| 626 | * abstract pathname. |
| 627 | * |
| 628 | * All platforms support file-modification times to the nearest second, |
| 629 | * but some provide more precision. The argument will be truncated to fit |
| 630 | * the supported precision. If the operation succeeds and no intervening |
| 631 | * operations on the file take place, then the next invocation of the |
| 632 | * lastModified method will return the (possibly truncated) time argument |
| 633 | * that was passed to this method. |
| 634 | * |
| 635 | * @param int $time The new last-modified time, measured in milliseconds since |
| 636 | * the epoch (00:00:00 GMT, January 1, 1970) |
| 637 | * @return boolean Whether operation succeeded |
| 638 | */ |
| 639 | public function setLastModified($time) { |
| 640 | $time = (int) $time; |
| 641 | if ($time < 0) { |
| 642 | throw new Exception("IllegalArgumentException, Negative $time\n"); |
| 643 | } |
| 644 | |
| 645 | // FIXME check if accessible |
| 646 | $fs = FileSystem::getFileSystem(); |
| 647 | if ($fs->checkAccess($this, true) !== true) { |
| 648 | throw new IOException("File::setLastModified(). No write access to file\n"); |
| 649 | } |
| 650 | return $fs->setLastModifiedTime($this, $time); |
| 651 | } |
| 652 | |
| 653 | /** |
| 654 | * Marks the file or directory named by this abstract pathname so that |
| 655 | * only read operations are allowed. |
| 656 | * |
| 657 | * @return boolean Whether operation succeeded |
| 658 | */ |
| 659 | public function setReadOnly() { |
| 660 | $fs = FileSystem::getFileSystem(); |
| 661 | if ($fs->checkAccess($this, true) !== true) { |
| 662 | // Error, no write access |
| 663 | throw new IOException("No write access to " . $this->getPath()); |
| 664 | } |
| 665 | return $fs->setReadOnly($this); |
| 666 | } |
| 667 | /** |
| 668 | * Sets the mode of the file |
| 669 | * @param string $user Name of the user |
| 670 | */ |
| 671 | public function setUser($user) { |
| 672 | $fs = FileSystem::getFileSystem(); |
| 673 | return $fs->chown($this->getPath(), $user); |
| 674 | } |
| 675 | |
| 676 | |
| 677 | /** |
| 678 | * Sets the mode of the file |
| 679 | * @param int $mode Ocatal mode. |
| 680 | */ |
| 681 | public function setMode($mode) { |
| 682 | $fs = FileSystem::getFileSystem(); |
| 683 | return $fs->chmod($this->getPath(), $mode); |
| 684 | } |
| 685 | |
| 686 | /** |
| 687 | * Retrieve the mode of this file. |
| 688 | * @return int |
| 689 | */ |
| 690 | public function getMode() { |
| 691 | return @fileperms($this->getPath()); |
| 692 | } |
| 693 | |
| 694 | /* -- Filesystem interface -- */ |
| 695 | |
| 696 | /** |
| 697 | * List the available filesystem roots. |
| 698 | * |
| 699 | * A particular platform may support zero or more hierarchically-organized |
| 700 | * file systems. Each file system has a root directory from which all |
| 701 | * other files in that file system can be reached. |
| 702 | * Windows platforms, for example, have a root directory for each active |
| 703 | * drive; UNIX platforms have a single root directory, namely "/". |
| 704 | * The set of available filesystem roots is affected by various system-level |
| 705 | * operations such the insertion or ejection of removable media and the |
| 706 | * disconnecting or unmounting of physical or virtual disk drives. |
| 707 | * |
| 708 | * This method returns an array of File objects that |
| 709 | * denote the root directories of the available filesystem roots. It is |
| 710 | * guaranteed that the canonical pathname of any file physically present on |
| 711 | * the local machine will begin with one of the roots returned by this |
| 712 | * method. |
| 713 | * |
| 714 | * The canonical pathname of a file that resides on some other machine |
| 715 | * and is accessed via a remote-filesystem protocol such as SMB or NFS may |
| 716 | * or may not begin with one of the roots returned by this method. If the |
| 717 | * pathname of a remote file is syntactically indistinguishable from the |
| 718 | * pathname of a local file then it will begin with one of the roots |
| 719 | * returned by this method. Thus, for example, File objects |
| 720 | * denoting the root directories of the mapped network drives of a Windows |
| 721 | * platform will be returned by this method, while File |
| 722 | * objects containing UNC pathnames will not be returned by this method. |
| 723 | * |
| 724 | * @return array File[] An array of File objects denoting the available |
| 725 | * filesystem roots, or null if the set of roots |
| 726 | * could not be determined. The array will be empty if there are |
| 727 | * no filesystem roots. |
| 728 | */ |
| 729 | public function listRoots() { |
| 730 | $fs = FileSystem::getFileSystem(); |
| 731 | return (array) $fs->listRoots(); |
| 732 | } |
| 733 | |
| 734 | /* -- Tempfile management -- */ |
| 735 | |
| 736 | /** |
| 737 | * Returns the path to the temp directory. |
| 738 | * @return string |
| 739 | */ |
| 740 | public function getTempDir() { |
| 741 | return Phing::getProperty('php.tmpdir'); |
| 742 | } |
| 743 | |
| 744 | /** |
| 745 | * Static method that creates a unique filename whose name begins with |
| 746 | * $prefix and ends with $suffix in the directory $directory. $directory |
| 747 | * is a reference to a File Object. |
| 748 | * Then, the file is locked for exclusive reading/writing. |
| 749 | * |
| 750 | * @throws IOException |
| 751 | */ |
| 752 | public static function createTempFile($prefix, $suffix, File $directory) { |
| 753 | |
| 754 | // quick but efficient hack to create a unique filename ;-) |
| 755 | $result = null; |
| 756 | do { |
| 757 | $result = new File($directory, $prefix . substr(md5(time()), 0, 8) . $suffix); |
| 758 | } while (file_exists($result->getPath())); |
| 759 | |
| 760 | $fs = FileSystem::getFileSystem(); |
| 761 | $fs->createNewFile($result->getPath()); |
| 762 | $fs->lock($result); |
| 763 | |
| 764 | return $result; |
| 765 | } |
| 766 | |
| 767 | /** |
| 768 | * If necessary, $File the lock on $File is removed and then the file is |
| 769 | * deleted |
| 770 | * |
| 771 | * @access public |
| 772 | */ |
| 773 | public function removeTempFile() { |
| 774 | $fs = FileSystem::getFileSystem(); |
| 775 | // catch IO Exception |
| 776 | $fs->unlock($this); |
| 777 | $this->delete(); |
| 778 | } |
| 779 | |
| 780 | |
| 781 | /* -- Basic infrastructure -- */ |
| 782 | |
| 783 | /** |
| 784 | * Compares two abstract pathnames lexicographically. The ordering |
| 785 | * defined by this method depends upon the underlying system. On UNIX |
| 786 | * systems, alphabetic case is significant in comparing pathnames; on Win32 |
| 787 | * systems it is not. |
| 788 | * |
| 789 | * @param File $file Th file whose pathname sould be compared to the pathname of this file. |
| 790 | * |
| 791 | * @return int Zero if the argument is equal to this abstract pathname, a |
| 792 | * value less than zero if this abstract pathname is |
| 793 | * lexicographically less than the argument, or a value greater |
| 794 | * than zero if this abstract pathname is lexicographically |
| 795 | * greater than the argument |
| 796 | */ |
| 797 | public function compareTo(File $file) { |
| 798 | $fs = FileSystem::getFileSystem(); |
| 799 | return $fs->compare($this, $file); |
| 800 | } |
| 801 | |
| 802 | /** |
| 803 | * Tests to see whether two File objects are equal. |
| 804 | * @return boolean |
| 805 | */ |
| 806 | public function equals($obj) { |
| 807 | if (($obj !== null) && ($obj instanceof File)) { |
| 808 | return ($this->compareTo($obj) === 0); |
| 809 | } |
| 810 | return false; |
| 811 | } |
| 812 | |
| 813 | /** |
| 814 | * Backwards compatibility -- use PHP5's native __tostring method. |
| 815 | * @deprecated |
| 816 | */ |
| 817 | public function toString() { |
| 818 | return $this->getPath(); |
| 819 | } |
| 820 | |
| 821 | /** |
| 822 | * PHP5's semi-magic __toString() method. |
| 823 | * @return string |
| 824 | */ |
| 825 | public function __toString() { |
| 826 | return $this->getPath(); |
| 827 | } |
| 828 | } |
