PageRenderTime 23ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/lib/Cake/Utility/File.php

https://github.com/Nervie/Beta
PHP | 507 lines | 347 code | 23 blank | 137 comment | 33 complexity | 0f53a12062226ed8ce62b28c38706c01 MD5 | raw file
  1. <?php
  2. /**
  3. * Convenience class for reading, writing and appending to files.
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice.
  12. *
  13. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://cakephp.org CakePHP(tm) Project
  15. * @package Cake.Utility
  16. * @since CakePHP(tm) v 0.2.9
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. /**
  20. * Included libraries.
  21. *
  22. */
  23. App::uses('Folder', 'Utility');
  24. /**
  25. * Convenience class for reading, writing and appending to files.
  26. *
  27. * @package Cake.Utility
  28. */
  29. class File {
  30. /**
  31. * Folder object of the File
  32. *
  33. * @var Folder
  34. * @access public
  35. */
  36. public $Folder = null;
  37. /**
  38. * Filename
  39. *
  40. * @var string
  41. * @access public
  42. */
  43. public $name = null;
  44. /**
  45. * file info
  46. *
  47. * @var string
  48. * @access public
  49. */
  50. public $info = array();
  51. /**
  52. * Holds the file handler resource if the file is opened
  53. *
  54. * @var resource
  55. * @access public
  56. */
  57. public $handle = null;
  58. /**
  59. * enable locking for file reading and writing
  60. *
  61. * @var boolean
  62. * @access public
  63. */
  64. public $lock = null;
  65. /**
  66. * path property
  67. *
  68. * Current file's absolute path
  69. *
  70. * @var mixed null
  71. * @access public
  72. */
  73. public $path = null;
  74. /**
  75. * Constructor
  76. *
  77. * @param string $path Path to file
  78. * @param boolean $create Create file if it does not exist (if true)
  79. * @param integer $mode Mode to apply to the folder holding the file
  80. */
  81. public function __construct($path, $create = false, $mode = 0755) {
  82. $this->Folder = new Folder(dirname($path), $create, $mode);
  83. if (!is_dir($path)) {
  84. $this->name = basename($path);
  85. }
  86. $this->pwd();
  87. $create && !$this->exists() && $this->safe($path) && $this->create();
  88. }
  89. /**
  90. * Closes the current file if it is opened
  91. *
  92. */
  93. public function __destruct() {
  94. $this->close();
  95. }
  96. /**
  97. * Creates the File.
  98. *
  99. * @return boolean Success
  100. */
  101. public function create() {
  102. $dir = $this->Folder->pwd();
  103. if (is_dir($dir) && is_writable($dir) && !$this->exists()) {
  104. $old = umask(0);
  105. if (touch($this->path)) {
  106. umask($old);
  107. return true;
  108. }
  109. }
  110. return false;
  111. }
  112. /**
  113. * Opens the current file with a given $mode
  114. *
  115. * @param string $mode A valid 'fopen' mode string (r|w|a ...)
  116. * @param boolean $force If true then the file will be re-opened even if its already opened, otherwise it won't
  117. * @return boolean True on success, false on failure
  118. */
  119. public function open($mode = 'r', $force = false) {
  120. if (!$force && is_resource($this->handle)) {
  121. return true;
  122. }
  123. clearstatcache();
  124. if ($this->exists() === false) {
  125. if ($this->create() === false) {
  126. return false;
  127. }
  128. }
  129. $this->handle = fopen($this->path, $mode);
  130. if (is_resource($this->handle)) {
  131. return true;
  132. }
  133. return false;
  134. }
  135. /**
  136. * Return the contents of this File as a string.
  137. *
  138. * @param string $bytes where to start
  139. * @param string $mode A `fread` compatible mode.
  140. * @param boolean $force If true then the file will be re-opened even if its already opened, otherwise it won't
  141. * @return mixed string on success, false on failure
  142. */
  143. public function read($bytes = false, $mode = 'rb', $force = false) {
  144. if ($bytes === false && $this->lock === null) {
  145. return file_get_contents($this->path);
  146. }
  147. if ($this->open($mode, $force) === false) {
  148. return false;
  149. }
  150. if ($this->lock !== null && flock($this->handle, LOCK_SH) === false) {
  151. return false;
  152. }
  153. if (is_int($bytes)) {
  154. return fread($this->handle, $bytes);
  155. }
  156. $data = '';
  157. while (!feof($this->handle)) {
  158. $data .= fgets($this->handle, 4096);
  159. }
  160. if ($this->lock !== null) {
  161. flock($this->handle, LOCK_UN);
  162. }
  163. if ($bytes === false) {
  164. $this->close();
  165. }
  166. return trim($data);
  167. }
  168. /**
  169. * Sets or gets the offset for the currently opened file.
  170. *
  171. * @param mixed $offset The $offset in bytes to seek. If set to false then the current offset is returned.
  172. * @param integer $seek PHP Constant SEEK_SET | SEEK_CUR | SEEK_END determining what the $offset is relative to
  173. * @return mixed True on success, false on failure (set mode), false on failure or integer offset on success (get mode)
  174. */
  175. public function offset($offset = false, $seek = SEEK_SET) {
  176. if ($offset === false) {
  177. if (is_resource($this->handle)) {
  178. return ftell($this->handle);
  179. }
  180. } elseif ($this->open() === true) {
  181. return fseek($this->handle, $offset, $seek) === 0;
  182. }
  183. return false;
  184. }
  185. /**
  186. * Prepares a ascii string for writing. Converts line endings to the
  187. * correct terminator for the current platform. If windows "\r\n" will be used
  188. * all other platforms will use "\n"
  189. *
  190. * @param string $data Data to prepare for writing.
  191. * @return string The with converted line endings.
  192. */
  193. public static function prepare($data, $forceWindows = false) {
  194. $lineBreak = "\n";
  195. if (DIRECTORY_SEPARATOR == '\\' || $forceWindows === true) {
  196. $lineBreak = "\r\n";
  197. }
  198. return strtr($data, array("\r\n" => $lineBreak, "\n" => $lineBreak, "\r" => $lineBreak));
  199. }
  200. /**
  201. * Write given data to this File.
  202. *
  203. * @param string $data Data to write to this File.
  204. * @param string $mode Mode of writing. {@link http://php.net/fwrite See fwrite()}.
  205. * @param string $force force the file to open
  206. * @return boolean Success
  207. */
  208. public function write($data, $mode = 'w', $force = false) {
  209. $success = false;
  210. if ($this->open($mode, $force) === true) {
  211. if ($this->lock !== null) {
  212. if (flock($this->handle, LOCK_EX) === false) {
  213. return false;
  214. }
  215. }
  216. if (fwrite($this->handle, $data) !== false) {
  217. $success = true;
  218. }
  219. if ($this->lock !== null) {
  220. flock($this->handle, LOCK_UN);
  221. }
  222. }
  223. return $success;
  224. }
  225. /**
  226. * Append given data string to this File.
  227. *
  228. * @param string $data Data to write
  229. * @param string $force force the file to open
  230. * @return boolean Success
  231. */
  232. public function append($data, $force = false) {
  233. return $this->write($data, 'a', $force);
  234. }
  235. /**
  236. * Closes the current file if it is opened.
  237. *
  238. * @return boolean True if closing was successful or file was already closed, otherwise false
  239. */
  240. public function close() {
  241. if (!is_resource($this->handle)) {
  242. return true;
  243. }
  244. return fclose($this->handle);
  245. }
  246. /**
  247. * Deletes the File.
  248. *
  249. * @return boolean Success
  250. */
  251. public function delete() {
  252. clearstatcache();
  253. if ($this->exists()) {
  254. return unlink($this->path);
  255. }
  256. return false;
  257. }
  258. /**
  259. * Returns the File info.
  260. *
  261. * @return string The File extension
  262. */
  263. public function info() {
  264. if ($this->info == null) {
  265. $this->info = pathinfo($this->path);
  266. }
  267. if (!isset($this->info['filename'])) {
  268. $this->info['filename'] = $this->name();
  269. }
  270. return $this->info;
  271. }
  272. /**
  273. * Returns the File extension.
  274. *
  275. * @return string The File extension
  276. */
  277. public function ext() {
  278. if ($this->info == null) {
  279. $this->info();
  280. }
  281. if (isset($this->info['extension'])) {
  282. return $this->info['extension'];
  283. }
  284. return false;
  285. }
  286. /**
  287. * Returns the File name without extension.
  288. *
  289. * @return string The File name without extension.
  290. */
  291. public function name() {
  292. if ($this->info == null) {
  293. $this->info();
  294. }
  295. if (isset($this->info['extension'])) {
  296. return basename($this->name, '.'.$this->info['extension']);
  297. } elseif ($this->name) {
  298. return $this->name;
  299. }
  300. return false;
  301. }
  302. /**
  303. * makes filename safe for saving
  304. *
  305. * @param string $name The name of the file to make safe if different from $this->name
  306. * @param strin $ext The name of the extension to make safe if different from $this->ext
  307. * @return string $ext the extension of the file
  308. */
  309. public function safe($name = null, $ext = null) {
  310. if (!$name) {
  311. $name = $this->name;
  312. }
  313. if (!$ext) {
  314. $ext = $this->ext();
  315. }
  316. return preg_replace( "/(?:[^\w\.-]+)/", "_", basename($name, $ext));
  317. }
  318. /**
  319. * Get md5 Checksum of file with previous check of Filesize
  320. *
  321. * @param mixed $maxsize in MB or true to force
  322. * @return string md5 Checksum {@link http://php.net/md5_file See md5_file()}
  323. */
  324. public function md5($maxsize = 5) {
  325. if ($maxsize === true) {
  326. return md5_file($this->path);
  327. }
  328. $size = $this->size();
  329. if ($size && $size < ($maxsize * 1024) * 1024) {
  330. return md5_file($this->path);
  331. }
  332. return false;
  333. }
  334. /**
  335. * Returns the full path of the File.
  336. *
  337. * @return string Full path to file
  338. */
  339. public function pwd() {
  340. if (is_null($this->path)) {
  341. $this->path = $this->Folder->slashTerm($this->Folder->pwd()) . $this->name;
  342. }
  343. return $this->path;
  344. }
  345. /**
  346. * Returns true if the File exists.
  347. *
  348. * @return boolean true if it exists, false otherwise
  349. */
  350. public function exists() {
  351. return (file_exists($this->path) && is_file($this->path));
  352. }
  353. /**
  354. * Returns the "chmod" (permissions) of the File.
  355. *
  356. * @return string Permissions for the file
  357. */
  358. public function perms() {
  359. if ($this->exists()) {
  360. return substr(sprintf('%o', fileperms($this->path)), -4);
  361. }
  362. return false;
  363. }
  364. /**
  365. * Returns the Filesize
  366. *
  367. * @return integer size of the file in bytes, or false in case of an error
  368. */
  369. public function size() {
  370. if ($this->exists()) {
  371. return filesize($this->path);
  372. }
  373. return false;
  374. }
  375. /**
  376. * Returns true if the File is writable.
  377. *
  378. * @return boolean true if its writable, false otherwise
  379. */
  380. public function writable() {
  381. return is_writable($this->path);
  382. }
  383. /**
  384. * Returns true if the File is executable.
  385. *
  386. * @return boolean true if its executable, false otherwise
  387. */
  388. public function executable() {
  389. return is_executable($this->path);
  390. }
  391. /**
  392. * Returns true if the File is readable.
  393. *
  394. * @return boolean true if file is readable, false otherwise
  395. */
  396. public function readable() {
  397. return is_readable($this->path);
  398. }
  399. /**
  400. * Returns the File's owner.
  401. *
  402. * @return integer the Fileowner
  403. */
  404. public function owner() {
  405. if ($this->exists()) {
  406. return fileowner($this->path);
  407. }
  408. return false;
  409. }
  410. /**
  411. * Returns the File's group.
  412. *
  413. * @return integer the Filegroup
  414. */
  415. public function group() {
  416. if ($this->exists()) {
  417. return filegroup($this->path);
  418. }
  419. return false;
  420. }
  421. /**
  422. * Returns last access time.
  423. *
  424. * @return integer timestamp Timestamp of last access time
  425. */
  426. public function lastAccess() {
  427. if ($this->exists()) {
  428. return fileatime($this->path);
  429. }
  430. return false;
  431. }
  432. /**
  433. * Returns last modified time.
  434. *
  435. * @return integer timestamp Timestamp of last modification
  436. */
  437. public function lastChange() {
  438. if ($this->exists()) {
  439. return filemtime($this->path);
  440. }
  441. return false;
  442. }
  443. /**
  444. * Returns the current folder.
  445. *
  446. * @return Folder Current folder
  447. */
  448. public function &Folder() {
  449. return $this->Folder;
  450. }
  451. /**
  452. * Copy the File to $dest
  453. *
  454. * @param string $dest destination for the copy
  455. * @param boolean $overwrite Overwrite $dest if exists
  456. * @return boolean Succes
  457. */
  458. public function copy($dest, $overwrite = true) {
  459. if (!$this->exists() || is_file($dest) && !$overwrite) {
  460. return false;
  461. }
  462. return copy($this->path, $dest);
  463. }
  464. }