Completed
Push — master ( b4d6a5...352f6d )
by Basil
02:42
created

FileHelper::getFileInfo()   B

Complexity

Conditions 7
Paths 64

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 8.8333
c 0
b 0
f 0
cc 7
nc 64
nop 1
1
<?php
2
3
namespace luya\helpers;
4
5
use Yii;
6
use Exception;
7
8
/**
9
 * Helper methods when dealing with Files.
10
 *
11
 * Extends the {{yii\helpers\FileHelper}} class by some usefull functions like:
12
 *
13
 * + {{luya\helpers\FileHelper::humanReadableFilesize()}}
14
 * + {{luya\helpers\FileHelper::ensureExtension()}}
15
 * + {{luya\helpers\FileHelper::md5sum()}}
16
 * + {{luya\helpers\FileHelper::writeFile()}}
17
 * + {{luya\helpers\FileHelper::getFileContent()}}
18
 * + {{luya\helpers\FileHelper::unlink()}}
19
 *
20
 * @author Basil Suter <[email protected]>
21
 * @since 1.0.0
22
 */
23
class FileHelper extends \yii\helpers\BaseFileHelper
24
{
25
    /**
26
     * Generate a human readable size informations from provided Byte/s size
27
     *
28
     * @param integer $size The size to convert in Byte
29
     * @return string The readable size definition
30
     */
31
    public static function humanReadableFilesize($size)
32
    {
33
        $mod = 1024;
34
        $units = explode(' ', 'B KB MB GB TB PB');
35
        for ($i = 0; $size > $mod; ++$i) {
36
            $size /= $mod;
37
        }
38
39
        return round($size, 2).' '.$units[$i];
40
    }
41
42
    /**
43
     * Append a file extension to a path/file if there is no or an empty extension provided, this
44
     * helper methods is used to make sure the right extension existing on files.
45
     *
46
     * @param string $file The file where extension should be append if not existing
47
     * @param string $extension
48
     * @return string the ensured file/path with extension
49
     */
50
    public static function ensureExtension($file, $extension)
51
    {
52
        $info = pathinfo($file);
53
        if (!isset($info['extension']) || empty($info['extension'])) {
54
            $file = rtrim($file, '.') . '.' . $extension;
55
        }
56
57
        return $file;
58
    }
59
    
60
    
61
    
62
    /**
63
     * Provide class informations from a file path or file content.
64
     *
65
     * This is used when working with file paths from composer, in order to detect class and namespace from a given file.
66
     *
67
     * @param string $file The file path to the class into order to get infos from, could also be the content directly from a given file.
68
     * @return array If the given filepath is a file, it will return an array with the keys:
69
     * + namespace: the namespace of the file, if false no namespace could have been determined.
70
     * + class: the class name of the file, if false no class could have been determined.
71
     */
72
    public static function classInfo($file)
73
    {
74
        if (is_file($file)) {
75
            $phpCode = file_get_contents($file);
76
        } else {
77
            $phpCode = $file;
78
        }
79
        
80
        $namespace = false;
81
        
82
        if (preg_match('/^namespace\s+(.+?);(\s+|\r\n)?$/sm', $phpCode, $results)) {
83
            $namespace = $results[1];
84
        }
85
        
86
        $classes = self::classNameByTokens($phpCode);
87
        
88
        return ['namespace' => $namespace, 'class' => end($classes)];
89
    }
90
    
91
    /**
92
     * Tokenize the php code from a given class in in order to determine the class name.
93
     *
94
     * @param string $phpCode The php code to tokenize and find the clas name from
95
     * @return array
96
     */
97
    private static function classNameByTokens($phpCode)
98
    {
99
        $classes = [];
100
        $tokens = token_get_all($phpCode);
101
        $count = count($tokens);
102
        for ($i = 2; $i < $count; $i++) {
103
            if ($tokens[$i - 2][0] == T_CLASS && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING) {
104
                $classes[] = $tokens[$i][1];
105
            }
106
        }
107
        
108
        return $classes;
109
    }
110
111
    /**
112
     * Create a unique hash name from a given file.
113
     *
114
     * Warning
115
     * Because PHP's integer type is signed many crc32 checksums will result in negative integers on 32bit platforms. On 64bit installations all crc32() results will be positive integers though.
116
     * So you need to use the "%u" formatter of sprintf() or printf() to get the string representation of the unsigned crc32() checksum in decimal format.
117
     *
118
     * @var string $fileName The file name which should be hashed
119
     * @return string
120
     */
121
    public static function hashName($fileName)
122
    {
123
        return sprintf('%s', hash('crc32b', uniqid($fileName, true)));
124
    }
125
    
126
    /**
127
     * Get extension and name from a file for the provided source/path of the file.
128
     *
129
     * @param string $sourceFile The path of the file
130
     * @return object With extension and name keys.
131
     */
132
    public static function getFileInfo($sourceFile)
133
    {
134
        $path = pathinfo($sourceFile);
135
    
136
        return (object) [
137
            'extension' => (isset($path['extension']) && !empty($path['extension'])) ? mb_strtolower($path['extension'], 'UTF-8') : false,
138
            'name' => (isset($path['filename']) && !empty($path['filename'])) ? $path['filename'] : false,
139
            'source' => $sourceFile,
140
            'sourceFilename' => (isset($path['dirname']) && isset($path['filename'])) ? $path['dirname'] . DIRECTORY_SEPARATOR . $path['filename'] : false,
141
        ];
142
    }
143
    
144
    /**
145
     * Generate a md5 hash of a file. This is eqauls to `md5sum` command
146
     *
147
     * @param string $sourceFile The path to the file
148
     * @return false|string Returns false or the md5 hash of this file
149
     */
150
    public static function md5sum($sourceFile)
151
    {
152
        return file_exists($sourceFile) ? hash_file('md5', $sourceFile) : false;
153
    }
154
    
155
    /**
156
     * Basic helper method to write files with exception capture. The fileName will auto wrapped
157
     * trough the Yii::getAlias function.
158
     *
159
     * @param string $fileName The path to the file with file name
160
     * @param string $content The content to store in this File
161
     * @return boolean
162
     */
163
    public static function writeFile($fileName, $content)
164
    {
165
        try {
166
            $response = file_put_contents(Yii::getAlias($fileName), $content);
167
            if ($response === false) {
168
                return false;
169
            }
170
        } catch (Exception $error) {
171
            return false;
172
        }
173
        
174
        return true;
175
    }
176
    
177
    /**
178
     * Basic helper to retreive the content of a file and catched exception. The filename
179
     * will auto alias encode by Yii::getAlias function.
180
     *
181
     * @param string $fileName The path to the file to get the content
182
     * @return string|boolean
183
     */
184
    public static function getFileContent($fileName)
185
    {
186
        try {
187
            return file_get_contents(Yii::getAlias($fileName));
188
        } catch (Exception $error) {
189
            return false;
190
        }
191
    }
192
    
193
    /**
194
     * Unlink a file, which handles symlinks.
195
     *
196
     * @param string $file The file path to the file to delete.
197
     * @return boolean Whether the file has been removed or not.
198
     */
199
    public static function unlink($file)
200
    {
201
        // no errors should be thrown, return false instead.
202
        try {
203
            if (parent::unlink($file)) {
204
                return true;
205
            }
206
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
207
        }
208
        
209
        // try to force symlinks
210
        if (is_link($file)) {
211
            $sym = @readlink($file);
212
            if ($sym) {
213
                if (@unlink($file)) {
214
                    return true;
215
                }
216
            }
217
        }
218
        
219
        // try to use realpath
220
        if (realpath($file) && realpath($file) !== $file) {
221
            if (@unlink(realpath($file))) {
222
                return true;
223
            }
224
        }
225
        
226
        return false;
227
    }
228
}
229