PhingFile.php 34 KB

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