File.php 11 KB

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