2003-12-26 23:03:21 +00:00
< ? php
2003-12-27 21:29:20 +00:00
2004-08-21 06:42:38 +00:00
/**
* @ file
* API for handling file uploads and server file management .
*/
2009-07-27 19:53:18 +00:00
/**
2009-12-30 08:16:55 +00:00
* Manually include stream wrapper code .
*
2009-07-27 19:53:18 +00:00
* Stream wrapper code is included here because there are cases where
* File API is needed before a bootstrap , or in an alternate order ( e . g .
* maintenance theme ) .
*/
2011-10-31 04:05:57 +00:00
require_once DRUPAL_ROOT . '/core/includes/stream_wrappers.inc' ;
2009-07-27 19:53:18 +00:00
2003-12-27 21:29:20 +00:00
/**
2004-01-06 19:52:14 +00:00
* @ defgroup file File interface
2003-12-27 21:29:20 +00:00
* @ {
2004-09-09 05:51:08 +00:00
* Common file handling functions .
2008-09-15 09:28:50 +00:00
*
* Fields on the file object :
2009-10-13 15:46:03 +00:00
* - fid : File ID
* - uid : The { users } . uid of the user who is associated with the file .
* - filename : Name of the file with no path components . This may differ from
2008-10-09 20:07:00 +00:00
* the basename of the filepath if the file is renamed to avoid overwriting
* an existing file .
2009-10-13 15:46:03 +00:00
* - uri : URI of the file .
* - filemime : The file ' s MIME type .
* - filesize : The size of the file in bytes .
* - status : A bitmapped field indicating the status of the file . The first 8
2010-01-25 10:38:35 +00:00
* bits are reserved for Drupal core . The least significant bit indicates
2009-01-02 21:45:11 +00:00
* temporary ( 0 ) or permanent ( 1 ) . Temporary files older than
* DRUPAL_MAXIMUM_TEMP_FILE_AGE will be removed during cron runs .
2009-10-13 15:46:03 +00:00
* - timestamp : UNIX timestamp for the date the file was added to the database .
2003-12-26 23:03:21 +00:00
*/
2008-05-26 17:12:55 +00:00
/**
2009-08-17 19:14:42 +00:00
* Flag used by file_prepare_directory () -- create directory if not present .
2008-05-26 17:12:55 +00:00
*/
2011-11-29 09:56:53 +00:00
const FILE_CREATE_DIRECTORY = 1 ;
2008-05-26 17:12:55 +00:00
/**
2009-08-17 19:14:42 +00:00
* Flag used by file_prepare_directory () -- file permissions may be changed .
2008-05-26 17:12:55 +00:00
*/
2011-11-29 09:56:53 +00:00
const FILE_MODIFY_PERMISSIONS = 2 ;
2008-05-26 17:12:55 +00:00
/**
2008-09-15 09:28:50 +00:00
* Flag for dealing with existing files : Appends number until name is unique .
2008-05-26 17:12:55 +00:00
*/
2011-11-29 09:56:53 +00:00
const FILE_EXISTS_RENAME = 0 ;
2008-05-26 17:12:55 +00:00
/**
* Flag for dealing with existing files : Replace the existing file .
*/
2011-11-29 09:56:53 +00:00
const FILE_EXISTS_REPLACE = 1 ;
2008-05-26 17:12:55 +00:00
/**
* Flag for dealing with existing files : Do nothing and return FALSE .
*/
2011-11-29 09:56:53 +00:00
const FILE_EXISTS_ERROR = 2 ;
2003-12-26 23:03:21 +00:00
2007-05-30 08:08:59 +00:00
/**
2009-12-30 08:16:55 +00:00
* Indicates that the file is permanent and should not be deleted .
*
* Temporary files older than DRUPAL_MAXIMUM_TEMP_FILE_AGE will be removed
* during cron runs , but permanent files will not be removed during the file
* garbage collection process .
2008-05-26 17:12:55 +00:00
*/
2011-11-29 09:56:53 +00:00
const FILE_STATUS_PERMANENT = 1 ;
2007-05-30 08:08:59 +00:00
2009-07-27 19:53:18 +00:00
/**
* Methods to manage a registry of stream wrappers .
*/
/**
* Drupal stream wrapper registry .
*
* A stream wrapper is an abstraction of a file system that allows Drupal to
* use the same set of methods to access both local files and remote resources .
*
* Provide a facility for managing and querying user - defined stream wrappers
* in PHP . PHP 's internal stream_get_wrappers() doesn' t return the class
* registered to handle a stream , which we need to be able to find the handler
* for class instantiation .
*
* If a module registers a scheme that is already registered with PHP , the
* existing scheme will be unregistered and replaced with the specified class .
*
* A stream is referenced as " scheme://target " .
*
2010-10-21 12:09:41 +00:00
* The optional $filter parameter can be used to retrieve only the stream
* wrappers that are appropriate for particular usage . For example , this returns
* only stream wrappers that use local file storage :
* @ code
* $local_stream_wrappers = file_get_stream_wrappers ( STEAM_WRAPPERS_LOCAL );
* @ endcode
*
* The $filter parameter can only filter to types containing a particular flag .
* In some cases , you may want to filter to types that do not contain a
* particular flag . For example , you may want to retrieve all stream wrappers
* that are not writable , or all stream wrappers that are not local . PHP ' s
* array_diff_key () function can be used to help with this . For example , this
* returns only stream wrappers that do not use local file storage :
* @ code
* $remote_stream_wrappers = array_diff_key ( file_get_stream_wrappers ( STREAM_WRAPPERS_ALL ), file_get_stream_wrappers ( STEAM_WRAPPERS_LOCAL ));
* @ endcode
*
2010-01-26 08:29:25 +00:00
* @ param $filter
2010-10-21 12:09:41 +00:00
* ( Optional ) Filters out all types except those with an on bit for each on
* bit in $filter . For example , if $filter is STREAM_WRAPPERS_WRITE_VISIBLE ,
* which is equal to ( STREAM_WRAPPERS_READ | STREAM_WRAPPERS_WRITE |
* STREAM_WRAPPERS_VISIBLE ), then only stream wrappers with all three of these
* bits set are returned . Defaults to STREAM_WRAPPERS_ALL , which returns all
* registered stream wrappers .
2010-01-26 08:29:25 +00:00
*
2009-07-27 19:53:18 +00:00
* @ return
2010-10-21 12:09:41 +00:00
* An array keyed by scheme , with values containing an array of information
* about the stream wrapper , as returned by hook_stream_wrappers () . If $filter
* is omitted or set to STREAM_WRAPPERS_ALL , the entire Drupal stream wrapper
* registry is returned . Otherwise only the stream wrappers whose 'type'
* bitmask has an on bit for each bit specified in $filter are returned .
2010-07-07 01:10:35 +00:00
*
2009-07-27 19:53:18 +00:00
* @ see hook_stream_wrappers ()
* @ see hook_stream_wrappers_alter ()
*/
2010-01-26 08:29:25 +00:00
function file_get_stream_wrappers ( $filter = STREAM_WRAPPERS_ALL ) {
$wrappers_storage = & drupal_static ( __FUNCTION__ );
2009-07-27 19:53:18 +00:00
2010-01-26 08:29:25 +00:00
if ( ! isset ( $wrappers_storage )) {
2009-07-27 19:53:18 +00:00
$wrappers = module_invoke_all ( 'stream_wrappers' );
2010-01-26 08:29:25 +00:00
foreach ( $wrappers as $scheme => $info ) {
// Add defaults.
$wrappers [ $scheme ] += array ( 'type' => STREAM_WRAPPERS_NORMAL );
}
2009-07-27 19:53:18 +00:00
drupal_alter ( 'stream_wrappers' , $wrappers );
$existing = stream_get_wrappers ();
foreach ( $wrappers as $scheme => $info ) {
// We only register classes that implement our interface.
if ( in_array ( 'DrupalStreamWrapperInterface' , class_implements ( $info [ 'class' ]), TRUE )) {
// Record whether we are overriding an existing scheme.
if ( in_array ( $scheme , $existing , TRUE )) {
$wrappers [ $scheme ][ 'override' ] = TRUE ;
stream_wrapper_unregister ( $scheme );
}
else {
$wrappers [ $scheme ][ 'override' ] = FALSE ;
}
2010-10-21 12:09:41 +00:00
if (( $info [ 'type' ] & STREAM_WRAPPERS_LOCAL ) == STREAM_WRAPPERS_LOCAL ) {
stream_wrapper_register ( $scheme , $info [ 'class' ]);
2010-10-12 03:10:03 +00:00
}
else {
2010-10-21 12:09:41 +00:00
stream_wrapper_register ( $scheme , $info [ 'class' ], STREAM_IS_URL );
2010-10-12 03:10:03 +00:00
}
2009-07-27 19:53:18 +00:00
}
2010-01-26 08:29:25 +00:00
// Pre-populate the static cache with the filters most typically used.
$wrappers_storage [ STREAM_WRAPPERS_ALL ][ $scheme ] = $wrappers [ $scheme ];
if (( $info [ 'type' ] & STREAM_WRAPPERS_WRITE_VISIBLE ) == STREAM_WRAPPERS_WRITE_VISIBLE ) {
$wrappers_storage [ STREAM_WRAPPERS_WRITE_VISIBLE ][ $scheme ] = $wrappers [ $scheme ];
}
2009-07-27 19:53:18 +00:00
}
}
2010-01-26 08:29:25 +00:00
if ( ! isset ( $wrappers_storage [ $filter ])) {
$wrappers_storage [ $filter ] = array ();
foreach ( $wrappers_storage [ STREAM_WRAPPERS_ALL ] as $scheme => $info ) {
// Bit-wise filter.
2010-10-21 12:09:41 +00:00
if (( $info [ 'type' ] & $filter ) == $filter ) {
2010-01-26 08:29:25 +00:00
$wrappers_storage [ $filter ][ $scheme ] = $info ;
}
}
}
return $wrappers_storage [ $filter ];
2009-07-27 19:53:18 +00:00
}
/**
* Returns the stream wrapper class name for a given scheme .
*
* @ param $scheme
* Stream scheme .
2010-07-07 01:10:35 +00:00
*
2009-07-27 19:53:18 +00:00
* @ return
* Return string if a scheme has a registered handler , or FALSE .
*/
function file_stream_wrapper_get_class ( $scheme ) {
$wrappers = file_get_stream_wrappers ();
return empty ( $wrappers [ $scheme ]) ? FALSE : $wrappers [ $scheme ][ 'class' ];
}
/**
* Returns the scheme of a URI ( e . g . a stream ) .
*
* @ param $uri
* A stream , referenced as " scheme://target " .
2010-07-07 01:10:35 +00:00
*
2009-07-27 19:53:18 +00:00
* @ return
* A string containing the name of the scheme , or FALSE if none . For example ,
* the URI " public://example.txt " would return " public " .
2010-06-02 13:09:34 +00:00
*
* @ see file_uri_target ()
2009-07-27 19:53:18 +00:00
*/
function file_uri_scheme ( $uri ) {
2011-02-23 20:28:40 +00:00
$position = strpos ( $uri , '://' );
return $position ? substr ( $uri , 0 , $position ) : FALSE ;
2009-07-27 19:53:18 +00:00
}
/**
* Check that the scheme of a stream URI is valid .
*
* Confirms that there is a registered stream handler for the provided scheme
* and that it is callable . This is useful if you want to confirm a valid
* scheme without creating a new instance of the registered handler .
*
* @ param $scheme
* A URI scheme , a stream is referenced as " scheme://target " .
2010-07-07 01:10:35 +00:00
*
2009-07-27 19:53:18 +00:00
* @ return
* Returns TRUE if the string is the name of a validated stream ,
* or FALSE if the scheme does not have a registered handler .
*/
function file_stream_wrapper_valid_scheme ( $scheme ) {
// Does the scheme have a registered handler that is callable?
$class = file_stream_wrapper_get_class ( $scheme );
if ( class_exists ( $class )) {
return TRUE ;
}
else {
return FALSE ;
}
}
2010-09-11 21:14:32 +00:00
2009-07-27 19:53:18 +00:00
/**
2010-08-17 16:29:16 +00:00
* Returns the part of an URI after the schema .
2009-07-27 19:53:18 +00:00
*
* @ param $uri
* A stream , referenced as " scheme://target " .
2010-07-07 01:10:35 +00:00
*
2009-07-27 19:53:18 +00:00
* @ return
* A string containing the target ( path ), or FALSE if none .
* For example , the URI " public://sample/test.txt " would return
* " sample/test.txt " .
2010-06-02 13:09:34 +00:00
*
* @ see file_uri_scheme ()
2009-07-27 19:53:18 +00:00
*/
function file_uri_target ( $uri ) {
2010-08-17 16:29:16 +00:00
$data = explode ( '://' , $uri , 2 );
// Remove erroneous leading or trailing, forward-slashes and backslashes.
return count ( $data ) == 2 ? trim ( $data [ 1 ], '\/' ) : FALSE ;
2009-07-27 19:53:18 +00:00
}
2010-09-01 20:08:17 +00:00
/**
* Get the default file stream implementation .
*
* @ return
* 'public' , 'private' or any other file scheme defined as the default .
*/
function file_default_scheme () {
return variable_get ( 'file_default_scheme' , 'public' );
}
2009-07-27 19:53:18 +00:00
/**
* Normalizes a URI by making it syntactically correct .
*
* A stream is referenced as " scheme://target " .
*
* The following actions are taken :
* - Remove trailing slashes from target
* - Trim erroneous leading slashes from target . e . g . " :/// " becomes " :// " .
*
* @ param $uri
* String reference containing the URI to normalize .
2010-07-07 01:10:35 +00:00
*
2009-08-17 19:14:42 +00:00
* @ return
* The normalized URI .
2009-07-27 19:53:18 +00:00
*/
function file_stream_wrapper_uri_normalize ( $uri ) {
$scheme = file_uri_scheme ( $uri );
if ( $scheme && file_stream_wrapper_valid_scheme ( $scheme )) {
$target = file_uri_target ( $uri );
2010-06-02 13:09:34 +00:00
if ( $target !== FALSE ) {
$uri = $scheme . '://' . $target ;
}
2009-07-27 19:53:18 +00:00
}
2010-09-11 21:14:32 +00:00
else {
// The default scheme is file://
$url = 'file://' . $uri ;
}
2009-07-27 19:53:18 +00:00
return $uri ;
}
/**
2009-12-30 08:16:55 +00:00
* Returns a reference to the stream wrapper class responsible for a given URI .
2009-07-27 19:53:18 +00:00
*
* The scheme determines the stream wrapper class that should be
* used by consulting the stream wrapper registry .
*
* @ param $uri
* A stream , referenced as " scheme://target " .
2010-07-07 01:10:35 +00:00
*
2009-07-27 19:53:18 +00:00
* @ return
* Returns a new stream wrapper object appropriate for the given URI or FALSE
* if no registered handler could be found . For example , a URI of
* " private://example.txt " would return a new private stream wrapper object
* ( DrupalPrivateStreamWrapper ) .
*/
function file_stream_wrapper_get_instance_by_uri ( $uri ) {
$scheme = file_uri_scheme ( $uri );
$class = file_stream_wrapper_get_class ( $scheme );
if ( class_exists ( $class )) {
2010-06-17 13:16:57 +00:00
$instance = new $class ();
2009-07-27 19:53:18 +00:00
$instance -> setUri ( $uri );
return $instance ;
}
else {
return FALSE ;
}
}
/**
* Returns a reference to the stream wrapper class responsible for a given scheme .
*
* This helper method returns a stream instance using a scheme . That is , the
* passed string does not contain a " :// " . For example , " public " is a scheme
* but " public:// " is a URI ( stream ) . This is because the later contains both
* a scheme and target despite target being empty .
*
* Note : the instance URI will be initialized to " scheme:// " so that you can
* make the customary method calls as if you had retrieved an instance by URI .
*
* @ param $scheme
* If the stream was " public://target " , " public " would be the scheme .
2010-07-07 01:10:35 +00:00
*
2009-07-27 19:53:18 +00:00
* @ return
* Returns a new stream wrapper object appropriate for the given $scheme .
* For example , for the public scheme a stream wrapper object
* ( DrupalPublicStreamWrapper ) .
* FALSE is returned if no registered handler could be found .
*/
function file_stream_wrapper_get_instance_by_scheme ( $scheme ) {
$class = file_stream_wrapper_get_class ( $scheme );
if ( class_exists ( $class )) {
2010-06-17 13:16:57 +00:00
$instance = new $class ();
2009-07-27 19:53:18 +00:00
$instance -> setUri ( $scheme . '://' );
return $instance ;
}
else {
return FALSE ;
}
}
2003-12-26 23:03:21 +00:00
/**
2009-08-29 06:57:27 +00:00
* Creates a web - accessible URL for a stream to an external or local file .
2004-09-17 18:18:04 +00:00
*
2009-08-17 19:14:42 +00:00
* Compatibility : normal paths and stream wrappers .
* @ see http :// drupal . org / node / 515192
2004-09-17 18:18:04 +00:00
*
2009-08-29 06:57:27 +00:00
* There are two kinds of local files :
2010-09-01 20:08:17 +00:00
* - " managed files " , i . e . those stored by a Drupal - compatible stream wrapper .
* These are files that have either been uploaded by users or were generated
* automatically ( for example through CSS aggregation ) .
2009-08-29 06:57:27 +00:00
* - " shipped files " , i . e . those outside of the files directory , which ship as
* part of Drupal core or contributed modules or themes .
*
2009-08-17 19:14:42 +00:00
* @ param $uri
2009-08-29 06:57:27 +00:00
* The URI to a file for which we need an external URL , or the path to a
* shipped file .
2010-07-07 01:10:35 +00:00
*
2008-10-09 20:07:00 +00:00
* @ return
2009-08-17 19:14:42 +00:00
* A string containing a URL that may be used to access the file .
2010-08-17 21:31:13 +00:00
* If the provided string already contains a preceding 'http' , 'https' , or
* '/' , nothing is done and the same string is returned . If a stream wrapper
* could not be found to generate an external URL , then FALSE is returned .
2003-12-26 23:03:21 +00:00
*/
2009-08-17 19:14:42 +00:00
function file_create_url ( $uri ) {
2009-08-29 06:57:27 +00:00
// Allow the URI to be altered, e.g. to serve a file from a CDN or static
// file server.
drupal_alter ( 'file_url' , $uri );
2009-09-28 22:22:54 +00:00
2009-08-17 19:14:42 +00:00
$scheme = file_uri_scheme ( $uri );
if ( ! $scheme ) {
2010-05-11 10:56:04 +00:00
// Allow for:
// - root-relative URIs (e.g. /foo.jpg in http://example.com/foo.jpg)
// - protocol-relative URIs (e.g. //bar.jpg, which is expanded to
// http://example.com/bar.jpg by the browser when viewing a page over
// HTTP and to https://example.com/bar.jpg when viewing a HTTPS page)
// Both types of relative URIs are characterized by a leading slash, hence
// we can use a single check.
if ( drupal_substr ( $uri , 0 , 1 ) == '/' ) {
return $uri ;
}
else {
// If this is not a properly formatted stream, then it is a shipped file.
2010-08-17 21:31:13 +00:00
// Therefore, return the urlencoded URI with the base URL prepended.
return $GLOBALS [ 'base_url' ] . '/' . drupal_encode_path ( $uri );
2010-05-11 10:56:04 +00:00
}
2009-08-17 19:14:42 +00:00
}
elseif ( $scheme == 'http' || $scheme == 'https' ) {
// Check for http so that we don't have to implement getExternalUrl() for
// the http wrapper.
return $uri ;
}
else {
// Attempt to return an external URL using the appropriate wrapper.
if ( $wrapper = file_stream_wrapper_get_instance_by_uri ( $uri )) {
return $wrapper -> getExternalUrl ();
}
else {
return FALSE ;
}
}
2003-12-26 23:03:21 +00:00
}
/**
2008-10-09 20:07:00 +00:00
* Check that the directory exists and is writable .
*
* Directories need to have execute permissions to be considered a directory by
* FTP servers , etc .
*
2011-05-08 19:50:38 +00:00
* @ param $directory
2009-08-17 19:14:42 +00:00
* A string reference containing the name of a directory path or URI . A
* trailing slash will be trimmed from a path .
* @ param $options
2008-10-19 20:18:58 +00:00
* A bitmask to indicate if the directory should be created if it does
* not exist ( FILE_CREATE_DIRECTORY ) or made writable if it is read - only
* ( FILE_MODIFY_PERMISSIONS ) .
2010-07-07 01:10:35 +00:00
*
2008-10-09 20:07:00 +00:00
* @ return
2009-08-17 19:14:42 +00:00
* TRUE if the directory exists ( or was created ) and is writable . FALSE
* otherwise .
2003-12-26 23:03:21 +00:00
*/
2009-08-17 19:14:42 +00:00
function file_prepare_directory ( & $directory , $options = FILE_MODIFY_PERMISSIONS ) {
if ( ! file_stream_wrapper_valid_scheme ( file_uri_scheme ( $directory ))) {
// Only trim if we're not dealing with a stream.
$directory = rtrim ( $directory , '/\\' );
}
2004-08-17 21:35:26 +00:00
// Check if directory exists.
if ( ! is_dir ( $directory )) {
2009-07-10 03:46:33 +00:00
// Let mkdir() recursively create directories and use the default directory
// permissions.
2009-08-17 19:14:42 +00:00
if (( $options & FILE_CREATE_DIRECTORY ) && @ drupal_mkdir ( $directory , NULL , TRUE )) {
return drupal_chmod ( $directory );
2004-08-17 21:35:26 +00:00
}
2009-08-17 19:14:42 +00:00
return FALSE ;
2004-08-17 21:35:26 +00:00
}
2009-08-17 19:14:42 +00:00
// The directory exists, so check to see if it is writable.
$writable = is_writable ( $directory );
if ( ! $writable && ( $options & FILE_MODIFY_PERMISSIONS )) {
return drupal_chmod ( $directory );
2004-08-17 21:35:26 +00:00
}
2009-08-17 19:14:42 +00:00
return $writable ;
2003-12-26 23:03:21 +00:00
}
/**
2009-08-17 19:14:42 +00:00
* If missing , create a . htaccess file in each Drupal files directory .
2003-12-26 23:03:21 +00:00
*/
2009-08-17 19:14:42 +00:00
function file_ensure_htaccess () {
2011-08-02 00:58:40 +00:00
file_save_htaccess ( 'public://' , FALSE );
2010-04-30 01:33:17 +00:00
if ( variable_get ( 'file_private_path' , FALSE )) {
2011-08-02 00:58:40 +00:00
file_save_htaccess ( 'private://' , TRUE );
2010-04-30 01:33:17 +00:00
}
2011-08-02 00:58:40 +00:00
file_save_htaccess ( 'temporary://' , TRUE );
2003-12-26 23:03:21 +00:00
}
/**
2009-08-17 19:14:42 +00:00
* Creates an . htaccess file in the given directory .
2003-12-26 23:03:21 +00:00
*
2008-10-09 20:07:00 +00:00
* @ param $directory
2009-08-17 19:14:42 +00:00
* The directory .
* @ param $private
* FALSE indicates that $directory should be an open and public directory .
* The default is TRUE which indicates a private and protected directory .
2003-12-26 23:03:21 +00:00
*/
2011-08-02 00:58:40 +00:00
function file_save_htaccess ( $directory , $private = TRUE ) {
2009-08-17 19:14:42 +00:00
if ( file_uri_scheme ( $directory )) {
$directory = file_stream_wrapper_uri_normalize ( $directory );
2005-05-17 20:49:54 +00:00
}
else {
2009-08-17 19:14:42 +00:00
$directory = rtrim ( $directory , '/\\' );
2005-05-17 20:49:54 +00:00
}
2009-08-17 19:14:42 +00:00
$htaccess_path = $directory . '/.htaccess' ;
if ( file_exists ( $htaccess_path )) {
// Short circuit if the .htaccess file already exists.
return ;
}
if ( $private ) {
// Private .htaccess file.
$htaccess_lines = " SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006 \n Deny from all \n Options None \n Options +FollowSymLinks " ;
}
else {
// Public .htaccess file.
$htaccess_lines = " SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006 \n Options None \n Options +FollowSymLinks " ;
}
// Write the .htaccess file.
if ( file_put_contents ( $htaccess_path , $htaccess_lines )) {
drupal_chmod ( $htaccess_path , 0444 );
}
else {
$variables = array ( '%directory' => $directory , '!htaccess' => '<br />' . nl2br ( check_plain ( $htaccess_lines )));
2011-07-04 16:58:33 +00:00
watchdog ( 'security' , " Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <code>!htaccess</code> " , $variables , WATCHDOG_ERROR );
2003-12-26 23:03:21 +00:00
}
}
/**
2010-07-01 00:44:04 +00:00
* Loads file objects from the database .
2008-10-09 00:02:29 +00:00
*
2008-12-31 11:08:47 +00:00
* @ param $fids
* An array of file IDs .
* @ param $conditions
2010-11-20 09:43:43 +00:00
* ( deprecated ) An associative array of conditions on the { file_managed }
* table , where the keys are the database fields and the values are the
* values those fields must have . Instead , it is preferable to use
* EntityFieldQuery to retrieve a list of entity IDs loadable by
* this function .
2009-10-13 15:46:03 +00:00
*
2008-10-09 00:02:29 +00:00
* @ return
2009-12-30 08:16:55 +00:00
* An array of file objects , indexed by fid .
2008-10-09 00:02:29 +00:00
*
* @ see hook_file_load ()
2008-12-31 11:08:47 +00:00
* @ see file_load ()
2010-11-20 09:43:43 +00:00
* @ see entity_load ()
* @ see EntityFieldQuery
*
* @ todo Remove $conditions in Drupal 8.
2008-10-09 00:02:29 +00:00
*/
2008-12-31 11:08:47 +00:00
function file_load_multiple ( $fids = array (), $conditions = array ()) {
2009-08-25 21:53:48 +00:00
return entity_load ( 'file' , $fids , $conditions );
2008-12-31 11:08:47 +00:00
}
2008-10-09 00:02:29 +00:00
2008-12-31 11:08:47 +00:00
/**
* Load a file object from the database .
*
* @ param $fid
2009-12-30 08:16:55 +00:00
* A file ID .
2010-08-22 13:52:59 +00:00
*
2008-12-31 11:08:47 +00:00
* @ return
* A file object .
*
* @ see hook_file_load ()
* @ see file_load_multiple ()
*/
function file_load ( $fid ) {
$files = file_load_multiple ( array ( $fid ), array ());
return reset ( $files );
2008-10-09 00:02:29 +00:00
}
/**
* Save a file object to the database .
*
2010-09-25 18:02:39 +00:00
* If the $file -> fid is not set a new record will be added .
2008-10-09 00:02:29 +00:00
*
* @ param $file
* A file object returned by file_load () .
2010-07-07 01:10:35 +00:00
*
2008-10-09 00:02:29 +00:00
* @ return
* The updated file object .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see hook_file_insert ()
* @ see hook_file_update ()
*/
2009-08-29 05:39:37 +00:00
function file_save ( stdClass $file ) {
2008-10-09 00:02:29 +00:00
$file -> timestamp = REQUEST_TIME ;
2009-08-17 19:14:42 +00:00
$file -> filesize = filesize ( $file -> uri );
2008-10-09 00:02:29 +00:00
2010-11-30 19:31:47 +00:00
// Load the stored entity, if any.
if ( ! empty ( $file -> fid ) && ! isset ( $file -> original )) {
$file -> original = entity_load_unchanged ( 'file' , $file -> fid );
}
2010-12-15 03:39:42 +00:00
module_invoke_all ( 'file_presave' , $file );
module_invoke_all ( 'entity_presave' , $file , 'file' );
2008-10-09 00:02:29 +00:00
if ( empty ( $file -> fid )) {
2010-04-10 17:30:15 +00:00
drupal_write_record ( 'file_managed' , $file );
2008-10-09 00:02:29 +00:00
// Inform modules about the newly added file.
module_invoke_all ( 'file_insert' , $file );
2010-06-23 02:45:35 +00:00
module_invoke_all ( 'entity_insert' , $file , 'file' );
2008-10-09 00:02:29 +00:00
}
else {
2010-04-10 17:30:15 +00:00
drupal_write_record ( 'file_managed' , $file , 'fid' );
2008-10-09 00:02:29 +00:00
// Inform modules that the file has been updated.
module_invoke_all ( 'file_update' , $file );
2010-06-23 02:45:35 +00:00
module_invoke_all ( 'entity_update' , $file , 'file' );
2008-10-09 00:02:29 +00:00
}
2010-11-30 19:31:47 +00:00
unset ( $file -> original );
2008-10-09 00:02:29 +00:00
return $file ;
}
/**
2010-08-22 13:52:59 +00:00
* Determines where a file is used .
*
* @ param $file
* A file object .
*
* @ return
* A nested array with usage data . The first level is keyed by module name ,
2011-08-02 00:50:59 +00:00
* the second by object type and the third by the object id . The value
* of the third level contains the usage count .
2010-08-22 13:52:59 +00:00
*
* @ see file_usage_add ()
* @ see file_usage_delete ()
*/
function file_usage_list ( stdClass $file ) {
$result = db_select ( 'file_usage' , 'f' )
-> fields ( 'f' , array ( 'module' , 'type' , 'id' , 'count' ))
-> condition ( 'fid' , $file -> fid )
-> condition ( 'count' , 0 , '>' )
-> execute ();
$references = array ();
foreach ( $result as $usage ) {
2011-08-02 00:50:59 +00:00
$references [ $usage -> module ][ $usage -> type ][ $usage -> id ] = $usage -> count ;
2010-08-22 13:52:59 +00:00
}
return $references ;
}
/**
* Records that a module is using a file .
*
* This usage information will be queried during file_delete () to ensure that
* a file is not in use before it is physically removed from disk .
*
* Examples :
* - A module that associates files with nodes , so $type would be
* 'node' and $id would be the node ' s nid . Files for all revisions are stored
* within a single nid .
* - The User module associates an image with a user , so $type would be 'user'
* and the $id would be the user ' s uid .
*
* @ param $file
* A file object .
* @ param $module
* The name of the module using the file .
* @ param $type
2010-09-11 21:14:32 +00:00
* The type of the object that contains the referenced file .
2010-08-22 13:52:59 +00:00
* @ param $id
2010-09-11 21:14:32 +00:00
* The unique , numeric ID of the object containing the referenced file .
2010-08-22 13:52:59 +00:00
* @ param $count
* ( optional ) The number of references to add to the object . Defaults to 1.
*
* @ see file_usage_list ()
* @ see file_usage_delete ()
*/
function file_usage_add ( stdClass $file , $module , $type , $id , $count = 1 ) {
db_merge ( 'file_usage' )
-> key ( array (
'fid' => $file -> fid ,
'module' => $module ,
'type' => $type ,
'id' => $id ,
))
-> fields ( array ( 'count' => $count ))
-> expression ( 'count' , 'count + :count' , array ( ':count' => $count ))
-> execute ();
}
/**
* Removes a record to indicate that a module is no longer using a file .
*
* The file_delete () function is typically called after removing a file usage
* to remove the record from the file_managed table and delete the file itself .
*
* @ param $file
* A file object .
* @ param $module
* The name of the module using the file .
* @ param $type
* ( optional ) The type of the object that contains the referenced file . May
* be omitted if all module references to a file are being deleted .
* @ param $id
* ( optional ) The unique , numeric ID of the object containing the referenced
* file . May be omitted if all module references to a file are being deleted .
* @ param $count
* ( optional ) The number of references to delete from the object . Defaults to
* 1. 0 may be specified to delete all references to the file within a
* specific object .
*
* @ see file_usage_add ()
* @ see file_usage_list ()
* @ see file_delete ()
*/
function file_usage_delete ( stdClass $file , $module , $type = NULL , $id = NULL , $count = 1 ) {
// Delete rows that have a exact or less value to prevent empty rows.
$query = db_delete ( 'file_usage' )
-> condition ( 'module' , $module )
-> condition ( 'fid' , $file -> fid );
if ( $type && $id ) {
$query
-> condition ( 'type' , $type )
-> condition ( 'id' , $id );
}
if ( $count ) {
$query -> condition ( 'count' , $count , '<=' );
}
$result = $query -> execute ();
// If the row has more than the specified count decrement it by that number.
2010-09-28 02:34:42 +00:00
if ( ! $result && $count > 0 ) {
2010-08-22 13:52:59 +00:00
$query = db_update ( 'file_usage' )
-> condition ( 'module' , $module )
-> condition ( 'fid' , $file -> fid );
if ( $type && $id ) {
$query
-> condition ( 'type' , $type )
-> condition ( 'id' , $id );
}
2010-09-28 02:34:42 +00:00
$query -> expression ( 'count' , 'count - :count' , array ( ':count' => $count ));
2010-08-22 13:52:59 +00:00
$query -> execute ();
}
}
/**
* Copies a file to a new location and adds a file record to the database .
2008-10-09 00:02:29 +00:00
*
* This function should be used when manipulating files that have records
* stored in the database . This is a powerful function that in many ways
* performs like an advanced version of copy () .
* - Checks if $source and $destination are valid and readable / writable .
* - Checks that $source is not equal to $destination ; if they are an error
* is reported .
* - If file already exists in $destination either the call will error out ,
* replace the file or rename the file based on the $replace parameter .
* - Adds the new file to the files database . If the source file is a
2010-03-26 17:14:46 +00:00
* temporary file , the resulting file will also be a temporary file . See
* file_save_upload () for details on temporary files .
2008-10-09 00:02:29 +00:00
*
* @ param $source
* A file object .
* @ param $destination
2009-08-17 19:14:42 +00:00
* A string containing the destination that $source should be copied to .
2011-06-22 06:21:39 +00:00
* This must be a stream wrapper URI .
2008-10-09 00:02:29 +00:00
* @ param $replace
* Replace behavior when the destination file already exists :
2009-01-10 06:09:54 +00:00
* - FILE_EXISTS_REPLACE - Replace the existing file . If a managed file with
* the destination name exists then its database entry will be updated . If
* no database entry is found then a new one will be created .
2008-10-09 00:02:29 +00:00
* - FILE_EXISTS_RENAME - Append _ { incrementing number } until the filename is
2009-01-10 06:09:54 +00:00
* unique .
2008-10-09 00:02:29 +00:00
* - FILE_EXISTS_ERROR - Do nothing and return FALSE .
2010-03-26 17:14:46 +00:00
*
2008-10-09 00:02:29 +00:00
* @ return
* File object if the copy is successful , or FALSE in the event of an error .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see file_unmanaged_copy ()
* @ see hook_file_copy ()
*/
2009-08-29 05:39:37 +00:00
function file_copy ( stdClass $source , $destination = NULL , $replace = FILE_EXISTS_RENAME ) {
2010-09-11 21:14:32 +00:00
if ( ! file_valid_uri ( $destination )) {
2011-06-30 05:31:12 +00:00
if (( $realpath = drupal_realpath ( $source -> uri )) !== FALSE ) {
2011-10-01 19:47:01 +00:00
watchdog ( 'file' , 'File %file (%realpath) could not be copied because the destination %destination is invalid. This is often caused by improper use of file_copy() or a missing stream wrapper.' , array ( '%file' => $source -> uri , '%realpath' => $realpath , '%destination' => $destination ));
2011-06-30 05:31:12 +00:00
}
else {
2011-10-01 19:47:01 +00:00
watchdog ( 'file' , 'File %file could not be copied because the destination %destination is invalid. This is often caused by improper use of file_copy() or a missing stream wrapper.' , array ( '%file' => $source -> uri , '%destination' => $destination ));
2011-06-30 05:31:12 +00:00
}
2011-10-01 19:47:01 +00:00
drupal_set_message ( t ( 'The specified file %file could not be copied because the destination is invalid. More information is available in the system log.' , array ( '%file' => $source -> uri )), 'error' );
2010-09-11 21:14:32 +00:00
return FALSE ;
}
2009-08-17 19:14:42 +00:00
if ( $uri = file_unmanaged_copy ( $source -> uri , $destination , $replace )) {
2008-10-09 00:02:29 +00:00
$file = clone $source ;
2009-01-10 06:09:54 +00:00
$file -> fid = NULL ;
2009-08-17 19:14:42 +00:00
$file -> uri = $uri ;
2012-01-18 04:10:02 +00:00
$file -> filename = drupal_basename ( $uri );
2009-01-10 06:09:54 +00:00
// If we are replacing an existing file re-use its database record.
if ( $replace == FILE_EXISTS_REPLACE ) {
2009-08-17 19:14:42 +00:00
$existing_files = file_load_multiple ( array (), array ( 'uri' => $uri ));
2009-01-10 06:09:54 +00:00
if ( count ( $existing_files )) {
$existing = reset ( $existing_files );
$file -> fid = $existing -> fid ;
$file -> filename = $existing -> filename ;
}
2008-10-09 00:02:29 +00:00
}
2009-01-10 06:09:54 +00:00
// If we are renaming around an existing file (rather than a directory),
// use its basename for the filename.
2009-08-17 19:14:42 +00:00
elseif ( $replace == FILE_EXISTS_RENAME && is_file ( $destination )) {
2012-01-18 04:10:02 +00:00
$file -> filename = drupal_basename ( $destination );
2009-01-10 06:09:54 +00:00
}
$file = file_save ( $file );
// Inform modules that the file has been copied.
module_invoke_all ( 'file_copy' , $file , $source );
return $file ;
2008-10-09 00:02:29 +00:00
}
return FALSE ;
}
2010-09-11 21:14:32 +00:00
/**
* Determine whether the URI has a valid scheme for file API operations .
*
* There must be a scheme and it must be a Drupal - provided scheme like
* 'public' , 'private' , 'temporary' , or an extension provided with
* hook_stream_wrappers () .
*
* @ param $uri
* The URI to be tested .
*
* @ return
* TRUE if the URI is allowed .
*/
function file_valid_uri ( $uri ) {
// Assert that the URI has an allowed scheme. Barepaths are not allowed.
$uri_scheme = file_uri_scheme ( $uri );
if ( empty ( $uri_scheme ) || ! file_stream_wrapper_valid_scheme ( $uri_scheme )) {
return FALSE ;
}
return TRUE ;
}
2008-10-09 00:02:29 +00:00
/**
2010-08-22 13:52:59 +00:00
* Copies a file to a new location without invoking the file API .
2003-12-26 23:03:21 +00:00
*
2008-09-15 09:28:50 +00:00
* This is a powerful function that in many ways performs like an advanced
* version of copy () .
* - Checks if $source and $destination are valid and readable / writable .
* - Checks that $source is not equal to $destination ; if they are an error
* is reported .
* - If file already exists in $destination either the call will error out ,
* replace the file or rename the file based on the $replace parameter .
2011-12-20 05:50:23 +00:00
* - Provides a fallback using realpaths if the move fails using stream
* wrappers . This can occur because PHP ' s copy () function does not properly
* support streams if safe_mode or open_basedir are enabled . See
* https :// bugs . php . net / bug . php ? id = 60456
2008-09-15 09:28:50 +00:00
*
* @ param $source
2010-09-11 21:14:32 +00:00
* A string specifying the filepath or URI of the source file .
2008-09-15 09:28:50 +00:00
* @ param $destination
2010-09-11 21:14:32 +00:00
* A URI containing the destination that $source should be copied to . The
* URI may be a bare filepath ( without a scheme ) and in that case the default
* scheme ( file :// ) will be used . If this value is omitted , Drupal ' s default
* files scheme will be used , usually " public:// " .
2008-09-15 09:28:50 +00:00
* @ param $replace
* Replace behavior when the destination file already exists :
* - FILE_EXISTS_REPLACE - Replace the existing file .
* - FILE_EXISTS_RENAME - Append _ { incrementing number } until the filename is
2009-01-10 06:09:54 +00:00
* unique .
2006-07-05 11:45:51 +00:00
* - FILE_EXISTS_ERROR - Do nothing and return FALSE .
2010-07-07 01:10:35 +00:00
*
2008-09-15 09:28:50 +00:00
* @ return
* The path to the new file , or FALSE in the event of an error .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see file_copy ()
2003-12-26 23:03:21 +00:00
*/
2008-10-09 00:02:29 +00:00
function file_unmanaged_copy ( $source , $destination = NULL , $replace = FILE_EXISTS_RENAME ) {
2009-07-07 08:59:07 +00:00
$original_source = $source ;
$original_destination = $destination ;
2009-08-17 19:14:42 +00:00
// Assert that the source file actually exists.
2008-09-15 09:28:50 +00:00
if ( ! file_exists ( $source )) {
2009-08-17 19:14:42 +00:00
// @todo Replace drupal_set_message() calls with exceptions instead.
2011-10-01 19:47:01 +00:00
drupal_set_message ( t ( 'The specified file %file could not be copied because no file by that name exists. Please check that you supplied the correct filename.' , array ( '%file' => $original_source )), 'error' );
2011-06-30 05:31:12 +00:00
if (( $realpath = drupal_realpath ( $original_source )) !== FALSE ) {
watchdog ( 'file' , 'File %file (%realpath) could not be copied because it does not exist.' , array ( '%file' => $original_source , '%realpath' => $realpath ));
}
else {
watchdog ( 'file' , 'File %file could not be copied because it does not exist.' , array ( '%file' => $original_source ));
}
2008-09-15 09:28:50 +00:00
return FALSE ;
}
2003-12-26 23:03:21 +00:00
2009-08-17 19:14:42 +00:00
// Build a destination URI if necessary.
if ( ! isset ( $destination )) {
2012-01-18 04:10:02 +00:00
$destination = file_build_uri ( drupal_basename ( $source ));
2009-08-17 19:14:42 +00:00
}
2003-12-26 23:03:21 +00:00
2009-08-17 19:14:42 +00:00
// Prepare the destination directory.
if ( file_prepare_directory ( $destination )) {
// The destination is already a directory, so append the source basename.
2012-01-18 04:10:02 +00:00
$destination = file_stream_wrapper_uri_normalize ( $destination . '/' . drupal_basename ( $source ));
2009-08-17 19:14:42 +00:00
}
else {
// Perhaps $destination is a dir/file?
$dirname = drupal_dirname ( $destination );
if ( ! file_prepare_directory ( $dirname )) {
// The destination is not valid.
2011-10-01 19:47:01 +00:00
watchdog ( 'file' , 'File %file could not be copied because the destination directory %destination is not configured correctly.' , array ( '%file' => $original_source , '%destination' => $dirname ));
drupal_set_message ( t ( 'The specified file %file could not be copied because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.' , array ( '%file' => $original_source )), 'error' );
2009-08-17 19:14:42 +00:00
return FALSE ;
}
}
2005-11-04 20:19:14 +00:00
2009-08-17 19:14:42 +00:00
// Determine whether we can perform this operation based on overwrite rules.
$destination = file_destination ( $destination , $replace );
2008-09-15 09:28:50 +00:00
if ( $destination === FALSE ) {
2010-09-11 21:14:32 +00:00
drupal_set_message ( t ( 'The file %file could not be copied because a file by that name already exists in the destination directory.' , array ( '%file' => $original_source )), 'error' );
2011-06-30 05:31:12 +00:00
watchdog ( 'file' , 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)' , array ( '%file' => $original_source , '%destination' => $destination ));
2008-09-15 09:28:50 +00:00
return FALSE ;
2003-12-26 23:03:21 +00:00
}
2009-08-17 19:14:42 +00:00
// Assert that the source and destination filenames are not the same.
2011-06-30 05:31:12 +00:00
$real_source = drupal_realpath ( $source );
$real_destination = drupal_realpath ( $destination );
if ( $source == $destination || ( $real_source !== FALSE ) && ( $real_source == $real_destination )) {
2008-09-15 09:28:50 +00:00
drupal_set_message ( t ( 'The specified file %file was not copied because it would overwrite itself.' , array ( '%file' => $source )), 'error' );
2010-09-11 21:14:32 +00:00
watchdog ( 'file' , 'File %file could not be copied because it would overwrite itself.' , array ( '%file' => $source ));
2008-09-15 09:28:50 +00:00
return FALSE ;
2003-12-26 23:03:21 +00:00
}
2009-08-17 19:14:42 +00:00
// Make sure the .htaccess files are present.
file_ensure_htaccess ();
// Perform the copy operation.
2008-09-15 09:28:50 +00:00
if ( !@ copy ( $source , $destination )) {
2011-12-20 05:50:23 +00:00
// If the copy failed and realpaths exist, retry the operation using them
// instead.
if ( $real_source === FALSE || $real_destination === FALSE || !@ copy ( $real_source , $real_destination )) {
watchdog ( 'file' , 'The specified file %file could not be copied to %destination.' , array ( '%file' => $source , '%destination' => $destination ), WATCHDOG_ERROR );
return FALSE ;
}
2003-12-26 23:03:21 +00:00
}
2004-08-17 21:35:26 +00:00
2009-04-20 20:02:31 +00:00
// Set the permissions on the new file.
drupal_chmod ( $destination );
2008-09-15 09:28:50 +00:00
return $destination ;
2003-12-26 23:03:21 +00:00
}
2009-08-17 19:14:42 +00:00
/**
* Given a relative path , construct a URI into Drupal ' s default files location .
*/
function file_build_uri ( $path ) {
2010-09-01 20:08:17 +00:00
$uri = file_default_scheme () . '://' . $path ;
2009-08-17 19:14:42 +00:00
return file_stream_wrapper_uri_normalize ( $uri );
}
2007-05-30 08:08:59 +00:00
/**
* Determines the destination path for a file depending on how replacement of
* existing files should be handled .
*
2008-10-09 20:07:00 +00:00
* @ param $destination
2009-08-17 19:14:42 +00:00
* A string specifying the desired final URI or filepath .
2008-10-09 20:07:00 +00:00
* @ param $replace
* Replace behavior when the destination file already exists .
2008-09-15 09:28:50 +00:00
* - FILE_EXISTS_REPLACE - Replace the existing file .
2007-05-30 08:08:59 +00:00
* - FILE_EXISTS_RENAME - Append _ { incrementing number } until the filename is
2009-01-10 06:09:54 +00:00
* unique .
2007-05-30 08:08:59 +00:00
* - FILE_EXISTS_ERROR - Do nothing and return FALSE .
2010-07-07 01:10:35 +00:00
*
2008-10-09 20:07:00 +00:00
* @ return
2009-08-17 19:14:42 +00:00
* The destination filepath , or FALSE if the file already exists
* and FILE_EXISTS_ERROR is specified .
2007-05-30 08:08:59 +00:00
*/
function file_destination ( $destination , $replace ) {
if ( file_exists ( $destination )) {
switch ( $replace ) {
2008-09-15 09:28:50 +00:00
case FILE_EXISTS_REPLACE :
// Do nothing here, we want to overwrite the existing file.
break ;
2007-05-30 08:08:59 +00:00
case FILE_EXISTS_RENAME :
2012-01-18 04:10:02 +00:00
$basename = drupal_basename ( $destination );
2009-08-17 19:14:42 +00:00
$directory = drupal_dirname ( $destination );
2007-05-30 08:08:59 +00:00
$destination = file_create_filename ( $basename , $directory );
break ;
case FILE_EXISTS_ERROR :
2009-08-11 04:50:36 +00:00
// Error reporting handled by calling function.
2007-05-30 08:08:59 +00:00
return FALSE ;
}
}
return $destination ;
}
2004-09-17 18:18:04 +00:00
/**
2008-10-09 00:02:29 +00:00
* Move a file to a new location and update the file ' s database entry .
*
* Moving a file is performed by copying the file to the new location and then
* deleting the original .
* - Checks if $source and $destination are valid and readable / writable .
* - Performs a file move if $source is not equal to $destination .
* - If file already exists in $destination either the call will error out ,
* replace the file or rename the file based on the $replace parameter .
* - Adds the new file to the files database .
*
* @ param $source
* A file object .
* @ param $destination
2010-06-20 23:53:52 +00:00
* A string containing the destination that $source should be moved to .
2011-06-22 05:54:54 +00:00
* This must be a stream wrapper URI .
2008-10-09 00:02:29 +00:00
* @ param $replace
* Replace behavior when the destination file already exists :
2009-01-10 06:09:54 +00:00
* - FILE_EXISTS_REPLACE - Replace the existing file . If a managed file with
* the destination name exists then its database entry will be updated and
* file_delete () called on the source file after hook_file_move is called .
* If no database entry is found then the source files record will be
* updated .
2008-10-09 00:02:29 +00:00
* - FILE_EXISTS_RENAME - Append _ { incrementing number } until the filename is
2009-01-10 06:09:54 +00:00
* unique .
2008-10-09 00:02:29 +00:00
* - FILE_EXISTS_ERROR - Do nothing and return FALSE .
2010-07-07 01:10:35 +00:00
*
2008-10-09 00:02:29 +00:00
* @ return
* Resulting file object for success , or FALSE in the event of an error .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see file_unmanaged_move ()
* @ see hook_file_move ()
*/
2009-08-29 05:39:37 +00:00
function file_move ( stdClass $source , $destination = NULL , $replace = FILE_EXISTS_RENAME ) {
2010-09-11 21:14:32 +00:00
if ( ! file_valid_uri ( $destination )) {
2011-06-30 05:31:12 +00:00
if (( $realpath = drupal_realpath ( $source -> uri )) !== FALSE ) {
2011-10-01 19:47:01 +00:00
watchdog ( 'file' , 'File %file (%realpath) could not be moved because the destination %destination is invalid. This may be caused by improper use of file_move() or a missing stream wrapper.' , array ( '%file' => $source -> uri , '%realpath' => $realpath , '%destination' => $destination ));
2011-06-30 05:31:12 +00:00
}
else {
2011-10-01 19:47:01 +00:00
watchdog ( 'file' , 'File %file could not be moved because the destination %destination is invalid. This may be caused by improper use of file_move() or a missing stream wrapper.' , array ( '%file' => $source -> uri , '%destination' => $destination ));
2011-06-30 05:31:12 +00:00
}
2011-10-01 19:47:01 +00:00
drupal_set_message ( t ( 'The specified file %file could not be moved because the destination is invalid. More information is available in the system log.' , array ( '%file' => $source -> uri )), 'error' );
2010-09-11 21:14:32 +00:00
return FALSE ;
}
2009-08-17 19:14:42 +00:00
if ( $uri = file_unmanaged_move ( $source -> uri , $destination , $replace )) {
2009-01-10 06:09:54 +00:00
$delete_source = FALSE ;
2008-10-09 00:02:29 +00:00
$file = clone $source ;
2009-08-17 19:14:42 +00:00
$file -> uri = $uri ;
2009-01-10 06:09:54 +00:00
// If we are replacing an existing file re-use its database record.
if ( $replace == FILE_EXISTS_REPLACE ) {
2009-08-17 19:14:42 +00:00
$existing_files = file_load_multiple ( array (), array ( 'uri' => $uri ));
2009-01-10 06:09:54 +00:00
if ( count ( $existing_files )) {
$existing = reset ( $existing_files );
$delete_source = TRUE ;
$file -> fid = $existing -> fid ;
}
}
// If we are renaming around an existing file (rather than a directory),
// use its basename for the filename.
2009-08-17 19:14:42 +00:00
elseif ( $replace == FILE_EXISTS_RENAME && is_file ( $destination )) {
2012-01-18 04:10:02 +00:00
$file -> filename = drupal_basename ( $destination );
2008-10-09 00:02:29 +00:00
}
2009-01-10 06:09:54 +00:00
$file = file_save ( $file );
// Inform modules that the file has been moved.
module_invoke_all ( 'file_move' , $file , $source );
if ( $delete_source ) {
// Try a soft delete to remove original if it's not in use elsewhere.
file_delete ( $source );
}
return $file ;
2008-10-09 00:02:29 +00:00
}
return FALSE ;
}
/**
* Move a file to a new location without calling any hooks or making any
* changes to the database .
2004-09-17 18:18:04 +00:00
*
2008-09-15 09:28:50 +00:00
* @ param $source
2009-08-17 19:14:42 +00:00
* A string specifying the filepath or URI of the original file .
2008-09-15 09:28:50 +00:00
* @ param $destination
2010-06-20 23:53:52 +00:00
* A string containing the destination that $source should be moved to .
* This must be a stream wrapper URI . If this value is omitted , Drupal ' s
* default files scheme will be used , usually " public:// " .
2008-09-15 09:28:50 +00:00
* @ param $replace
* Replace behavior when the destination file already exists :
* - FILE_EXISTS_REPLACE - Replace the existing file .
* - FILE_EXISTS_RENAME - Append _ { incrementing number } until the filename is
2009-01-10 06:09:54 +00:00
* unique .
2006-07-05 11:45:51 +00:00
* - FILE_EXISTS_ERROR - Do nothing and return FALSE .
2010-07-07 01:10:35 +00:00
*
2008-09-15 09:28:50 +00:00
* @ return
2009-08-17 19:14:42 +00:00
* The URI of the moved file , or FALSE in the event of an error .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see file_move ()
2004-09-17 18:18:04 +00:00
*/
2008-10-09 00:02:29 +00:00
function file_unmanaged_move ( $source , $destination = NULL , $replace = FILE_EXISTS_RENAME ) {
$filepath = file_unmanaged_copy ( $source , $destination , $replace );
if ( $filepath == FALSE || file_unmanaged_delete ( $source ) == FALSE ) {
2008-09-15 09:28:50 +00:00
return FALSE ;
2003-12-26 23:03:21 +00:00
}
2008-09-15 09:28:50 +00:00
return $filepath ;
2003-12-26 23:03:21 +00:00
}
2007-05-30 08:08:59 +00:00
/**
2009-10-18 18:36:24 +00:00
* Modify a filename as needed for security purposes .
2008-10-09 20:07:00 +00:00
*
2010-08-08 01:37:34 +00:00
* Munging a file name prevents unknown file extensions from masking exploit
* files . When web servers such as Apache decide how to process a URL request ,
* they use the file extension . If the extension is not recognized , Apache
* skips that extension and uses the previous file extension . For example , if
* the file being requested is exploit . php . pps , and Apache does not recognize
* the '.pps' extension , it treats the file as PHP and executes it . To make
* this file name safe for Apache and prevent it from executing as PHP , the
* . php extension is " munged " into . php_ , making the safe file name
* exploit . php_ . pps .
*
* Specifically , this function adds an underscore to all extensions that are
2009-10-18 18:36:24 +00:00
* between 2 and 5 characters in length , internal to the file name , and not
2010-08-08 01:37:34 +00:00
* included in $extensions .
*
* Function behavior is also controlled by the Drupal variable
* 'allow_insecure_uploads' . If 'allow_insecure_uploads' evaluates to TRUE , no
* alterations will be made , if it evaluates to FALSE , the filename is 'munged' .
2008-10-09 20:07:00 +00:00
*
* @ param $filename
2009-10-18 18:36:24 +00:00
* File name to modify .
2008-10-09 20:07:00 +00:00
* @ param $extensions
2009-10-18 18:36:24 +00:00
* A space - separated list of extensions that should not be altered .
2008-10-09 20:07:00 +00:00
* @ param $alerts
2009-10-18 18:36:24 +00:00
* If TRUE , drupal_set_message () will be called to display a message if the
* file name was changed .
*
2008-10-09 20:07:00 +00:00
* @ return
2009-10-18 18:36:24 +00:00
* The potentially modified $filename .
2007-05-30 08:08:59 +00:00
*/
function file_munge_filename ( $filename , $extensions , $alerts = TRUE ) {
$original = $filename ;
// Allow potentially insecure uploads for very savvy users and admin
if ( ! variable_get ( 'allow_insecure_uploads' , 0 )) {
$whitelist = array_unique ( explode ( ' ' , trim ( $extensions )));
// Split the filename up by periods. The first part becomes the basename
// the last part the final extension.
$filename_parts = explode ( '.' , $filename );
$new_filename = array_shift ( $filename_parts ); // Remove file basename.
$final_extension = array_pop ( $filename_parts ); // Remove final extension.
// Loop through the middle parts of the name and add an underscore to the
// end of each section that could be a file extension but isn't in the list
// of allowed extensions.
foreach ( $filename_parts as $filename_part ) {
2008-04-14 17:48:46 +00:00
$new_filename .= '.' . $filename_part ;
2007-05-30 08:08:59 +00:00
if ( ! in_array ( $filename_part , $whitelist ) && preg_match ( " /^[a-zA-Z] { 2,5} \ d? $ / " , $filename_part )) {
$new_filename .= '_' ;
}
}
2008-04-14 17:48:46 +00:00
$filename = $new_filename . '.' . $final_extension ;
2007-05-30 08:08:59 +00:00
if ( $alerts && $original != $filename ) {
drupal_set_message ( t ( 'For security reasons, your upload has been renamed to %filename.' , array ( '%filename' => $filename )));
}
}
return $filename ;
}
/**
2011-12-08 04:29:32 +00:00
* Undo the effect of file_munge_filename () .
2007-05-30 08:08:59 +00:00
*
2008-10-09 20:07:00 +00:00
* @ param $filename
* String with the filename to be unmunged .
2010-07-07 01:10:35 +00:00
*
2008-10-09 20:07:00 +00:00
* @ return
* An unmunged filename string .
2007-05-30 08:08:59 +00:00
*/
function file_unmunge_filename ( $filename ) {
return str_replace ( '_.' , '.' , $filename );
}
2006-03-08 23:42:55 +00:00
/**
2008-10-09 20:07:00 +00:00
* Create a full file path from a directory and filename .
*
* If a file with the specified name already exists , an alternative will be
* used .
2006-03-08 23:42:55 +00:00
*
2008-10-09 20:07:00 +00:00
* @ param $basename
* String filename
* @ param $directory
2009-08-17 19:14:42 +00:00
* String containing the directory or parent URI .
2010-07-07 01:10:35 +00:00
*
2006-03-08 23:42:55 +00:00
* @ return
2008-10-09 20:07:00 +00:00
* File path consisting of $directory and a unique filename based off
* of $basename .
2006-03-08 23:42:55 +00:00
*/
2004-08-17 21:35:26 +00:00
function file_create_filename ( $basename , $directory ) {
2010-01-29 22:40:41 +00:00
// Strip control characters (ASCII value < 32). Though these are allowed in
// some filesystems, not many applications handle them well.
$basename = preg_replace ( '/[\x00-\x1F]/u' , '_' , $basename );
2010-08-17 22:05:22 +00:00
if ( substr ( PHP_OS , 0 , 3 ) == 'WIN' ) {
// These characters are not allowed in Windows filenames
$basename = str_replace ( array ( ':' , '*' , '?' , '"' , '<' , '>' , '|' ), '_' , $basename );
}
2010-01-29 22:40:41 +00:00
2009-08-17 19:14:42 +00:00
// A URI or path may already have a trailing slash or look like "public://".
if ( substr ( $directory , - 1 ) == '/' ) {
$separator = '' ;
}
else {
$separator = '/' ;
}
$destination = $directory . $separator . $basename ;
2004-08-17 21:35:26 +00:00
2008-09-15 09:28:50 +00:00
if ( file_exists ( $destination )) {
2004-08-17 21:35:26 +00:00
// Destination file already exists, generate an alternative.
2008-09-15 09:28:50 +00:00
$pos = strrpos ( $basename , '.' );
if ( $pos !== FALSE ) {
2004-08-17 21:35:26 +00:00
$name = substr ( $basename , 0 , $pos );
$ext = substr ( $basename , $pos );
}
else {
$name = $basename ;
2008-09-15 09:28:50 +00:00
$ext = '' ;
2004-08-17 21:35:26 +00:00
}
$counter = 0 ;
do {
2009-08-17 19:14:42 +00:00
$destination = $directory . $separator . $name . '_' . $counter ++ . $ext ;
2008-09-15 09:28:50 +00:00
} while ( file_exists ( $destination ));
2004-08-17 21:35:26 +00:00
}
2008-09-15 09:28:50 +00:00
return $destination ;
2004-08-17 21:35:26 +00:00
}
2006-03-08 23:42:55 +00:00
/**
2008-10-09 00:02:29 +00:00
* Delete a file and its database record .
*
2010-08-22 13:52:59 +00:00
* If the $force parameter is not TRUE , file_usage_list () will be called to
* determine if the file is being used by any modules . If the file is being
* used the delete will be canceled .
2008-10-09 00:02:29 +00:00
*
* @ param $file
* A file object .
* @ param $force
2010-08-22 13:52:59 +00:00
* Boolean indicating that the file should be deleted even if the file is
* reported as in use by the file_usage table .
2010-07-07 01:10:35 +00:00
*
2008-10-09 00:02:29 +00:00
* @ return mixed
* TRUE for success , FALSE in the event of an error , or an array if the file
2010-08-22 13:52:59 +00:00
* is being used by any modules .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see file_unmanaged_delete ()
2010-08-22 13:52:59 +00:00
* @ see file_usage_list ()
* @ see file_usage_delete ()
2011-12-17 12:43:37 +00:00
* @ see hook_file_predelete ()
2008-10-09 00:02:29 +00:00
* @ see hook_file_delete ()
*/
2009-08-29 05:39:37 +00:00
function file_delete ( stdClass $file , $force = FALSE ) {
2010-09-11 21:14:32 +00:00
if ( ! file_valid_uri ( $file -> uri )) {
2011-06-30 05:31:12 +00:00
if (( $realpath = drupal_realpath ( $file -> uri )) !== FALSE ) {
watchdog ( 'file' , 'File %file (%realpath) could not be deleted because it is not a valid URI. This may be caused by improper use of file_delete() or a missing stream wrapper.' , array ( '%file' => $file -> uri , '%realpath' => $realpath ));
}
else {
watchdog ( 'file' , 'File %file could not be deleted because it is not a valid URI. This may be caused by improper use of file_delete() or a missing stream wrapper.' , array ( '%file' => $file -> uri ));
}
2011-10-01 19:47:01 +00:00
drupal_set_message ( t ( 'The specified file %file could not be deleted because it is not a valid URI. More information is available in the system log.' , array ( '%file' => $file -> uri )), 'error' );
2010-09-11 21:14:32 +00:00
return FALSE ;
}
2010-08-22 13:52:59 +00:00
// If any module still has a usage entry in the file_usage table, the file
// will not be deleted, but file_delete() will return a populated array
// that tests as TRUE.
if ( ! $force && ( $references = file_usage_list ( $file ))) {
2008-10-09 00:02:29 +00:00
return $references ;
}
2011-12-17 12:43:37 +00:00
// Let other modules clean up any references to the file prior to deletion.
module_invoke_all ( 'file_predelete' , $file );
module_invoke_all ( 'entity_predelete' , $file , 'file' );
2008-10-09 00:02:29 +00:00
// Make sure the file is deleted before removing its row from the
// database, so UIs can still find the file in the database.
2009-08-17 19:14:42 +00:00
if ( file_unmanaged_delete ( $file -> uri )) {
2010-04-10 17:30:15 +00:00
db_delete ( 'file_managed' ) -> condition ( 'fid' , $file -> fid ) -> execute ();
2010-08-22 13:52:59 +00:00
db_delete ( 'file_usage' ) -> condition ( 'fid' , $file -> fid ) -> execute ();
2011-12-17 12:43:37 +00:00
// Let other modules respond to file deletion.
module_invoke_all ( 'file_delete' , $file );
module_invoke_all ( 'entity_delete' , $file , 'file' );
2008-10-09 00:02:29 +00:00
return TRUE ;
}
return FALSE ;
}
/**
* Delete a file without calling any hooks or making any changes to the
* database .
*
* This function should be used when the file to be deleted does not have an
* entry recorded in the files table .
2006-03-08 23:42:55 +00:00
*
2008-09-15 09:28:50 +00:00
* @ param $path
2009-10-09 18:38:52 +00:00
* A string containing a file path or ( streamwrapper ) URI .
2010-07-07 01:10:35 +00:00
*
2008-09-15 09:28:50 +00:00
* @ return
* TRUE for success or path does not exist , or FALSE in the event of an
* error .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see file_delete ()
2009-02-13 00:39:01 +00:00
* @ see file_unmanaged_delete_recursive ()
2006-03-08 23:42:55 +00:00
*/
2008-10-09 00:02:29 +00:00
function file_unmanaged_delete ( $path ) {
2008-09-15 09:28:50 +00:00
if ( is_dir ( $path )) {
2011-07-04 16:58:33 +00:00
watchdog ( 'file' , '%path is a directory and cannot be removed using file_unmanaged_delete().' , array ( '%path' => $path ), WATCHDOG_ERROR );
2008-09-15 09:28:50 +00:00
return FALSE ;
}
2003-12-27 19:21:48 +00:00
if ( is_file ( $path )) {
2010-08-17 22:05:22 +00:00
return drupal_unlink ( $path );
2003-12-27 19:21:48 +00:00
}
2008-12-30 16:43:20 +00:00
// Return TRUE for non-existent file, but log that nothing was actually
2010-01-25 10:38:35 +00:00
// deleted, as the current state is the intended result.
2008-09-15 09:28:50 +00:00
if ( ! file_exists ( $path )) {
2011-10-01 19:47:01 +00:00
watchdog ( 'file' , 'The file %path was not deleted because it does not exist.' , array ( '%path' => $path ), WATCHDOG_NOTICE );
2008-09-15 09:28:50 +00:00
return TRUE ;
}
2009-02-13 00:39:01 +00:00
// We cannot handle anything other than files and directories. Log an error
// for everything else (sockets, symbolic links, etc).
2011-07-04 16:58:33 +00:00
watchdog ( 'file' , 'The file %path is not of a recognized type so it was not deleted.' , array ( '%path' => $path ), WATCHDOG_ERROR );
2008-09-15 09:28:50 +00:00
return FALSE ;
2003-12-26 23:03:21 +00:00
}
2009-02-13 00:39:01 +00:00
/**
* Recursively delete all files and directories in the specified filepath .
*
* If the specified path is a directory then the function will call itself
* recursively to process the contents . Once the contents have been removed the
* directory will also be removed .
*
* If the specified path is a file then it will be passed to
* file_unmanaged_delete () .
*
* Note that this only deletes visible files with write permission .
*
* @ param $path
2010-01-25 10:38:35 +00:00
* A string containing either an URI or a file or directory path .
2010-07-07 01:10:35 +00:00
*
2009-02-13 00:39:01 +00:00
* @ return
2009-10-09 18:38:52 +00:00
* TRUE for success or if path does not exist , FALSE in the event of an
2009-02-13 00:39:01 +00:00
* error .
*
* @ see file_unmanaged_delete ()
*/
function file_unmanaged_delete_recursive ( $path ) {
if ( is_dir ( $path )) {
$dir = dir ( $path );
while (( $entry = $dir -> read ()) !== FALSE ) {
if ( $entry == '.' || $entry == '..' ) {
continue ;
}
$entry_path = $path . '/' . $entry ;
file_unmanaged_delete_recursive ( $entry_path );
}
2009-03-10 09:47:42 +00:00
$dir -> close ();
2010-08-17 22:05:22 +00:00
return drupal_rmdir ( $path );
2009-02-13 00:39:01 +00:00
}
return file_unmanaged_delete ( $path );
}
2007-05-30 08:08:59 +00:00
/**
2008-01-28 19:56:27 +00:00
* Determine total disk space used by a single user or the whole filesystem .
2007-05-30 08:08:59 +00:00
*
2008-01-28 19:56:27 +00:00
* @ param $uid
2008-09-15 09:28:50 +00:00
* Optional . A user id , specifying NULL returns the total space used by all
* non - temporary files .
* @ param $status
2010-07-26 03:04:29 +00:00
* Optional . The file status to consider . The default is to only
* consider files in status FILE_STATUS_PERMANENT .
2010-07-07 01:10:35 +00:00
*
2008-09-15 09:28:50 +00:00
* @ return
* An integer containing the number of bytes used .
2007-05-30 08:08:59 +00:00
*/
2008-09-15 09:28:50 +00:00
function file_space_used ( $uid = NULL , $status = FILE_STATUS_PERMANENT ) {
2010-04-10 17:30:15 +00:00
$query = db_select ( 'file_managed' , 'f' );
2010-07-26 03:04:29 +00:00
$query -> condition ( 'f.status' , $status );
2009-01-06 12:00:40 +00:00
$query -> addExpression ( 'SUM(f.filesize)' , 'filesize' );
2010-09-24 02:10:06 +00:00
if ( isset ( $uid )) {
2009-01-06 12:00:40 +00:00
$query -> condition ( 'f.uid' , $uid );
2007-05-30 08:08:59 +00:00
}
2009-01-06 12:00:40 +00:00
return $query -> execute () -> fetchField ();
2007-05-30 08:08:59 +00:00
}
2003-12-26 23:03:21 +00:00
/**
2008-10-09 20:07:00 +00:00
* Saves a file upload to a new location .
2003-12-26 23:03:21 +00:00
*
2010-04-10 17:30:15 +00:00
* The file will be added to the { file_managed } table as a temporary file .
* Temporary files are periodically cleaned . To make the file a permanent file ,
* assign the status and use file_save () to save the changes .
2007-05-30 08:08:59 +00:00
*
* @ param $source
2009-08-19 08:38:09 +00:00
* A string specifying the filepath or URI of the uploaded file to save .
2007-05-30 08:08:59 +00:00
* @ param $validators
* An optional , associative array of callback functions used to validate the
2009-04-13 19:06:32 +00:00
* file . See file_validate () for a full discussion of the array format .
2010-06-26 19:55:47 +00:00
* If no extension validator is provided it will default to a limited safe
* list of extensions which is as follows : " jpg jpeg gif png txt
* doc xls pdf ppt pps odt ods odp " . To allow all extensions you must
* explicitly set the 'file_validate_extensions' validator to an empty array
* ( Beware : this is not safe and should only be allowed for trusted users , if
* at all ) .
2008-09-15 09:28:50 +00:00
* @ param $destination
2010-06-20 23:53:52 +00:00
* A string containing the URI $source should be copied to .
* This must be a stream wrapper URI . If this value is omitted , Drupal ' s
* temporary files scheme will be used ( " temporary:// " ) .
2007-05-30 08:08:59 +00:00
* @ param $replace
2009-08-02 05:43:54 +00:00
* Replace behavior when the destination file already exists :
* - FILE_EXISTS_REPLACE : Replace the existing file .
* - FILE_EXISTS_RENAME : Append _ { incrementing number } until the filename is
* unique .
* - FILE_EXISTS_ERROR : Do nothing and return FALSE .
2010-07-07 01:10:35 +00:00
*
2007-05-30 08:08:59 +00:00
* @ return
2009-01-20 02:56:05 +00:00
* An object containing the file information if the upload succeeded , FALSE
2009-10-13 15:46:03 +00:00
* in the event of an error , or NULL if no file was uploaded . The
* documentation for the " File interface " group , which you can find under
* Related topics , or the header at the top of this file , documents the
* components of a file object . In addition to the standard components ,
* this function adds :
* - source : Path to the file before it is moved .
* - destination : Path to the file after it is moved ( same as 'uri' ) .
2003-12-26 23:03:21 +00:00
*/
2008-09-15 09:28:50 +00:00
function file_save_upload ( $source , $validators = array (), $destination = FALSE , $replace = FILE_EXISTS_RENAME ) {
2007-05-30 08:08:59 +00:00
global $user ;
static $upload_cache ;
// Return cached objects without processing since the file will have
// already been processed and the paths in _FILES will be invalid.
if ( isset ( $upload_cache [ $source ])) {
return $upload_cache [ $source ];
}
2009-01-05 04:26:54 +00:00
// Make sure there's an upload to process.
2009-01-20 02:56:05 +00:00
if ( empty ( $_FILES [ 'files' ][ 'name' ][ $source ])) {
return NULL ;
2009-01-05 04:26:54 +00:00
}
2008-09-15 09:28:50 +00:00
2009-01-05 04:26:54 +00:00
// Check for file upload errors and return FALSE if a lower level system
// error occurred. For a complete list of errors:
2010-03-26 17:14:46 +00:00
// See http://php.net/manual/en/features.file-upload.errors.php.
2009-01-05 04:26:54 +00:00
switch ( $_FILES [ 'files' ][ 'error' ][ $source ]) {
case UPLOAD_ERR_INI_SIZE :
case UPLOAD_ERR_FORM_SIZE :
2011-10-01 19:47:01 +00:00
drupal_set_message ( t ( 'The file %file could not be saved because it exceeds %maxsize, the maximum allowed size for uploads.' , array ( '%file' => $_FILES [ 'files' ][ 'name' ][ $source ], '%maxsize' => format_size ( file_upload_max_size ()))), 'error' );
2009-01-05 04:26:54 +00:00
return FALSE ;
2008-09-15 09:28:50 +00:00
2009-01-05 04:26:54 +00:00
case UPLOAD_ERR_PARTIAL :
case UPLOAD_ERR_NO_FILE :
2011-10-01 19:47:01 +00:00
drupal_set_message ( t ( 'The file %file could not be saved because the upload did not complete.' , array ( '%file' => $_FILES [ 'files' ][ 'name' ][ $source ])), 'error' );
2009-01-05 04:26:54 +00:00
return FALSE ;
2007-05-30 08:08:59 +00:00
2009-01-05 04:26:54 +00:00
case UPLOAD_ERR_OK :
// Final check that this is a valid upload, if it isn't, use the
// default error handler.
if ( is_uploaded_file ( $_FILES [ 'files' ][ 'tmp_name' ][ $source ])) {
2009-05-24 17:39:35 +00:00
break ;
2009-01-05 04:26:54 +00:00
}
2007-05-30 08:08:59 +00:00
2009-01-05 04:26:54 +00:00
// Unknown error
default :
2009-01-21 02:07:10 +00:00
drupal_set_message ( t ( 'The file %file could not be saved. An unknown error has occurred.' , array ( '%file' => $_FILES [ 'files' ][ 'name' ][ $source ])), 'error' );
2009-01-05 04:26:54 +00:00
return FALSE ;
}
2007-05-30 08:08:59 +00:00
2009-01-05 04:26:54 +00:00
// Begin building file object.
$file = new stdClass ();
$file -> uid = $user -> uid ;
$file -> status = 0 ;
2012-01-18 04:10:02 +00:00
$file -> filename = trim ( drupal_basename ( $_FILES [ 'files' ][ 'name' ][ $source ]), '.' );
2009-08-17 19:14:42 +00:00
$file -> uri = $_FILES [ 'files' ][ 'tmp_name' ][ $source ];
2009-01-05 04:26:54 +00:00
$file -> filemime = file_get_mimetype ( $file -> filename );
$file -> filesize = $_FILES [ 'files' ][ 'size' ][ $source ];
2006-03-07 19:14:30 +00:00
2010-06-26 19:55:47 +00:00
$extensions = '' ;
if ( isset ( $validators [ 'file_validate_extensions' ])) {
if ( isset ( $validators [ 'file_validate_extensions' ][ 0 ])) {
// Build the list of non-munged extensions if the caller provided them.
$extensions = $validators [ 'file_validate_extensions' ][ 0 ];
}
else {
// If 'file_validate_extensions' is set and the list is empty then the
// caller wants to allow any extension. In this case we have to remove the
// validator or else it will reject all extensions.
unset ( $validators [ 'file_validate_extensions' ]);
}
}
else {
// No validator was provided, so add one using the default list.
// Build a default non-munged safe list for file_munge_filename().
$extensions = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp' ;
$validators [ 'file_validate_extensions' ] = array ();
$validators [ 'file_validate_extensions' ][ 0 ] = $extensions ;
}
if ( ! empty ( $extensions )) {
// Munge the filename to protect against possible malicious extension hiding
// within an unknown file type (ie: filename.html.foo).
$file -> filename = file_munge_filename ( $file -> filename , $extensions );
}
// Rename potentially executable files, to help prevent exploits (i.e. will
// rename filename.php.foo and filename.php to filename.php.foo.txt and
// filename.php.txt, respectively). Don't rename if 'allow_insecure_uploads'
// evaluates to TRUE.
if ( ! variable_get ( 'allow_insecure_uploads' , 0 ) && preg_match ( '/\.(php|pl|py|cgi|asp|js)(\.|$)/i' , $file -> filename ) && ( substr ( $file -> filename , - 4 ) != '.txt' )) {
2009-01-05 04:26:54 +00:00
$file -> filemime = 'text/plain' ;
2009-08-17 19:14:42 +00:00
$file -> uri .= '.txt' ;
2009-01-05 04:26:54 +00:00
$file -> filename .= '.txt' ;
2010-06-26 19:55:47 +00:00
// The .txt extension may not be in the allowed list of extensions. We have
// to add it here or else the file upload will fail.
if ( ! empty ( $extensions )) {
$validators [ 'file_validate_extensions' ][ 0 ] .= ' txt' ;
drupal_set_message ( t ( 'For security reasons, your upload has been renamed to %filename.' , array ( '%filename' => $file -> filename )));
}
2009-01-05 04:26:54 +00:00
}
2007-05-30 08:08:59 +00:00
2009-08-17 19:14:42 +00:00
// If the destination is not provided, use the temporary directory.
if ( empty ( $destination )) {
$destination = 'temporary://' ;
}
// Assert that the destination contains a valid stream.
$destination_scheme = file_uri_scheme ( $destination );
if ( ! $destination_scheme || ! file_stream_wrapper_valid_scheme ( $destination_scheme )) {
2011-10-01 19:47:01 +00:00
drupal_set_message ( t ( 'The file could not be uploaded because the destination %destination is invalid.' , array ( '%destination' => $destination )), 'error' );
2009-08-17 19:14:42 +00:00
return FALSE ;
2009-01-05 04:26:54 +00:00
}
2007-10-25 09:05:45 +00:00
2009-01-05 04:26:54 +00:00
$file -> source = $source ;
2009-08-19 08:38:09 +00:00
// A URI may already have a trailing slash or look like "public://".
if ( substr ( $destination , - 1 ) != '/' ) {
$destination .= '/' ;
}
2009-08-17 19:14:42 +00:00
$file -> destination = file_destination ( $destination . $file -> filename , $replace );
2009-01-10 06:09:54 +00:00
// If file_destination() returns FALSE then $replace == FILE_EXISTS_ERROR and
// there's an existing file so we need to bail.
if ( $file -> destination === FALSE ) {
2009-08-11 04:50:36 +00:00
drupal_set_message ( t ( 'The file %source could not be uploaded because a file by that name already exists in the destination %directory.' , array ( '%source' => $source , '%directory' => $destination )), 'error' );
2009-01-10 06:09:54 +00:00
return FALSE ;
}
2007-05-30 08:08:59 +00:00
2009-01-05 04:26:54 +00:00
// Add in our check of the the file name length.
$validators [ 'file_validate_name_length' ] = array ();
2003-12-26 23:03:21 +00:00
2009-01-05 04:26:54 +00:00
// Call the validation functions specified by this function's caller.
$errors = file_validate ( $file , $validators );
2007-05-30 08:08:59 +00:00
2009-01-05 04:26:54 +00:00
// Check for errors.
if ( ! empty ( $errors )) {
$message = t ( 'The specified file %name could not be uploaded.' , array ( '%name' => $file -> filename ));
if ( count ( $errors ) > 1 ) {
2009-10-09 01:00:08 +00:00
$message .= theme ( 'item_list' , array ( 'items' => $errors ));
2007-05-30 08:08:59 +00:00
}
2009-01-05 04:26:54 +00:00
else {
$message .= ' ' . array_pop ( $errors );
2008-10-09 00:02:29 +00:00
}
2009-01-05 04:26:54 +00:00
form_set_error ( $source , $message );
return FALSE ;
}
// Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary
// directory. This overcomes open_basedir restrictions for future file
// operations.
2009-08-17 19:14:42 +00:00
$file -> uri = $file -> destination ;
2011-08-30 07:35:47 +00:00
if ( ! drupal_move_uploaded_file ( $_FILES [ 'files' ][ 'tmp_name' ][ $source ], $file -> uri )) {
2009-01-05 04:26:54 +00:00
form_set_error ( $source , t ( 'File upload error. Could not move uploaded file.' ));
2009-08-17 19:14:42 +00:00
watchdog ( 'file' , 'Upload error. Could not move uploaded file %file to destination %destination.' , array ( '%file' => $file -> filename , '%destination' => $file -> uri ));
2009-01-05 04:26:54 +00:00
return FALSE ;
}
2009-04-20 20:02:31 +00:00
// Set the permissions on the new file.
2009-08-17 19:14:42 +00:00
drupal_chmod ( $file -> uri );
2009-04-20 20:02:31 +00:00
2009-01-10 06:09:54 +00:00
// If we are replacing an existing file re-use its database record.
if ( $replace == FILE_EXISTS_REPLACE ) {
2009-08-17 19:14:42 +00:00
$existing_files = file_load_multiple ( array (), array ( 'uri' => $file -> uri ));
2009-01-10 06:09:54 +00:00
if ( count ( $existing_files )) {
$existing = reset ( $existing_files );
$file -> fid = $existing -> fid ;
}
}
2009-01-05 04:26:54 +00:00
// If we made it this far it's safe to record this file in the database.
if ( $file = file_save ( $file )) {
// Add file to the cache.
$upload_cache [ $source ] = $file ;
return $file ;
2003-12-26 23:03:21 +00:00
}
2008-06-18 03:36:24 +00:00
return FALSE ;
2003-12-26 23:03:21 +00:00
}
2011-08-30 07:35:47 +00:00
/**
* Moves an uploaded file to a new location .
*
* PHP ' s move_uploaded_file () does not properly support streams if safe_mode
* or open_basedir are enabled , so this function fills that gap .
*
* Compatibility : normal paths and stream wrappers .
* @ see http :// drupal . org / node / 515192
*
* @ param $filename
* The filename of the uploaded file .
* @ param $uri
* A string containing the destination URI of the file .
*
* @ return
* TRUE on success , or FALSE on failure .
*
* @ see move_uploaded_file ()
* @ ingroup php_wrappers
*/
function drupal_move_uploaded_file ( $filename , $uri ) {
$result = @ move_uploaded_file ( $filename , $uri );
// PHP's move_uploaded_file() does not properly support streams if safe_mode
// or open_basedir are enabled so if the move failed, try finding a real path
// and retry the move operation.
if ( ! $result ) {
if ( $realpath = drupal_realpath ( $uri )) {
$result = move_uploaded_file ( $filename , $realpath );
}
else {
$result = move_uploaded_file ( $filename , $uri );
}
}
return $result ;
}
2008-09-15 09:28:50 +00:00
/**
* Check that a file meets the criteria specified by the validators .
*
2008-10-09 00:02:29 +00:00
* After executing the validator callbacks specified hook_file_validate () will
* also be called to allow other modules to report errors about the file .
*
2008-09-15 09:28:50 +00:00
* @ param $file
* A Drupal file object .
* @ param $validators
* An optional , associative array of callback functions used to validate the
* file . The keys are function names and the values arrays of callback
2009-04-13 19:06:32 +00:00
* parameters which will be passed in after the file object . The
* functions should return an array of error messages ; an empty array
2008-09-15 09:28:50 +00:00
* indicates that the file passed validation . The functions will be called in
* the order specified .
2010-07-07 01:10:35 +00:00
*
2008-09-15 09:28:50 +00:00
* @ return
2010-01-25 10:38:35 +00:00
* An array containing validation error messages .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see hook_file_validate ()
2008-09-15 09:28:50 +00:00
*/
2009-08-29 05:39:37 +00:00
function file_validate ( stdClass & $file , $validators = array ()) {
2008-09-15 09:28:50 +00:00
// Call the validation functions specified by this function's caller.
$errors = array ();
foreach ( $validators as $function => $args ) {
2009-08-24 00:14:23 +00:00
if ( function_exists ( $function )) {
2009-07-16 10:46:46 +00:00
array_unshift ( $args , $file );
$errors = array_merge ( $errors , call_user_func_array ( $function , $args ));
}
2008-09-15 09:28:50 +00:00
}
2008-10-09 00:02:29 +00:00
// Let other modules perform validation on the new file.
return array_merge ( $errors , module_invoke_all ( 'file_validate' , $file ));
2008-09-15 09:28:50 +00:00
}
2007-05-30 08:08:59 +00:00
/**
* Check for files with names longer than we can store in the database .
*
* @ param $file
* A Drupal file object .
* @ return
* An array . If the file name is too long , it will contain an error message .
*/
2009-08-29 05:39:37 +00:00
function file_validate_name_length ( stdClass $file ) {
2007-05-30 08:08:59 +00:00
$errors = array ();
2008-09-15 09:28:50 +00:00
if ( empty ( $file -> filename )) {
$errors [] = t ( " The file's name is empty. Please give a name to the file. " );
}
2009-08-17 19:14:42 +00:00
if ( strlen ( $file -> filename ) > 240 ) {
$errors [] = t ( " The file's name exceeds the 240 characters limit. Please rename the file and try again. " );
2007-05-30 08:08:59 +00:00
}
return $errors ;
}
/**
2008-09-15 09:28:50 +00:00
* Check that the filename ends with an allowed extension .
2007-05-30 08:08:59 +00:00
*
* @ param $file
* A Drupal file object .
* @ param $extensions
2009-02-24 17:08:18 +00:00
* A string with a space separated list of allowed extensions .
2010-07-07 01:10:35 +00:00
*
2007-05-30 08:08:59 +00:00
* @ return
2008-09-15 09:28:50 +00:00
* An array . If the file extension is not allowed , it will contain an error
* message .
2008-10-09 20:07:00 +00:00
*
* @ see hook_file_validate ()
2007-05-30 08:08:59 +00:00
*/
2009-08-29 05:39:37 +00:00
function file_validate_extensions ( stdClass $file , $extensions ) {
2007-05-30 08:08:59 +00:00
$errors = array ();
2008-09-15 09:28:50 +00:00
$regex = '/\.(' . preg_replace ( '/ +/' , '|' , preg_quote ( $extensions )) . ')$/i' ;
if ( ! preg_match ( $regex , $file -> filename )) {
$errors [] = t ( 'Only files with the following extensions are allowed: %files-allowed.' , array ( '%files-allowed' => $extensions ));
2007-05-30 08:08:59 +00:00
}
return $errors ;
}
/**
2008-10-09 20:07:00 +00:00
* Check that the file ' s size is below certain limits .
*
* This check is not enforced for the user #1.
2007-05-30 08:08:59 +00:00
*
* @ param $file
* A Drupal file object .
* @ param $file_limit
* An integer specifying the maximum file size in bytes . Zero indicates that
* no limit should be enforced .
2008-09-19 03:40:32 +00:00
* @ param $user_limit
2008-09-15 09:28:50 +00:00
* An integer specifying the maximum number of bytes the user is allowed .
* Zero indicates that no limit should be enforced .
2010-07-07 01:10:35 +00:00
*
2007-05-30 08:08:59 +00:00
* @ return
2008-09-15 09:28:50 +00:00
* An array . If the file size exceeds limits , it will contain an error
* message .
2008-10-09 20:07:00 +00:00
*
* @ see hook_file_validate ()
2007-05-30 08:08:59 +00:00
*/
2009-08-29 05:39:37 +00:00
function file_validate_size ( stdClass $file , $file_limit = 0 , $user_limit = 0 ) {
2007-05-30 08:08:59 +00:00
global $user ;
$errors = array ();
// Bypass validation for uid = 1.
if ( $user -> uid != 1 ) {
if ( $file_limit && $file -> filesize > $file_limit ) {
$errors [] = t ( 'The file is %filesize exceeding the maximum file size of %maxsize.' , array ( '%filesize' => format_size ( $file -> filesize ), '%maxsize' => format_size ( $file_limit )));
}
2009-06-09 21:33:12 +00:00
// Save a query by only calling file_space_used() when a limit is provided.
2008-09-19 03:40:32 +00:00
if ( $user_limit && ( file_space_used ( $user -> uid ) + $file -> filesize ) > $user_limit ) {
2007-05-30 08:08:59 +00:00
$errors [] = t ( 'The file is %filesize which would exceed your disk quota of %quota.' , array ( '%filesize' => format_size ( $file -> filesize ), '%quota' => format_size ( $user_limit )));
}
}
return $errors ;
}
/**
* Check that the file is recognized by image_get_info () as an image .
*
* @ param $file
* A Drupal file object .
2010-07-07 01:10:35 +00:00
*
2007-05-30 08:08:59 +00:00
* @ return
* An array . If the file is not an image , it will contain an error message .
2008-10-09 20:07:00 +00:00
*
* @ see hook_file_validate ()
2007-05-30 08:08:59 +00:00
*/
2009-08-29 05:39:37 +00:00
function file_validate_is_image ( stdClass $file ) {
2007-05-30 08:08:59 +00:00
$errors = array ();
2009-08-17 19:14:42 +00:00
$info = image_get_info ( $file -> uri );
2007-05-30 08:08:59 +00:00
if ( ! $info || empty ( $info [ 'extension' ])) {
$errors [] = t ( 'Only JPEG, PNG and GIF images are allowed.' );
}
return $errors ;
}
/**
2009-12-30 08:16:55 +00:00
* Verify that image dimensions are within the specified maximum and minimum .
2008-10-09 20:07:00 +00:00
*
* Non - image files will be ignored . If a image toolkit is available the image
2010-01-25 10:38:35 +00:00
* will be scaled to fit within the desired maximum dimensions .
2007-05-30 08:08:59 +00:00
*
* @ param $file
2008-09-15 09:28:50 +00:00
* A Drupal file object . This function may resize the file affecting its
* size .
2007-05-30 08:08:59 +00:00
* @ param $maximum_dimensions
* An optional string in the form WIDTHxHEIGHT e . g . '640x480' or '85x85' . If
* an image toolkit is installed the image will be resized down to these
* dimensions . A value of 0 indicates no restriction on size , so resizing
* will be attempted .
* @ param $minimum_dimensions
2008-09-15 09:28:50 +00:00
* An optional string in the form WIDTHxHEIGHT . This will check that the
* image meets a minimum size . A value of 0 indicates no restriction .
2010-07-07 01:10:35 +00:00
*
2007-05-30 08:08:59 +00:00
* @ return
* An array . If the file is an image and did not meet the requirements , it
* will contain an error message .
2008-10-09 20:07:00 +00:00
*
* @ see hook_file_validate ()
2007-05-30 08:08:59 +00:00
*/
2009-08-29 05:39:37 +00:00
function file_validate_image_resolution ( stdClass $file , $maximum_dimensions = 0 , $minimum_dimensions = 0 ) {
2007-05-30 08:08:59 +00:00
$errors = array ();
// Check first that the file is an image.
2009-08-17 19:14:42 +00:00
if ( $info = image_get_info ( $file -> uri )) {
2007-05-30 08:08:59 +00:00
if ( $maximum_dimensions ) {
// Check that it is smaller than the given dimensions.
list ( $width , $height ) = explode ( 'x' , $maximum_dimensions );
if ( $info [ 'width' ] > $width || $info [ 'height' ] > $height ) {
// Try to resize the image to fit the dimensions.
2009-08-17 19:14:42 +00:00
if ( $image = image_load ( $file -> uri )) {
2009-03-09 11:44:54 +00:00
image_scale ( $image , $width , $height );
image_save ( $image );
$file -> filesize = $image -> info [ 'file_size' ];
2007-05-30 08:08:59 +00:00
drupal_set_message ( t ( 'The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.' , array ( '%dimensions' => $maximum_dimensions )));
}
else {
$errors [] = t ( 'The image is too large; the maximum dimensions are %dimensions pixels.' , array ( '%dimensions' => $maximum_dimensions ));
}
}
}
if ( $minimum_dimensions ) {
// Check that it is larger than the given dimensions.
list ( $width , $height ) = explode ( 'x' , $minimum_dimensions );
2007-07-25 17:41:27 +00:00
if ( $info [ 'width' ] < $width || $info [ 'height' ] < $height ) {
2007-05-30 08:08:59 +00:00
$errors [] = t ( 'The image is too small; the minimum dimensions are %dimensions pixels.' , array ( '%dimensions' => $minimum_dimensions ));
}
}
}
return $errors ;
}
2004-06-04 18:00:48 +00:00
/**
2008-10-09 00:02:29 +00:00
* Save a string to the specified destination and create a database file entry .
2004-06-04 18:00:48 +00:00
*
2008-09-15 09:28:50 +00:00
* @ param $data
* A string containing the contents of the file .
* @ param $destination
2011-06-22 16:54:26 +00:00
* A string containing the destination URI . This must be a stream wrapper URI .
* If no value is provided , a randomized name will be generated and the file
* will be saved using Drupal ' s default files scheme , usually " public:// " .
2008-09-15 09:28:50 +00:00
* @ param $replace
* Replace behavior when the destination file already exists :
2009-01-10 06:09:54 +00:00
* - FILE_EXISTS_REPLACE - Replace the existing file . If a managed file with
* the destination name exists then its database entry will be updated . If
* no database entry is found then a new one will be created .
2008-09-15 09:28:50 +00:00
* - FILE_EXISTS_RENAME - Append _ { incrementing number } until the filename is
2009-01-10 06:09:54 +00:00
* unique .
2006-07-05 11:45:51 +00:00
* - FILE_EXISTS_ERROR - Do nothing and return FALSE .
2010-07-07 01:10:35 +00:00
*
2008-09-15 09:28:50 +00:00
* @ return
2008-10-09 00:02:29 +00:00
* A file object , or FALSE on error .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see file_unmanaged_save_data ()
2004-06-04 18:00:48 +00:00
*/
2008-09-15 09:28:50 +00:00
function file_save_data ( $data , $destination = NULL , $replace = FILE_EXISTS_RENAME ) {
2008-10-09 00:02:29 +00:00
global $user ;
2010-09-11 21:14:32 +00:00
if ( empty ( $destination )) {
$destination = file_default_scheme () . '://' ;
}
if ( ! file_valid_uri ( $destination )) {
watchdog ( 'file' , 'The data could not be saved because the destination %destination is invalid. This may be caused by improper use of file_save_data() or a missing stream wrapper.' , array ( '%destination' => $destination ));
2011-10-01 19:47:01 +00:00
drupal_set_message ( t ( 'The data could not be saved because the destination is invalid. More information is available in the system log.' ), 'error' );
2010-09-11 21:14:32 +00:00
return FALSE ;
}
2009-08-17 19:14:42 +00:00
if ( $uri = file_unmanaged_save_data ( $data , $destination , $replace )) {
2008-10-09 00:02:29 +00:00
// Create a file object.
$file = new stdClass ();
2009-01-10 06:09:54 +00:00
$file -> fid = NULL ;
2009-08-17 19:14:42 +00:00
$file -> uri = $uri ;
2012-01-18 04:10:02 +00:00
$file -> filename = drupal_basename ( $uri );
2009-08-17 19:14:42 +00:00
$file -> filemime = file_get_mimetype ( $file -> uri );
2008-10-09 00:02:29 +00:00
$file -> uid = $user -> uid ;
2010-07-26 03:04:29 +00:00
$file -> status = FILE_STATUS_PERMANENT ;
2009-01-10 06:09:54 +00:00
// If we are replacing an existing file re-use its database record.
if ( $replace == FILE_EXISTS_REPLACE ) {
2009-08-17 19:14:42 +00:00
$existing_files = file_load_multiple ( array (), array ( 'uri' => $uri ));
2009-01-10 06:09:54 +00:00
if ( count ( $existing_files )) {
$existing = reset ( $existing_files );
$file -> fid = $existing -> fid ;
$file -> filename = $existing -> filename ;
}
}
// If we are renaming around an existing file (rather than a directory),
// use its basename for the filename.
2009-08-17 19:14:42 +00:00
elseif ( $replace == FILE_EXISTS_RENAME && is_file ( $destination )) {
2012-01-18 04:10:02 +00:00
$file -> filename = drupal_basename ( $destination );
2009-01-10 06:09:54 +00:00
}
2008-10-09 00:02:29 +00:00
return file_save ( $file );
}
return FALSE ;
}
/**
2009-12-30 08:16:55 +00:00
* Save a string to the specified destination without invoking file API .
2008-10-09 00:02:29 +00:00
*
* This function is identical to file_save_data () except the file will not be
2010-04-10 17:30:15 +00:00
* saved to the { file_managed } table and none of the file_ * hooks will be
* called .
2008-10-09 00:02:29 +00:00
*
* @ param $data
* A string containing the contents of the file .
* @ param $destination
2011-06-23 00:56:03 +00:00
* A string containing the destination location . This must be a stream wrapper
* URI . If no value is provided , a randomized name will be generated and the
* file will be saved using Drupal ' s default files scheme , usually " public:// " .
2008-10-09 00:02:29 +00:00
* @ param $replace
* Replace behavior when the destination file already exists :
* - FILE_EXISTS_REPLACE - Replace the existing file .
* - FILE_EXISTS_RENAME - Append _ { incrementing number } until the filename is
* unique .
* - FILE_EXISTS_ERROR - Do nothing and return FALSE .
2010-07-07 01:10:35 +00:00
*
2008-10-09 00:02:29 +00:00
* @ return
* A string with the path of the resulting file , or FALSE on error .
2008-10-09 20:07:00 +00:00
*
2008-10-09 00:02:29 +00:00
* @ see file_save_data ()
*/
function file_unmanaged_save_data ( $data , $destination = NULL , $replace = FILE_EXISTS_RENAME ) {
2008-09-15 09:28:50 +00:00
// Write the data to a temporary file.
2009-08-17 19:14:42 +00:00
$temp_name = drupal_tempnam ( 'temporary://' , 'file' );
2008-09-15 09:28:50 +00:00
if ( file_put_contents ( $temp_name , $data ) === FALSE ) {
2005-05-05 22:22:46 +00:00
drupal_set_message ( t ( 'The file could not be created.' ), 'error' );
2008-06-18 03:36:24 +00:00
return FALSE ;
2004-06-04 18:00:48 +00:00
}
2008-09-15 09:28:50 +00:00
// Move the file to its final destination.
2008-10-09 00:02:29 +00:00
return file_unmanaged_move ( $temp_name , $destination , $replace );
2004-06-04 18:00:48 +00:00
}
2003-12-26 23:03:21 +00:00
/**
2009-12-30 08:16:55 +00:00
* Transfer file using HTTP to client .
*
* Pipes a file through Drupal to the client .
2003-12-26 23:03:21 +00:00
*
2009-08-17 19:14:42 +00:00
* @ param $uri
* String specifying the file URI to transfer .
2008-09-15 09:28:50 +00:00
* @ param $headers
* An array of HTTP headers to send along with file .
2003-12-26 23:03:21 +00:00
*/
2009-08-17 19:14:42 +00:00
function file_transfer ( $uri , $headers ) {
2008-10-11 20:41:53 +00:00
if ( ob_get_level ()) {
ob_end_clean ();
}
2003-12-26 23:03:21 +00:00
2009-04-22 09:45:03 +00:00
foreach ( $headers as $name => $value ) {
2009-09-30 18:36:02 +00:00
drupal_add_http_header ( $name , $value );
2003-12-26 23:03:21 +00:00
}
2009-04-22 09:45:03 +00:00
drupal_send_headers ();
2009-08-17 19:14:42 +00:00
$scheme = file_uri_scheme ( $uri );
2003-12-26 23:03:21 +00:00
// Transfer file in 1024 byte chunks to save memory usage.
2009-08-17 19:14:42 +00:00
if ( $scheme && file_stream_wrapper_valid_scheme ( $scheme ) && $fd = fopen ( $uri , 'rb' )) {
2005-05-06 09:31:45 +00:00
while ( ! feof ( $fd )) {
print fread ( $fd , 1024 );
}
fclose ( $fd );
}
else {
drupal_not_found ();
2003-12-26 23:03:21 +00:00
}
2009-10-13 21:16:44 +00:00
drupal_exit ();
2003-12-26 23:03:21 +00:00
}
/**
2008-10-09 20:07:00 +00:00
* Menu handler for private file transfers .
2008-09-15 09:28:50 +00:00
*
2006-03-08 23:42:55 +00:00
* Call modules that implement hook_file_download () to find out if a file is
2011-08-02 00:25:32 +00:00
* accessible and what headers it should be transferred with . If one or more
* modules returned headers the download will start with the returned headers .
* If a module returns - 1 drupal_access_denied () will be returned . If the file
* exists but no modules responded drupal_access_denied () will be returned .
* If the file does not exist drupal_not_found () will be returned .
2008-10-09 00:02:29 +00:00
*
* @ see hook_file_download ()
2003-12-26 23:03:21 +00:00
*/
function file_download () {
2006-03-30 17:45:32 +00:00
// Merge remainder of arguments from GET['q'], into relative file path.
2006-03-29 06:49:25 +00:00
$args = func_get_args ();
2009-08-17 19:14:42 +00:00
$scheme = array_shift ( $args );
$target = implode ( '/' , $args );
$uri = $scheme . '://' . $target ;
2010-04-30 01:33:17 +00:00
if ( file_stream_wrapper_valid_scheme ( $scheme ) && file_exists ( $uri )) {
2008-09-15 09:28:50 +00:00
// Let other modules provide headers and controls access to the file.
2010-09-11 05:07:22 +00:00
// module_invoke_all() uses array_merge_recursive() which merges header
// values into a new array. To avoid that and allow modules to override
// headers instead, use array_merge() to merge the returned arrays.
$headers = array ();
foreach ( module_implements ( 'file_download' ) as $module ) {
$function = $module . '_file_download' ;
$result = $function ( $uri );
if ( $result == - 1 ) {
return drupal_access_denied ();
}
if ( isset ( $result ) && is_array ( $result )) {
$headers = array_merge ( $headers , $result );
}
2006-03-10 19:02:06 +00:00
}
if ( count ( $headers )) {
2009-08-17 19:14:42 +00:00
file_transfer ( $uri , $headers );
2003-12-26 23:03:21 +00:00
}
2011-08-02 00:25:32 +00:00
return drupal_access_denied ();
2003-12-26 23:03:21 +00:00
}
2006-03-10 19:02:06 +00:00
return drupal_not_found ();
2003-12-26 23:03:21 +00:00
}
2006-03-10 19:02:06 +00:00
2003-12-26 23:03:21 +00:00
/**
2006-12-11 16:45:17 +00:00
* Finds all files that match a given mask in a given directory .
2008-10-09 20:07:00 +00:00
*
2006-12-11 16:45:17 +00:00
* Directories and files beginning with a period are excluded ; this
* prevents hidden files and directories ( such as SVN working directories )
* from being scanned .
2004-09-17 18:18:04 +00:00
*
2004-11-24 22:44:01 +00:00
* @ param $dir
2009-11-05 03:37:08 +00:00
* The base directory or URI to scan , without trailing slash .
2004-11-24 22:44:01 +00:00
* @ param $mask
2008-09-20 03:49:24 +00:00
* The preg_match () regular expression of the files to find .
2009-02-18 15:07:27 +00:00
* @ param $options
2009-11-05 03:37:08 +00:00
* An associative array of additional options , with the following elements :
* - 'nomask' : The preg_match () regular expression of the files to ignore .
* Defaults to '/(\.\.?|CVS)$/' .
* - 'callback' : The callback function to call for each match . There is no
* default callback .
* - 'recurse' : When TRUE , the directory scan will recurse the entire tree
* starting at the provided directory . Defaults to TRUE .
* - 'key' : The key to be used for the returned associative array of files .
* Possible values are 'uri' , for the file 's URI; ' filename ' , for the
* basename of the file ; and 'name' for the name of the file without the
* extension . Defaults to 'uri' .
* - 'min_depth' : Minimum depth of directories to return files from . Defaults
* to 0.
2005-03-08 22:06:11 +00:00
* @ param $depth
2008-09-15 09:28:50 +00:00
* Current depth of recursion . This parameter is only used internally and
2009-11-05 03:37:08 +00:00
* should not be passed in .
*
2004-11-24 22:44:01 +00:00
* @ return
2009-11-05 03:37:08 +00:00
* An associative array ( keyed on the chosen key ) of objects with 'uri' ,
* 'filename' , and 'name' members corresponding to the matching files .
2003-12-26 23:03:21 +00:00
*/
2009-02-18 15:07:27 +00:00
function file_scan_directory ( $dir , $mask , $options = array (), $depth = 0 ) {
// Merge in defaults.
$options += array (
'nomask' => '/(\.\.?|CVS)$/' ,
'callback' => 0 ,
'recurse' => TRUE ,
2009-08-17 19:14:42 +00:00
'key' => 'uri' ,
2009-02-18 15:07:27 +00:00
'min_depth' => 0 ,
);
2009-08-17 19:14:42 +00:00
$options [ 'key' ] = in_array ( $options [ 'key' ], array ( 'uri' , 'filename' , 'name' )) ? $options [ 'key' ] : 'uri' ;
2003-12-26 23:03:21 +00:00
$files = array ();
if ( is_dir ( $dir ) && $handle = opendir ( $dir )) {
2009-02-22 17:55:30 +00:00
while ( FALSE !== ( $filename = readdir ( $handle ))) {
if ( ! preg_match ( $options [ 'nomask' ], $filename ) && $filename [ 0 ] != '.' ) {
2009-08-17 19:14:42 +00:00
$uri = " $dir / $filename " ;
$uri = file_stream_wrapper_uri_normalize ( $uri );
if ( is_dir ( $uri ) && $options [ 'recurse' ]) {
2007-11-04 16:22:27 +00:00
// Give priority to files in this folder by merging them in after any subdirectory files.
2009-08-17 19:14:42 +00:00
$files = array_merge ( file_scan_directory ( $uri , $mask , $options , $depth + 1 ), $files );
2003-12-26 23:03:21 +00:00
}
2009-02-22 17:55:30 +00:00
elseif ( $depth >= $options [ 'min_depth' ] && preg_match ( $mask , $filename )) {
2008-09-15 09:28:50 +00:00
// Always use this match over anything already set in $files with the
2009-02-18 15:07:27 +00:00
// same $$options['key'].
2010-06-17 13:16:57 +00:00
$file = new stdClass ();
2009-08-29 05:39:37 +00:00
$file -> uri = $uri ;
$file -> filename = $filename ;
$file -> name = pathinfo ( $filename , PATHINFO_FILENAME );
2009-02-22 17:55:30 +00:00
$key = $options [ 'key' ];
$files [ $file -> $key ] = $file ;
2009-02-18 15:07:27 +00:00
if ( $options [ 'callback' ]) {
2009-08-17 19:14:42 +00:00
$options [ 'callback' ]( $uri );
2003-12-26 23:03:21 +00:00
}
}
}
}
2004-11-24 22:44:01 +00:00
2003-12-26 23:03:21 +00:00
closedir ( $handle );
}
2004-11-24 22:44:01 +00:00
2003-12-26 23:03:21 +00:00
return $files ;
}
2006-08-06 22:49:27 +00:00
/**
* Determine the maximum file upload size by querying the PHP settings .
*
* @ return
2008-09-15 09:28:50 +00:00
* A file size limit in bytes based on the PHP upload_max_filesize and
* post_max_size
2006-08-06 22:49:27 +00:00
*/
function file_upload_max_size () {
static $max_size = - 1 ;
2005-08-25 21:14:17 +00:00
2006-08-06 22:49:27 +00:00
if ( $max_size < 0 ) {
2010-08-01 01:33:42 +00:00
// Start with post_max_size.
$max_size = parse_size ( ini_get ( 'post_max_size' ));
// If upload_max_size is less, then reduce. Except if upload_max_size is
// zero, which indicates no limit.
2006-12-07 17:02:25 +00:00
$upload_max = parse_size ( ini_get ( 'upload_max_filesize' ));
2010-08-01 01:33:42 +00:00
if ( $upload_max > 0 && $upload_max < $max_size ) {
$max_size = $upload_max ;
}
2006-08-06 22:49:27 +00:00
}
return $max_size ;
}
2008-01-28 16:05:17 +00:00
2008-08-14 12:10:47 +00:00
/**
* Determine an Internet Media Type , or MIME type from a filename .
*
2009-08-17 19:14:42 +00:00
* @ param $uri
* A string containing the URI , path , or filename .
2008-08-14 12:10:47 +00:00
* @ param $mapping
2009-06-02 13:42:40 +00:00
* An optional map of extensions to their mimetypes , in the form :
* - 'mimetypes' : a list of mimetypes , keyed by an identifier ,
* - 'extensions' : the mapping itself , an associative array in which
2009-08-31 05:47:34 +00:00
* the key is the extension ( lowercase ) and the value is the mimetype
* identifier . If $mapping is NULL file_mimetype_mapping () is called .
2008-08-14 12:10:47 +00:00
*
* @ return
2009-08-31 05:47:34 +00:00
* The internet media type registered for the extension or
* application / octet - stream for unknown extensions .
2010-03-26 17:14:46 +00:00
*
* @ see file_default_mimetype_mapping ()
2008-08-14 12:10:47 +00:00
*/
2009-08-17 19:14:42 +00:00
function file_get_mimetype ( $uri , $mapping = NULL ) {
if ( $wrapper = file_stream_wrapper_get_instance_by_uri ( $uri )) {
return $wrapper -> getMimeType ( $uri , $mapping );
2009-06-02 13:42:40 +00:00
}
2009-08-17 19:14:42 +00:00
else {
// getMimeType() is not implementation specific, so we can directly
// call it without an instance.
return DrupalLocalStreamWrapper :: getMimeType ( $uri , $mapping );
2008-08-14 12:10:47 +00:00
}
}
2009-04-20 20:02:31 +00:00
2008-01-28 16:05:17 +00:00
/**
2009-04-20 20:02:31 +00:00
* Set the permissions on a file or directory .
*
* This function will use the 'file_chmod_directory' and 'file_chmod_file'
2009-12-30 08:16:55 +00:00
* variables for the default modes for directories and uploaded / generated
* files . By default these will give everyone read access so that users
* accessing the files with a user account without the webserver group ( e . g .
* via FTP ) can read these files , and give group write permissions so webserver
* group members ( e . g . a vhost account ) can alter files uploaded and owned by
* the webserver .
2009-04-20 20:02:31 +00:00
*
2009-12-30 08:16:55 +00:00
* PHP ' s chmod does not support stream wrappers so we use our wrapper
* implementation which interfaces with chmod () by default . Contrib wrappers
2010-01-25 10:38:35 +00:00
* may override this behavior in their implementations as needed .
2009-08-17 19:14:42 +00:00
*
* @ param $uri
* A string containing a URI file , or directory path .
2009-04-20 20:02:31 +00:00
* @ param $mode
* Integer value for the permissions . Consult PHP chmod () documentation for
* more information .
2010-07-07 01:10:35 +00:00
*
2009-04-20 20:02:31 +00:00
* @ return
* TRUE for success , FALSE in the event of an error .
2009-09-28 22:22:54 +00:00
*
* @ ingroup php_wrappers
2008-01-28 16:05:17 +00:00
*/
2009-08-17 19:14:42 +00:00
function drupal_chmod ( $uri , $mode = NULL ) {
2009-04-20 20:02:31 +00:00
if ( ! isset ( $mode )) {
2009-08-17 19:14:42 +00:00
if ( is_dir ( $uri )) {
2009-04-20 20:02:31 +00:00
$mode = variable_get ( 'file_chmod_directory' , 0775 );
}
else {
$mode = variable_get ( 'file_chmod_file' , 0664 );
}
}
2009-08-17 19:14:42 +00:00
// If this URI is a stream, pass it off to the appropriate stream wrapper.
// Otherwise, attempt PHP's chmod. This allows use of drupal_chmod even
// for unmanaged files outside of the stream wrapper interface.
if ( $wrapper = file_stream_wrapper_get_instance_by_uri ( $uri )) {
if ( $wrapper -> chmod ( $mode )) {
return TRUE ;
}
}
else {
if ( @ chmod ( $uri , $mode )) {
return TRUE ;
}
2009-04-20 20:02:31 +00:00
}
2011-07-04 16:58:33 +00:00
watchdog ( 'file' , 'The file permissions could not be set on %uri.' , array ( '%uri' => $uri ), WATCHDOG_ERROR );
2009-04-20 20:02:31 +00:00
return FALSE ;
}
2010-08-17 22:05:22 +00:00
/**
* Deletes a file .
*
* PHP ' s unlink () is broken on Windows , as it can fail to remove a file
* when it has a read - only flag set .
*
* @ param $uri
* A URI or pathname .
* @ param $context
* Refer to http :// php . net / manual / en / ref . stream . php
*
* @ return
* Boolean TRUE on success , or FALSE on failure .
*
* @ see unlink ()
* @ ingroup php_wrappers
*/
function drupal_unlink ( $uri , $context = NULL ) {
$scheme = file_uri_scheme ( $uri );
if (( ! $scheme || ! file_stream_wrapper_valid_scheme ( $scheme )) && ( substr ( PHP_OS , 0 , 3 ) == 'WIN' )) {
chmod ( $uri , 0600 );
}
if ( $context ) {
return unlink ( $uri , $context );
}
else {
return unlink ( $uri );
}
}
2009-08-17 19:14:42 +00:00
/**
2011-09-25 09:45:29 +00:00
* Returns the absolute local filesystem path of a stream URI .
2009-08-17 19:14:42 +00:00
*
2011-09-25 09:45:29 +00:00
* This function was originally written to ease the conversion of 6. x code to
* use 7. x stream wrappers . However , it assumes that every URI may be resolved
* to an absolute local filesystem path , and this assumption fails when stream
* wrappers are used to support remote file storage . Remote stream wrappers
* may implement the realpath method by always returning FALSE . The use of
* drupal_realpath () is discouraged , and is slowly being removed from core
* functions where possible .
2009-08-17 19:14:42 +00:00
*
2011-09-25 09:45:29 +00:00
* Only use this function if you know that the stream wrapper in the URI uses
* the local file system , and you need to pass an absolute path to a function
* that is incompatible with stream URIs .
2009-08-17 19:14:42 +00:00
*
* @ param $uri
2011-09-25 09:45:29 +00:00
* A stream wrapper URI or a filesystem path , possibly including one or more
* symbolic links .
2010-03-26 17:14:46 +00:00
*
2009-08-17 19:14:42 +00:00
* @ return
2011-09-25 09:45:29 +00:00
* The absolute local filesystem path ( with no symbolic links ), or FALSE on
* failure .
2009-08-17 19:14:42 +00:00
*
2011-09-25 09:45:29 +00:00
* @ see DrupalStreamWrapperInterface :: realpath ()
* @ see http :// php . net / manual / function . realpath . php
2009-09-28 22:22:54 +00:00
* @ ingroup php_wrappers
2011-09-25 09:45:29 +00:00
* @ todo : This function is deprecated , and should be removed wherever possible .
2009-08-17 19:14:42 +00:00
*/
function drupal_realpath ( $uri ) {
// If this URI is a stream, pass it off to the appropriate stream wrapper.
// Otherwise, attempt PHP's realpath. This allows use of drupal_realpath even
// for unmanaged files outside of the stream wrapper interface.
if ( $wrapper = file_stream_wrapper_get_instance_by_uri ( $uri )) {
return $wrapper -> realpath ();
}
2011-06-11 23:33:58 +00:00
return realpath ( $uri );
2009-08-17 19:14:42 +00:00
}
/**
* Gets the name of the directory from a given path .
*
* PHP ' s dirname () does not properly pass streams , so this function fills
* that gap . It is backwards compatible with normal paths and will use
* PHP ' s dirname () as a fallback .
*
* Compatibility : normal paths and stream wrappers .
* @ see http :// drupal . org / node / 515192
*
* @ param $uri
* A URI or path .
2010-03-26 17:14:46 +00:00
*
2009-08-17 19:14:42 +00:00
* @ return
* A string containing the directory name .
*
* @ see dirname ()
2009-09-28 22:22:54 +00:00
* @ ingroup php_wrappers
2009-08-17 19:14:42 +00:00
*/
function drupal_dirname ( $uri ) {
2009-12-30 08:16:55 +00:00
$scheme = file_uri_scheme ( $uri );
2009-08-17 19:14:42 +00:00
if ( $scheme && file_stream_wrapper_valid_scheme ( $scheme )) {
2010-06-02 13:09:34 +00:00
return file_stream_wrapper_get_instance_by_scheme ( $scheme ) -> dirname ( $uri );
2009-08-17 19:14:42 +00:00
}
else {
return dirname ( $uri );
}
}
2012-01-18 04:10:02 +00:00
/**
* Gets the filename from a given path .
*
* PHP ' s basename () does not properly support streams or filenames beginning
* with a non - US - ASCII character .
*
* @ see http :// bugs . php . net / bug . php ? id = 37738
* @ see basename ()
*
* @ ingroup php_wrappers
*/
function drupal_basename ( $uri , $suffix = NULL ) {
$separators = '/' ;
if ( DIRECTORY_SEPARATOR != '/' ) {
// For Windows OS add special separator.
$separators .= DIRECTORY_SEPARATOR ;
}
// Remove right-most slashes when $uri points to directory.
$uri = rtrim ( $uri , $separators );
// Returns the trailing part of the $uri starting after one of the directory
// separators.
$filename = preg_match ( '@[^' . preg_quote ( $separators , '@' ) . ']+$@' , $uri , $matches ) ? $matches [ 0 ] : '' ;
// Cuts off a suffix from the filename.
if ( $suffix ) {
$filename = preg_replace ( '@' . preg_quote ( $suffix , '@' ) . '$@' , '' , $filename );
}
return $filename ;
}
2009-08-17 19:14:42 +00:00
/**
* Creates a directory using Drupal ' s default mode .
*
* PHP 's mkdir() does not respect Drupal' s default permissions mode . If a mode
* is not provided , this function will make sure that Drupal ' s is used .
*
* Compatibility : normal paths and stream wrappers .
* @ see http :// drupal . org / node / 515192
*
* @ param $uri
* A URI or pathname .
* @ param $mode
* By default the Drupal mode is used .
* @ param $recursive
* Default to FALSE .
* @ param $context
* Refer to http :// php . net / manual / en / ref . stream . php
2010-03-26 17:14:46 +00:00
*
2009-08-17 19:14:42 +00:00
* @ return
* Boolean TRUE on success , or FALSE on failure .
*
* @ see mkdir ()
2009-09-28 22:22:54 +00:00
* @ ingroup php_wrappers
2009-08-17 19:14:42 +00:00
*/
function drupal_mkdir ( $uri , $mode = NULL , $recursive = FALSE , $context = NULL ) {
2010-09-26 23:31:36 +00:00
if ( ! isset ( $mode )) {
2009-08-17 19:14:42 +00:00
$mode = variable_get ( 'file_chmod_directory' , 0775 );
}
2010-09-26 23:31:36 +00:00
if ( ! isset ( $context )) {
2009-08-17 19:14:42 +00:00
return mkdir ( $uri , $mode , $recursive );
}
else {
return mkdir ( $uri , $mode , $recursive , $context );
}
}
2010-08-17 22:05:22 +00:00
/**
* Remove a directory .
*
* PHP ' s rmdir () is broken on Windows , as it can fail to remove a directory
* when it has a read - only flag set .
*
* @ param $uri
* A URI or pathname .
* @ param $context
* Refer to http :// php . net / manual / en / ref . stream . php
*
* @ return
* Boolean TRUE on success , or FALSE on failure .
*
* @ see rmdir ()
* @ ingroup php_wrappers
*/
function drupal_rmdir ( $uri , $context = NULL ) {
$scheme = file_uri_scheme ( $uri );
if (( ! $scheme || ! file_stream_wrapper_valid_scheme ( $scheme )) && ( substr ( PHP_OS , 0 , 3 ) == 'WIN' )) {
chmod ( $uri , 0700 );
}
if ( $context ) {
return rmdir ( $uri , $context );
}
else {
return rmdir ( $uri );
}
}
2009-08-17 19:14:42 +00:00
/**
* Creates a file with a unique filename in the specified directory .
*
* PHP ' s tempnam () does not return a URI like we want . This function
* will return a URI if given a URI , or it will return a filepath if
* given a filepath .
*
* Compatibility : normal paths and stream wrappers .
* @ see http :// drupal . org / node / 515192
*
* @ param $directory
* The directory where the temporary filename will be created .
* @ param $prefix
* The prefix of the generated temporary filename .
* Note : Windows uses only the first three characters of prefix .
2010-03-26 17:14:46 +00:00
*
2009-08-17 19:14:42 +00:00
* @ return
2010-01-25 10:38:35 +00:00
* The new temporary filename , or FALSE on failure .
2009-08-17 19:14:42 +00:00
*
* @ see tempnam ()
2009-09-28 22:22:54 +00:00
* @ ingroup php_wrappers
2009-08-17 19:14:42 +00:00
*/
function drupal_tempnam ( $directory , $prefix ) {
2009-12-30 08:16:55 +00:00
$scheme = file_uri_scheme ( $directory );
2009-08-17 19:14:42 +00:00
if ( $scheme && file_stream_wrapper_valid_scheme ( $scheme )) {
$wrapper = file_stream_wrapper_get_instance_by_scheme ( $scheme );
if ( $filename = tempnam ( $wrapper -> getDirectoryPath (), $prefix )) {
2012-01-18 04:10:02 +00:00
return $scheme . '://' . drupal_basename ( $filename );
2009-08-17 19:14:42 +00:00
}
else {
return FALSE ;
}
}
else {
// Handle as a normal tempnam() call.
return tempnam ( $directory , $prefix );
}
}
2010-06-12 08:15:15 +00:00
/**
* Get the path of system - appropriate temporary directory .
*/
function file_directory_temp () {
2010-10-05 06:23:18 +00:00
$temporary_directory = variable_get ( 'file_temporary_path' , NULL );
2010-06-12 08:15:15 +00:00
2010-10-05 06:23:18 +00:00
if ( empty ( $temporary_directory )) {
2010-06-12 08:15:15 +00:00
$directories = array ();
// Has PHP been set with an upload_tmp_dir?
if ( ini_get ( 'upload_tmp_dir' )) {
$directories [] = ini_get ( 'upload_tmp_dir' );
}
// Operating system specific dirs.
if ( substr ( PHP_OS , 0 , 3 ) == 'WIN' ) {
$directories [] = 'c:\\windows\\temp' ;
$directories [] = 'c:\\winnt\\temp' ;
}
else {
$directories [] = '/tmp' ;
}
// PHP may be able to find an alternative tmp directory.
2011-06-11 23:33:58 +00:00
$directories [] = sys_get_temp_dir ();
2010-06-12 08:15:15 +00:00
foreach ( $directories as $directory ) {
if ( is_dir ( $directory ) && is_writable ( $directory )) {
$temporary_directory = $directory ;
break ;
}
}
if ( empty ( $temporary_directory )) {
2011-07-14 03:05:21 +00:00
// If no directory has been found default to 'files/tmp'.
$temporary_directory = variable_get ( 'file_public_path' , conf_path () . '/files' ) . '/tmp' ;
// Windows accepts paths with either slash (/) or backslash (\), but will
// not accept a path which contains both a slash and a backslash. Since
// the 'file_public_path' variable may have either format, we sanitize
// everything to use slash which is supported on all platforms.
$temporary_directory = str_replace ( '\\' , '/' , $temporary_directory );
2010-06-12 08:15:15 +00:00
}
// Save the path of the discovered directory.
2010-10-05 06:23:18 +00:00
variable_set ( 'file_temporary_path' , $temporary_directory );
2010-06-12 08:15:15 +00:00
}
return $temporary_directory ;
}
2010-10-18 01:00:39 +00:00
/**
* Examines a file object and returns appropriate content headers for download .
*
* @ param $file
* A file object .
* @ return
* An associative array of headers , as expected by file_transfer () .
*/
function file_get_content_headers ( $file ) {
$name = mime_header_encode ( $file -> filename );
$type = mime_header_encode ( $file -> filemime );
// Serve images, text, and flash content for display rather than download.
$inline_types = variable_get ( 'file_inline_types' , array ( '^text/' , '^image/' , 'flash$' ));
$disposition = 'attachment' ;
foreach ( $inline_types as $inline_type ) {
// Exclamation marks are used as delimiters to avoid escaping slashes.
if ( preg_match ( '!' . $inline_type . '!' , $file -> filemime )) {
$disposition = 'inline' ;
}
}
return array (
'Content-Type' => $type . '; name="' . $name . '"' ,
'Content-Length' => $file -> filesize ,
'Content-Disposition' => $disposition . '; filename="' . $name . '"' ,
'Cache-Control' => 'private' ,
);
}
2009-04-20 20:02:31 +00:00
/**
* @ } End of " defgroup file " .
2009-06-09 21:33:12 +00:00
*/