| 1 |
<?php
|
| 2 |
// $Id: filemanager.module,v 1.20 2006/11/19 02:36:51 drewish Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @defgroup filemanager File Upload/Download Manager
|
| 6 |
* Functions for modules to use the managed file repository. Modules using
|
| 7 |
* this repository don't have to deal with filenames, directory, size limits,
|
| 8 |
* or creating download URLs.
|
| 9 |
*
|
| 10 |
* File Manager supports both private(access controlled) and public files.
|
| 11 |
* When a module adds a file to the file manager they specify which type of
|
| 12 |
* file it is. A module may use both public and private files at the same
|
| 13 |
* time, but an individual may only be public or private.
|
| 14 |
*
|
| 15 |
* @{
|
| 16 |
*/
|
| 17 |
|
| 18 |
/**
|
| 19 |
* Create the URL to download a file in the filestore.
|
| 20 |
*
|
| 21 |
* @param $file
|
| 22 |
* Filestore file to create the URL for
|
| 23 |
* @param $working
|
| 24 |
* If this is true and there is a working copy of the file then a URL to the
|
| 25 |
* working copy will be returned, otherwise the URL will point to the active
|
| 26 |
* copy.
|
| 27 |
* @param $absolute
|
| 28 |
* Whether to force the output to be an absolute URL (beginning with http:).
|
| 29 |
* Useful for URLs that will be displayed outside the site, such as in an RSS
|
| 30 |
* feed.
|
| 31 |
* @return
|
| 32 |
* a string containing the URL to the given path.
|
| 33 |
*/
|
| 34 |
function filemanager_url($file, $working = FALSE, $absolute = FALSE) {
|
| 35 |
global $base_url;
|
| 36 |
|
| 37 |
// Load file info if we only got a $fid
|
| 38 |
$file = filemanager_get_file_info($file);
|
| 39 |
|
| 40 |
$subdir = ($file->working && $working) ? 'working' : 'active';
|
| 41 |
|
| 42 |
if ($file->private) {
|
| 43 |
return url('filemanager/' . $subdir, 'fid=' . $file->fid, NULL, $absolute);
|
| 44 |
}
|
| 45 |
else {
|
| 46 |
return variable_get('filemanager_public_url', 'files') . "/$subdir/{$file->directory}/{$file->filename}";
|
| 47 |
}
|
| 48 |
}
|
| 49 |
|
| 50 |
/**
|
| 51 |
* Create a link to download a file in the filestore.
|
| 52 |
*
|
| 53 |
* @param $text
|
| 54 |
* The text to be enclosed with the anchor tag.
|
| 55 |
* @param $file
|
| 56 |
* Filestore file to create the URL for
|
| 57 |
* @param $working
|
| 58 |
* If this is true and there is a working copy of the file then a link
|
| 59 |
* to the working copy will be returned, otherwise the link will point to
|
| 60 |
* the active copy.
|
| 61 |
* @param $attributes
|
| 62 |
* An associative array of HTML attributes to apply to the anchor tag.
|
| 63 |
* @param $absolute
|
| 64 |
* Whether to force the output to be an absolute link (beginning with http:).
|
| 65 |
* Useful for links that will be displayed outside the site, such as in an RSS feed.
|
| 66 |
* @return
|
| 67 |
* an HTML string containing a link to the given path.
|
| 68 |
*/
|
| 69 |
function filemanager_l($text, $file, $working = FALSE, $attributes = array(), $absolute = FALSE) {
|
| 70 |
return '<a href="' . filemanager_url($file, $working, $absolute) . '"' . drupal_attributes($attributes) . '>' . $text . '</a>';
|
| 71 |
}
|
| 72 |
|
| 73 |
/**
|
| 74 |
* Returns the path to a file in the filestore
|
| 75 |
*
|
| 76 |
* @param $file
|
| 77 |
* Filestore file or id to create the path for
|
| 78 |
* @param $working
|
| 79 |
* If this is true return the path to where the working copy
|
| 80 |
* would reside. This does not guarantee a working copy exists.
|
| 81 |
*/
|
| 82 |
function filemanager_create_path($file, $working = FALSE) {
|
| 83 |
$file = filemanager_get_file_info($file);
|
| 84 |
return filemanager_create_directory_path($file->private, $working, $file->directory) . '/' . $file->filename;
|
| 85 |
}
|
| 86 |
|
| 87 |
/**
|
| 88 |
* Returns the path to a the directory where this file is located.
|
| 89 |
*
|
| 90 |
* @param $private
|
| 91 |
* If true creates a path to a private directory
|
| 92 |
* @param $working
|
| 93 |
* If this is true return the path to where the working copy
|
| 94 |
* would reside. This does not guarantee a working copy exists.
|
| 95 |
* @param $subdir
|
| 96 |
* Subdirectory underneath the root which you want
|
| 97 |
*/
|
| 98 |
function filemanager_create_directory_path($private = FALSE, $working = FALSE, $subdir = FALSE) {
|
| 99 |
return ($private ? variable_get('filemanager_private_path', 'private') : variable_get('filemanager_public_path', 'files')) . '/' . ($working ? 'working' : 'active') . ($subdir !== FALSE ? '/' . $subdir : '');
|
| 100 |
}
|
| 101 |
|
| 102 |
/**
|
| 103 |
* Saves a file uploaded into a the file store as a working copy.
|
| 104 |
*
|
| 105 |
* @param $source
|
| 106 |
* Name of the fileupload field to check
|
| 107 |
* @param $area
|
| 108 |
* Name of the area where the file resides which will usually be the name of the module
|
| 109 |
* managing the file. Ignored if over if you supply a file to overwrite
|
| 110 |
* @param $private
|
| 111 |
* True if you want this file to be a private download. This is ignored if you
|
| 112 |
* supply a file to overwrite.
|
| 113 |
* @param $file
|
| 114 |
* Filestore file which this upload should replace
|
| 115 |
* @return File object containing file information or 0 if there
|
| 116 |
* was an error during save.
|
| 117 |
*/
|
| 118 |
function filemanager_add_upload($source, $area, $private = FALSE, $file = FALSE) {
|
| 119 |
$upload = file_check_upload($source);
|
| 120 |
return filemanager_add_file($area, $upload->filepath, $upload->filename, $upload->filemime, FALSE, $private, $file);
|
| 121 |
}
|
| 122 |
|
| 123 |
/**
|
| 124 |
* Adds a file into the repository as a working copy
|
| 125 |
*
|
| 126 |
* @param $area
|
| 127 |
* Name of the area where the file resides which will usually be the name of the module
|
| 128 |
* managing the file. Ignored if over if you supply a file to overwrite
|
| 129 |
* @param $path
|
| 130 |
* Path to the file to be added to the
|
| 131 |
* @param $filename
|
| 132 |
* @param $mimetype
|
| 133 |
* Mime type that should be used for the HTTP header when downloading this file.
|
| 134 |
* Ignored if over if you supply a file to overwrite
|
| 135 |
* @param $remove
|
| 136 |
* If true the original file will be removed once it is put into the repository.
|
| 137 |
* @param $private
|
| 138 |
* True if you want this file to be a private download. This is ignored if you
|
| 139 |
* supply a file to overwrite.
|
| 140 |
* @param $file
|
| 141 |
* Filestore file which this upload should replace
|
| 142 |
* @return
|
| 143 |
* Fileobject on success, otherwise FALSE
|
| 144 |
*/
|
| 145 |
function filemanager_add_file($area, $path, $filename, $mimetype = 'application/unknown', $remove = TRUE, $private = FALSE, $file = FALSE) {
|
| 146 |
if(variable_get('filemanager_force_private_' . $area, 0)) {
|
| 147 |
$private = TRUE;
|
| 148 |
}
|
| 149 |
|
| 150 |
$size = filesize($path);
|
| 151 |
|
| 152 |
// Lock on a lock file to prevent naming conflict race conditions
|
| 153 |
$lock = _filemanager_lock();
|
| 154 |
|
| 155 |
if ($file === FALSE) {
|
| 156 |
|
| 157 |
if ($area == '') {
|
| 158 |
$area = 'general';
|
| 159 |
}
|
| 160 |
|
| 161 |
// This is a net new file find a directory for it and setup the object
|
| 162 |
$file->fid = db_next_id('{file}_fid');
|
| 163 |
$file->area = $area;
|
| 164 |
$file->filename = $filename;
|
| 165 |
$file->active = FALSE;
|
| 166 |
$file->working = FALSE;
|
| 167 |
$file->private = $private;
|
| 168 |
$file->size = $size;
|
| 169 |
$file = _filemanager_find_directory($file);
|
| 170 |
$update = false;
|
| 171 |
}
|
| 172 |
else {
|
| 173 |
|
| 174 |
// We're replacing a file so delete it's existing working version
|
| 175 |
$file = filemanager_get_file_info($file);
|
| 176 |
if ($file->working) {
|
| 177 |
file_delete(filemanager_create_path($file, TRUE));
|
| 178 |
}
|
| 179 |
$file->working = FALSE;
|
| 180 |
$update = true;
|
| 181 |
// We don't update the size for existing files until they are promoted
|
| 182 |
}
|
| 183 |
|
| 184 |
// Purge out any old working files, we do this every time since
|
| 185 |
// not all sites have cron support and we don't one upload to have
|
| 186 |
// to delete several weeks worth of build up
|
| 187 |
filemanager_purge_orphans();
|
| 188 |
|
| 189 |
|
| 190 |
// Verify we are not going to exceed our working directory size
|
| 191 |
$sizelimit = variable_get('filemanager_working_sizelimit', '10') * 1024 * 1024;
|
| 192 |
if ($sizelimit > -1 && $size + filemanager_get_working_size() > $sizelimit) {
|
| 193 |
drupal_set_message(t('Filestore add failed: Working space limit has been reached.'), 'error');
|
| 194 |
_filemanager_unlock($lock);
|
| 195 |
return FALSE;
|
| 196 |
}
|
| 197 |
|
| 198 |
// Verify working directory exists
|
| 199 |
filemanager_create_directory(filemanager_create_directory_path($file->private, TRUE));
|
| 200 |
filemanager_create_directory(filemanager_create_directory_path($file->private, TRUE, $file->directory));
|
| 201 |
|
| 202 |
// Move upload file to new location and name
|
| 203 |
$orig_path = $path;
|
| 204 |
if (_filemanager_copy($path, filemanager_create_path($file, TRUE), FILE_EXISTS_ERROR)) {
|
| 205 |
|
| 206 |
$file->working = TRUE;
|
| 207 |
$file->mimetype = $mimetype;
|
| 208 |
|
| 209 |
// Save database record
|
| 210 |
if ($update) {
|
| 211 |
db_query("UPDATE {file} SET working='%s' WHERE fid=%d", $file->working, $file->fid);
|
| 212 |
}
|
| 213 |
else {
|
| 214 |
db_query("INSERT INTO {file} (fid, area, directory, filename, mimetype, size, active, working, private) VALUES (%d,'%s',%d,'%s','%s',%d,'%s','%s','%s')",
|
| 215 |
$file->fid, $file->area, $file->directory, $file->filename, $file->mimetype, $file->size, $file->active, $file->working, $file->private);
|
| 216 |
}
|
| 217 |
|
| 218 |
if ($remove) {
|
| 219 |
file_delete($orig_path);
|
| 220 |
}
|
| 221 |
} else {
|
| 222 |
$file = FALSE;
|
| 223 |
}
|
| 224 |
|
| 225 |
_filemanager_unlock($lock);
|
| 226 |
return $file;
|
| 227 |
}
|
| 228 |
|
| 229 |
/**
|
| 230 |
* Renames an existing file in the filestore
|
| 231 |
*
|
| 232 |
* @param $file
|
| 233 |
* file or fid to rename
|
| 234 |
* @param $name
|
| 235 |
* new name for the file, use NULL or blank to retain old name
|
| 236 |
* @return
|
| 237 |
* the renamed file object on success or false on failure
|
| 238 |
*/
|
| 239 |
function filemanager_rename($file, $name) {
|
| 240 |
$file = filemanager_get_file_info($file);
|
| 241 |
|
| 242 |
// Exit immediately if the rename does nothing
|
| 243 |
if (! $file || $name == $file->filename) {
|
| 244 |
return $file;
|
| 245 |
}
|
| 246 |
|
| 247 |
// Begin rename operation
|
| 248 |
$oldworking = filemanager_create_path($file, true);
|
| 249 |
$oldactive = filemanager_create_path($file, false);
|
| 250 |
$lock = _filemanager_lock();
|
| 251 |
|
| 252 |
$file->filename = $name;
|
| 253 |
|
| 254 |
$updated = _filemanager_update_file($file, $oldworking, $oldactive);
|
| 255 |
|
| 256 |
if ($file != false) {
|
| 257 |
db_query("UPDATE {file} SET filename = '%s', directory = '%d' WHERE fid=%d", $file->filename, $file->directory, $file->fid);
|
| 258 |
}
|
| 259 |
_filemanager_unlock($lock);
|
| 260 |
return $file;
|
| 261 |
}
|
| 262 |
|
| 263 |
/**
|
| 264 |
* Moves the file from public to private or vice versa
|
| 265 |
*
|
| 266 |
* @param $file
|
| 267 |
* file or fid to modify
|
| 268 |
* @param $private
|
| 269 |
* new private state for the file
|
| 270 |
* @return
|
| 271 |
* the modified file object on success or false on failure.
|
| 272 |
*/
|
| 273 |
function filemanager_set_private($file, $private) {
|
| 274 |
$file = filemanager_get_file_info($file);
|
| 275 |
|
| 276 |
// The private column is a char, adjust the flag to match
|
| 277 |
if ($private) {
|
| 278 |
$private = '1';
|
| 279 |
}
|
| 280 |
else {
|
| 281 |
$private = '0';
|
| 282 |
}
|
| 283 |
|
| 284 |
// Exit immediately if file is already in the right state
|
| 285 |
if (! $file || $file->private == $private) {
|
| 286 |
return $file;
|
| 287 |
}
|
| 288 |
|
| 289 |
// Begin set_private operation
|
| 290 |
$oldworking = filemanager_create_path($file, true);
|
| 291 |
$oldactive = filemanager_create_path($file, false);
|
| 292 |
$lock = _filemanager_lock();
|
| 293 |
|
| 294 |
$file->private = $private;
|
| 295 |
|
| 296 |
$updated = _filemanager_update_file($file, $oldworking, $oldactive);
|
| 297 |
|
| 298 |
if ($file != false) {
|
| 299 |
db_query("UPDATE {file} SET private='%s', directory = '%d' WHERE fid=%d", $file->private, $file->directory, $file->fid);
|
| 300 |
}
|
| 301 |
_filemanager_unlock($lock);
|
| 302 |
return $file;
|
| 303 |
}
|
| 304 |
|
| 305 |
/**
|
| 306 |
* helper function for filemanager_rename and filemanager_set_private
|
| 307 |
* does the actual file moving from $oldactive and $oldworking to the
|
| 308 |
* values set in the $file object
|
| 309 |
*
|
| 310 |
* @param $file
|
| 311 |
* file or fid containing new name/directory/private info
|
| 312 |
* @param $oldworking
|
| 313 |
* the path to the current working file
|
| 314 |
* @param $oldactive
|
| 315 |
* the path to the current active file
|
| 316 |
* @return
|
| 317 |
* true on success and false on failure
|
| 318 |
*/
|
| 319 |
function _filemanager_update_file(&$file, $oldworking, $oldactive) {
|
| 320 |
// Using the new file object find/create an appropiate area for this file
|
| 321 |
$file = _filemanager_find_directory($file);
|
| 322 |
$newworking = filemanager_create_path($file, true);
|
| 323 |
$newactive = filemanager_create_path($file, false);
|
| 324 |
if (file_exists($oldworking)) {
|
| 325 |
filemanager_create_directory(dirname(dirname($newworking)));
|
| 326 |
filemanager_create_directory(dirname($newworking));
|
| 327 |
if (!_filemanager_move($oldworking, $newworking, FILE_EXISTS_ERROR)) {
|
| 328 |
drupal_set_message("file exists: {$file->filename}", 'error');
|
| 329 |
return false;
|
| 330 |
}
|
| 331 |
}
|
| 332 |
if (file_exists($oldactive)) {
|
| 333 |
filemanager_create_directory(dirname(dirname($newactive)));
|
| 334 |
filemanager_create_directory(dirname($newactive));
|
| 335 |
if (!_filemanager_move($oldactive, $newactive, FILE_EXISTS_ERROR)) {
|
| 336 |
drupal_set_message("file exists: {$file->filename}", 'error');
|
| 337 |
return false;
|
| 338 |
}
|
| 339 |
}
|
| 340 |
|
| 341 |
return true;
|
| 342 |
}
|
| 343 |
|
| 344 |
/**
|
| 345 |
* Gets a working copy of the active version of a file in the filestore
|
| 346 |
* @param $file
|
| 347 |
* file or fid to copy into working stage area
|
| 348 |
* @param $overwrite
|
| 349 |
* if true, create a new copy, overwriting an existing working copy
|
| 350 |
* otherwise, only return the new copy if an existing working copy doesn't exist
|
| 351 |
* @return
|
| 352 |
* a file object on success or false on failure
|
| 353 |
*/
|
| 354 |
function filemanager_get_working_copy($file, $overwrite=false) {
|
| 355 |
$file = filemanager_get_file_info($file);
|
| 356 |
if ($file->working && !$overwrite) {
|
| 357 |
return $file;
|
| 358 |
}
|
| 359 |
|
| 360 |
// Purge out any old working files, we do this every time since
|
| 361 |
// not all sites have cron support and we don't one upload to have
|
| 362 |
// to delete several weeks worth of build up
|
| 363 |
filemanager_purge_orphans();
|
| 364 |
|
| 365 |
// Verify we are not going to exceed our working directory size
|
| 366 |
$sizelimit = variable_get('filemanager_working_sizelimit', '10') * 1024 * 1024;
|
| 367 |
if ($sizelimit > -1 && $file->size + filemanager_get_working_size() > $sizelimit) {
|
| 368 |
drupal_set_message(t('Filestore get working copy failed: Working space limit has been reached.'), 'error');
|
| 369 |
return;
|
| 370 |
}
|
| 371 |
|
| 372 |
$active_path = filemanager_create_path($file, false);
|
| 373 |
$working_path = filemanager_create_path($file, true);
|
| 374 |
if (_filemanager_copy($active_path, $working_path, FILE_EXISTS_REPLACE)) {
|
| 375 |
$file->working = 1;
|
| 376 |
db_query("UPDATE {file} SET working=%d WHERE fid=%d", $file->working, $file->fid);
|
| 377 |
} else {
|
| 378 |
$file = false;
|
| 379 |
}
|
| 380 |
return $file;
|
| 381 |
}
|
| 382 |
|
| 383 |
/**
|
| 384 |
* Returns the total size in bytes of all current active files.
|
| 385 |
*/
|
| 386 |
function filemanager_get_size() {
|
| 387 |
$size = db_fetch_object(db_query("SELECT SUM(size) AS size FROM {file} WHERE working = 0"));
|
| 388 |
return $size->size;
|
| 389 |
}
|
| 390 |
|
| 391 |
/**
|
| 392 |
* Returns the total size in bytes of all the current working files.
|
| 393 |
* We have to use the filesystem since sizes of working files will
|
| 394 |
* not be accurate in the database.
|
| 395 |
*/
|
| 396 |
function filemanager_get_working_size() {
|
| 397 |
$size = 0;
|
| 398 |
|
| 399 |
$files = file_scan_directory(filemanager_create_directory_path(TRUE, TRUE), '.*');
|
| 400 |
foreach($files as $file) {
|
| 401 |
$size += filesize($file->filename);
|
| 402 |
}
|
| 403 |
|
| 404 |
$files = file_scan_directory(filemanager_create_directory_path(FALSE, TRUE), '.*');
|
| 405 |
foreach($files as $file) {
|
| 406 |
$size += filesize($file->filename);
|
| 407 |
}
|
| 408 |
|
| 409 |
return $size;
|
| 410 |
}
|
| 411 |
|
| 412 |
/**
|
| 413 |
* Returns statistics object about a given filestore area. The object contains
|
| 414 |
* the following fields:
|
| 415 |
* - size - the total size of all files in the area
|
| 416 |
* - filecount - which is the number of files in the area.
|
| 417 |
* - sizelimit - the size limit for this area
|
| 418 |
*
|
| 419 |
* @param $area
|
| 420 |
* Name of the area where the file resides which will usually be the name of the module
|
| 421 |
* managing the file.
|
| 422 |
*/
|
| 423 |
function filemanager_get_area_info($area) {
|
| 424 |
if ($area == '') {
|
| 425 |
$area = 'general';
|
| 426 |
}
|
| 427 |
$result = db_query("SELECT SUM(size) AS size, COUNT(1) AS filecount FROM {file} WHERE area = '%s'", $area);
|
| 428 |
|
| 429 |
$area_info = db_fetch_object($result);
|
| 430 |
$area_info->sizelimit = variable_get("filemanager_area_limit_" . $area, '-1');
|
| 431 |
return $area_info;
|
| 432 |
}
|
| 433 |
|
| 434 |
/**
|
| 435 |
* Returns a filestore object containing information about a given file.
|
| 436 |
* Passing in a filestore object will just pass the same object back out.
|
| 437 |
*
|
| 438 |
* @param $file
|
| 439 |
* File id which you want information about.
|
| 440 |
*/
|
| 441 |
function filemanager_get_file_info($file) {
|
| 442 |
if (is_object($file)) {
|
| 443 |
return $file;
|
| 444 |
}
|
| 445 |
$result = db_query("SELECT fid, area, directory, filename, mimetype, size, active, working, private FROM {file} WHERE fid = %d", $file);
|
| 446 |
return db_fetch_object($result);
|
| 447 |
}
|
| 448 |
|
| 449 |
/**
|
| 450 |
* Promotes a working copy of a file to the active copy
|
| 451 |
*
|
| 452 |
* @param $file
|
| 453 |
* File object or file id you want to promote
|
| 454 |
* @return
|
| 455 |
* Updated $file object for promoted file
|
| 456 |
*/
|
| 457 |
function filemanager_promote_working($file) {
|
| 458 |
$file = filemanager_get_file_info($file);
|
| 459 |
|
| 460 |
if ($file->working) {
|
| 461 |
$size = filesize(filemanager_create_path($file, TRUE));
|
| 462 |
|
| 463 |
$area = filemanager_get_area_info($file->area);
|
| 464 |
if ($area->sizelimit > -1 && ($size + $area->size) > ($area->sizelimit * 1024 * 1024)) {
|
| 465 |
drupal_set_message(t('File promotion failed: area out of space'), 'error');
|
| 466 |
return FALSE;
|
| 467 |
}
|
| 468 |
|
| 469 |
$maxsize = variable_get('filemanager_max_size', '400');
|
| 470 |
if ($maxsize > -1 && ($size + filemanager_get_size()) > ($maxsize * 1024 * 1024)) {
|
| 471 |
drupal_set_message(t('File promotion failed: out of space'), 'error');
|
| 472 |
return FALSE;
|
| 473 |
}
|
| 474 |
|
| 475 |
// Verify working directory exists
|
| 476 |
$activedir = filemanager_create_directory_path($file->private, FALSE);
|
| 477 |
if (!file_exists($activedir)) {
|
| 478 |
mkdir($activedir);
|
| 479 |
}
|
| 480 |
$filedir = filemanager_create_directory_path($file->private, FALSE, $file->directory);
|
| 481 |
if (!file_exists($filedir)) {
|
| 482 |
mkdir($filedir);
|
| 483 |
}
|
| 484 |
|
| 485 |
$current_path = filemanager_create_path($file, TRUE);
|
| 486 |
$destination_path = filemanager_create_path($file, FALSE);
|
| 487 |
if (_filemanager_move($current_path, $destination_path, FILE_EXISTS_REPLACE)) {
|
| 488 |
$file->working = FALSE;
|
| 489 |
$file->active = TRUE;
|
| 490 |
$file->size = $size;
|
| 491 |
db_query("UPDATE {file} SET working='%s', active='%s', size=%d WHERE fid=%d", $file->working, $file->active, $file->size, $file->fid);
|
| 492 |
return $file;
|
| 493 |
}
|
| 494 |
}
|
| 495 |
return FALSE;
|
| 496 |
}
|
| 497 |
|
| 498 |
/**
|
| 499 |
* Purge a working file from the repository
|
| 500 |
*
|
| 501 |
* @param $file
|
| 502 |
* File object or file id you want to purge the working file for
|
| 503 |
*/
|
| 504 |
function filemanager_purge_working($file) {
|
| 505 |
$file = filemanager_get_file_info($file);
|
| 506 |
|
| 507 |
file_delete(filemanager_create_path($file, TRUE));
|
| 508 |
if ($file->active) {
|
| 509 |
db_query("UPDATE {file} SET working = '%s' WHERE fid = %d", FALSE, $file->fid);
|
| 510 |
}
|
| 511 |
else {
|
| 512 |
db_query("DELETE FROM {file} WHERE fid = %d", $file->fid);
|
| 513 |
}
|
| 514 |
}
|
| 515 |
|
| 516 |
/**
|
| 517 |
* Removes a file from a repository
|
| 518 |
*
|
| 519 |
* @param $file
|
| 520 |
* File object or file id you want to promote
|
| 521 |
*/
|
| 522 |
function filemanager_delete($file) {
|
| 523 |
$file = filemanager_get_file_info($file);
|
| 524 |
file_delete(filemanager_create_path($file, TRUE));
|
| 525 |
file_delete(filemanager_create_path($file, FALSE));
|
| 526 |
db_query("DELETE FROM {file} WHERE fid=%d", $file->fid);
|
| 527 |
}
|
| 528 |
|
| 529 |
/**
|
| 530 |
* Returns a list of file areas used by the current module set
|
| 531 |
*
|
| 532 |
* @return
|
| 533 |
* A list of all file areas
|
| 534 |
*/
|
| 535 |
function filemanager_area_list() {
|
| 536 |
$areas = array();
|
| 537 |
$areas[] = array('area' => 'general', 'name' => t('General'), 'description' => t('All files not specifically stored in another area.'));
|
| 538 |
foreach (module_list() as $module) {
|
| 539 |
$module_areas = module_invoke($module, 'filemanager_areas');
|
| 540 |
if ($module_areas) {
|
| 541 |
foreach ($module_areas as $area) {
|
| 542 |
$areas[] = $area;
|
| 543 |
}
|
| 544 |
}
|
| 545 |
}
|
| 546 |
return $areas;
|
| 547 |
}
|
| 548 |
|
| 549 |
/**
|
| 550 |
* Purges out files over the age limit in the working repository for all areas
|
| 551 |
*/
|
| 552 |
function filemanager_purge_orphans() {
|
| 553 |
$result = db_query("SELECT fid, area, directory, filename, mimetype, size, active, working, private FROM {file} WHERE working = '%s'", TRUE);
|
| 554 |
while ($file = db_fetch_object($result)) {
|
| 555 |
$path = filemanager_create_path($file, TRUE);
|
| 556 |
if (file_exists($path) && (time() - filemtime($path) > 60*variable_get('attachment_tmp_age', '120'))) {
|
| 557 |
filemanager_purge_working($file);
|
| 558 |
}
|
| 559 |
}
|
| 560 |
}
|
| 561 |
|
| 562 |
/**
|
| 563 |
* Transfers a file to the client after calling modules to find out
|
| 564 |
* if a file is accessible for a given user. This function
|
| 565 |
* is here to support legacy private downloads
|
| 566 |
*
|
| 567 |
* @param $file
|
| 568 |
* File object or file id you want to promote
|
| 569 |
* @param $working
|
| 570 |
* Boolean value to indicate if the working version of the file should be returned.
|
| 571 |
* @param $headers
|
| 572 |
* Custom headers, in case you want to stream the file, change the name, etc
|
| 573 |
*/
|
| 574 |
function filemanager_transfer($file, $working, $headers = FALSE) {
|
| 575 |
$file = filemanager_get_file_info($file);
|
| 576 |
$filepath = filemanager_create_path($file, $working);
|
| 577 |
$default_headers = array(
|
| 578 |
'Content-Type: '. $file->mimetype,
|
| 579 |
'Content-Length: '. $file->size,
|
| 580 |
'Content-Disposition: attachment; filename="'. $file->filename .'"'
|
| 581 |
);
|
| 582 |
|
| 583 |
if ($file->private) {
|
| 584 |
if (file_check_location($filepath, variable_get('filemanager_private_path','private')) && file_exists($filepath)) {
|
| 585 |
foreach (module_list() as $module) {
|
| 586 |
$headers = module_invoke($module, 'filemanager_download', $file);
|
| 587 |
|
| 588 |
if ($headers === FALSE) {
|
| 589 |
return drupal_access_denied();
|
| 590 |
}
|
| 591 |
|
| 592 |
elseif ($headers === TRUE) {
|
| 593 |
return _filemanager_transfer($filepath, $default_headers);
|
| 594 |
}
|
| 595 |
|
| 596 |
elseif (is_array($headers)) {
|
| 597 |
return _filemanager_transfer($filepath, $headers);
|
| 598 |
}
|
| 599 |
}
|
| 600 |
|
| 601 |
// Since no modules responded check to see if this is a general area file
|
| 602 |
// and allow download if so.
|
| 603 |
if ($file->area == 'general' || variable_get('filemanager_force_private_' . $file->area, 0)) {
|
| 604 |
return _filemanager_transfer($filepath, $default_headers);
|
| 605 |
}
|
| 606 |
}
|
| 607 |
|
| 608 |
return drupal_not_found();
|
| 609 |
}
|
| 610 |
else {
|
| 611 |
// It's a public file so no auth check is required.
|
| 612 |
return file_transfer($filepath, (is_array($headers)) ? $headers : $default_headers);
|
| 613 |
}
|
| 614 |
}
|
| 615 |
|
| 616 |
/**
|
| 617 |
* @}
|
| 618 |
*/
|
| 619 |
|
| 620 |
function filemanager_menu($may_cache) {
|
| 621 |
$items = array();
|
| 622 |
|
| 623 |
if ($may_cache) {
|
| 624 |
$items[] = array('path' => 'filemanager/active', 'title' => t('File download'),
|
| 625 |
'callback' => 'filemanager_download_active',
|
| 626 |
'access' => TRUE,
|
| 627 |
'type' => MENU_CALLBACK);
|
| 628 |
$items[] = array('path' => 'filemanager/working', 'title' => t('File download'),
|
| 629 |
'callback' => 'filemanager_download_working',
|
| 630 |
'access' => TRUE,
|
| 631 |
'type' => MENU_CALLBACK);
|
| 632 |
$items[] = array(
|
| 633 |
'path' => 'admin/settings/filemanager',
|
| 634 |
'title' => t('Filemanager'),
|
| 635 |
'description' => t('Settings for Filemanger module'),
|
| 636 |
'callback' => 'drupal_get_form',
|
| 637 |
'callback arguments' => array('filemanager_admin_settings'),
|
| 638 |
'access' => user_access('administer site configuration'),
|
| 639 |
'type' => MENU_NORMAL_ITEM );
|
| 640 |
}
|
| 641 |
|
| 642 |
return $items;
|
| 643 |
}
|
| 644 |
|
| 645 |
/**
|
| 646 |
* Menu callback to download the latest active file
|
| 647 |
*/
|
| 648 |
function filemanager_download_active() {
|
| 649 |
$file = filemanager_get_file_info($_GET['fid']);
|
| 650 |
if ($file) {
|
| 651 |
filemanager_transfer($file, FALSE);
|
| 652 |
}
|
| 653 |
else {
|
| 654 |
drupal_not_found();
|
| 655 |
}
|
| 656 |
}
|
| 657 |
|
| 658 |
/**
|
| 659 |
* Menu callback to download the working version of a file. If no working
|
| 660 |
* version is available then the latest active version will be downloaded.
|
| 661 |
*/
|
| 662 |
function filemanager_download_working() {
|
| 663 |
$file = filemanager_get_file_info($_GET['fid']);
|
| 664 |
if ($file) {
|
| 665 |
filemanager_transfer($file, TRUE);
|
| 666 |
}
|
| 667 |
else {
|
| 668 |
drupal_not_found();
|
| 669 |
}
|
| 670 |
}
|
| 671 |
|
| 672 |
function filemanager_help($section) {
|
| 673 |
switch ($section) {
|
| 674 |
}
|
| 675 |
}
|
| 676 |
|
| 677 |
|
| 678 |
|
| 679 |
/**
|
| 680 |
* Checks the existence of the directory specified in $form_element. If
|
| 681 |
* validation fails, the form element is flagged with an error from within the
|
| 682 |
* file_check_directory function. See: system_check_directory()
|
| 683 |
*
|
| 684 |
* @param $form_element
|
| 685 |
* The form element containing the name of the directory to check.
|
| 686 |
*/
|
| 687 |
function _filemanager_settings_check_directory($form_element) {
|
| 688 |
file_check_directory($form_element['#value'], 0, $form_element['#parents'][0]);
|
| 689 |
return $form_element;
|
| 690 |
}
|
| 691 |
|
| 692 |
/**
|
| 693 |
* Displays filemanager admin screen
|
| 694 |
*/
|
| 695 |
function filemanager_admin_settings() {
|
| 696 |
global $base_url;
|
| 697 |
|
| 698 |
$form['filemanager_public_path'] = array(
|
| 699 |
'#type' => 'textfield',
|
| 700 |
'#title' => t('Public file system path'),
|
| 701 |
'#default_value' => variable_get('filemanager_public_path', 'files'),
|
| 702 |
'#maxlength' => 255,
|
| 703 |
'#after_build' => array('_filemanager_settings_check_directory'),
|
| 704 |
'#description' => t('A file system path where public files will be stored. This directory has to exist and be writable by Drupal. This directory has to be accessible over the web. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.')
|
| 705 |
);
|
| 706 |
$form['filemanager_public_url'] = array(
|
| 707 |
'#type' => 'textfield',
|
| 708 |
'#title' => t('Public file system URL'),
|
| 709 |
'#default_value' => variable_get('filemanager_public_url', $base_url .'/'. $public_directory_path),
|
| 710 |
'#maxlength' => 255,
|
| 711 |
'#description' => t('Base URL that points to the public files directory.')
|
| 712 |
);
|
| 713 |
$form['filemanager_private_path'] = array(
|
| 714 |
'#type' => 'textfield',
|
| 715 |
'#title' => t('Private file system path'),
|
| 716 |
'#default_value' => variable_get('filemanager_private_path', 'private'),
|
| 717 |
'#maxlength' => 255,
|
| 718 |
'#after_build' => array('_filemanager_settings_check_directory'),
|
| 719 |
'#description' => t('A file system path where private access controlled files will be stored. This directory has to exist and be writable by Drupal. This directory should not be accessible over the web. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.')
|
| 720 |
);
|
| 721 |
$form['filemanager_max_filecount'] = array(
|
| 722 |
'#type' => 'textfield',
|
| 723 |
'#title' => t('Maximum files per directory'),
|
| 724 |
'#default_value' => variable_get('filemanager_max_filecount', '200'),
|
| 725 |
'#size' => 6,
|
| 726 |
'#maxlength' => 10,
|
| 727 |
'#description' => t('Maximum number of files to put in each directory.'));
|
| 728 |
$form['filemanager_working_sizelimit'] = array(
|
| 729 |
'#type' => 'textfield',
|
| 730 |
'#title' => t('Working size limit'),
|
| 731 |
'#default_value' => variable_get('filemanager_working_sizelimit', '10'),
|
| 732 |
'#size' => 6,
|
| 733 |
'#maxlength' => 10,
|
| 734 |
'#description' => t('Maximum total size in megabytes for the working storage directory. Enter -1 for unlimited.'),
|
| 735 |
'#requred' => true
|
| 736 |
);
|
| 737 |
$form['filemanager_working_maxage'] = array(
|
| 738 |
'#type' => 'textfield',
|
| 739 |
'#title' => t('Maximum working age'),
|
| 740 |
'#default_value' => variable_get('filemanager_working_maxage', '120'),
|
| 741 |
'#size' => 6,
|
| 742 |
'#maxlength' => 10,
|
| 743 |
'#description' => t('Maximum amoung of time in minutes that an attachment is allowed to live in working storage. Enter -1 for unlimited.'),
|
| 744 |
'#requred' => true
|
| 745 |
);
|
| 746 |
$form['filemanager_max_size'] = array(
|
| 747 |
'#type' => 'textfield',
|
| 748 |
'#title' => t('Maximum size limit'),
|
| 749 |
'#default_value' => variable_get('filemanager_max_size', '400'),
|
| 750 |
'#size' => 6,
|
| 751 |
'#maxlength' => 10,
|
| 752 |
'#description' => t('Maximum amount of disk space that can be consumed by all files. Enter in megabytes.'),
|
| 753 |
'#requred' => true
|
| 754 |
);
|
| 755 |
|
| 756 |
$form['file_areas'] = array(
|
| 757 |
'#type' => 'fieldset',
|
| 758 |
'#title' => t('File areas'),
|
| 759 |
'#tree' => true,
|
| 760 |
'#theme' => 'filemanager_fileareas_admin',
|
| 761 |
'info' => array(
|
| 762 |
'#type' => 'markup',
|
| 763 |
'#value' => '<em>'. t("The following numbers control the total size of all files allowed in a particular area. Enter '-1' to allow unlimited size. Select force private to force all files in that area to be streamed (no direct access) through the private directory. If the module that controls that area does not enforce security it will default to allow all access.") .'</em>'
|
| 764 |
),
|
| 765 |
);
|
| 766 |
foreach(filemanager_area_list() as $area) {
|
| 767 |
$key = $area['area'];
|
| 768 |
$form['file_areas']['areas'][$key] = array(
|
| 769 |
'#description' => $area['description'],
|
| 770 |
'#title' => $area['name'],
|
| 771 |
'limit' => array(
|
| 772 |
'filemanager_area_limit_' . $key => array(
|
| 773 |
'#type' => 'textfield',
|
| 774 |
'#default_value' => variable_get('filemanager_area_limit_' . $key, '-1'),
|
| 775 |
'#size' => 6,
|
| 776 |
'#maxlength' => 10,
|
| 777 |
),
|
| 778 |
),
|
| 779 |
'force' => array(
|
| 780 |
'filemanager_force_private_' . $key => array(
|
| 781 |
'#type' => 'checkbox',
|
| 782 |
'#default_value' => variable_get('filemanager_force_private_' . $key, 0),
|
| 783 |
'#return_value' => 1,
|
| 784 |
),
|
| 785 |
),
|
| 786 |
);
|
| 787 |
}
|
| 788 |
|
| 789 |
return system_settings_form($form);
|
| 790 |
}
|
| 791 |
|
| 792 |
function theme_filemanager_fileareas_admin($form) {
|
| 793 |
$output = drupal_render($form['info']);
|
| 794 |
|
| 795 |
$header = array(t('Area'),t('Description'),t('Max size (Mb)'),t('Force Private'));
|
| 796 |
foreach (element_children($form['areas']) as $key) {
|
| 797 |
$row = array();
|
| 798 |
$row[] = $form['areas'][$key]['#title'];
|
| 799 |
$row[] = $form['areas'][$key]['#description'];
|
| 800 |
$row[] = drupal_render($form['areas'][$key]['limit']);
|
| 801 |
$row[] = drupal_render($form['areas'][$key]['force']);
|
| 802 |
$rows[] = $row;
|
| 803 |
}
|
| 804 |
$output .= theme('table', $header, $rows);
|
| 805 |
|
| 806 |
$output .= drupal_render($form);
|
| 807 |
return $output;
|
| 808 |
}
|
| 809 |
|
| 810 |
/**
|
| 811 |
* Handle the submission of the admin/settings form. This is a bit unusual
|
| 812 |
* since the settings form is normally handled automatically, but due to the
|
| 813 |
* deep fileareas->areas array used for the file areas table, the
|
| 814 |
* system_settings_form_submit can't handle all the values without some
|
| 815 |
* pre-processing.
|
| 816 |
*/
|
| 817 |
function filemanager_admin_settings_submit($form_id, $values) {
|
| 818 |
// Flatten the fileareas array into $values
|
| 819 |
foreach ($values['file_areas']['areas'] as $area => $settings) {
|
| 820 |
foreach ($settings as $value_key => $value_array) {
|
| 821 |
foreach ($value_array as $key => $value) {
|
| 822 |
$values[$key] = $value;
|
| 823 |
}
|
| 824 |
}
|
| 825 |
}
|
| 826 |
system_settings_form_submit($form_id, $values);
|
| 827 |
}
|
| 828 |
|
| 829 |
/**
|
| 830 |
* Creates a directory if it does not already exist.
|
| 831 |
*
|
| 832 |
* @param $directory
|
| 833 |
*/
|
| 834 |
function filemanager_create_directory($directory) {
|
| 835 |
if (!file_exists($directory)) {
|
| 836 |
mkdir($directory);
|
| 837 |
}
|
| 838 |
}
|
| 839 |
|
| 840 |
/**
|
| 841 |
* Removes a directory and all files contained within.
|
| 842 |
*
|
| 843 |
* @param $directory
|
| 844 |
*/
|
| 845 |
function filemanager_remove_directory($directory) {
|
| 846 |
if (is_dir($directory)) {
|
| 847 |
$files = file_scan_directory($directory, ".*");
|
| 848 |
foreach($files as $file) {
|
| 849 |
file_delete($file);
|
| 850 |
}
|
| 851 |
rmdir($directory);
|
| 852 |
}
|
| 853 |
}
|
| 854 |
|
| 855 |
function _filemanager_lock() {
|
| 856 |
$lock_file = variable_get('filemanager_private_path', 'private') .'/'. 'filemanager.lck';
|
| 857 |
$flk = fopen($lock_file,'w+');
|
| 858 |
flock($flk, LOCK_EX);
|
| 859 |
return $flk;
|
| 860 |
}
|
| 861 |
|
| 862 |
function _filemanager_unlock(&$handle) {
|
| 863 |
flock($handle, LOCK_UN);
|
| 864 |
fclose($handle);
|
| 865 |
}
|
| 866 |
|
| 867 |
/**
|
| 868 |
* this must be called while the lock is held
|
| 869 |
* @param $file
|
| 870 |
*/
|
| 871 |
function _filemanager_find_directory(&$file) {
|
| 872 |
// Find a directory that is not already full and does not contain our files
|
| 873 |
$file->directory = 0;
|
| 874 |
$directories = db_query("SELECT directory, count(1) AS filecount FROM {file} WHERE private = '%s' GROUP BY directory ORDER BY directory ASC", $file->private);
|
| 875 |
|
| 876 |
// this while loop requires the $directories array to be ordered in ascending order
|
| 877 |
while ($directory = db_fetch_object($directories)) {
|
| 878 |
// The idea here is to find a directory where the filename doesn't exist
|
| 879 |
// and we haven't hit the maximum file limit. The directories are named
|
| 880 |
// numerically and the first part of the test makes sure that the they're
|
| 881 |
// filled in sequenceially. $file->directory is incremented by 1 each time
|
| 882 |
// but $directory->directory comes from the database. If
|
| 883 |
// $directory->directory > $file->directory, then $file->directory doesn't
|
| 884 |
// exist and would be a safe place to save the file.
|
| 885 |
if ($directory->directory > $file->directory || $directory->filecount < variable_get('filemanager_max_file_count', '2000')) {
|
| 886 |
// If the directory is ok now lets make sure we don't already have this
|
| 887 |
// filename in the directory (checking both working and active).
|
| 888 |
if (!file_exists(filemanager_create_path($file, FALSE)) && !file_exists(filemanager_create_path($file, TRUE))) {
|
| 889 |
break;
|
| 890 |
}
|
| 891 |
}
|
| 892 |
$file->directory++;
|
| 893 |
}
|
| 894 |
return $file;
|
| 895 |
}
|
| 896 |
|
| 897 |
/**
|
| 898 |
* Copies a file to a new location. This is a powerful function that in many
|
| 899 |
* ways performs like an advanced version of copy().
|
| 900 |
* - Checks if $source and $dest are valid and readable/writable.
|
| 901 |
* - Performs a file copy if $source is not equal to $dest.
|
| 902 |
* - If file already exists in $dest either the call will error out, replace the
|
| 903 |
* file or rename the file based on the $replace parameter.
|
| 904 |
*
|
| 905 |
* @param $source A string specifying the file location of the original file.
|
| 906 |
* This parameter will contain the resulting destination filename in case of
|
| 907 |
* success.
|
| 908 |
* @param $dest A string containing the directory $source should be copied to.
|
| 909 |
* @param $replace Replace behavior when the destination file already exists.
|
| 910 |
* - FILE_EXISTS_REPLACE - Replace the existing file
|
| 911 |
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
|
| 912 |
* unique
|
| 913 |
* - FILE_EXISTS_ERROR - Do nothing and return false.
|
| 914 |
* @return True for success, false for failure.
|
| 915 |
*/
|
| 916 |
function _filemanager_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
|
| 917 |
$directory = $dest;
|
| 918 |
$basename = file_check_path($directory);
|
| 919 |
|
| 920 |
// Make sure we at least have a valid directory.
|
| 921 |
if ($basename === false) {
|
| 922 |
drupal_set_message(t('The selected file %file could not be uploaded, because the destination %directory is not properly configured.', array('%file' => theme('placeholder', $source), '%directory' => theme('placeholder', $dest))), 'error');
|
| 923 |
watchdog('file system', t('The selected file %file could not not be uploaded, because the destination %directory could not be found, or because its permissions do not allow the file to be written.', array('%file' => theme('placeholder', $source), '%directory' => theme('placeholder', $dest))), WATCHDOG_ERROR);
|
| 924 |
return 0;
|
| 925 |
}
|
| 926 |
|
| 927 |
// Process a file upload object.
|
| 928 |
if (is_object($source)) {
|
| 929 |
$file = $source;
|
| 930 |
$source = $file->filepath;
|
| 931 |
if (!$basename) {
|
| 932 |
$basename = $file->filename;
|
| 933 |
}
|
| 934 |
}
|
| 935 |
|
| 936 |
$source = realpath($source);
|
| 937 |
|
| 938 |
if (!file_exists($source)) {
|
| 939 |
drupal_set_message(t('The selected file %file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => theme('placeholder', $source))), 'error');
|
| 940 |
return 0;
|
| 941 |
}
|
| 942 |
|
| 943 |
// If the destination file is not specified then use the filename of the
|
| 944 |
// source file.
|
| 945 |
$basename = $basename ? $basename : basename($source);
|
| 946 |
$dest = $directory .'/'. $basename;
|
| 947 |
|
| 948 |
// Make sure source and destination filenames are not the same, makes no sense
|
| 949 |
// to copy it if they are. In fact copying the file will most likely result in
|
| 950 |
// a 0 byte file. Which is bad. Real bad.
|
| 951 |
if ($source != realpath($dest)) {
|
| 952 |
if (file_exists($dest)) {
|
| 953 |
switch ($replace) {
|
| 954 |
case FILE_EXISTS_RENAME:
|
| 955 |
// Destination file already exists and we can't replace is so we try
|
| 956 |
// and and find a new filename.
|
| 957 |
if ($pos = strrpos($basename, '.')) {
|
| 958 |
$name = substr($basename, 0, $pos);
|
| 959 |
$ext = substr($basename, $pos);
|
| 960 |
}
|
| 961 |
else {
|
| 962 |
$name = $basename;
|
| 963 |
}
|
| 964 |
|
| 965 |
$counter = 0;
|
| 966 |
do {
|
| 967 |
$dest = $directory .'/'. $name .'_'. $counter++ . $ext;
|
| 968 |
} while (file_exists($dest));
|
| 969 |
break;
|
| 970 |
|
| 971 |
case FILE_EXISTS_ERROR:
|
| 972 |
drupal_set_message(t('The selected file %file could not be copied, because a file by that name already exists in the destination.', array('%file' => theme('placeholder', $source))), 'error');
|
| 973 |
return 0;
|
| 974 |
}
|
| 975 |
}
|
| 976 |
|
| 977 |
if (!@copy($source, $dest)) {
|
| 978 |
drupal_set_message(t('The selected file %file could not be copied.', array('%file' => theme('placeholder', $source))), 'error');
|
| 979 |
return 0;
|
| 980 |
}
|
| 981 |
|
| 982 |
// Give everyone read access so that FTP'd users or non-webserver users
|
| 983 |
// can see/read these files.
|
| 984 |
@chmod($dest, 0664);
|
| 985 |
}
|
| 986 |
|
| 987 |
if (is_object($file)) {
|
| 988 |
$file->filename = $basename;
|
| 989 |
$file->filepath = $dest;
|
| 990 |
$source = $file;
|
| 991 |
}
|
| 992 |
else {
|
| 993 |
$source = $dest;
|
| 994 |
}
|
| 995 |
|
| 996 |
return 1; // Everything went ok.
|
| 997 |
}
|
| 998 |
|
| 999 |
/**
|
| 1000 |
* Moves a file to a new location.
|
| 1001 |
* - Checks if $source and $dest are valid and readable/writable.
|
| 1002 |
* - Performs a file move if $source is not equal to $dest.
|
| 1003 |
* - If file already exists in $dest either the call will error out, replace the
|
| 1004 |
* file or rename the file based on the $replace parameter.
|
| 1005 |
*
|
| 1006 |
* @param $source A string specifying the file location of the original file.
|
| 1007 |
* This parameter will contain the resulting destination filename in case of
|
| 1008 |
* success.
|
| 1009 |
* @param $dest A string containing the directory $source should be copied to.
|
| 1010 |
* @param $replace Replace behavior when the destination file already exists.
|
| 1011 |
* - FILE_EXISTS_REPLACE - Replace the existing file
|
| 1012 |
* - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
|
| 1013 |
* unique
|
| 1014 |
* - FILE_EXISTS_ERROR - Do nothing and return false.
|
| 1015 |
* @return True for success, false for failure.
|
| 1016 |
*/
|
| 1017 |
function _filemanager_move(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
|
| 1018 |
$path_original = is_object($source) ? $source->filepath : $source;
|
| 1019 |
|
| 1020 |
if (_filemanager_copy($source, $dest, $replace)) {
|
| 1021 |
$path_current = is_object($source) ? $source->filepath : $source;
|
| 1022 |
|
| 1023 |
if ($path_original == $path_current || file_delete($path_original)) {
|
| 1024 |
return 1;
|
| 1025 |
}
|
| 1026 |
drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => theme('placeholder', $source))), 'error');
|
| 1027 |
}
|
| 1028 |
return 0;
|
| 1029 |
}
|
| 1030 |
|
| 1031 |
/**
|
| 1032 |
* Transfer file using http to client. Pipes a file through Drupal to the
|
| 1033 |
* client.
|
| 1034 |
*
|
| 1035 |
* @param $source File to transfer.
|
| 1036 |
* @param $headers An array of http headers to send along with file.
|
| 1037 |
*/
|
| 1038 |
function _filemanager_transfer($source, $headers) {
|
| 1039 |
ob_end_clean();
|
| 1040 |
|
| 1041 |
foreach ($headers as $header) {
|
| 1042 |
// To prevent HTTP header injection, we delete new lines that are
|
| 1043 |
// not followed by a space or a tab.
|
| 1044 |
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
|
| 1045 |
$header = preg_replace('/\r?\n(?!\t| )/', '', $header);
|
| 1046 |
header($header);
|
| 1047 |
}
|
| 1048 |
|
| 1049 |
// Transfer file in 1024 byte chunks to save memory usage.
|
| 1050 |
if ($fd = fopen($source, 'rb')) {
|
| 1051 |
set_time_limit(0);
|
| 1052 |
while (!feof($fd)) {
|
| 1053 |
print fread($fd, 1024);
|
| 1054 |
ob_flush();
|
| 1055 |
flush();
|
| 1056 |
}
|
| 1057 |
fclose($fd);
|
| 1058 |
}
|
| 1059 |
else {
|
| 1060 |
drupal_not_found();
|
| 1061 |
}
|
| 1062 |
exit();
|
| 1063 |
}
|