FileUtil.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2015 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\io;
12 
16 
17 /**
18  * FileUtil provides basic support for file functionality like HTTP file upload.
19  *
20  * @author ingo herwig <ingo@wemove.com>
21  */
22 class FileUtil {
23 
24  /**
25  * Copy an uploaded file to a given destination (only if the mime type mathes the given one).
26  * @param $mediaFile An assoziative array with the following keys: 'name', 'type', 'tmp_name' (typically a $_FILES entry)
27  * @param $destName The destination file name
28  * @param $mimeTypes An array holding the allowed mimetypes, null if arbitrary (default: _null_)
29  * @param $override Boolean whether an existing file should be overridden, if false an unque id will be placed in the filename to prevent overriding (default: _true_)
30  * @return The filename of the uploaded file
31  */
32  public static function uploadFile($mediaFile, $destName, $mimeTypes=null, $override=true) {
33  $message = ObjectFactory::getInstance('message');
34 
35  // check if the file was uploaded
36  if (!is_uploaded_file($mediaFile['tmp_name'])) {
37  $msg = $message->getText("Possible file upload attack: filename %0%.", array($mediaFile['name']));
38  throw new IOException($msg);
39  }
40 
41  // check mime type
42  if ($mimeTypes != null && !in_array($mediaFile['type'], $mimeTypes)) {
43  throw new IOException($message->getText("File '%0%' has wrong mime type: %1%. Allowed types: %2%.",
44  array($mediaFile['name'], $mediaFile['type'], join(", ", $mimeTypes))));
45  }
46 
47  // check if we need a new name
48  if ($override == false && file_exists($destName)) {
49  $pieces = preg_split('/\./', basename($destName));
50  $extension = array_pop($pieces);
51  $name = join('.', $pieces);
52  $destName = dirname($destName)."/".$name.uniqid(rand()).".".$extension;
53  }
54  $result = move_uploaded_file($mediaFile['tmp_name'], $destName);
55  if ($result === false) {
56  throw new IOException("Failed to move %0% to %1%.", array($mediaFile['tmp_name'], $destName));
57  }
58  chmod($destName, 0644);
59  $filename = basename($destName);
60  return $filename;
61  }
62 
63  /**
64  * Write unicode to file.
65  * @param $fp File Handle
66  * @param $str String to write
67  */
68  public static function fputsUnicode($fp, $str) {
69  fputs($fp, utf8_encode($str));
70  }
71 
72  /*
73  * Get the files in a directory that match a pattern
74  * @param $directory The directory to search in
75  * @param $pattern The pattern (regexp) to match (default: _/./_)
76  * @param $prependDirectoryName Boolean whether to prepend the directory name to each file (default: _false_)
77  * @param $recursive Boolean whether to recurse into subdirectories (default: _false_)
78  * @return An array containing the filenames sorted by modification date
79  */
80  public static function getFiles($directory, $pattern='/./', $prependDirectoryName=false, $recursive=false) {
81  if (strrpos($directory, '/') != strlen($directory)-1) {
82  $directory .= '/';
83  }
84  if (!is_dir($directory)) {
85  $message = ObjectFactory::getInstance('message');
86  throw new IllegalArgumentException($message->getText("The directory '%0%' does not exist.", array($directory)));
87  }
88  $result = array();
89  $d = dir($directory);
90  $d->rewind();
91  while(false !== ($file = $d->read())) {
92  if($file != '.' && $file != '..') {
93  if ($recursive && is_dir($directory.$file)) {
94  $files = self::getFiles($directory.$file, $pattern, $prependDirectoryName, $recursive);
95  $result = array_merge($result, $files);
96  }
97  else if(is_file($directory.$file) && preg_match($pattern, $file)) {
98  $sortkey = filectime($directory.$file).',';
99  if ($prependDirectoryName) {
100  $file = $directory.$file;
101  }
102  $sortkey .= $file;
103  $result[$sortkey] = $file;
104  }
105  }
106  }
107  $d->close();
108  krsort($result);
109  return array_values($result);
110  }
111 
112  /*
113  * Get the directories in a directory that match a pattern
114  * @param $directory The directory to search in
115  * @param $pattern The pattern (regexp) to match (default: _/./_)
116  * @param $prependDirectoryName Boolean whether to prepend the directory name to each directory (default: _false_)
117  * @param $recursive Boolean whether to recurse into subdirectories (default: _false_)
118  * @return An array containing the directory names
119  */
120  public static function getDirectories($directory, $pattern='/./', $prependDirectoryName=false, $recursive=false) {
121  if (strrpos($directory, '/') != strlen($directory)-1) {
122  $directory .= '/';
123  }
124  if (!is_dir($directory)) {
125  $message = ObjectFactory::getInstance('message');
126  throw new IllegalArgumentException($message->getText("The directory '%0%' does not exist.", array($directory)));
127  }
128 
129  $result = array();
130  $d = dir($directory);
131  $d->rewind();
132  // iterate over all files
133  while(false !== ($file = $d->read())) {
134  // exclude this and parent directory
135  if($file != '.' && $file != '..') {
136  // include directories only
137  if (is_dir($directory.$file)) {
138  // recurse
139  if ($recursive) {
140  $dirs = self::getDirectories($directory.$file, $pattern, $prependDirectoryName, $recursive);
141  $result = array_merge($result, $dirs);
142  }
143  if(preg_match($pattern, $file)) {
144  if ($prependDirectoryName) {
145  $file = $directory.$file;
146  }
147  $result[] = $file;
148  }
149  }
150  }
151  }
152  $d->close();
153  return $result;
154  }
155 
156  /**
157  * Recursive copy for files/directories.
158  * @param $source The name of the source directory/file
159  * @param $dest The name of the destination directory/file
160  */
161  public static function copyRec($source, $dest) {
162  if (is_file($source)) {
163  $perms = fileperms($source);
164  return copy($source, $dest) && chmod($dest, $perms);
165  }
166  if (!is_dir($source)) {
167  $message = ObjectFactory::getInstance('message');
168  throw new IllegalArgumentException($message->getText("Cannot copy %0% (it's neither a file nor a directory).", array($source)));
169  }
170  self::copyRecDir($source, $dest);
171  }
172 
173  /**
174  * Recursive copy for directories.
175  * @param $source The name of the source directory
176  * @param $dest The name of the destination directory
177  */
178  public static function copyRecDir($source, $dest) {
179  if (!is_dir($dest)) {
180  self::mkdirRec($dest);
181  }
182  $dir = opendir($source);
183  while ($file = readdir($dir)) {
184  if ($file == "." || $file == "..") {
185  continue;
186  }
187  self::copyRec("$source/$file", "$dest/$file");
188  }
189  closedir($dir);
190  }
191 
192  /**
193  * Recursive directory creation.
194  * @param $dirname The name of the directory
195  */
196  public static function mkdirRec($dirname) {
197  if (!is_dir($dirname)) {
198  @mkdir($dirname, 0755, true);
199  }
200  }
201 
202  /**
203  * Empty a directory.
204  * @param $dirname The name of the directory
205  */
206  public static function emptyDir($dirname) {
207  if (is_dir($dirname)) {
208  $files = self::getFiles($dirname, '/./', true, true);
209  foreach ($files as $file) {
210  @unlink($file);
211  }
212  $dirs = self::getDirectories($dirname, '/./', true, true);
213  foreach ($dirs as $dir) {
214  @rmdir($dir);
215  }
216  }
217  }
218 
219  /**
220  * Realpath function that also works for non existing paths
221  * code from http://www.php.net/manual/en/function.realpath.php
222  * @param $path
223  * @return String
224  */
225  public static function realpath($path) {
226  if (file_exists($path)) {
227  return str_replace("\\", "/", realpath($path));
228  }
229  $path = str_replace("\\", "/", $path);
230  $parts = array_filter(explode("/", $path), 'strlen');
231  $absolutes = array();
232  foreach ($parts as $part) {
233  if ('.' == $part) {
234  continue;
235  }
236  if ('..' == $part) {
237  array_pop($absolutes);
238  }
239  else {
240  $absolutes[] = $part;
241  }
242  }
243  $result = implode("/", $absolutes);
244  if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') {
245  $result = '/'.$result;
246  }
247  return $result;
248  }
249 
250  /**
251  * Get a sanitized filename
252  * code from: http://stackoverflow.com/questions/2021624/string-sanitizer-for-filename#2021729
253  * @param $file
254  * @return String
255  */
256  public static function sanitizeFilename($file) {
257  $file = preg_replace("([^\w\s\d\-_~,;:\[\]\(\).])", '', $file);
258  $file = preg_replace("([\.]{2,})", '', $file);
259  return $file;
260  }
261 }
262 ?>
static fputsUnicode($fp, $str)
Write unicode to file.
Definition: FileUtil.php:68
IllegalArgumentException signals an exception in method arguments.
Input/Output related interfaces and classes.
Definition: namespaces.php:21
static sanitizeFilename($file)
Get a sanitized filename code from: http://stackoverflow.com/questions/2021624/string-sanitizer-for-f...
Definition: FileUtil.php:256
static getInstance($name, $dynamicConfiguration=array())
static uploadFile($mediaFile, $destName, $mimeTypes=null, $override=true)
Copy an uploaded file to a given destination (only if the mime type mathes the given one)...
Definition: FileUtil.php:32
static mkdirRec($dirname)
Recursive directory creation.
Definition: FileUtil.php:196
static copyRecDir($source, $dest)
Recursive copy for directories.
Definition: FileUtil.php:178
static copyRec($source, $dest)
Recursive copy for files/directories.
Definition: FileUtil.php:161
static getDirectories($directory, $pattern='/./', $prependDirectoryName=false, $recursive=false)
Definition: FileUtil.php:120
static realpath($path)
Realpath function that also works for non existing paths code from http://www.php.net/manual/en/function.realpath.php.
Definition: FileUtil.php:225
static getFiles($directory, $pattern='/./', $prependDirectoryName=false, $recursive=false)
Definition: FileUtil.php:80
IOException signals an exception in i/o operations.
Definition: IOException.php:18
static emptyDir($dirname)
Empty a directory.
Definition: FileUtil.php:206
FileUtil provides basic support for file functionality like HTTP file upload.
Definition: FileUtil.php:22