統計
| ブランチ: | リビジョン:

pictcode / lib / Cake / Utility / File.php @ 635eef61

履歴 | 表示 | アノテート | ダウンロード (15.981 KB)

1
<?php
2
/**
3
 * Convenience class for reading, writing and appending to files.
4
 *
5
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7
 *
8
 * Licensed under The MIT License
9
 * For full copyright and license information, please see the LICENSE.txt
10
 * Redistributions of files must retain the above copyright notice.
11
 *
12
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13
 * @link          http://cakephp.org CakePHP(tm) Project
14
 * @package       Cake.Utility
15
 * @since         CakePHP(tm) v 0.2.9
16
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
17
 */
18

    
19
App::uses('Folder', 'Utility');
20

    
21
/**
22
 * Convenience class for reading, writing and appending to files.
23
 *
24
 * @package       Cake.Utility
25
 */
26
class File {
27

    
28
/**
29
 * Folder object of the file
30
 *
31
 * @var Folder
32
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$Folder
33
 */
34
        public $Folder = null;
35

    
36
/**
37
 * File name
38
 *
39
 * @var string
40
 * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$name
41
 */
42
        public $name = null;
43

    
44
/**
45
 * File info
46
 *
47
 * @var array
48
 * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$info
49
 */
50
        public $info = array();
51

    
52
/**
53
 * Holds the file handler resource if the file is opened
54
 *
55
 * @var resource
56
 * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$handle
57
 */
58
        public $handle = null;
59

    
60
/**
61
 * Enable locking for file reading and writing
62
 *
63
 * @var bool
64
 * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$lock
65
 */
66
        public $lock = null;
67

    
68
/**
69
 * Path property
70
 *
71
 * Current file's absolute path
72
 *
73
 * @var mixed
74
 * http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::$path
75
 */
76
        public $path = null;
77

    
78
/**
79
 * Constructor
80
 *
81
 * @param string $path Path to file
82
 * @param bool $create Create file if it does not exist (if true)
83
 * @param int $mode Mode to apply to the folder holding the file
84
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File
85
 */
86
        public function __construct($path, $create = false, $mode = 0755) {
87
                $this->Folder = new Folder(dirname($path), $create, $mode);
88
                if (!is_dir($path)) {
89
                        $this->name = basename($path);
90
                }
91
                $this->pwd();
92
                $create && !$this->exists() && $this->safe($path) && $this->create();
93
        }
94

    
95
/**
96
 * Closes the current file if it is opened
97
 */
98
        public function __destruct() {
99
                $this->close();
100
        }
101

    
102
/**
103
 * Creates the file.
104
 *
105
 * @return bool Success
106
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::create
107
 */
108
        public function create() {
109
                $dir = $this->Folder->pwd();
110
                if (is_dir($dir) && is_writable($dir) && !$this->exists()) {
111
                        if (touch($this->path)) {
112
                                return true;
113
                        }
114
                }
115
                return false;
116
        }
117

    
118
/**
119
 * Opens the current file with a given $mode
120
 *
121
 * @param string $mode A valid 'fopen' mode string (r|w|a ...)
122
 * @param bool $force If true then the file will be re-opened even if its already opened, otherwise it won't
123
 * @return bool True on success, false on failure
124
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::open
125
 */
126
        public function open($mode = 'r', $force = false) {
127
                if (!$force && is_resource($this->handle)) {
128
                        return true;
129
                }
130
                if ($this->exists() === false) {
131
                        if ($this->create() === false) {
132
                                return false;
133
                        }
134
                }
135

    
136
                $this->handle = fopen($this->path, $mode);
137
                if (is_resource($this->handle)) {
138
                        return true;
139
                }
140
                return false;
141
        }
142

    
143
/**
144
 * Return the contents of this file as a string.
145
 *
146
 * @param string $bytes where to start
147
 * @param string $mode A `fread` compatible mode.
148
 * @param bool $force If true then the file will be re-opened even if its already opened, otherwise it won't
149
 * @return mixed string on success, false on failure
150
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::read
151
 */
152
        public function read($bytes = false, $mode = 'rb', $force = false) {
153
                if ($bytes === false && $this->lock === null) {
154
                        return file_get_contents($this->path);
155
                }
156
                if ($this->open($mode, $force) === false) {
157
                        return false;
158
                }
159
                if ($this->lock !== null && flock($this->handle, LOCK_SH) === false) {
160
                        return false;
161
                }
162
                if (is_int($bytes)) {
163
                        return fread($this->handle, $bytes);
164
                }
165

    
166
                $data = '';
167
                while (!feof($this->handle)) {
168
                        $data .= fgets($this->handle, 4096);
169
                }
170

    
171
                if ($this->lock !== null) {
172
                        flock($this->handle, LOCK_UN);
173
                }
174
                if ($bytes === false) {
175
                        $this->close();
176
                }
177
                return trim($data);
178
        }
179

    
180
/**
181
 * Sets or gets the offset for the currently opened file.
182
 *
183
 * @param int|bool $offset The $offset in bytes to seek. If set to false then the current offset is returned.
184
 * @param int $seek PHP Constant SEEK_SET | SEEK_CUR | SEEK_END determining what the $offset is relative to
185
 * @return mixed True on success, false on failure (set mode), false on failure or integer offset on success (get mode)
186
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::offset
187
 */
188
        public function offset($offset = false, $seek = SEEK_SET) {
189
                if ($offset === false) {
190
                        if (is_resource($this->handle)) {
191
                                return ftell($this->handle);
192
                        }
193
                } elseif ($this->open() === true) {
194
                        return fseek($this->handle, $offset, $seek) === 0;
195
                }
196
                return false;
197
        }
198

    
199
/**
200
 * Prepares an ASCII string for writing. Converts line endings to the
201
 * correct terminator for the current platform. If Windows, "\r\n" will be used,
202
 * all other platforms will use "\n"
203
 *
204
 * @param string $data Data to prepare for writing.
205
 * @param bool $forceWindows If true forces usage Windows newline string.
206
 * @return string The with converted line endings.
207
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::prepare
208
 */
209
        public static function prepare($data, $forceWindows = false) {
210
                $lineBreak = "\n";
211
                if (DIRECTORY_SEPARATOR === '\\' || $forceWindows === true) {
212
                        $lineBreak = "\r\n";
213
                }
214
                return strtr($data, array("\r\n" => $lineBreak, "\n" => $lineBreak, "\r" => $lineBreak));
215
        }
216

    
217
/**
218
 * Write given data to this file.
219
 *
220
 * @param string $data Data to write to this File.
221
 * @param string $mode Mode of writing. {@link http://php.net/fwrite See fwrite()}.
222
 * @param string $force Force the file to open
223
 * @return bool Success
224
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::write
225
 */
226
        public function write($data, $mode = 'w', $force = false) {
227
                $success = false;
228
                if ($this->open($mode, $force) === true) {
229
                        if ($this->lock !== null) {
230
                                if (flock($this->handle, LOCK_EX) === false) {
231
                                        return false;
232
                                }
233
                        }
234

    
235
                        if (fwrite($this->handle, $data) !== false) {
236
                                $success = true;
237
                        }
238
                        if ($this->lock !== null) {
239
                                flock($this->handle, LOCK_UN);
240
                        }
241
                }
242
                return $success;
243
        }
244

    
245
/**
246
 * Append given data string to this file.
247
 *
248
 * @param string $data Data to write
249
 * @param string $force Force the file to open
250
 * @return bool Success
251
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::append
252
 */
253
        public function append($data, $force = false) {
254
                return $this->write($data, 'a', $force);
255
        }
256

    
257
/**
258
 * Closes the current file if it is opened.
259
 *
260
 * @return bool True if closing was successful or file was already closed, otherwise false
261
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::close
262
 */
263
        public function close() {
264
                if (!is_resource($this->handle)) {
265
                        return true;
266
                }
267
                return fclose($this->handle);
268
        }
269

    
270
/**
271
 * Deletes the file.
272
 *
273
 * @return bool Success
274
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::delete
275
 */
276
        public function delete() {
277
                if (is_resource($this->handle)) {
278
                        fclose($this->handle);
279
                        $this->handle = null;
280
                }
281
                if ($this->exists()) {
282
                        return unlink($this->path);
283
                }
284
                return false;
285
        }
286

    
287
/**
288
 * Returns the file info as an array with the following keys:
289
 *
290
 * - dirname
291
 * - basename
292
 * - extension
293
 * - filename
294
 * - filesize
295
 * - mime
296
 *
297
 * @return array File information.
298
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::info
299
 */
300
        public function info() {
301
                if (!$this->info) {
302
                        $this->info = pathinfo($this->path);
303
                }
304
                if (!isset($this->info['filename'])) {
305
                        $this->info['filename'] = $this->name();
306
                }
307
                if (!isset($this->info['filesize'])) {
308
                        $this->info['filesize'] = $this->size();
309
                }
310
                if (!isset($this->info['mime'])) {
311
                        $this->info['mime'] = $this->mime();
312
                }
313
                return $this->info;
314
        }
315

    
316
/**
317
 * Returns the file extension.
318
 *
319
 * @return string The file extension
320
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::ext
321
 */
322
        public function ext() {
323
                if (!$this->info) {
324
                        $this->info();
325
                }
326
                if (isset($this->info['extension'])) {
327
                        return $this->info['extension'];
328
                }
329
                return false;
330
        }
331

    
332
/**
333
 * Returns the file name without extension.
334
 *
335
 * @return string The file name without extension.
336
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::name
337
 */
338
        public function name() {
339
                if (!$this->info) {
340
                        $this->info();
341
                }
342
                if (isset($this->info['extension'])) {
343
                        return basename($this->name, '.' . $this->info['extension']);
344
                } elseif ($this->name) {
345
                        return $this->name;
346
                }
347
                return false;
348
        }
349

    
350
/**
351
 * Makes file name safe for saving
352
 *
353
 * @param string $name The name of the file to make safe if different from $this->name
354
 * @param string $ext The name of the extension to make safe if different from $this->ext
355
 * @return string ext The extension of the file
356
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::safe
357
 */
358
        public function safe($name = null, $ext = null) {
359
                if (!$name) {
360
                        $name = $this->name;
361
                }
362
                if (!$ext) {
363
                        $ext = $this->ext();
364
                }
365
                return preg_replace("/(?:[^\w\.-]+)/", "_", basename($name, $ext));
366
        }
367

    
368
/**
369
 * Get md5 Checksum of file with previous check of Filesize
370
 *
371
 * @param int|bool $maxsize in MB or true to force
372
 * @return string|false md5 Checksum {@link http://php.net/md5_file See md5_file()}, or false in case of an error
373
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::md5
374
 */
375
        public function md5($maxsize = 5) {
376
                if ($maxsize === true) {
377
                        return md5_file($this->path);
378
                }
379

    
380
                $size = $this->size();
381
                if ($size && $size < ($maxsize * 1024) * 1024) {
382
                        return md5_file($this->path);
383
                }
384

    
385
                return false;
386
        }
387

    
388
/**
389
 * Returns the full path of the file.
390
 *
391
 * @return string Full path to the file
392
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::pwd
393
 */
394
        public function pwd() {
395
                if ($this->path === null) {
396
                        $dir = $this->Folder->pwd();
397
                        if (is_dir($dir)) {
398
                                $this->path = $this->Folder->slashTerm($dir) . $this->name;
399
                        }
400
                }
401
                return $this->path;
402
        }
403

    
404
/**
405
 * Returns true if the file exists.
406
 *
407
 * @return bool True if it exists, false otherwise
408
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::exists
409
 */
410
        public function exists() {
411
                $this->clearStatCache();
412
                return (file_exists($this->path) && is_file($this->path));
413
        }
414

    
415
/**
416
 * Returns the "chmod" (permissions) of the file.
417
 *
418
 * @return string|false Permissions for the file, or false in case of an error
419
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::perms
420
 */
421
        public function perms() {
422
                if ($this->exists()) {
423
                        return substr(sprintf('%o', fileperms($this->path)), -4);
424
                }
425
                return false;
426
        }
427

    
428
/**
429
 * Returns the file size
430
 *
431
 * @return int|false Size of the file in bytes, or false in case of an error
432
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::size
433
 */
434
        public function size() {
435
                if ($this->exists()) {
436
                        return filesize($this->path);
437
                }
438
                return false;
439
        }
440

    
441
/**
442
 * Returns true if the file is writable.
443
 *
444
 * @return bool True if it's writable, false otherwise
445
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::writable
446
 */
447
        public function writable() {
448
                return is_writable($this->path);
449
        }
450

    
451
/**
452
 * Returns true if the File is executable.
453
 *
454
 * @return bool True if it's executable, false otherwise
455
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::executable
456
 */
457
        public function executable() {
458
                return is_executable($this->path);
459
        }
460

    
461
/**
462
 * Returns true if the file is readable.
463
 *
464
 * @return bool True if file is readable, false otherwise
465
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::readable
466
 */
467
        public function readable() {
468
                return is_readable($this->path);
469
        }
470

    
471
/**
472
 * Returns the file's owner.
473
 *
474
 * @return int|false The file owner, or false in case of an error
475
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::owner
476
 */
477
        public function owner() {
478
                if ($this->exists()) {
479
                        return fileowner($this->path);
480
                }
481
                return false;
482
        }
483

    
484
/**
485
 * Returns the file's group.
486
 *
487
 * @return int|false The file group, or false in case of an error
488
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::group
489
 */
490
        public function group() {
491
                if ($this->exists()) {
492
                        return filegroup($this->path);
493
                }
494
                return false;
495
        }
496

    
497
/**
498
 * Returns last access time.
499
 *
500
 * @return int|false Timestamp of last access time, or false in case of an error
501
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::lastAccess
502
 */
503
        public function lastAccess() {
504
                if ($this->exists()) {
505
                        return fileatime($this->path);
506
                }
507
                return false;
508
        }
509

    
510
/**
511
 * Returns last modified time.
512
 *
513
 * @return int|false Timestamp of last modification, or false in case of an error
514
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::lastChange
515
 */
516
        public function lastChange() {
517
                if ($this->exists()) {
518
                        return filemtime($this->path);
519
                }
520
                return false;
521
        }
522

    
523
/**
524
 * Returns the current folder.
525
 *
526
 * @return Folder Current folder
527
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::Folder
528
 */
529
        public function folder() {
530
                return $this->Folder;
531
        }
532

    
533
/**
534
 * Copy the File to $dest
535
 *
536
 * @param string $dest Destination for the copy
537
 * @param bool $overwrite Overwrite $dest if exists
538
 * @return bool Success
539
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#File::copy
540
 */
541
        public function copy($dest, $overwrite = true) {
542
                if (!$this->exists() || is_file($dest) && !$overwrite) {
543
                        return false;
544
                }
545
                return copy($this->path, $dest);
546
        }
547

    
548
/**
549
 * Get the mime type of the file. Uses the finfo extension if
550
 * its available, otherwise falls back to mime_content_type
551
 *
552
 * @return false|string The mimetype of the file, or false if reading fails.
553
 */
554
        public function mime() {
555
                if (!$this->exists()) {
556
                        return false;
557
                }
558
                if (function_exists('finfo_open')) {
559
                        $finfo = finfo_open(FILEINFO_MIME);
560
                        $finfo = finfo_file($finfo, $this->pwd());
561
                        if (!$finfo) {
562
                                return false;
563
                        }
564
                        list($type) = explode(';', $finfo);
565
                        return $type;
566
                }
567
                if (function_exists('mime_content_type')) {
568
                        return mime_content_type($this->pwd());
569
                }
570
                return false;
571
        }
572

    
573
/**
574
 * Clear PHP's internal stat cache
575
 *
576
 * For 5.3 onwards it's possible to clear cache for just a single file. Passing true
577
 * will clear all the stat cache.
578
 *
579
 * @param bool $all Clear all cache or not
580
 * @return void
581
 */
582
        public function clearStatCache($all = false) {
583
                if ($all === false && version_compare(PHP_VERSION, '5.3.0') >= 0) {
584
                        return clearstatcache(true, $this->path);
585
                }
586

    
587
                return clearstatcache();
588
        }
589

    
590
/**
591
 * Searches for a given text and replaces the text if found.
592
 *
593
 * @param string|array $search Text(s) to search for.
594
 * @param string|array $replace Text(s) to replace with.
595
 * @return bool Success
596
 */
597
        public function replaceText($search, $replace) {
598
                if (!$this->open('r+')) {
599
                        return false;
600
                }
601

    
602
                if ($this->lock !== null) {
603
                        if (flock($this->handle, LOCK_EX) === false) {
604
                                return false;
605
                        }
606
                }
607

    
608
                $replaced = $this->write(str_replace($search, $replace, $this->read()), 'w', true);
609

    
610
                if ($this->lock !== null) {
611
                        flock($this->handle, LOCK_UN);
612
                }
613
                $this->close();
614

    
615
                return $replaced;
616
        }
617

    
618
}