2008-07-31 22:15:30 +00:00
< ? php //$Id$
require_once ( " $CFG->libdir /file/stored_file.php " );
class file_storage {
private $filedir ;
/**
* Contructor
* @ param string $filedir full path to pool directory
*/
2008-08-04 13:21:38 +00:00
public function __construct ( $filedir ) {
$this -> filedir = $filedir ;
2008-07-31 22:15:30 +00:00
// make sure the file pool directory exists
if ( ! is_dir ( $this -> filedir )) {
if ( ! check_dir_exists ( $this -> filedir , true , true )) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfilecannotcreatefiledirs' ); // permission trouble
2008-07-31 22:15:30 +00:00
}
// place warning file in file pool root
2008-08-02 18:33:11 +00:00
file_put_contents ( $this -> filedir . '/warning.txt' ,
2008-08-02 12:45:02 +00:00
'This directory contains the content of uploaded files and is controlled by Moodle code. Do not manually move, change or rename any of the files and subdirectories here.' );
2008-07-31 22:15:30 +00:00
}
}
2008-08-04 13:21:38 +00:00
/**
* Returns location of filedir ( file pool )
2008-09-06 10:09:33 +00:00
* @ return string pathname
2008-08-04 13:21:38 +00:00
*/
public function get_filedir () {
return $this -> filedir ;
}
2008-07-31 22:15:30 +00:00
/**
* Calculates sha1 hash of unique full path name information
* @ param int $contextid
* @ param string $filearea
* @ param int $itemid
* @ param string $filepath
* @ param string $filename
* @ return string
*/
public static function get_pathname_hash ( $contextid , $filearea , $itemid , $filepath , $filename ) {
return sha1 ( $contextid . $filearea . $itemid . $filepath . $filename );
}
/**
* Does this file exist ?
* @ param int $contextid
* @ param string $filearea
* @ param int $itemid
* @ param string $filepath
* @ param string $filename
* @ return bool
*/
public function file_exists ( $contextid , $filearea , $itemid , $filepath , $filename ) {
$filepath = clean_param ( $filepath , PARAM_PATH );
$filename = clean_param ( $filename , PARAM_FILE );
if ( $filename === '' ) {
$filename = '.' ;
}
$pathnamehash = $this -> get_pathname_hash ( $contextid , $filearea , $itemid , $filepath , $filename );
return $this -> file_exists_by_hash ( $pathnamehash );
}
/**
* Does this file exist ?
* @ param string $pathnamehash
* @ return bool
*/
public function file_exists_by_hash ( $pathnamehash ) {
global $DB ;
return $DB -> record_exists ( 'files' , array ( 'pathnamehash' => $pathnamehash ));
}
/**
* Fetch file using local file id
* @ param int $fileid
* @ return mixed stored_file instance if exists , false if not
*/
public function get_file_by_id ( $fileid ) {
global $DB ;
if ( $file_record = $DB -> get_record ( 'files' , array ( 'id' => $fileid ))) {
return new stored_file ( $this , $file_record );
} else {
return false ;
}
}
/**
* Fetch file using local file full pathname hash
* @ param string $pathnamehash
* @ return mixed stored_file instance if exists , false if not
*/
public function get_file_by_hash ( $pathnamehash ) {
global $DB ;
if ( $file_record = $DB -> get_record ( 'files' , array ( 'pathnamehash' => $pathnamehash ))) {
return new stored_file ( $this , $file_record );
} else {
return false ;
}
}
/**
* Fetch file
* @ param int $contextid
* @ param string $filearea
* @ param int $itemid
* @ param string $filepath
* @ param string $filename
* @ return mixed stored_file instance if exists , false if not
*/
public function get_file ( $contextid , $filearea , $itemid , $filepath , $filename ) {
global $DB ;
$filepath = clean_param ( $filepath , PARAM_PATH );
$filename = clean_param ( $filename , PARAM_FILE );
if ( $filename === '' ) {
$filename = '.' ;
}
$pathnamehash = $this -> get_pathname_hash ( $contextid , $filearea , $itemid , $filepath , $filename );
return $this -> get_file_by_hash ( $pathnamehash );
}
/**
* Returns all area files ( optionally limited by itemid )
* @ param int $contextid
* @ param string $filearea
* @ param int $itemid ( all files if not specified )
* @ param string $sort
* @ param bool $includedirs
* @ return array of stored_files
*/
2008-08-29 05:32:10 +00:00
public function get_area_files ( $contextid , $filearea , $itemid = false , $sort = " itemid, filepath, filename " , $includedirs = true ) {
2008-07-31 22:15:30 +00:00
global $DB ;
$conditions = array ( 'contextid' => $contextid , 'filearea' => $filearea );
if ( $itemid !== false ) {
$conditions [ 'itemid' ] = $itemid ;
}
$result = array ();
$file_records = $DB -> get_records ( 'files' , $conditions , $sort );
foreach ( $file_records as $file_record ) {
2008-08-29 05:32:10 +00:00
if ( ! $includedirs and $file_record -> filename === '.' ) {
2008-07-31 22:15:30 +00:00
continue ;
}
$result [] = new stored_file ( $this , $file_record );
}
return $result ;
}
2008-08-03 17:05:09 +00:00
/**
* Returns all files and otionally directories
* @ param int $contextid
* @ param string $filearea
* @ param int $itemid
* @ param int $filepath directory path
* @ param bool $recursive include all subdirectories
2008-08-29 05:32:10 +00:00
* @ param bool $includedirs include files and directories
2008-08-03 17:05:09 +00:00
* @ param string $sort
* @ return array of stored_files
*/
2008-08-29 05:32:10 +00:00
public function get_directory_files ( $contextid , $filearea , $itemid , $filepath , $recursive = false , $includedirs = true , $sort = " filepath, filename " ) {
2008-08-03 17:05:09 +00:00
global $DB ;
if ( ! $directory = $this -> get_file ( $contextid , $filearea , $itemid , $filepath , '.' )) {
return array ();
}
if ( $recursive ) {
2008-08-29 05:32:10 +00:00
$dirs = $includedirs ? " " : " AND filename <> '.' " ;
2008-08-03 17:05:09 +00:00
$length = textlib_get_instance () -> strlen ( $filepath );
$sql = " SELECT *
FROM { files }
WHERE contextid = : contextid AND filearea = : filearea AND itemid = : itemid
AND " . $DB->sql_substr (). " ( filepath , 1 , $length ) = : filepath
AND id <> : dirid
$dirs
ORDER BY $sort " ;
$params = array ( 'contextid' => $contextid , 'filearea' => $filearea , 'itemid' => $itemid , 'filepath' => $filepath , 'dirid' => $directory -> get_id ());
$files = array ();
$dirs = array ();
$file_records = $DB -> get_records_sql ( $sql , $params );
foreach ( $file_records as $file_record ) {
if ( $file_record -> filename == '.' ) {
$dirs [] = new stored_file ( $this , $file_record );
} else {
$files [] = new stored_file ( $this , $file_record );
}
}
$result = array_merge ( $dirs , $files );
} else {
$result = array ();
$params = array ( 'contextid' => $contextid , 'filearea' => $filearea , 'itemid' => $itemid , 'filepath' => $filepath , 'dirid' => $directory -> get_id ());
$length = textlib_get_instance () -> strlen ( $filepath );
2008-08-29 05:32:10 +00:00
if ( $includedirs ) {
2008-08-03 17:05:09 +00:00
$sql = " SELECT *
FROM { files }
WHERE contextid = : contextid AND filearea = : filearea
AND itemid = : itemid AND filename = '.'
AND " . $DB->sql_substr (). " ( filepath , 1 , $length ) = : filepath
AND id <> : dirid
ORDER BY $sort " ;
$reqlevel = substr_count ( $filepath , '/' ) + 1 ;
$file_records = $DB -> get_records_sql ( $sql , $params );
foreach ( $file_records as $file_record ) {
if ( substr_count ( $file_record -> filepath , '/' ) !== $reqlevel ) {
continue ;
}
$result [] = new stored_file ( $this , $file_record );
}
}
$sql = " SELECT *
FROM { files }
WHERE contextid = : contextid AND filearea = : filearea AND itemid = : itemid
AND filepath = : filepath AND filename <> '.'
ORDER BY $sort " ;
$file_records = $DB -> get_records_sql ( $sql , $params );
foreach ( $file_records as $file_record ) {
$result [] = new stored_file ( $this , $file_record );
}
}
return $result ;
}
2008-07-31 22:15:30 +00:00
/**
* Delete all area files ( optionally limited by itemid )
* @ param int $contextid
2008-08-27 08:23:07 +00:00
* @ param string $filearea ( all areas in context if not specified )
2008-07-31 22:15:30 +00:00
* @ param int $itemid ( all files if not specified )
* @ return success
*/
2008-08-27 08:23:07 +00:00
public function delete_area_files ( $contextid , $filearea = false , $itemid = false ) {
2008-07-31 22:15:30 +00:00
global $DB ;
2008-08-27 08:23:07 +00:00
$conditions = array ( 'contextid' => $contextid );
if ( $filearea !== false ) {
$conditions [ 'filearea' ] = $filearea ;
}
2008-07-31 22:15:30 +00:00
if ( $itemid !== false ) {
$conditions [ 'itemid' ] = $itemid ;
}
$success = true ;
$file_records = $DB -> get_records ( 'files' , $conditions );
foreach ( $file_records as $file_record ) {
$stored_file = new stored_file ( $this , $file_record );
$success = $stored_file -> delete () && $success ;
}
return $success ;
}
/**
* Recursively creates director
* @ param int $contextid
* @ param string $filearea
* @ param int $itemid
* @ param string $filepath
* @ param string $filename
* @ return bool success
*/
public function create_directory ( $contextid , $filearea , $itemid , $filepath , $userid = null ) {
global $DB ;
// validate all parameters, we do not want any rubbish stored in database, right?
if ( ! is_number ( $contextid ) or $contextid < 1 ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid contextid' );
2008-07-31 22:15:30 +00:00
}
2008-08-02 12:45:02 +00:00
$filearea = clean_param ( $filearea , PARAM_ALPHAEXT );
2008-07-31 22:15:30 +00:00
if ( $filearea === '' ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid filearea' );
2008-07-31 22:15:30 +00:00
}
if ( ! is_number ( $itemid ) or $itemid < 0 ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid itemid' );
2008-07-31 22:15:30 +00:00
}
$filepath = clean_param ( $filepath , PARAM_PATH );
if ( strpos ( $filepath , '/' ) !== 0 or strrpos ( $filepath , '/' ) !== strlen ( $filepath ) - 1 ) {
// path must start and end with '/'
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file path' );
2008-07-31 22:15:30 +00:00
}
$pathnamehash = $this -> get_pathname_hash ( $contextid , $filearea , $itemid , $filepath , '.' );
if ( $dir_info = $this -> get_file_by_hash ( $pathnamehash )) {
return $dir_info ;
}
static $contenthash = null ;
if ( ! $contenthash ) {
2008-08-06 20:51:14 +00:00
$this -> add_string_to_pool ( '' );
2008-07-31 22:15:30 +00:00
$contenthash = sha1 ( '' );
}
$now = time ();
$dir_record = new object ();
$dir_record -> contextid = $contextid ;
$dir_record -> filearea = $filearea ;
$dir_record -> itemid = $itemid ;
$dir_record -> filepath = $filepath ;
$dir_record -> filename = '.' ;
$dir_record -> contenthash = $contenthash ;
$dir_record -> filesize = 0 ;
$dir_record -> timecreated = $now ;
$dir_record -> timemodified = $now ;
$dir_record -> mimetype = null ;
$dir_record -> userid = $userid ;
$dir_record -> pathnamehash = $pathnamehash ;
$DB -> insert_record ( 'files' , $dir_record );
$dir_info = $this -> get_file_by_hash ( $pathnamehash );
if ( $filepath !== '/' ) {
//recurse to parent dirs
$filepath = trim ( $filepath , '/' );
$filepath = explode ( '/' , $filepath );
array_pop ( $filepath );
$filepath = implode ( '/' , $filepath );
$filepath = ( $filepath === '' ) ? '/' : " / $filepath / " ;
$this -> create_directory ( $contextid , $filearea , $itemid , $filepath , $userid );
}
return $dir_info ;
}
/**
* Add new local file based on existing local file
* @ param mixed $file_record object or array describing changes
* @ param int $fid id of existing local file
* @ return object stored_file instance
*/
2008-08-08 09:34:12 +00:00
public function create_file_from_storedfile ( $file_record , $fid ) {
2008-07-31 22:15:30 +00:00
global $DB ;
2008-08-16 21:21:23 +00:00
if ( $fid instanceof stored_file ) {
$fid = $fid -> get_id ();
}
2008-07-31 22:15:30 +00:00
$file_record = ( array ) $file_record ; // we support arrays too
unset ( $file_record [ 'id' ]);
unset ( $file_record [ 'filesize' ]);
unset ( $file_record [ 'contenthash' ]);
2008-08-16 21:21:23 +00:00
unset ( $file_record [ 'pathnamehash' ]);
2008-07-31 22:15:30 +00:00
$now = time ();
2008-08-09 13:33:20 +00:00
if ( ! $newrecord = $DB -> get_record ( 'files' , array ( 'id' => $fid ))) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'File does not exist' );
2008-07-31 22:15:30 +00:00
}
unset ( $newrecord -> id );
foreach ( $file_record as $key => $value ) {
// validate all parameters, we do not want any rubbish stored in database, right?
if ( $key == 'contextid' and ( ! is_number ( $value ) or $value < 1 )) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid contextid' );
2008-07-31 22:15:30 +00:00
}
if ( $key == 'filearea' ) {
2008-08-02 12:45:02 +00:00
$value = clean_param ( $value , PARAM_ALPHAEXT );
2008-07-31 22:15:30 +00:00
if ( $value === '' ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid filearea' );
2008-07-31 22:15:30 +00:00
}
}
if ( $key == 'itemid' and ( ! is_number ( $value ) or $value < 0 )) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid itemid' );
2008-07-31 22:15:30 +00:00
}
if ( $key == 'filepath' ) {
$value = clean_param ( $value , PARAM_PATH );
2008-09-05 09:23:36 +00:00
if ( strpos ( $value , '/' ) !== 0 or strrpos ( $value , '/' ) !== strlen ( $value ) - 1 ) {
2008-07-31 22:15:30 +00:00
// path must start and end with '/'
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file path' );
2008-07-31 22:15:30 +00:00
}
}
if ( $key == 'filename' ) {
$value = clean_param ( $value , PARAM_FILE );
if ( $value === '' ) {
// path must start and end with '/'
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file name' );
2008-07-31 22:15:30 +00:00
}
}
$newrecord -> $key = $value ;
}
$newrecord -> pathnamehash = $this -> get_pathname_hash ( $newrecord -> contextid , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> filename );
try {
$newrecord -> id = $DB -> insert_record ( 'files' , $newrecord );
} catch ( database_exception $e ) {
$newrecord -> id = false ;
}
if ( ! $newrecord -> id ) {
throw new stored_file_creation_exception ( $newrecord -> contextid , $newrecord -> filearea , $newrecord -> itemid ,
$newrecord -> filepath , $newrecord -> filename );
}
$this -> create_directory ( $newrecord -> contextid , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> userid );
return new stored_file ( $this , $newrecord );
}
2008-09-06 10:09:33 +00:00
/**
* Add new local file
* @ param mixed $file_record object or array describing file
* @ param string $path path to file or content of file
* @ param array $options @ see download_file_content () options
* @ return object stored_file instance
*/
public function create_file_from_url ( $file_record , $url , $options = null ) {
$file_record = ( object ) $file_record ; // we support arrays too
$headers = isset ( $options [ 'headers' ]) ? $options [ 'headers' ] : null ;
$postdata = isset ( $options [ 'postdata' ]) ? $options [ 'postdata' ] : null ;
$fullresponse = isset ( $options [ 'fullresponse' ]) ? $options [ 'fullresponse' ] : false ;
$timeout = isset ( $options [ 'timeout' ]) ? $options [ 'timeout' ] : 300 ;
$connecttimeout = isset ( $options [ 'connecttimeout' ]) ? $options [ 'connecttimeout' ] : 20 ;
$skipcertverify = isset ( $options [ 'skipcertverify' ]) ? $options [ 'skipcertverify' ] : false ;
// TODO: it might be better to add a new option to file file content to temp file,
// the problem here is that the size of file is limited by available memory
$content = download_file_content ( $url , $headers , $postdata , $fullresponse , $timeout , $connecttimeout , $skipcertverify );
if ( ! isset ( $file_record -> filename )) {
$parts = explode ( '/' , $url );
$filename = array_pop ( $parts );
$file_record -> filename = clean_param ( $filename , PARAM_FILE );
}
return $this -> create_file_from_string ( $file_record , $content );
}
2008-07-31 22:15:30 +00:00
/**
* Add new local file
* @ param mixed $file_record object or array describing file
* @ param string $path path to file or content of file
* @ return object stored_file instance
*/
public function create_file_from_pathname ( $file_record , $pathname ) {
global $DB ;
$file_record = ( object ) $file_record ; // we support arrays too
// validate all parameters, we do not want any rubbish stored in database, right?
if ( ! is_number ( $file_record -> contextid ) or $file_record -> contextid < 1 ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid contextid' );
2008-07-31 22:15:30 +00:00
}
2008-08-02 12:45:02 +00:00
$file_record -> filearea = clean_param ( $file_record -> filearea , PARAM_ALPHAEXT );
2008-07-31 22:15:30 +00:00
if ( $file_record -> filearea === '' ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid filearea' );
2008-07-31 22:15:30 +00:00
}
if ( ! is_number ( $file_record -> itemid ) or $file_record -> itemid < 0 ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid itemid' );
2008-07-31 22:15:30 +00:00
}
$file_record -> filepath = clean_param ( $file_record -> filepath , PARAM_PATH );
if ( strpos ( $file_record -> filepath , '/' ) !== 0 or strrpos ( $file_record -> filepath , '/' ) !== strlen ( $file_record -> filepath ) - 1 ) {
// path must start and end with '/'
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file path' );
2008-07-31 22:15:30 +00:00
}
$file_record -> filename = clean_param ( $file_record -> filename , PARAM_FILE );
if ( $file_record -> filename === '' ) {
2008-09-05 02:57:19 +00:00
// filename must not be empty
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file name' );
2008-07-31 22:15:30 +00:00
}
$now = time ();
$newrecord = new object ();
$newrecord -> contextid = $file_record -> contextid ;
$newrecord -> filearea = $file_record -> filearea ;
$newrecord -> itemid = $file_record -> itemid ;
$newrecord -> filepath = $file_record -> filepath ;
$newrecord -> filename = $file_record -> filename ;
$newrecord -> timecreated = empty ( $file_record -> timecreated ) ? $now : $file_record -> timecreated ;
$newrecord -> timemodified = empty ( $file_record -> timemodified ) ? $now : $file_record -> timemodified ;
$newrecord -> mimetype = empty ( $file_record -> mimetype ) ? mimeinfo ( 'type' , $file_record -> filename ) : $file_record -> mimetype ;
$newrecord -> userid = empty ( $file_record -> userid ) ? null : $file_record -> userid ;
2008-08-06 20:51:14 +00:00
list ( $newrecord -> contenthash , $newrecord -> filesize , $newfile ) = $this -> add_file_to_pool ( $pathname );
2008-07-31 22:15:30 +00:00
$newrecord -> pathnamehash = $this -> get_pathname_hash ( $newrecord -> contextid , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> filename );
try {
$newrecord -> id = $DB -> insert_record ( 'files' , $newrecord );
} catch ( database_exception $e ) {
$newrecord -> id = false ;
}
if ( ! $newrecord -> id ) {
if ( $newfile ) {
$this -> mark_delete_candidate ( $newrecord -> contenthash );
}
throw new stored_file_creation_exception ( $newrecord -> contextid , $newrecord -> filearea , $newrecord -> itemid ,
$newrecord -> filepath , $newrecord -> filename );
}
$this -> create_directory ( $newrecord -> contextid , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> userid );
return new stored_file ( $this , $newrecord );
}
/**
* Add new local file
* @ param mixed $file_record object or array describing file
* @ param string $content content of file
* @ return object stored_file instance
*/
public function create_file_from_string ( $file_record , $content ) {
global $DB ;
$file_record = ( object ) $file_record ; // we support arrays too
// validate all parameters, we do not want any rubbish stored in database, right?
if ( ! is_number ( $file_record -> contextid ) or $file_record -> contextid < 1 ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid contextid' );
2008-07-31 22:15:30 +00:00
}
2008-08-02 12:45:02 +00:00
$file_record -> filearea = clean_param ( $file_record -> filearea , PARAM_ALPHAEXT );
2008-07-31 22:15:30 +00:00
if ( $file_record -> filearea === '' ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid filearea' );
2008-07-31 22:15:30 +00:00
}
if ( ! is_number ( $file_record -> itemid ) or $file_record -> itemid < 0 ) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid itemid' );
2008-07-31 22:15:30 +00:00
}
$file_record -> filepath = clean_param ( $file_record -> filepath , PARAM_PATH );
if ( strpos ( $file_record -> filepath , '/' ) !== 0 or strrpos ( $file_record -> filepath , '/' ) !== strlen ( $file_record -> filepath ) - 1 ) {
// path must start and end with '/'
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file path' );
2008-07-31 22:15:30 +00:00
}
$file_record -> filename = clean_param ( $file_record -> filename , PARAM_FILE );
if ( $file_record -> filename === '' ) {
// path must start and end with '/'
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file name' );
2008-07-31 22:15:30 +00:00
}
$now = time ();
$newrecord = new object ();
$newrecord -> contextid = $file_record -> contextid ;
$newrecord -> filearea = $file_record -> filearea ;
$newrecord -> itemid = $file_record -> itemid ;
$newrecord -> filepath = $file_record -> filepath ;
$newrecord -> filename = $file_record -> filename ;
$newrecord -> timecreated = empty ( $file_record -> timecreated ) ? $now : $file_record -> timecreated ;
$newrecord -> timemodified = empty ( $file_record -> timemodified ) ? $now : $file_record -> timemodified ;
$newrecord -> mimetype = empty ( $file_record -> mimetype ) ? mimeinfo ( 'type' , $file_record -> filename ) : $file_record -> mimetype ;
$newrecord -> userid = empty ( $file_record -> userid ) ? null : $file_record -> userid ;
2008-08-06 20:51:14 +00:00
list ( $newrecord -> contenthash , $newrecord -> filesize , $newfile ) = $this -> add_string_to_pool ( $content );
2008-07-31 22:15:30 +00:00
$newrecord -> pathnamehash = $this -> get_pathname_hash ( $newrecord -> contextid , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> filename );
try {
$newrecord -> id = $DB -> insert_record ( 'files' , $newrecord );
} catch ( database_exception $e ) {
$newrecord -> id = false ;
}
if ( ! $newrecord -> id ) {
if ( $newfile ) {
$this -> mark_delete_candidate ( $newrecord -> contenthash );
}
throw new stored_file_creation_exception ( $newrecord -> contextid , $newrecord -> filearea , $newrecord -> itemid ,
$newrecord -> filepath , $newrecord -> filename );
}
$this -> create_directory ( $newrecord -> contextid , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> userid );
return new stored_file ( $this , $newrecord );
}
2008-09-03 05:14:24 +00:00
/**
2008-09-06 10:09:33 +00:00
* Move one or more files from a given itemid location in the current user ' s draft files
2008-09-03 05:14:24 +00:00
* to a new filearea . Note that you can ' t rename files using this function .
* @ param int $itemid - existing itemid in user draft_area with one or more files
* @ param int $newcontextid - the new contextid to move files to
* @ param string $newfilearea - the new filearea to move files to
2008-09-04 05:42:17 +00:00
* @ param int $newitemid - the new itemid to use ( this is ignored and automatically set to 0 when moving to a user ' s user_private area )
2008-09-03 05:14:24 +00:00
* @ param string $newfilepath - the new path to move all files to
* @ param bool $overwrite - overwrite files from the destination if they exist
* @ param int $newuserid - new userid if required
* @ return mixed stored_file object or false if error ; may throw exception if duplicate found
* @ return array ( contenthash , filesize , newfile )
*/
2008-09-06 10:09:33 +00:00
public function move_draft_to_final ( $itemid , $newcontextid , $newfilearea , $newitemid ,
2008-09-03 05:14:24 +00:00
$newfilepath = '/' , $overwrite = false ) {
global $USER ;
2008-09-06 10:09:33 +00:00
/// Get files from the draft area
2008-09-03 05:14:24 +00:00
if ( ! $usercontext = get_context_instance ( CONTEXT_USER , $USER -> id )) {
return false ;
}
if ( ! $files = $this -> get_area_files ( $usercontext -> id , 'user_draft' , $itemid , 'filename' , false )) {
return false ;
}
2008-09-04 05:42:17 +00:00
$newcontext = get_context_instance_by_id ( $newcontextid );
2008-09-05 10:47:34 +00:00
if (( $newcontext -> contextlevel == CONTEXT_USER ) && ( $newfilearea != 'user_draft' )) {
2008-09-04 05:42:17 +00:00
$newitemid = 0 ;
}
2008-09-06 10:09:33 +00:00
/// Process each file in turn
2008-09-03 05:14:24 +00:00
$returnfiles = array ();
foreach ( $files as $file ) {
/// Delete any existing files in destination if required
2008-09-06 10:09:33 +00:00
if ( $oldfile = $this -> get_file ( $newcontextid , $newfilearea , $newitemid ,
2008-09-03 05:14:24 +00:00
$newfilepath , $file -> get_filename ())) {
if ( $overwrite ) {
$oldfile -> delete ();
} else {
2008-09-05 09:23:36 +00:00
$returnfiles [] = $oldfile ;
2008-09-03 05:14:24 +00:00
continue ; // Can't overwrite the existing file so skip it
}
}
/// Create the new file
$newrecord = new object ();
$newrecord -> contextid = $newcontextid ;
$newrecord -> filearea = $newfilearea ;
$newrecord -> itemid = $newitemid ;
$newrecord -> filepath = $newfilepath ;
$newrecord -> filename = $file -> get_filename ();
$newrecord -> timecreated = $file -> get_timecreated ();
$newrecord -> timemodified = $file -> get_timemodified ();
$newrecord -> mimetype = $file -> get_mimetype ();
$newrecord -> userid = $file -> get_userid ();
if ( $newfile = $this -> create_file_from_storedfile ( $newrecord , $file -> get_id ())) {
$file -> delete ();
$returnfiles [] = $newfile ;
}
}
return $returnfiles ;
}
2008-07-31 22:15:30 +00:00
/**
* Add file content to sha1 pool
* @ param string $pathname path to file
* @ param string sha1 hash of content if known ( performance only )
* @ return array ( contenthash , filesize , newfile )
*/
2008-08-06 20:51:14 +00:00
public function add_file_to_pool ( $pathname , $contenthash = null ) {
2008-07-31 22:15:30 +00:00
if ( ! is_readable ( $pathname )) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfilecannotread' );
2008-07-31 22:15:30 +00:00
}
if ( is_null ( $contenthash )) {
$contenthash = sha1_file ( $pathname );
}
$filesize = filesize ( $pathname );
$hashpath = $this -> path_from_hash ( $contenthash );
$hashfile = " $hashpath / $contenthash " ;
if ( file_exists ( $hashfile )) {
if ( filesize ( $hashfile ) !== $filesize ) {
throw new file_pool_content_exception ( $contenthash );
}
$newfile = false ;
} else {
if ( ! check_dir_exists ( $hashpath , true , true )) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfilecannotcreatefiledirs' ); // permission trouble
2008-07-31 22:15:30 +00:00
}
$newfile = true ;
2008-08-02 12:45:02 +00:00
if ( ! copy ( $pathname , $hashfile )) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfilecannotread' );
2008-07-31 22:15:30 +00:00
}
if ( filesize ( $hashfile ) !== $filesize ) {
@ unlink ( $hashfile );
throw new file_pool_content_exception ( $contenthash );
}
}
return array ( $contenthash , $filesize , $newfile );
}
/**
* Add string content to sha1 pool
* @ param string $content file content - binary string
* @ return array ( contenthash , filesize , newfile )
*/
2008-08-06 20:51:14 +00:00
public function add_string_to_pool ( $content ) {
2008-07-31 22:15:30 +00:00
$contenthash = sha1 ( $content );
$filesize = strlen ( $content ); // binary length
$hashpath = $this -> path_from_hash ( $contenthash );
$hashfile = " $hashpath / $contenthash " ;
if ( file_exists ( $hashfile )) {
if ( filesize ( $hashfile ) !== $filesize ) {
throw new file_pool_content_exception ( $contenthash );
}
$newfile = false ;
} else {
if ( ! check_dir_exists ( $hashpath , true , true )) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfilecannotcreatefiledirs' ); // permission trouble
2008-07-31 22:15:30 +00:00
}
$newfile = true ;
2008-08-02 12:45:02 +00:00
file_put_contents ( $hashfile , $content );
2008-07-31 22:15:30 +00:00
if ( filesize ( $hashfile ) !== $filesize ) {
@ unlink ( $hashfile );
throw new file_pool_content_exception ( $contenthash );
}
}
return array ( $contenthash , $filesize , $newfile );
}
/**
* Return path to file with given hash
*
2008-08-02 18:33:11 +00:00
* NOTE : must not be public , files in pool must not be modified
2008-07-31 22:15:30 +00:00
*
* @ param string $contenthash
* @ return string expected file location
*/
2008-08-02 18:33:11 +00:00
protected function path_from_hash ( $contenthash ) {
2008-07-31 22:15:30 +00:00
$l1 = $contenthash [ 0 ] . $contenthash [ 1 ];
$l2 = $contenthash [ 2 ] . $contenthash [ 3 ];
$l3 = $contenthash [ 4 ] . $contenthash [ 5 ];
return " $this->filedir / $l1 / $l2 / $l3 " ;
}
/**
* Marks pool file as candidate for deleting
* @ param string $contenthash
*/
public function mark_delete_candidate ( $contenthash ) {
global $DB ;
if ( $DB -> record_exists ( 'files_cleanup' , array ( 'contenthash' => $contenthash ))) {
return ;
}
$rec = new object ();
$rec -> contenthash = $contenthash ;
$DB -> insert_record ( 'files_cleanup' , $rec );
}
/**
* Cron cleanup job .
*/
public function cron () {
global $DB ;
//TODO: there is a small chance that reused files might be deleted
// if this function takes too long we should add some table locking here
$sql = " SELECT 1 AS id, fc.contenthash
FROM { files_cleanup } fc
LEFT JOIN { files } f ON f . contenthash = fc . contenthash
WHERE f . id IS NULL " ;
while ( $hash = $DB -> get_record_sql ( $sql , null , true )) {
$file = $this -> path_from_hash ( $hash -> contenthash ) . '/' . $hash -> contenthash ;
@ unlink ( $file );
$DB -> delete_records ( 'files_cleanup' , array ( 'contenthash' => $hash -> contenthash ));
}
}
}