Completed
Push — xmfasserts ( b960a9 )
by Richard
06:03
created

XoopsFileHandler::__destruct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
/*
13
 * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
14
 * Copyright 2005-2008, Cake Software Foundation, Inc.
15
 *                                     1785 E. Sahara Avenue, Suite 490-204
16
 *                                     Las Vegas, Nevada 89104
17
 *
18
 * Licensed under The MIT License
19
 * Redistributions of files must retain the above copyright notice.
20
 *
21
 */
22
23
/**
24
 * File engine For XOOPS
25
 * Convenience class for reading, writing and appending to files.
26
 * PHP 5.3
27
 *
28
 * @category  Xoops\Class\File\File
29
 * @package   File
30
 * @author    Taiwen Jiang <[email protected]>
31
 * @copyright 2005-2008 Cake Software Foundation, Inc.
32
 * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
33
 * @version   $Id$
34
 * @link      http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
35
 * @since     CakePHP(tm) v 0.2.9
36
 */
37
class XoopsFileHandler
38
{
39
    /**
40
     * folder object of the File
41
     *
42
     * @var XoopsFolderHandler
43
     * @access public
44
     */
45
    public $folder = null;
46
47
    /**
48
     * Filename
49
     *
50
     * @var string
51
     */
52
    public $name = null;
53
54
    /**
55
     * file info
56
     *
57
     * @var string
58
     */
59
    public $info = array();
60
61
    /**
62
     * Holds the file handler resource if the file is opened
63
     *
64
     * @var resource
65
     */
66
    public $handle = null;
67
68
    /**
69
     * enable locking for file reading and writing
70
     *
71
     * @var boolean
72
     */
73
    public $lock = null;
74
75
    /**
76
     * Constructor
77
     *
78
     * @param string  $path   Path to file
79
     * @param boolean $create Create file if it does not exist (if true)
80
     * @param integer $mode   Mode to apply to the folder holding the file
81
     *
82
     * @todo reconsider validity this class, if valid add exceptions to __construct()
83
     */
84 45
    public function __construct($path, $create = false, $mode = 0755)
85
    {
86 45
        $this->folder = XoopsFile::getHandler('folder', dirname($path), $create, $mode);
0 ignored issues
show
Documentation Bug introduced by
It seems like \XoopsFile::getHandler('...$path), $create, $mode) can also be of type false. However, the property $folder is declared as type object<XoopsFolderHandler>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
87 45
        if (!is_dir($path)) {
88 45
            $this->name = basename($path);
89
        } else {
90
            return; // false;
91
        }
92 45
        if (!$this->exists()) {
93 22
            if ($create === true) {
94 8
                if ($this->safe($path) && $this->create() === false) {
95 8
                    return; // false;
96
                }
97
            } else {
98 15
                return; // false;
99
            }
100
        }
101 40
        return; // true;
102
    }
103
104
105
    /**
106
     * Closes the current file if it is opened
107
     */
108 45
    public function __destruct()
109
    {
110 45
        $this->close();
111 45
    }
112
113
    /**
114
     * Creates the File.
115
     *
116
     * @return boolean Success
117
     */
118 11
    public function create()
119
    {
120 11
        $dir = $this->folder->pwd();
121 11
        if (is_dir($dir) && is_writable($dir) && !$this->exists()) {
122 11
            if (touch($this->pwd())) {
123 11
                return true;
124
            }
125
        }
126
        return false;
127
    }
128
129
    /**
130
     * Opens the current file with a given $mode
131
     *
132
     * @param string  $mode  A valid 'fopen' mode string (r|w|a ...)
133
     * @param boolean $force If true then the file will be re-opened even if
134
     * its already opened, otherwise it won't
135
     *
136
     * @return boolean True on success, false on failure
137
     */
138 5
    public function open($mode = 'r', $force = false)
139
    {
140 5
        if (!$force && is_resource($this->handle)) {
141 2
            return true;
142
        }
143 5
        if ($this->exists() === false) {
144 3
            if ($this->create() === false) {
145
                return false;
146
            }
147
        }
148 5
        $this->handle = fopen($this->pwd(), $mode);
149 5
        if (is_resource($this->handle)) {
150 5
            return true;
151
        }
152
        return false;
153
    }
154
155
    /**
156
     * Return the contents of this File as a string.
157
     *
158
     * @param string|bool $bytes where to start
159
     * @param string      $mode  mode of file access
160
     * @param boolean     $force If true then the file will be re-opened even if its already opened, otherwise it won't
161
     *
162
     * @return mixed string on success, false on failure
163
     */
164 21
    public function read($bytes = false, $mode = 'rb', $force = false)
165
    {
166 21
        $success = false;
167 21
        if ($this->lock !== null) {
168
            if (flock($this->handle, LOCK_SH) === false) {
169
                return false;
170
            }
171
        }
172 21
        if ($bytes === false) {
173 21
            $success = file_get_contents($this->pwd());
174
        } else {
175 1
            if ($this->open($mode, $force) === true) {
176 1
                if (is_int($bytes)) {
177 1
                    $success = fread($this->handle, $bytes);
178
                } else {
179 1
                    $data = '';
180 1
                    while (!feof($this->handle)) {
181 1
                        $data .= fgets($this->handle, 4096);
182
                    }
183 1
                    $success = trim($data);
184
                }
185
            }
186
        }
187 21
        if ($this->lock !== null) {
188
            flock($this->handle, LOCK_UN);
189
        }
190 21
        return $success;
191
    }
192
193
    /**
194
     * Sets or gets the offset for the currently opened file.
195
     *
196
     * @param mixed   $offset The $offset in bytes to seek. If set to false then the current offset is returned.
197
     * @param integer $seek   PHP Constant SEEK_SET | SEEK_CUR | SEEK_END determining what the $offset is relative to
198
     *
199
     * @return mixed True on success, false on failure (set mode),
200
     * false on failure or integer offset on success (get mode)
201
     */
202 1
    public function offset($offset = false, $seek = SEEK_SET)
203
    {
204 1
        if ($offset === false) {
205
            if (is_resource($this->handle)) {
206
                return ftell($this->handle);
207
            }
208
        } else {
209 1
            if ($this->open() === true) {
210 1
                return fseek($this->handle, $offset, $seek) === 0;
211
            }
212
        }
213
        return false;
214
    }
215
216
    /**
217
     * Prepares a ascii string for writing
218
     * fixes line endings
219
     *
220
     * @param string $data Data to prepare for writing.
221
     *
222
     * @return string
223
     */
224 1
    public function prepare($data)
225
    {
226 1
        $lineBreak = "\n";
227 1
        if (substr(PHP_OS, 0, 3) === 'WIN') {
228
            $lineBreak = "\r\n";
229
        }
230 1
        return strtr($data, array("\r\n" => $lineBreak, "\n" => $lineBreak, "\r" => $lineBreak));
231
    }
232
233
    /**
234
     * Write given data to this File.
235
     *
236
     * @param string $data  Data to write to this File.
237
     * @param string $mode  Mode of writing. {@link http://php.net/fwrite See fwrite()}.
238
     * @param bool   $force force the file to open
239
     *
240
     * @return bool Success
241
     */
242 3
    public function write($data, $mode = 'w', $force = false)
243
    {
244 3
        $success = false;
245 3
        if ($this->open($mode, $force) === true) {
246 3
            if ($this->lock !== null) {
247
                if (flock($this->handle, LOCK_EX) === false) {
248
                    return false;
249
                }
250
            }
251 3
            if (fwrite($this->handle, $data) !== false) {
252 3
                $success = true;
253
            }
254 3
            if ($this->lock !== null) {
255
                flock($this->handle, LOCK_UN);
256
            }
257
        }
258 3
        return $success;
259
    }
260
261
    /**
262
     * Append given data string to this File.
263
     *
264
     * @param string $data  Data to write
265
     * @param bool   $force force the file to open
266
     *
267
     * @return bool Success
268
     */
269 1
    public function append($data, $force = false)
270
    {
271 1
        return $this->write($data, 'a', $force);
272
    }
273
274
    /**
275
     * Closes the current file if it is opened.
276
     *
277
     * @return boolean True if closing was successful or file was already closed, otherwise false
278
     */
279 45
    public function close()
280
    {
281 45
        if (!is_resource($this->handle)) {
282 44
            return true;
283
        }
284 5
        return fclose($this->handle);
285
    }
286
287
    /**
288
     * Deletes the File.
289
     *
290
     * @return boolean Success
291
     */
292 5
    public function delete()
293
    {
294 5
        if ($this->exists()) {
295 5
            return unlink($this->pwd());
296
        }
297 1
        return false;
298
    }
299
300
    /**
301
     * Returns the File information array
302
     *
303
     * @return array The File information
304
     */
305 9
    public function info()
306
    {
307 9
        if ($this->info == null) {
308 9
            $this->info = pathinfo($this->pwd());
309
        }
310 9
        if (!isset($this->info['filename'])) {
311
            $this->info['filename'] = $this->name();
312
        }
313 9
        return $this->info;
314
    }
315
316
    /**
317
     * Returns the File extension.
318
     *
319
     * @return string The File extension
320
     */
321 9
    public function ext()
322
    {
323 9
        if ($this->info == null) {
324 9
            $this->info();
325
        }
326 9
        if (isset($this->info['extension'])) {
327 9
            return $this->info['extension'];
328
        }
329 1
        return false;
330
    }
331
332
    /**
333
     * Returns the File name without extension.
334
     *
335
     * @return string The File name without extension.
336
     */
337 1
    public function name()
338
    {
339 1
        if ($this->info == null) {
340
            $this->info();
341
        }
342 1
        if (isset($this->info['extension'])) {
343 1
            return basename($this->name, '.' . $this->info['extension']);
344 1
        } elseif ($this->name) {
345 1
            return $this->name;
346
        }
347
        return false;
348
    }
349
350
    /**
351
     * makes filename 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 extension of the file
355
     *
356
     * @return string
357
     */
358 9
    public function safe($name = null, $ext = null)
359
    {
360 9
        if (!$name) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $name of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
361 1
            $name = $this->name;
362
        }
363 9
        if (!$ext) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ext of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
364 9
            $ext = $this->ext();
365
        }
366 9
        return preg_replace('/[^\w\.-]+/', '_', basename($name, $ext));
367
    }
368
369
    /**
370
     * Get md5 Checksum of file with previous check of Filesize
371
     *
372
     * @param integer $maxsize in MB or true to force
373
     *
374
     * @return string md5 Checksum {@link http://php.net/md5_file See md5_file()}
375
     */
376 1
    public function md5($maxsize = 5)
377
    {
378 1
        if ($maxsize === true) {
379 1
            return md5_file($this->pwd());
380
        } else {
381 1
            $size = $this->size();
382 1
            if ($size && $size < ($maxsize * 1024) * 1024) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $size of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
383 1
                return md5_file($this->pwd());
384
            }
385
        }
386 1
        return false;
387
    }
388
389
    /**
390
     * Returns the full path of the File.
391
     *
392
     * @return string Full path to file
393
     */
394 45
    public function pwd()
395
    {
396 45
        return $this->folder->slashTerm($this->folder->pwd()) . $this->name;
397
    }
398
399
    /**
400
     * Returns true if the File exists.
401
     *
402
     * @return bool true if it exists, false otherwise
403
     */
404 45
    public function exists()
405
    {
406 45
        $exists = is_file($this->pwd());
407 45
        return $exists;
408
    }
409
410
    /**
411
     * Returns the "chmod" (permissions) of the File.
412
     *
413
     * @return string Permissions for the file
414
     */
415 1
    public function perms()
416
    {
417 1
        if ($this->exists()) {
418 1
            return substr(sprintf('%o', fileperms($this->pwd())), -4);
419
        }
420 1
        return false;
421
    }
422
423
    /**
424
     * Returns the Filesize, either in bytes or in human-readable format.
425
     *
426
     * @return bool|int filesize as int or as a human-readable string
427
     */
428 2
    public function size()
429
    {
430 2
        if ($this->exists()) {
431 2
            clearstatcache();
432 2
            return filesize($this->pwd());
433
        }
434 1
        return false;
435
    }
436
437
    /**
438
     * Returns true if the File is writable.
439
     *
440
     * @return boolean true if its writable, false otherwise
441
     */
442 1
    public function writable()
443
    {
444 1
        return is_writable($this->pwd());
445
    }
446
447
    /**
448
     * Returns true if the File is executable.
449
     *
450
     * @return boolean true if its executable, false otherwise
451
     */
452 1
    public function executable()
453
    {
454 1
        return is_executable($this->pwd());
455
    }
456
457
    /**
458
     * Returns true if the File is readable.
459
     *
460
     * @return boolean true if file is readable, false otherwise
461
     */
462 1
    public function readable()
463
    {
464 1
        return is_readable($this->pwd());
465
    }
466
467
    /**
468
     * Returns the File's owner.
469
     *
470
     * @return int|bool the Fileowner
471
     */
472 1
    public function owner()
473
    {
474 1
        if ($this->exists()) {
475 1
            return fileowner($this->pwd());
476
        }
477 1
        return false;
478
    }
479
480
    /**
481
     * Returns the File group.
482
     *
483
     * @return int|bool the Filegroup
484
     */
485 1
    public function group()
486
    {
487 1
        if ($this->exists()) {
488 1
            return filegroup($this->pwd());
489
        }
490 1
        return false;
491
    }
492
493
    /**
494
     * Returns last access time.
495
     *
496
     * @return int|bool timestamp Timestamp of last access time
497
     */
498 1
    public function lastAccess()
499
    {
500 1
        if ($this->exists()) {
501 1
            return fileatime($this->pwd());
502
        }
503 1
        return false;
504
    }
505
506
    /**
507
     * Returns last modified time.
508
     *
509
     * @return int|bool timestamp Timestamp of last modification
510
     */
511 1
    public function lastChange()
512
    {
513 1
        if ($this->exists()) {
514 1
            return filemtime($this->pwd());
515
        }
516 1
        return false;
517
    }
518
519
    /**
520
     * Returns the current folder.
521
     *
522
     * @return XoopsFolderHandler Current folder
523
     */
524 1
    public function folder()
525
    {
526 1
        return $this->folder;
527
    }
528
}
529