This repository has been archived by the owner on Mar 30, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 38
/
file.php
361 lines (294 loc) · 9.5 KB
/
file.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
<?php
/**
* Spoon Library
*
* This source file is part of the Spoon Library. More information,
* documentation and tutorials can be found @ http://www.spoon-library.com
*
* @package spoon
* @subpackage file
*
*
* @author Davy Hellemans <davy@spoon-library.com>
* @since 0.1.1
*/
/**
* This class provides a wide range of methods to be used on
* files.
*
* @package spoon
* @subpackage file
*
*
* @author Davy Hellemans <davy@spoon-library.com>
* @author Tijs Verkoyen <tijs@spoon-library.com>
* @since 0.1.1
*/
class SpoonFile
{
/**
* Deletes one or more files.
*
* @return bool True if the file was deleted, false if not.
* @param mixed $filename Full path (including filename) of the file(s) that should be deleted.
*/
public static function delete($filename)
{
// an array
if(is_array($filename)) foreach($filename as $file) @unlink((string) $file);
// string
else return @unlink((string) $filename);
}
/**
* Download a file from a public URL.
*
* @return bool True if the file was downloaded, false if not.
* @param string $sourceURL The URL of the file to download.
* @param string $destinationPath The path where the file should be downloaded to.
* @param bool[optional] $overwrite In case the destinationPath already exists, should we overwrite this file?
*/
public static function download($sourceURL, $destinationPath, $overwrite = true)
{
// check if curl is available
if(!function_exists('curl_init')) throw new SpoonFileException('This method requires cURL (http://php.net/curl), it seems like the extension isn\'t installed.');
// redefine
$sourceURL = (string) $sourceURL;
$destinationPath = (string) $destinationPath;
$overwrite = (bool) $overwrite;
// validate if the file already exists
if(!$overwrite && self::exists($destinationPath)) return false;
// open file handler
$fileHandle = @fopen($destinationPath, 'w');
// validate filehandle
if($fileHandle === false) return false;
$options[CURLOPT_URL] = $sourceURL;
$options[CURLOPT_FILE] = $fileHandle;
$options[CURLOPT_HEADER] = false;
if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) $options[CURLOPT_FOLLOWLOCATION] = true;
// init curl
$curl = curl_init();
// set options
curl_setopt_array($curl, $options);
// execute the call
curl_exec($curl);
// get errornumber
$errorNumber = curl_errno($curl);
$errorMessage = curl_error($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
// close
curl_close($curl);
fclose($fileHandle);
// validate the errornumber
if($errorNumber != 0) throw new SpoonFileException($errorMessage);
if($httpCode != 200)
{
// delete the destination path file, which is empty
SpoonFile::delete($destinationPath);
// throw exception
throw new SpoonFileException('The file "' . $sourceURL . '" isn\'t available for download.');
}
// return
return true;
}
/**
* Does this file exist.
*
* @return bool True if the file exists, false if not.
* @param string $filename The full path of the file to check for existance.
*/
public static function exists($filename)
{
return (@file_exists((string) $filename) && is_file((string) $filename));
}
/**
* Fetch the content from a file or URL.
*
* @return string The content.
* @param string $filename The path or URL to the file. URLs will only work if fopen-wrappers are enabled.
*/
public static function getContent($filename)
{
return @file_get_contents((string) $filename);
}
/**
* Fetch the extension for a filename.
*
* @return string The extension.
* @param string $filename The full path of the file.
* @param bool[optional] $lowercase Should the extension be returned in lowercase or in its original form.
*/
public static function getExtension($filename, $lowercase = true)
{
if ( strpos($filename, '.') )
{
$chunks = explode('.', $filename);
$ext = end($chunks);
if ( SpoonFilter::isAlphaNumeric($ext))
{
return $ext;
}
}
// no extension
return '';
}
/**
* Fetch the information about a file.
*
* @return array An array that contains a lot of information about the file.
* @param string $filename The path of the file.
*/
public static function getInfo($filename)
{
// redefine
$filename = (string) $filename;
// init var
$units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
// fetch pathinfo
$pathInfo = pathinfo($filename);
// clear cache
@clearstatcache();
// build details array
$file = array();
$file['basename'] = $pathInfo['basename'];
$file['extension'] = self::getExtension($filename);
$file['name'] = substr($file['basename'], 0, strlen($file['basename']) - strlen($file['extension']) -1);
$file['size'] = @filesize($filename);
$file['is_executable'] = @is_executable($filename);
$file['is_readable'] = @is_readable($filename);
$file['is_writable'] = @is_writable($filename);
$file['modification_date'] = @filemtime($filename);
$file['path'] = $pathInfo['dirname'];
$file['permissions'] = @fileperms($filename);
// calculate human readable size
$size = $file['size'];
$mod = 1024;
for($i = 0; $size > $mod; $i++) $size /= $mod;
$file['human_readable_size'] = round($size, 2) . ' ' . $units[$i];
// clear cache
@clearstatcache();
// cough it up
return $file;
}
/**
* Retrieves a list of files within a directory.
*
* @return array An array containing a list of files in the given directory.
* @param string $path The path to the directory.
* @param string[optional] $includeRegexp A regular expresion that filters the files that should be included in the list.
*/
public static function getList($path, $includeRegexp = null)
{
// redefine arguments
$path = (string) $path;
// validate regex
if($includeRegexp !== null)
{
// redefine
$includeRegexp = (string) $includeRegexp;
// validate
if(!SpoonFilter::isValidRegexp($includeRegexp)) throw new SpoonFileException('Invalid regular expression (' . $includeRegexp . ')');
}
// define list
$files = array();
// directory exists
if(SpoonDirectory::exists($path))
{
// attempt to open directory
if($directory = @opendir($path))
{
// start reading
while((($file = readdir($directory)) !== false))
{
// no '.' and '..' and it's a file
if(($file != '.') && ($file != '..') && is_file($path . '/' . $file))
{
// is there a include-pattern?
if($includeRegexp !== null)
{
// init var
$matches = array();
// is this a match?
if(preg_match($includeRegexp, $file, $matches) != 0) $files[] = $file;
}
// no excludes defined
else $files[] = $file;
}
}
}
// close directory
@closedir($directory);
}
// directory doesn't exist or a problem occured
return $files;
}
/**
* Move/rename a directory/file.
*
* @return bool True if the file was moved or renamed, false if not.
* @param string $source Path of the source file.
* @param string $destination Path of the destination.
* @param bool[optional] $overwrite Should an existing file be overwritten?
* @param int[optional] $chmod Chmod mode that should be applied on the file/directory. Defaults to 0777 (+rwx for all) for directories and 0666 (+rw for all) for files.
*/
public static function move($source, $destination, $overwrite = true, $chmod = null)
{
if($chmod === null)
{
$chmod = is_dir($source) ? 0777 : 0666;
}
return SpoonDirectory::move($source, $destination, $overwrite, $chmod);
}
/**
* Writes a string to a file.
*
* @return bool True if the content was written, false if not.
* @param string $filename The path of the file.
* @param string $content The content that should be written.
* @param bool[optional] $createFile Should the file be created if it doesn't exists?
* @param bool[optional] $append Should the content be appended if the file already exists?
* @param int[optional] $chmod Mode that should be applied on the file.
*/
public static function setContent($filename, $content, $createFile = true, $append = false, $chmod = 0666)
{
// redefine vars
$filename = (string) $filename;
$content = (string) $content;
$createFile = (bool) $createFile;
$append = (bool) $append;
// file may not be created, but it doesn't exist either
if(!$createFile && self::exists($filename)) throw new SpoonFileException('The file "' . $filename . '" doesn\'t exist');
// create directory recursively if needed
SpoonDirectory::create(dirname($filename));
// create file & open for writing
$handler = ($append) ? @fopen($filename, 'a') : @fopen($filename, 'w');
// something went wrong
if($handler === false) throw new SpoonFileException('The file "' . $filename . '" could not be created. Check if PHP has enough permissions.');
// store error reporting level
$level = error_reporting();
// disable errors
error_reporting(0);
// write to file
$write = fwrite($handler, $content);
// validate write
if($write === false) throw new SpoonFileException('The file "' . $filename . '" could not be written to. Check if PHP has enough permissions.');
// close the file
fclose($handler);
// chmod file
chmod($filename, $chmod);
// restore error reporting level
error_reporting($level);
// status
return true;
}
}
/**
* This exception is used to handle file related exceptions.
*
* @package spoon
* @subpackage file
*
*
* @author Davy Hellemans <davy@spoon-library.com>
* @since 0.1.1
*/
class SpoonFileException extends SpoonException {}