RSI helpers  0.1
RSI helpers
File.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Rsi;
4 
5 /**
6  * File and file system helper functions.
7  */
8 class File{
9 
10  const FIND_FILTER_TYPE = 'type'; //!< Specify the type (see FIND_TYPE_* constants).
11  const FIND_FILTER_NAME = 'name'; //!< Specify the name.
12  const FIND_FILTER_TIME = 'time'; //!< Specify the time (Unix format).
13  const FIND_FILTER_SIZE = 'size'; //!< Speficy the size (shorthand notation allowed).
14  const FIND_FILTER_FUNC = 'func'; //!< Specify a callback function (1st param = full name, 2nd param = info gathered). The
15  // entry is only included when the function returns a non-empty value (this value is added to the info).
16 
17  const FIND_TYPE_DIR = 1;
18  const FIND_TYPE_FILE = 2;
19  const FIND_TYPE_ALL = 255;
20 
21  const EXT_MASK = '/\\.([^\\.\\/\\\\]*)$/';
22 
23  /**
24  * Add a directory separator to the path (if not present)
25  * @param string $path
26  * @return string Path including the final directory separator.s
27  */
28  public static function addDirSeparator($path){
29  return preg_match('/[\\\\\\/]$/',$path) ? $path : $path . DIRECTORY_SEPARATOR;
30  }
31  /**
32  * Normalize a Windows filename.
33  * @param string $filename
34  * @return string Filename with backward slashes as directory separator and all lower case (because: case insensitive).
35  */
36  public static function windows($filename){
37  return strtolower(str_replace('/','\\',$filename));
38  }
39  /**
40  * Check if a filename is within a directory.
41  * @param string $path Directory (absolute path).
42  * @param string $filename Filename (absolute path).
43  * @return bool True if the file is within the directory.
44  */
45  public static function inDir($path,$filename){
46  $path = self::addDirSeparator($path);
47  if(\Rsi::windows()){
48  $path = self::windows($path);
49  $filename = self::windows($filename);
50  }
51  return strpos($path,$filename) === 0;
52  }
53  /**
54  * Check if a filename is within the base dir restriction.
55  * @param string $filename
56  * @return bool True if within the base dir, or no base dir at all.
57  */
58  public static function inBaseDir($filename){
59  if(!($paths = ini_get('open_basedir'))) return true;
60  foreach(explode(PATH_SEPARATOR,$paths) as $path) if(self::inDir($path,$filename)) return true;
61  return false;
62  }
63  /**
64  * Create a directory (if not exists).
65  * @param string $path.
66  * @param int $mode Mode (read/write/exec) for the new directory.
67  * @return bool True on success.
68  */
69  public static function mkdir($path,$mode = 0777){
70  $mask = umask(0);
71  $result = is_dir($path) || mkdir($path,$mode,true);
72  umask($mask);
73  return $result;
74  }
75  /**
76  * Recursivly remove a directory, including all files.
77  * @param string $path Directory to remove.
78  * @return bool True on success.
79  */
80  public static function rmdir($path){
81  if(!is_dir($path)) return true;
82  foreach((new \FilesystemIterator($path,\FilesystemIterator::SKIP_DOTS)) as $filename => $file)
83  if($file->isDir()) self::rmdir($filename);
84  else unlink($filename);
85  return rmdir($path);
86  }
87  /**
88  * Dirname that does not care about separator, and does not return '.' when no directory.
89  * @param string $path
90  * @param int $levels Number of levels to go up.
91  * @return string Name of the directory of the given path.
92  */
93  public static function dirname($path,$levels = 1){
94  while($levels-- && $path) $path = substr($path,0,max(strrpos($path,'/'),strrpos($path,'\\')));
95  return $path;
96  }
97  /**
98  * Basename that does not care about separator, and also removes possible query parameters.
99  * @param string $path
100  * @return string Base name of the given path.
101  */
102  public static function basename($path){
103  return preg_replace('/(^.*[\\\\\\/]|\\?.*$)/','',$path);
104  }
105  /**
106  * Get extension of a filename.
107  * @param string $filename Filename.
108  * @param bool $lower_case True to convert the extension to lower case.
109  * @return string Extension (without the leading dot).
110  */
111  public static function ext($filename,$lower_case = true){
112  return preg_match(self::EXT_MASK,$filename,$match) ? ($lower_case ? strtolower($match[1]) : $match[1]) : null;
113  }
114  /**
115  * Change the extension of a filename.
116  * @param string $filename Filename.
117  * @param string $ext New extension (with the leading dot, and optional characters before it).
118  * @return string
119  */
120  public static function changeExt($filename,$ext){
121  return preg_replace(self::EXT_MASK,'',$filename) . $ext;
122  }
123  /**
124  * Temporarily directory of the system.
125  * @return string
126  */
127  public static function tempDir(){
128  $path = sys_get_temp_dir();
129  if(!$path){
130  $path = dirname($filename = tempnam(__FILE__,''));
131  unlink($filename);
132  }
133  return self::addDirSeparator($path);
134  }
135  /**
136  * Create a temporarily file.
137  * @param string $ext Extension of the temporarily file (without the leading dot).
138  * @param string $data Data to put in the file (file will be created anyway if empty).
139  * @return string Name of the temporarily file.
140  */
141  public static function tempFile($ext = 'tmp',$data = null){
142  $dir = self::tempDir();
143  while(file_exists($filename = $dir . Str::random() . '.' . $ext));
144  file_put_contents($filename,$data);
145  return $filename;
146  }
147  /**
148  * Optimistic filemtime (no need to check file_exists() first).
149  * @param string $filename File to get modification time for.
150  * @return int Last modification time. False if file does not exists.
151  */
152  public static function mtime($filename){
153  try{
154  return filemtime($filename);
155  }
156  catch(\Exception $e){
157  return false;
158  }
159  }
160  /**
161  * Safe unlink.
162  * @param string $filename File to delete.
163  * @return bool True if file does not exist afterwards.
164  */
165  public static function unlink($filename){
166  try{
167  return unlink($filename);
168  }
169  catch(\Exception $e){
170  return !file_exists($filename);
171  }
172  }
173  /**
174  * Write data to a file.
175  * @param string $filename File to write to.
176  * @param mixed $data Data to save.
177  * @param int $mode File mode (not set if empty).
178  * @param bool $append Append on true, overwrite on false.
179  * @return int Number of bytes written or false on error.
180  */
181  public static function write($filename,$data,$mode = null,$append = false){
182  $result = file_put_contents($filename,$data,$append ? FILE_APPEND : null);
183  if($mode) @chmod($filename,$mode);
184  return $result;
185  }
186  /**
187  * Read the content of a file.
188  * @param string $filename File to read from.
189  * @param mixed $default Value to return if the file does not exist.
190  * @return mixed Data.
191  */
192  public static function read($filename,$default = false){
193  return is_file($filename) ? file_get_contents($filename) : $default;
194  }
195  /**
196  * Serialize data and write it to a file.
197  * @param string $filename File to write to.
198  * @param mixed $data Data to serialize and save.
199  * @param int $mode File mode (not set if empty).
200  * @return int Number of bytes written or false on error.
201  */
202  public static function serialize($filename,$data,$mode = null){
203  return self::write($filename,serialize($data),$mode);
204  }
205  /**
206  * Unserialize the content of a file.
207  * @param string $filename File to read from.
208  * @param mixed $default Value to return if the file does not exist.
209  * @return mixed Unserialized data.
210  */
211  public static function unserialize($filename,$default = false){
212  return is_file($filename) ? unserialize(file_get_contents($filename)) : $default;
213  }
214  /**
215  * Encode data to JSON and write it to a file.
216  * @param string $filename File to write to.
217  * @param mixed $data Data to decode and save.
218  * @param int $mode File mode (not set if empty).
219  * @param int $options PHP's json_encode options.
220  * @return int Number of bytes written or false on error.
221  */
222  public static function jsonEncode($filename,$data,$mode = null,$options = JSON_PRETTY_PRINT){
223  return self::write($filename,json_encode($data,$options),$mode);
224  }
225  /**
226  * Decode the JSON content of a file.
227  * @param string $filename File to read from.
228  * @param mixed $default Value to return if the file does not exist.
229  * @param bool $assoc When true, returned objects will be converted into assoc.arrays.
230  * @return mixed Decoded data.
231  */
232  public static function jsonDecode($filename,$default = false,$assoc = true){
233  return is_file($filename) ? json_decode(file_get_contents($filename),$assoc) : $default;
234  }
235  /**
236  * Get MIME type for a file.
237  * @param string $filename Filename.
238  * @return string MIME type.
239  */
240  public static function mime($filename){
241  if(function_exists('mime_content_type()') && is_file($filename)) return mime_content_type($filename);
242  if(array_key_exists($ext = self::ext($filename),$types = require(__DIR__ . '/../../data/mime.php'))) return $types[$ext];
243  return 'application/' . $ext;
244  }
245  /**
246  * Find and filter files.
247  * @param string $path Base path.
248  * @param array $filters Array with filters. Key = filter (see FIND_FILTER_* constants) plus optional operator (see
249  * Str::operator()), value = value to compare to.
250  * @param bool $recursive True to do a recursive search.
251  * @return array Key = full name, value = info gathered for the filtering (key = filter key, value = entry value). False if
252  * path is not a directory.
253  */
254  public static function find($path,$filters = null,$recursive = false){
255  if(!is_dir($path)) return false;
256  if(!$filters) $filters = [];
257  if(!array_key_exists(self::FIND_FILTER_TYPE,$filters)) $filters[self::FIND_FILTER_TYPE] = self::FIND_TYPE_FILE;
258  $files = [];
259  $dir = dir($path = self::addDirSeparator($path));
260  while(($entry = $dir->read()) !== false) if(trim($entry,'.') !== '') try{
261  $info = ['dir' => $is_dir = is_dir($full = $path . $entry)];
262  if($is_dir && $recursive) $files += self::find($full,$filters,$recursive);
263  foreach($filters as $key => $value){
264  if($operator = preg_match('/^(\\w+)(\\W+)$/',$key,$match) ? $match[2] : null) $key = $match[1];
265  else $operator = '==';
266  switch($key){
267  case self::FIND_FILTER_TYPE:
268  if($value == self::FIND_TYPE_ALL) break;
269  if(($value & self::FIND_TYPE_DIR) && !$is_dir) continue 3;
270  if(($value & self::FIND_TYPE_FILE) && $is_dir) continue 3;
271  break;
272  case self::FIND_FILTER_NAME:
273  if(!Str::operator($info[$key] = $entry,$operator,$value)) continue 3;
274  break;
275  case self::FIND_FILTER_TIME:
276  if($is_dir || !Str::operator($info[$key] = filemtime($full),$operator,$value)) continue 3;
277  break;
278  case self::FIND_FILTER_SIZE:
279  if($is_dir || !Str::operator($info[$key] = filesize($full),$operator,\Rsi\Number::shorthandBytes($value))) continue 3;
280  break;
281  case self::FIND_FILTER_FUNC:
282  if(!($info[$key] = call_user_func($value,$full,$info))) continue 3;
283  break;
284  }
285  }
286  $files[$full] = $info;
287  }
288  catch(\Exception $e){}
289  $dir->close();
290  return $files;
291  }
292  /**
293  * Find files.
294  * @param string $path Base path.
295  * @param string $pattern Filename pattern (with '*' and '?' as possible wildcards).
296  * @param bool $recursive True to do a recursive search.
297  * @return array Full names. False if path is not a directory.
298  */
299  public static function dir($path,$pattern = null,$recursive = false){
300  $filters = [self::FIND_FILTER_TYPE => self::FIND_TYPE_FILE];
301  if($pattern) $filters[self::FIND_FILTER_NAME . '//'] = '/^' . strtr(preg_quote($pattern,'/') . '$/i',['\\*' => '.*','\\?' => '.']);
302  return ($files = self::find($path,$filters,$recursive)) ? array_keys($files) : $files;
303  }
304 
305 }
static write($filename, $data, $mode=null, $append=false)
Write data to a file.
Definition: File.php:181
static inDir($path, $filename)
Check if a filename is within a directory.
Definition: File.php:45
static jsonDecode($filename, $default=false, $assoc=true)
Decode the JSON content of a file.
Definition: File.php:232
static ext($filename, $lower_case=true)
Get extension of a filename.
Definition: File.php:111
static rmdir($path)
Recursivly remove a directory, including all files.
Definition: File.php:80
static mtime($filename)
Optimistic filemtime (no need to check file_exists() first).
Definition: File.php:152
File and file system helper functions.
Definition: File.php:8
static windows($filename)
Normalize a Windows filename.
Definition: File.php:36
static jsonEncode($filename, $data, $mode=null, $options=JSON_PRETTY_PRINT)
Encode data to JSON and write it to a file.
Definition: File.php:222
static windows()
Check wether we are running on a Windows machine.
Definition: Rsi.php:16
static inBaseDir($filename)
Check if a filename is within the base dir restriction.
Definition: File.php:58
static tempFile($ext='tmp', $data=null)
Create a temporarily file.
Definition: File.php:141
static tempDir()
Temporarily directory of the system.
Definition: File.php:127
static dirname($path, $levels=1)
Dirname that does not care about separator, and does not return &#39;.
Definition: File.php:93
Definition: Color.php:3
static addDirSeparator($path)
Add a directory separator to the path (if not present)
Definition: File.php:28
static basename($path)
Basename that does not care about separator, and also removes possible query parameters.
Definition: File.php:102
static dir($path, $pattern=null, $recursive=false)
Find files.
Definition: File.php:299
static changeExt($filename, $ext)
Change the extension of a filename.
Definition: File.php:120
static read($filename, $default=false)
Read the content of a file.
Definition: File.php:192
static mkdir($path, $mode=0777)
Create a directory (if not exists).
Definition: File.php:69
static serialize($filename, $data, $mode=null)
Serialize data and write it to a file.
Definition: File.php:202
static find($path, $filters=null, $recursive=false)
Find and filter files.
Definition: File.php:254
static mime($filename)
Get MIME type for a file.
Definition: File.php:240
static unlink($filename)
Safe unlink.
Definition: File.php:165
static unserialize($filename, $default=false)
Unserialize the content of a file.
Definition: File.php:211