2009-05-20 21:16:38 +00:00
< ? php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Core file storage class definition .
*
2012-02-15 12:48:57 +08:00
* @ package core_files
* @ copyright 2008 Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2009-05-20 21:16:38 +00:00
*/
2008-07-31 22:15:30 +00:00
2010-07-03 13:37:13 +00:00
defined ( 'MOODLE_INTERNAL' ) || die ();
require_once ( " $CFG->libdir /filestorage/stored_file.php " );
2008-07-31 22:15:30 +00:00
2009-05-20 21:16:38 +00:00
/**
* File storage class used for low level access to stored files .
2010-05-03 21:04:06 +00:00
*
2009-05-20 21:16:38 +00:00
* Only owner of file area may use this class to access own files ,
* for example only code in mod / assignment /* may access assignment
2010-05-03 21:04:06 +00:00
* attachments . When some other part of moodle needs to access
* files of modules it has to use file_browser class instead or there
* has to be some callback API .
*
2012-02-15 12:48:57 +08:00
* @ package core_files
* @ category files
2010-05-03 21:04:06 +00:00
* @ copyright 2008 Petr Skoda { @ link http :// skodak . org }
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
* @ since Moodle 2.0
2009-05-20 21:16:38 +00:00
*/
2008-07-31 22:15:30 +00:00
class file_storage {
2010-05-03 21:04:06 +00:00
/** @var string Directory with file contents */
2008-07-31 22:15:30 +00:00
private $filedir ;
2010-05-03 21:04:06 +00:00
/** @var string Contents of deleted files not needed any more */
2009-06-03 08:10:21 +00:00
private $trashdir ;
2010-05-20 17:13:07 +00:00
/** @var string tempdir */
private $tempdir ;
2010-05-03 21:04:06 +00:00
/** @var int Permissions for new directories */
2009-06-03 08:10:21 +00:00
private $dirpermissions ;
2010-05-03 21:04:06 +00:00
/** @var int Permissions for new files */
2009-06-03 08:10:21 +00:00
private $filepermissions ;
2010-05-03 21:04:06 +00:00
2008-07-31 22:15:30 +00:00
/**
2012-02-15 12:48:57 +08:00
* Constructor - do not use directly use { @ link get_file_storage ()} call instead .
2010-05-03 21:04:06 +00:00
*
2008-07-31 22:15:30 +00:00
* @ param string $filedir full path to pool directory
2010-05-03 21:04:06 +00:00
* @ param string $trashdir temporary storage of deleted area
2010-05-20 17:13:07 +00:00
* @ param string $tempdir temporary storage of various files
2010-05-03 21:04:06 +00:00
* @ param int $dirpermissions new directory permissions
* @ param int $filepermissions new file permissions
2008-07-31 22:15:30 +00:00
*/
2010-05-20 17:13:07 +00:00
public function __construct ( $filedir , $trashdir , $tempdir , $dirpermissions , $filepermissions ) {
2009-06-03 08:10:21 +00:00
$this -> filedir = $filedir ;
$this -> trashdir = $trashdir ;
2010-05-20 17:13:07 +00:00
$this -> tempdir = $tempdir ;
2009-06-03 08:10:21 +00:00
$this -> dirpermissions = $dirpermissions ;
$this -> filepermissions = $filepermissions ;
2008-07-31 22:15:30 +00:00
// make sure the file pool directory exists
if ( ! is_dir ( $this -> filedir )) {
2009-06-03 08:10:21 +00:00
if ( ! mkdir ( $this -> filedir , $this -> dirpermissions , 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
2009-06-03 08:10:21 +00:00
if ( ! file_exists ( $this -> filedir . '/warning.txt' )) {
file_put_contents ( $this -> filedir . '/warning.txt' ,
'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.' );
}
}
// make sure the file pool directory exists
if ( ! is_dir ( $this -> trashdir )) {
if ( ! mkdir ( $this -> trashdir , $this -> dirpermissions , true )) {
throw new file_exception ( 'storedfilecannotcreatefiledirs' ); // permission trouble
}
2008-07-31 22:15:30 +00:00
}
}
/**
2010-05-03 21:04:06 +00:00
* Calculates sha1 hash of unique full path name information .
*
* This hash is a unique file identifier - it is used to improve
* performance and overcome db index size limits .
*
2012-02-15 12:48:57 +08:00
* @ param int $contextid context ID
* @ param string $component component
* @ param string $filearea file area
* @ param int $itemid item ID
* @ param string $filepath file path
* @ param string $filename file name
2010-05-03 21:04:06 +00:00
* @ return string sha1 hash
2008-07-31 22:15:30 +00:00
*/
2010-07-03 13:37:13 +00:00
public static function get_pathname_hash ( $contextid , $component , $filearea , $itemid , $filepath , $filename ) {
return sha1 ( " / $contextid / $component / $filearea / $itemid " . $filepath . $filename );
2008-07-31 22:15:30 +00:00
}
/**
* Does this file exist ?
2010-05-03 21:04:06 +00:00
*
2012-02-15 12:48:57 +08:00
* @ param int $contextid context ID
* @ param string $component component
* @ param string $filearea file area
* @ param int $itemid item ID
* @ param string $filepath file path
* @ param string $filename file name
2008-07-31 22:15:30 +00:00
* @ return bool
*/
2010-07-03 13:37:13 +00:00
public function file_exists ( $contextid , $component , $filearea , $itemid , $filepath , $filename ) {
2008-07-31 22:15:30 +00:00
$filepath = clean_param ( $filepath , PARAM_PATH );
$filename = clean_param ( $filename , PARAM_FILE );
if ( $filename === '' ) {
$filename = '.' ;
}
2010-07-03 13:37:13 +00:00
$pathnamehash = $this -> get_pathname_hash ( $contextid , $component , $filearea , $itemid , $filepath , $filename );
2008-07-31 22:15:30 +00:00
return $this -> file_exists_by_hash ( $pathnamehash );
}
/**
2012-02-15 12:48:57 +08:00
* Whether or not the file exist
2010-05-03 21:04:06 +00:00
*
2012-02-15 12:48:57 +08:00
* @ param string $pathnamehash path name hash
2008-07-31 22:15:30 +00:00
* @ return bool
*/
public function file_exists_by_hash ( $pathnamehash ) {
global $DB ;
return $DB -> record_exists ( 'files' , array ( 'pathnamehash' => $pathnamehash ));
}
2010-09-19 15:50:18 +00:00
/**
* Create instance of file class from database record .
*
2012-05-15 11:10:04 +08:00
* @ param stdClass $filerecord record from the files table left join files_reference table
2010-09-19 15:50:18 +00:00
* @ return stored_file instance of file abstraction class
*/
2012-05-12 04:14:53 +08:00
public function get_file_instance ( stdClass $filerecord ) {
$storedfile = new stored_file ( $this , $filerecord , $this -> filedir );
return $storedfile ;
2010-09-19 15:50:18 +00:00
}
2012-04-18 00:41:01 +02:00
/**
* Returns an image file that represent the given stored file as a preview
*
* At the moment , only GIF , JPEG and PNG files are supported to have previews . In the
* future , the support for other mimetypes can be added , too ( eg . generate an image
* preview of PDF , text documents etc ) .
*
* @ param stored_file $file the file we want to preview
* @ param string $mode preview mode , eg . 'thumb'
* @ return stored_file | bool false if unable to create the preview , stored file otherwise
*/
public function get_file_preview ( stored_file $file , $mode ) {
$context = context_system :: instance ();
$path = '/' . trim ( $mode , '/' ) . '/' ;
$preview = $this -> get_file ( $context -> id , 'core' , 'preview' , 0 , $path , $file -> get_contenthash ());
if ( ! $preview ) {
$preview = $this -> create_file_preview ( $file , $mode );
if ( ! $preview ) {
return false ;
}
}
return $preview ;
}
/**
* Generates a preview image for the stored file
*
* @ param stored_file $file the file we want to preview
* @ param string $mode preview mode , eg . 'thumb'
* @ return stored_file | bool the newly created preview file or false
*/
protected function create_file_preview ( stored_file $file , $mode ) {
$mimetype = $file -> get_mimetype ();
2012-04-24 16:10:46 +02:00
if ( $mimetype === 'image/gif' or $mimetype === 'image/jpeg' or $mimetype === 'image/png' ) {
2012-04-18 00:41:01 +02:00
// make a preview of the image
$data = $this -> create_imagefile_preview ( $file , $mode );
} else {
// unable to create the preview of this mimetype yet
return false ;
}
if ( empty ( $data )) {
return false ;
}
// getimagesizefromstring() is available from PHP 5.4 but we need to support
// lower versions, so...
$tmproot = make_temp_directory ( 'thumbnails' );
2012-04-25 11:53:57 +02:00
$tmpfilepath = $tmproot . '/' . $file -> get_contenthash () . '_' . $mode ;
2012-04-18 00:41:01 +02:00
file_put_contents ( $tmpfilepath , $data );
$imageinfo = getimagesize ( $tmpfilepath );
unlink ( $tmpfilepath );
$context = context_system :: instance ();
$record = array (
'contextid' => $context -> id ,
'component' => 'core' ,
'filearea' => 'preview' ,
'itemid' => 0 ,
'filepath' => '/' . trim ( $mode , '/' ) . '/' ,
'filename' => $file -> get_contenthash (),
);
if ( $imageinfo ) {
$record [ 'mimetype' ] = $imageinfo [ 'mime' ];
}
return $this -> create_file_from_string ( $record , $data );
}
/**
* Generates a preview for the stored image file
*
* @ param stored_file $file the image we want to preview
* @ param string $mode preview mode , eg . 'thumb'
* @ return string | bool false if a problem occurs , the thumbnail image data otherwise
*/
protected function create_imagefile_preview ( stored_file $file , $mode ) {
global $CFG ;
require_once ( $CFG -> libdir . '/gdlib.php' );
$tmproot = make_temp_directory ( 'thumbnails' );
$tmpfilepath = $tmproot . '/' . $file -> get_contenthash ();
$file -> copy_content_to ( $tmpfilepath );
2012-04-24 16:10:46 +02:00
if ( $mode === 'tinyicon' ) {
2012-05-21 11:29:47 +02:00
$data = generate_image_thumbnail ( $tmpfilepath , 24 , 24 );
2012-04-18 00:41:01 +02:00
2012-04-24 16:10:46 +02:00
} else if ( $mode === 'thumb' ) {
2012-04-18 00:41:01 +02:00
$data = generate_image_thumbnail ( $tmpfilepath , 90 , 90 );
} else {
throw new file_exception ( 'storedfileproblem' , 'Invalid preview mode requested' );
}
unlink ( $tmpfilepath );
return $data ;
}
2008-07-31 22:15:30 +00:00
/**
2009-05-20 21:16:38 +00:00
* Fetch file using local file id .
2010-05-03 21:04:06 +00:00
*
2009-05-20 21:16:38 +00:00
* Please do not rely on file ids , it is usually easier to use
* pathname hashes instead .
2010-05-03 21:04:06 +00:00
*
2012-02-15 12:48:57 +08:00
* @ param int $fileid file ID
* @ return stored_file | bool stored_file instance if exists , false if not
2008-07-31 22:15:30 +00:00
*/
public function get_file_by_id ( $fileid ) {
global $DB ;
2012-05-24 01:35:13 -04:00
$sql = " SELECT " . self :: instance_sql_fields ( 'f' , 'r' ) . "
2012-05-12 04:14:53 +08:00
FROM { files } f
LEFT JOIN { files_reference } r
ON f . referencefileid = r . id
WHERE f . id = ? " ;
if ( $filerecord = $DB -> get_record_sql ( $sql , array ( $fileid ))) {
return $this -> get_file_instance ( $filerecord );
2008-07-31 22:15:30 +00:00
} else {
return false ;
}
}
/**
* Fetch file using local file full pathname hash
2010-05-03 21:04:06 +00:00
*
2012-02-15 12:48:57 +08:00
* @ param string $pathnamehash path name hash
* @ return stored_file | bool stored_file instance if exists , false if not
2008-07-31 22:15:30 +00:00
*/
public function get_file_by_hash ( $pathnamehash ) {
global $DB ;
2012-05-24 01:35:13 -04:00
$sql = " SELECT " . self :: instance_sql_fields ( 'f' , 'r' ) . "
2012-05-12 04:14:53 +08:00
FROM { files } f
LEFT JOIN { files_reference } r
ON f . referencefileid = r . id
WHERE f . pathnamehash = ? " ;
if ( $filerecord = $DB -> get_record_sql ( $sql , array ( $pathnamehash ))) {
return $this -> get_file_instance ( $filerecord );
2008-07-31 22:15:30 +00:00
} else {
return false ;
}
}
/**
2010-05-03 21:04:06 +00:00
* Fetch locally stored file .
*
2012-02-15 12:48:57 +08:00
* @ param int $contextid context ID
* @ param string $component component
* @ param string $filearea file area
* @ param int $itemid item ID
* @ param string $filepath file path
* @ param string $filename file name
* @ return stored_file | bool stored_file instance if exists , false if not
2008-07-31 22:15:30 +00:00
*/
2010-07-03 13:37:13 +00:00
public function get_file ( $contextid , $component , $filearea , $itemid , $filepath , $filename ) {
2008-07-31 22:15:30 +00:00
$filepath = clean_param ( $filepath , PARAM_PATH );
$filename = clean_param ( $filename , PARAM_FILE );
if ( $filename === '' ) {
$filename = '.' ;
}
2010-07-03 13:37:13 +00:00
$pathnamehash = $this -> get_pathname_hash ( $contextid , $component , $filearea , $itemid , $filepath , $filename );
2008-07-31 22:15:30 +00:00
return $this -> get_file_by_hash ( $pathnamehash );
}
2010-09-12 12:29:32 +00:00
/**
* Are there any files ( or directories )
2012-02-15 12:48:57 +08:00
*
* @ param int $contextid context ID
* @ param string $component component
* @ param string $filearea file area
* @ param bool | int $itemid item id or false if all items
* @ param bool $ignoredirs whether or not ignore directories
2010-09-12 12:29:32 +00:00
* @ return bool empty
*/
public function is_area_empty ( $contextid , $component , $filearea , $itemid = false , $ignoredirs = true ) {
global $DB ;
$params = array ( 'contextid' => $contextid , 'component' => $component , 'filearea' => $filearea );
$where = " contextid = :contextid AND component = :component AND filearea = :filearea " ;
if ( $itemid !== false ) {
$params [ 'itemid' ] = $itemid ;
$where .= " AND itemid = :itemid " ;
}
if ( $ignoredirs ) {
$sql = " SELECT 'x'
FROM { files }
WHERE $where AND filename <> '.' " ;
} else {
$sql = " SELECT 'x'
FROM { files }
WHERE $where AND ( filename <> '.' OR filepath <> '/' ) " ;
}
return ! $DB -> record_exists_sql ( $sql , $params );
}
2012-05-12 04:14:53 +08:00
/**
* Returns all files belonging to given repository
*
* @ param int $repositoryid
2012-05-29 16:38:47 +12:00
* @ param string $sort A fragment of SQL to use for sorting
2012-05-12 04:14:53 +08:00
*/
public function get_external_files ( $repositoryid , $sort = 'sortorder, itemid, filepath, filename' ) {
global $DB ;
2012-05-24 01:35:13 -04:00
$sql = " SELECT " . self :: instance_sql_fields ( 'f' , 'r' ) . "
2012-05-12 04:14:53 +08:00
FROM { files } f
LEFT JOIN { files_reference } r
ON f . referencefileid = r . id
2012-05-29 16:38:47 +12:00
WHERE r . repositoryid = ? " ;
if ( ! empty ( $sort )) {
$sql .= " ORDER BY { $sort } " ;
}
2012-05-12 04:14:53 +08:00
$result = array ();
$filerecords = $DB -> get_records_sql ( $sql , array ( $repositoryid ));
foreach ( $filerecords as $filerecord ) {
$result [ $filerecord -> pathnamehash ] = $this -> get_file_instance ( $filerecord );
}
return $result ;
}
2008-07-31 22:15:30 +00:00
/**
* Returns all area files ( optionally limited by itemid )
2010-05-03 21:04:06 +00:00
*
2012-02-15 12:48:57 +08:00
* @ param int $contextid context ID
* @ param string $component component
* @ param string $filearea file area
* @ param int $itemid item ID or all files if not specified
2012-05-29 16:38:47 +12:00
* @ param string $sort A fragment of SQL to use for sorting
2012-02-15 12:48:57 +08:00
* @ param bool $includedirs whether or not include directories
2008-09-21 10:35:39 +00:00
* @ return array of stored_files indexed by pathanmehash
2008-07-31 22:15:30 +00:00
*/
2012-09-17 15:22:45 +08:00
public function get_area_files ( $contextid , $component , $filearea , $itemid = false , $sort = " itemid, filepath, filename " , $includedirs = true ) {
2008-07-31 22:15:30 +00:00
global $DB ;
2010-07-03 13:37:13 +00:00
$conditions = array ( 'contextid' => $contextid , 'component' => $component , 'filearea' => $filearea );
2008-07-31 22:15:30 +00:00
if ( $itemid !== false ) {
2012-05-12 04:14:53 +08:00
$itemidsql = ' AND f.itemid = :itemid ' ;
2008-07-31 22:15:30 +00:00
$conditions [ 'itemid' ] = $itemid ;
2012-05-12 04:14:53 +08:00
} else {
$itemidsql = '' ;
2008-07-31 22:15:30 +00:00
}
2012-05-24 01:35:13 -04:00
$sql = " SELECT " . self :: instance_sql_fields ( 'f' , 'r' ) . "
2012-05-12 04:14:53 +08:00
FROM { files } f
LEFT JOIN { files_reference } r
ON f . referencefileid = r . id
WHERE f . contextid = : contextid
AND f . component = : component
AND f . filearea = : filearea
2012-05-29 16:38:47 +12:00
$itemidsql " ;
if ( ! empty ( $sort )) {
$sql .= " ORDER BY { $sort } " ;
}
2012-05-12 04:14:53 +08:00
2008-07-31 22:15:30 +00:00
$result = array ();
2012-05-12 04:14:53 +08:00
$filerecords = $DB -> get_records_sql ( $sql , $conditions );
foreach ( $filerecords as $filerecord ) {
if ( ! $includedirs and $filerecord -> filename === '.' ) {
2008-07-31 22:15:30 +00:00
continue ;
}
2012-05-12 04:14:53 +08:00
$result [ $filerecord -> pathnamehash ] = $this -> get_file_instance ( $filerecord );
2008-07-31 22:15:30 +00:00
}
return $result ;
}
2009-06-21 18:22:52 +00:00
/**
* Returns array based tree structure of area files
2010-05-03 21:04:06 +00:00
*
2012-02-15 12:48:57 +08:00
* @ param int $contextid context ID
* @ param string $component component
* @ param string $filearea file area
* @ param int $itemid item ID
2009-06-21 18:22:52 +00:00
* @ return array each dir represented by dirname , subdirs , files and dirfile array elements
*/
2010-07-03 13:37:13 +00:00
public function get_area_tree ( $contextid , $component , $filearea , $itemid ) {
2009-06-21 18:22:52 +00:00
$result = array ( 'dirname' => '' , 'dirfile' => null , 'subdirs' => array (), 'files' => array ());
2012-09-17 15:22:45 +08:00
$files = $this -> get_area_files ( $contextid , $component , $filearea , $itemid , '' , true );
2009-06-21 18:22:52 +00:00
// first create directory structure
foreach ( $files as $hash => $dir ) {
if ( ! $dir -> is_directory ()) {
continue ;
}
unset ( $files [ $hash ]);
if ( $dir -> get_filepath () === '/' ) {
$result [ 'dirfile' ] = $dir ;
continue ;
}
$parts = explode ( '/' , trim ( $dir -> get_filepath (), '/' ));
$pointer =& $result ;
foreach ( $parts as $part ) {
2009-07-04 18:47:56 +00:00
if ( $part === '' ) {
continue ;
}
2009-06-21 18:22:52 +00:00
if ( ! isset ( $pointer [ 'subdirs' ][ $part ])) {
$pointer [ 'subdirs' ][ $part ] = array ( 'dirname' => $part , 'dirfile' => null , 'subdirs' => array (), 'files' => array ());
}
$pointer =& $pointer [ 'subdirs' ][ $part ];
}
$pointer [ 'dirfile' ] = $dir ;
unset ( $pointer );
}
foreach ( $files as $hash => $file ) {
$parts = explode ( '/' , trim ( $file -> get_filepath (), '/' ));
$pointer =& $result ;
foreach ( $parts as $part ) {
2009-07-04 18:47:56 +00:00
if ( $part === '' ) {
continue ;
}
2009-06-21 18:22:52 +00:00
$pointer =& $pointer [ 'subdirs' ][ $part ];
}
$pointer [ 'files' ][ $file -> get_filename ()] = $file ;
unset ( $pointer );
}
2012-09-17 15:22:45 +08:00
$result = $this -> sort_area_tree ( $result );
2009-06-21 18:22:52 +00:00
return $result ;
}
2012-09-17 15:22:45 +08:00
/**
* Sorts the result of { @ link file_storage :: get_area_tree ()} .
*
2012-09-25 09:51:28 +12:00
* @ param array $tree Array of results provided by { @ link file_storage :: get_area_tree ()}
2012-09-17 15:22:45 +08:00
* @ return array of sorted results
*/
protected function sort_area_tree ( $tree ) {
foreach ( $tree as $key => & $value ) {
if ( $key == 'subdirs' ) {
$value = $this -> sort_area_tree ( $value );
collatorlib :: ksort ( $value , collatorlib :: SORT_NATURAL );
} else if ( $key == 'files' ) {
collatorlib :: ksort ( $value , collatorlib :: SORT_NATURAL );
}
}
return $tree ;
}
2008-08-03 17:05:09 +00:00
/**
2010-05-03 21:04:06 +00:00
* Returns all files and optionally directories
*
2012-02-15 12:48:57 +08:00
* @ param int $contextid context ID
* @ param string $component component
* @ param string $filearea file area
* @ param int $itemid item ID
2008-08-03 17:05:09 +00:00
* @ 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
2012-05-29 16:38:47 +12:00
* @ param string $sort A fragment of SQL to use for sorting
2008-09-21 10:35:39 +00:00
* @ return array of stored_files indexed by pathanmehash
2008-08-03 17:05:09 +00:00
*/
2010-07-03 13:37:13 +00:00
public function get_directory_files ( $contextid , $component , $filearea , $itemid , $filepath , $recursive = false , $includedirs = true , $sort = " filepath, filename " ) {
2008-08-03 17:05:09 +00:00
global $DB ;
2010-07-03 13:37:13 +00:00
if ( ! $directory = $this -> get_file ( $contextid , $component , $filearea , $itemid , $filepath , '.' )) {
2008-08-03 17:05:09 +00:00
return array ();
}
2012-05-29 16:38:47 +12:00
$orderby = ( ! empty ( $sort )) ? " ORDER BY { $sort } " : '' ;
2008-08-03 17:05:09 +00:00
if ( $recursive ) {
2008-08-29 05:32:10 +00:00
$dirs = $includedirs ? " " : " AND filename <> '.' " ;
2012-01-21 13:28:20 +01:00
$length = textlib :: strlen ( $filepath );
2008-08-03 17:05:09 +00:00
2012-05-24 01:35:13 -04:00
$sql = " SELECT " . self :: instance_sql_fields ( 'f' , 'r' ) . "
2012-05-14 15:22:26 +08:00
FROM { files } f
LEFT JOIN { files_reference } r
ON f . referencefileid = r . id
WHERE f . contextid = : contextid AND f . component = : component AND f . filearea = : filearea AND f . itemid = : itemid
AND " . $DB->sql_substr ( " f . filepath " , 1, $length ). " = : filepath
AND f . id <> : dirid
2008-08-03 17:05:09 +00:00
$dirs
2012-05-29 16:38:47 +12:00
$orderby " ;
2010-07-03 13:37:13 +00:00
$params = array ( 'contextid' => $contextid , 'component' => $component , 'filearea' => $filearea , 'itemid' => $itemid , 'filepath' => $filepath , 'dirid' => $directory -> get_id ());
2008-08-03 17:05:09 +00:00
$files = array ();
$dirs = array ();
2012-05-12 04:14:53 +08:00
$filerecords = $DB -> get_records_sql ( $sql , $params );
foreach ( $filerecords as $filerecord ) {
if ( $filerecord -> filename == '.' ) {
$dirs [ $filerecord -> pathnamehash ] = $this -> get_file_instance ( $filerecord );
2008-08-03 17:05:09 +00:00
} else {
2012-05-12 04:14:53 +08:00
$files [ $filerecord -> pathnamehash ] = $this -> get_file_instance ( $filerecord );
2008-08-03 17:05:09 +00:00
}
}
$result = array_merge ( $dirs , $files );
} else {
$result = array ();
2010-07-03 13:37:13 +00:00
$params = array ( 'contextid' => $contextid , 'component' => $component , 'filearea' => $filearea , 'itemid' => $itemid , 'filepath' => $filepath , 'dirid' => $directory -> get_id ());
2008-08-03 17:05:09 +00:00
2012-01-21 13:28:20 +01:00
$length = textlib :: strlen ( $filepath );
2008-08-03 17:05:09 +00:00
2008-08-29 05:32:10 +00:00
if ( $includedirs ) {
2012-05-24 01:35:13 -04:00
$sql = " SELECT " . self :: instance_sql_fields ( 'f' , 'r' ) . "
2012-05-14 15:22:26 +08:00
FROM { files } f
LEFT JOIN { files_reference } r
ON f . referencefileid = r . id
WHERE f . contextid = : contextid AND f . component = : component AND f . filearea = : filearea
AND f . itemid = : itemid AND f . filename = '.'
AND " . $DB->sql_substr ( " f . filepath " , 1, $length ). " = : filepath
AND f . id <> : dirid
2012-05-29 16:38:47 +12:00
$orderby " ;
2008-08-03 17:05:09 +00:00
$reqlevel = substr_count ( $filepath , '/' ) + 1 ;
2012-05-12 04:14:53 +08:00
$filerecords = $DB -> get_records_sql ( $sql , $params );
foreach ( $filerecords as $filerecord ) {
if ( substr_count ( $filerecord -> filepath , '/' ) !== $reqlevel ) {
2008-08-03 17:05:09 +00:00
continue ;
}
2012-05-12 04:14:53 +08:00
$result [ $filerecord -> pathnamehash ] = $this -> get_file_instance ( $filerecord );
2008-08-03 17:05:09 +00:00
}
}
2012-05-24 01:35:13 -04:00
$sql = " SELECT " . self :: instance_sql_fields ( 'f' , 'r' ) . "
2012-05-14 15:22:26 +08:00
FROM { files } f
LEFT JOIN { files_reference } r
ON f . referencefileid = r . id
WHERE f . contextid = : contextid AND f . component = : component AND f . filearea = : filearea AND f . itemid = : itemid
AND f . filepath = : filepath AND f . filename <> '.'
2012-05-29 16:38:47 +12:00
$orderby " ;
2008-08-03 17:05:09 +00:00
2012-05-12 04:14:53 +08:00
$filerecords = $DB -> get_records_sql ( $sql , $params );
foreach ( $filerecords as $filerecord ) {
$result [ $filerecord -> pathnamehash ] = $this -> get_file_instance ( $filerecord );
2008-08-03 17:05:09 +00:00
}
}
return $result ;
}
2008-07-31 22:15:30 +00:00
/**
2010-05-03 21:04:06 +00:00
* Delete all area files ( optionally limited by itemid ) .
*
2012-02-15 12:48:57 +08:00
* @ param int $contextid context ID
* @ param string $component component
* @ param string $filearea file area or all areas in context if not specified
* @ param int $itemid item ID or all files if not specified
2010-05-03 21:04:06 +00:00
* @ return bool success
2008-07-31 22:15:30 +00:00
*/
2010-07-03 13:37:13 +00:00
public function delete_area_files ( $contextid , $component = false , $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 );
2010-07-03 13:37:13 +00:00
if ( $component !== false ) {
$conditions [ 'component' ] = $component ;
}
2008-08-27 08:23:07 +00:00
if ( $filearea !== false ) {
$conditions [ 'filearea' ] = $filearea ;
}
2008-07-31 22:15:30 +00:00
if ( $itemid !== false ) {
$conditions [ 'itemid' ] = $itemid ;
}
2012-05-12 04:14:53 +08:00
$filerecords = $DB -> get_records ( 'files' , $conditions );
foreach ( $filerecords as $filerecord ) {
$this -> get_file_instance ( $filerecord ) -> delete ();
2008-07-31 22:15:30 +00:00
}
2010-05-03 21:04:06 +00:00
return true ; // BC only
2008-07-31 22:15:30 +00:00
}
2011-03-16 18:52:36 +00:00
/**
* Delete all the files from certain areas where itemid is limited by an
* arbitrary bit of SQL .
*
* @ param int $contextid the id of the context the files belong to . Must be given .
* @ param string $component the owning component . Must be given .
* @ param string $filearea the file area name . Must be given .
* @ param string $itemidstest an SQL fragment that the itemid must match . Used
* in the query like WHERE itemid $itemidstest . Must used named parameters ,
* and may not used named parameters called contextid , component or filearea .
* @ param array $params any query params used by $itemidstest .
*/
public function delete_area_files_select ( $contextid , $component ,
$filearea , $itemidstest , array $params = null ) {
global $DB ;
$where = " contextid = :contextid
AND component = : component
AND filearea = : filearea
AND itemid $itemidstest " ;
$params [ 'contextid' ] = $contextid ;
$params [ 'component' ] = $component ;
$params [ 'filearea' ] = $filearea ;
2012-05-12 04:14:53 +08:00
$filerecords = $DB -> get_recordset_select ( 'files' , $where , $params );
foreach ( $filerecords as $filerecord ) {
$this -> get_file_instance ( $filerecord ) -> delete ();
2011-03-16 18:52:36 +00:00
}
2012-05-12 04:14:53 +08:00
$filerecords -> close ();
2011-03-16 18:52:36 +00:00
}
2010-11-11 18:58:06 +00:00
/**
* Move all the files in a file area from one context to another .
2012-02-15 12:48:57 +08:00
*
* @ param int $oldcontextid the context the files are being moved from .
* @ param int $newcontextid the context the files are being moved to .
2010-11-11 18:58:06 +00:00
* @ param string $component the plugin that these files belong to .
* @ param string $filearea the name of the file area .
2012-02-15 12:48:57 +08:00
* @ param int $itemid file item ID
* @ return int the number of files moved , for information .
2010-11-11 18:58:06 +00:00
*/
public function move_area_files_to_new_context ( $oldcontextid , $newcontextid , $component , $filearea , $itemid = false ) {
// Note, this code is based on some code that Petr wrote in
// forum_move_attachments in mod/forum/lib.php. I moved it here because
// I needed it in the question code too.
$count = 0 ;
$oldfiles = $this -> get_area_files ( $oldcontextid , $component , $filearea , $itemid , 'id' , false );
foreach ( $oldfiles as $oldfile ) {
$filerecord = new stdClass ();
$filerecord -> contextid = $newcontextid ;
$this -> create_file_from_storedfile ( $filerecord , $oldfile );
$count += 1 ;
}
if ( $count ) {
$this -> delete_area_files ( $oldcontextid , $component , $filearea , $itemid );
}
return $count ;
}
2008-07-31 22:15:30 +00:00
/**
2010-05-03 21:04:06 +00:00
* Recursively creates directory .
*
2012-02-15 12:48:57 +08:00
* @ param int $contextid context ID
* @ param string $component component
* @ param string $filearea file area
* @ param int $itemid item ID
* @ param string $filepath file path
* @ param int $userid the user ID
2008-07-31 22:15:30 +00:00
* @ return bool success
*/
2010-07-03 13:37:13 +00:00
public function create_directory ( $contextid , $component , $filearea , $itemid , $filepath , $userid = null ) {
2008-07-31 22:15:30 +00:00
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
}
2011-09-24 15:07:27 +02:00
$component = clean_param ( $component , PARAM_COMPONENT );
if ( empty ( $component )) {
2010-07-03 13:37:13 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid component' );
}
2011-09-24 15:07:27 +02:00
$filearea = clean_param ( $filearea , PARAM_AREA );
if ( empty ( $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
}
2010-07-03 13:37:13 +00:00
$pathnamehash = $this -> get_pathname_hash ( $contextid , $component , $filearea , $itemid , $filepath , '.' );
2008-07-31 22:15:30 +00:00
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 ();
2010-09-21 07:57:42 +00:00
$dir_record = new stdClass ();
2008-07-31 22:15:30 +00:00
$dir_record -> contextid = $contextid ;
2010-07-03 13:37:13 +00:00
$dir_record -> component = $component ;
2008-07-31 22:15:30 +00:00
$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 / " ;
2010-07-03 13:37:13 +00:00
$this -> create_directory ( $contextid , $component , $filearea , $itemid , $filepath , $userid );
2008-07-31 22:15:30 +00:00
}
return $dir_info ;
}
/**
2010-05-03 21:04:06 +00:00
* Add new local file based on existing local file .
*
2012-05-12 04:14:53 +08:00
* @ param stdClass | array $filerecord object or array describing changes
2012-02-15 12:48:57 +08:00
* @ param stored_file | int $fileorid id or stored_file instance of the existing local file
2010-05-03 21:04:06 +00:00
* @ return stored_file instance of newly created file
2008-07-31 22:15:30 +00:00
*/
2012-05-12 04:14:53 +08:00
public function create_file_from_storedfile ( $filerecord , $fileorid ) {
2010-04-06 18:34:38 +00:00
global $DB ;
2008-07-31 22:15:30 +00:00
2009-10-14 08:53:50 +00:00
if ( $fileorid instanceof stored_file ) {
$fid = $fileorid -> get_id ();
} else {
$fid = $fileorid ;
2008-08-16 21:21:23 +00:00
}
2012-05-12 04:14:53 +08:00
$filerecord = ( array ) $filerecord ; // We support arrays too, do not modify the submitted record!
2008-09-06 21:33:07 +00:00
2012-05-12 04:14:53 +08:00
unset ( $filerecord [ 'id' ]);
unset ( $filerecord [ 'filesize' ]);
unset ( $filerecord [ 'contenthash' ]);
unset ( $filerecord [ 'pathnamehash' ]);
2008-07-31 22:15:30 +00:00
2012-05-24 01:35:13 -04:00
$sql = " SELECT " . self :: instance_sql_fields ( 'f' , 'r' ) . "
2012-05-12 04:14:53 +08:00
FROM { files } f
LEFT JOIN { files_reference } r
ON f . referencefileid = r . id
WHERE f . id = ? " ;
if ( ! $newrecord = $DB -> get_record_sql ( $sql , array ( $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 );
2012-05-12 04:14:53 +08:00
foreach ( $filerecord as $key => $value ) {
2008-07-31 22:15:30 +00:00
// 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
}
2010-07-03 13:37:13 +00:00
if ( $key == 'component' ) {
2011-09-24 15:07:27 +02:00
$value = clean_param ( $value , PARAM_COMPONENT );
if ( empty ( $value )) {
2010-07-03 13:37:13 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid component' );
}
}
2008-07-31 22:15:30 +00:00
if ( $key == 'filearea' ) {
2011-09-24 15:07:27 +02:00
$value = clean_param ( $value , PARAM_AREA );
if ( empty ( $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
}
}
2011-10-14 15:50:27 +02:00
if ( $key === 'timecreated' or $key === 'timemodified' ) {
if ( ! is_number ( $value )) {
throw new file_exception ( 'storedfileproblem' , 'Invalid file ' . $key );
}
if ( $value < 0 ) {
//NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
$value = 0 ;
}
}
2012-05-12 04:14:53 +08:00
if ( $key == 'referencefileid' or $key == 'referencelastsync' or $key == 'referencelifetime' ) {
$value = clean_param ( $value , PARAM_INT );
}
2008-07-31 22:15:30 +00:00
$newrecord -> $key = $value ;
}
2010-07-03 13:37:13 +00:00
$newrecord -> pathnamehash = $this -> get_pathname_hash ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> filename );
2008-07-31 22:15:30 +00:00
2008-09-21 10:35:39 +00:00
if ( $newrecord -> filename === '.' ) {
// special case - only this function supports directories ;-)
2010-07-03 13:37:13 +00:00
$directory = $this -> create_directory ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> userid );
2008-09-21 10:35:39 +00:00
// update the existing directory with the new data
$newrecord -> id = $directory -> get_id ();
2009-06-13 16:47:05 +00:00
$DB -> update_record ( 'files' , $newrecord );
2010-09-19 15:50:18 +00:00
return $this -> get_file_instance ( $newrecord );
2008-09-21 10:35:39 +00:00
}
2012-05-30 00:58:50 +02:00
// note: referencefileid is copied from the original file so that
// creating a new file from an existing alias creates new alias implicitly.
// here we just check the database consistency.
2012-05-12 04:14:53 +08:00
if ( ! empty ( $newrecord -> repositoryid )) {
2012-05-30 00:58:50 +02:00
if ( $newrecord -> referencefileid != $this -> get_referencefileid ( $newrecord -> repositoryid , $newrecord -> reference , MUST_EXIST )) {
throw new file_reference_exception ( $newrecord -> repositoryid , $newrecord -> reference , $newrecord -> referencefileid );
2012-05-12 04:14:53 +08:00
}
}
2008-07-31 22:15:30 +00:00
try {
$newrecord -> id = $DB -> insert_record ( 'files' , $newrecord );
2010-09-18 10:31:31 +00:00
} catch ( dml_exception $e ) {
2010-07-03 13:37:13 +00:00
throw new stored_file_creation_exception ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid ,
2011-10-14 15:30:54 +02:00
$newrecord -> filepath , $newrecord -> filename , $e -> debuginfo );
2008-07-31 22:15:30 +00:00
}
2012-05-12 04:14:53 +08:00
2010-07-03 13:37:13 +00:00
$this -> create_directory ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> userid );
2008-07-31 22:15:30 +00:00
2010-09-19 15:50:18 +00:00
return $this -> get_file_instance ( $newrecord );
2008-07-31 22:15:30 +00:00
}
2008-09-06 10:09:33 +00:00
/**
2010-05-03 21:04:06 +00:00
* Add new local file .
*
2012-05-12 04:14:53 +08:00
* @ param stdClass | array $filerecord object or array describing file
2012-02-15 12:48:57 +08:00
* @ param string $url the URL to the file
* @ param array $options { @ link download_file_content ()} options
2010-05-20 17:13:07 +00:00
* @ param bool $usetempfile use temporary file for download , may prevent out of memory problems
2012-02-15 12:48:57 +08:00
* @ return stored_file
2008-09-06 10:09:33 +00:00
*/
2012-05-12 04:14:53 +08:00
public function create_file_from_url ( $filerecord , $url , array $options = null , $usetempfile = false ) {
2008-09-06 21:33:07 +00:00
2012-05-12 04:14:53 +08:00
$filerecord = ( array ) $filerecord ; // Do not modify the submitted record, this cast unlinks objects.
$filerecord = ( object ) $filerecord ; // We support arrays too.
2008-09-06 10:09:33 +00:00
$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 ;
2011-05-03 10:51:06 +08:00
$calctimeout = isset ( $options [ 'calctimeout' ]) ? $options [ 'calctimeout' ] : false ;
2008-09-06 10:09:33 +00:00
2012-05-12 04:14:53 +08:00
if ( ! isset ( $filerecord -> filename )) {
2008-09-06 10:09:33 +00:00
$parts = explode ( '/' , $url );
$filename = array_pop ( $parts );
2012-05-12 04:14:53 +08:00
$filerecord -> filename = clean_param ( $filename , PARAM_FILE );
2008-09-06 10:09:33 +00:00
}
2012-05-12 04:14:53 +08:00
$source = ! empty ( $filerecord -> source ) ? $filerecord -> source : $url ;
$filerecord -> source = clean_param ( $source , PARAM_URL );
2008-09-06 10:09:33 +00:00
2010-05-20 17:13:07 +00:00
if ( $usetempfile ) {
2010-08-29 14:51:09 +00:00
check_dir_exists ( $this -> tempdir );
2010-05-20 17:13:07 +00:00
$tmpfile = tempnam ( $this -> tempdir , 'newfromurl' );
2011-03-28 16:36:42 +08:00
$content = download_file_content ( $url , $headers , $postdata , $fullresponse , $timeout , $connecttimeout , $skipcertverify , $tmpfile , $calctimeout );
2010-05-20 17:13:07 +00:00
if ( $content === false ) {
throw new file_exception ( 'storedfileproblem' , 'Can not fetch file form URL' );
}
try {
2012-05-12 04:14:53 +08:00
$newfile = $this -> create_file_from_pathname ( $filerecord , $tmpfile );
2010-05-20 17:13:07 +00:00
@ unlink ( $tmpfile );
return $newfile ;
} catch ( Exception $e ) {
@ unlink ( $tmpfile );
throw $e ;
}
} else {
2011-03-28 16:36:42 +08:00
$content = download_file_content ( $url , $headers , $postdata , $fullresponse , $timeout , $connecttimeout , $skipcertverify , NULL , $calctimeout );
2010-05-20 17:13:07 +00:00
if ( $content === false ) {
throw new file_exception ( 'storedfileproblem' , 'Can not fetch file form URL' );
}
2012-05-12 04:14:53 +08:00
return $this -> create_file_from_string ( $filerecord , $content );
2010-05-20 17:13:07 +00:00
}
2008-09-06 10:09:33 +00:00
}
2008-07-31 22:15:30 +00:00
/**
2010-05-03 21:04:06 +00:00
* Add new local file .
*
2012-05-12 04:14:53 +08:00
* @ param stdClass | array $filerecord object or array describing file
2012-02-15 12:48:57 +08:00
* @ param string $pathname path to file or content of file
* @ return stored_file
2008-07-31 22:15:30 +00:00
*/
2012-05-12 04:14:53 +08:00
public function create_file_from_pathname ( $filerecord , $pathname ) {
2010-04-06 18:34:38 +00:00
global $DB ;
2008-07-31 22:15:30 +00:00
2012-05-12 04:14:53 +08:00
$filerecord = ( array ) $filerecord ; // Do not modify the submitted record, this cast unlinks objects.
$filerecord = ( object ) $filerecord ; // We support arrays too.
2008-07-31 22:15:30 +00:00
// validate all parameters, we do not want any rubbish stored in database, right?
2012-05-12 04:14:53 +08:00
if ( ! is_number ( $filerecord -> contextid ) or $filerecord -> 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
}
2012-05-12 04:14:53 +08:00
$filerecord -> component = clean_param ( $filerecord -> component , PARAM_COMPONENT );
if ( empty ( $filerecord -> component )) {
2010-07-03 13:37:13 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid component' );
}
2012-05-12 04:14:53 +08:00
$filerecord -> filearea = clean_param ( $filerecord -> filearea , PARAM_AREA );
if ( empty ( $filerecord -> filearea )) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid filearea' );
2008-07-31 22:15:30 +00:00
}
2012-05-12 04:14:53 +08:00
if ( ! is_number ( $filerecord -> itemid ) or $filerecord -> 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
}
2012-05-12 04:14:53 +08:00
if ( ! empty ( $filerecord -> sortorder )) {
if ( ! is_number ( $filerecord -> sortorder ) or $filerecord -> sortorder < 0 ) {
$filerecord -> sortorder = 0 ;
2010-05-28 07:29:11 +00:00
}
} else {
2012-05-12 04:14:53 +08:00
$filerecord -> sortorder = 0 ;
2010-05-28 07:29:11 +00:00
}
2012-05-12 04:14:53 +08:00
$filerecord -> filepath = clean_param ( $filerecord -> filepath , PARAM_PATH );
if ( strpos ( $filerecord -> filepath , '/' ) !== 0 or strrpos ( $filerecord -> filepath , '/' ) !== strlen ( $filerecord -> filepath ) - 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
}
2012-05-12 04:14:53 +08:00
$filerecord -> filename = clean_param ( $filerecord -> filename , PARAM_FILE );
if ( $filerecord -> 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 ();
2012-05-12 04:14:53 +08:00
if ( isset ( $filerecord -> timecreated )) {
if ( ! is_number ( $filerecord -> timecreated )) {
2011-10-14 15:50:27 +02:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file timecreated' );
}
2012-05-12 04:14:53 +08:00
if ( $filerecord -> timecreated < 0 ) {
2011-10-14 15:50:27 +02:00
//NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
2012-05-12 04:14:53 +08:00
$filerecord -> timecreated = 0 ;
2011-10-14 15:50:27 +02:00
}
} else {
2012-05-12 04:14:53 +08:00
$filerecord -> timecreated = $now ;
2011-10-14 15:50:27 +02:00
}
2012-05-12 04:14:53 +08:00
if ( isset ( $filerecord -> timemodified )) {
if ( ! is_number ( $filerecord -> timemodified )) {
2011-10-14 15:50:27 +02:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file timemodified' );
}
2012-05-12 04:14:53 +08:00
if ( $filerecord -> timemodified < 0 ) {
2011-10-14 15:50:27 +02:00
//NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
2012-05-12 04:14:53 +08:00
$filerecord -> timemodified = 0 ;
2011-10-14 15:50:27 +02:00
}
} else {
2012-05-12 04:14:53 +08:00
$filerecord -> timemodified = $now ;
2011-10-14 15:50:27 +02:00
}
2008-07-31 22:15:30 +00:00
2010-09-21 07:57:42 +00:00
$newrecord = new stdClass ();
2008-07-31 22:15:30 +00:00
2012-05-12 04:14:53 +08:00
$newrecord -> contextid = $filerecord -> contextid ;
$newrecord -> component = $filerecord -> component ;
$newrecord -> filearea = $filerecord -> filearea ;
$newrecord -> itemid = $filerecord -> itemid ;
$newrecord -> filepath = $filerecord -> filepath ;
$newrecord -> filename = $filerecord -> filename ;
$newrecord -> timecreated = $filerecord -> timecreated ;
$newrecord -> timemodified = $filerecord -> timemodified ;
2012-05-28 15:19:41 +08:00
$newrecord -> mimetype = empty ( $filerecord -> mimetype ) ? $this -> mimetype ( $pathname , $filerecord -> filename ) : $filerecord -> mimetype ;
2012-05-12 04:14:53 +08:00
$newrecord -> userid = empty ( $filerecord -> userid ) ? null : $filerecord -> userid ;
$newrecord -> source = empty ( $filerecord -> source ) ? null : $filerecord -> source ;
$newrecord -> author = empty ( $filerecord -> author ) ? null : $filerecord -> author ;
$newrecord -> license = empty ( $filerecord -> license ) ? null : $filerecord -> license ;
2012-06-14 14:52:31 +08:00
$newrecord -> status = empty ( $filerecord -> status ) ? 0 : $filerecord -> status ;
2012-05-12 04:14:53 +08:00
$newrecord -> sortorder = $filerecord -> sortorder ;
2008-07-31 22:15:30 +00:00
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
2010-07-03 13:37:13 +00:00
$newrecord -> pathnamehash = $this -> get_pathname_hash ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> filename );
2008-07-31 22:15:30 +00:00
try {
$newrecord -> id = $DB -> insert_record ( 'files' , $newrecord );
2010-09-18 10:31:31 +00:00
} catch ( dml_exception $e ) {
2008-07-31 22:15:30 +00:00
if ( $newfile ) {
2009-07-27 12:39:13 +00:00
$this -> deleted_file_cleanup ( $newrecord -> contenthash );
2008-07-31 22:15:30 +00:00
}
2010-07-03 13:37:13 +00:00
throw new stored_file_creation_exception ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid ,
2011-10-14 15:30:54 +02:00
$newrecord -> filepath , $newrecord -> filename , $e -> debuginfo );
2008-07-31 22:15:30 +00:00
}
2010-07-03 13:37:13 +00:00
$this -> create_directory ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> userid );
2008-07-31 22:15:30 +00:00
2010-09-19 15:50:18 +00:00
return $this -> get_file_instance ( $newrecord );
2008-07-31 22:15:30 +00:00
}
/**
2010-05-03 21:04:06 +00:00
* Add new local file .
*
2012-05-12 04:14:53 +08:00
* @ param stdClass | array $filerecord object or array describing file
2008-07-31 22:15:30 +00:00
* @ param string $content content of file
2012-02-15 12:48:57 +08:00
* @ return stored_file
2008-07-31 22:15:30 +00:00
*/
2012-05-12 04:14:53 +08:00
public function create_file_from_string ( $filerecord , $content ) {
2010-04-06 18:34:38 +00:00
global $DB ;
2008-07-31 22:15:30 +00:00
2012-05-12 04:14:53 +08:00
$filerecord = ( array ) $filerecord ; // Do not modify the submitted record, this cast unlinks objects.
$filerecord = ( object ) $filerecord ; // We support arrays too.
2008-07-31 22:15:30 +00:00
// validate all parameters, we do not want any rubbish stored in database, right?
2012-05-12 04:14:53 +08:00
if ( ! is_number ( $filerecord -> contextid ) or $filerecord -> 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
}
2012-05-12 04:14:53 +08:00
$filerecord -> component = clean_param ( $filerecord -> component , PARAM_COMPONENT );
if ( empty ( $filerecord -> component )) {
2010-07-03 13:37:13 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid component' );
}
2012-05-12 04:14:53 +08:00
$filerecord -> filearea = clean_param ( $filerecord -> filearea , PARAM_AREA );
if ( empty ( $filerecord -> filearea )) {
2008-08-08 11:50:45 +00:00
throw new file_exception ( 'storedfileproblem' , 'Invalid filearea' );
2008-07-31 22:15:30 +00:00
}
2012-05-12 04:14:53 +08:00
if ( ! is_number ( $filerecord -> itemid ) or $filerecord -> 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
}
2012-05-12 04:14:53 +08:00
if ( ! empty ( $filerecord -> sortorder )) {
if ( ! is_number ( $filerecord -> sortorder ) or $filerecord -> sortorder < 0 ) {
$filerecord -> sortorder = 0 ;
2010-05-28 07:29:11 +00:00
}
} else {
2012-05-12 04:14:53 +08:00
$filerecord -> sortorder = 0 ;
2010-05-28 07:29:11 +00:00
}
2012-05-12 04:14:53 +08:00
$filerecord -> filepath = clean_param ( $filerecord -> filepath , PARAM_PATH );
if ( strpos ( $filerecord -> filepath , '/' ) !== 0 or strrpos ( $filerecord -> filepath , '/' ) !== strlen ( $filerecord -> filepath ) - 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
}
2012-05-12 04:14:53 +08:00
$filerecord -> filename = clean_param ( $filerecord -> filename , PARAM_FILE );
if ( $filerecord -> filename === '' ) {
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 name' );
2008-07-31 22:15:30 +00:00
}
$now = time ();
2012-05-12 04:14:53 +08:00
if ( isset ( $filerecord -> timecreated )) {
if ( ! is_number ( $filerecord -> timecreated )) {
2011-10-14 15:50:27 +02:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file timecreated' );
}
2012-05-12 04:14:53 +08:00
if ( $filerecord -> timecreated < 0 ) {
2011-10-14 15:50:27 +02:00
//NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
2012-05-12 04:14:53 +08:00
$filerecord -> timecreated = 0 ;
2011-10-14 15:50:27 +02:00
}
} else {
2012-05-12 04:14:53 +08:00
$filerecord -> timecreated = $now ;
2011-10-14 15:50:27 +02:00
}
2012-05-12 04:14:53 +08:00
if ( isset ( $filerecord -> timemodified )) {
if ( ! is_number ( $filerecord -> timemodified )) {
2011-10-14 15:50:27 +02:00
throw new file_exception ( 'storedfileproblem' , 'Invalid file timemodified' );
}
2012-05-12 04:14:53 +08:00
if ( $filerecord -> timemodified < 0 ) {
2011-10-14 15:50:27 +02:00
//NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
2012-05-12 04:14:53 +08:00
$filerecord -> timemodified = 0 ;
2011-10-14 15:50:27 +02:00
}
} else {
2012-05-12 04:14:53 +08:00
$filerecord -> timemodified = $now ;
2011-10-14 15:50:27 +02:00
}
2008-07-31 22:15:30 +00:00
2010-09-21 07:57:42 +00:00
$newrecord = new stdClass ();
2008-07-31 22:15:30 +00:00
2012-05-12 04:14:53 +08:00
$newrecord -> contextid = $filerecord -> contextid ;
$newrecord -> component = $filerecord -> component ;
$newrecord -> filearea = $filerecord -> filearea ;
$newrecord -> itemid = $filerecord -> itemid ;
$newrecord -> filepath = $filerecord -> filepath ;
$newrecord -> filename = $filerecord -> filename ;
$newrecord -> timecreated = $filerecord -> timecreated ;
$newrecord -> timemodified = $filerecord -> timemodified ;
$newrecord -> userid = empty ( $filerecord -> userid ) ? null : $filerecord -> userid ;
$newrecord -> source = empty ( $filerecord -> source ) ? null : $filerecord -> source ;
$newrecord -> author = empty ( $filerecord -> author ) ? null : $filerecord -> author ;
$newrecord -> license = empty ( $filerecord -> license ) ? null : $filerecord -> license ;
2012-06-14 14:52:31 +08:00
$newrecord -> status = empty ( $filerecord -> status ) ? 0 : $filerecord -> status ;
2012-05-12 04:14:53 +08:00
$newrecord -> sortorder = $filerecord -> sortorder ;
2010-03-29 03:39:08 +00:00
2008-08-06 20:51:14 +00:00
list ( $newrecord -> contenthash , $newrecord -> filesize , $newfile ) = $this -> add_string_to_pool ( $content );
2012-05-21 13:30:41 +08:00
$filepathname = $this -> path_from_hash ( $newrecord -> contenthash ) . '/' . $newrecord -> contenthash ;
// get mimetype by magic bytes
2012-05-28 15:19:41 +08:00
$newrecord -> mimetype = empty ( $filerecord -> mimetype ) ? $this -> mimetype ( $filepathname , $filerecord -> filename ) : $filerecord -> mimetype ;
2008-07-31 22:15:30 +00:00
2010-07-03 13:37:13 +00:00
$newrecord -> pathnamehash = $this -> get_pathname_hash ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> filename );
2008-07-31 22:15:30 +00:00
try {
$newrecord -> id = $DB -> insert_record ( 'files' , $newrecord );
2010-09-18 10:31:31 +00:00
} catch ( dml_exception $e ) {
2008-07-31 22:15:30 +00:00
if ( $newfile ) {
2009-07-27 12:39:13 +00:00
$this -> deleted_file_cleanup ( $newrecord -> contenthash );
2008-07-31 22:15:30 +00:00
}
2010-07-03 13:37:13 +00:00
throw new stored_file_creation_exception ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid ,
2011-10-14 15:30:54 +02:00
$newrecord -> filepath , $newrecord -> filename , $e -> debuginfo );
2008-07-31 22:15:30 +00:00
}
2010-07-03 13:37:13 +00:00
$this -> create_directory ( $newrecord -> contextid , $newrecord -> component , $newrecord -> filearea , $newrecord -> itemid , $newrecord -> filepath , $newrecord -> userid );
2008-07-31 22:15:30 +00:00
2010-09-19 15:50:18 +00:00
return $this -> get_file_instance ( $newrecord );
2008-07-31 22:15:30 +00:00
}
2012-05-12 04:14:53 +08:00
/**
2012-05-30 00:58:50 +02:00
* Create a new alias / shortcut file from file reference information
2012-05-12 04:14:53 +08:00
*
2012-05-30 00:58:50 +02:00
* @ param stdClass | array $filerecord object or array describing the new file
* @ param int $repositoryid the id of the repository that provides the original file
* @ param string $reference the information required by the repository to locate the original file
* @ param array $options options for creating the new file
2012-05-12 04:14:53 +08:00
* @ return stored_file
*/
public function create_file_from_reference ( $filerecord , $repositoryid , $reference , $options = array ()) {
global $DB ;
$filerecord = ( array ) $filerecord ; // Do not modify the submitted record, this cast unlinks objects.
$filerecord = ( object ) $filerecord ; // We support arrays too.
// validate all parameters, we do not want any rubbish stored in database, right?
if ( ! is_number ( $filerecord -> contextid ) or $filerecord -> contextid < 1 ) {
throw new file_exception ( 'storedfileproblem' , 'Invalid contextid' );
}
$filerecord -> component = clean_param ( $filerecord -> component , PARAM_COMPONENT );
if ( empty ( $filerecord -> component )) {
throw new file_exception ( 'storedfileproblem' , 'Invalid component' );
}
$filerecord -> filearea = clean_param ( $filerecord -> filearea , PARAM_AREA );
if ( empty ( $filerecord -> filearea )) {
throw new file_exception ( 'storedfileproblem' , 'Invalid filearea' );
}
if ( ! is_number ( $filerecord -> itemid ) or $filerecord -> itemid < 0 ) {
throw new file_exception ( 'storedfileproblem' , 'Invalid itemid' );
}
if ( ! empty ( $filerecord -> sortorder )) {
if ( ! is_number ( $filerecord -> sortorder ) or $filerecord -> sortorder < 0 ) {
$filerecord -> sortorder = 0 ;
}
} else {
$filerecord -> sortorder = 0 ;
}
2012-08-10 12:26:19 +08:00
// TODO MDL-33416 [2.4] fields referencelastsync and referencelifetime to be removed from {files} table completely
unset ( $filerecord -> referencelastsync );
unset ( $filerecord -> referencelifetime );
2012-05-21 13:30:41 +08:00
$filerecord -> mimetype = empty ( $filerecord -> mimetype ) ? $this -> mimetype ( $filerecord -> filename ) : $filerecord -> mimetype ;
2012-05-12 04:14:53 +08:00
$filerecord -> userid = empty ( $filerecord -> userid ) ? null : $filerecord -> userid ;
$filerecord -> source = empty ( $filerecord -> source ) ? null : $filerecord -> source ;
$filerecord -> author = empty ( $filerecord -> author ) ? null : $filerecord -> author ;
$filerecord -> license = empty ( $filerecord -> license ) ? null : $filerecord -> license ;
2012-06-14 14:52:31 +08:00
$filerecord -> status = empty ( $filerecord -> status ) ? 0 : $filerecord -> status ;
2012-05-12 04:14:53 +08:00
$filerecord -> filepath = clean_param ( $filerecord -> filepath , PARAM_PATH );
if ( strpos ( $filerecord -> filepath , '/' ) !== 0 or strrpos ( $filerecord -> filepath , '/' ) !== strlen ( $filerecord -> filepath ) - 1 ) {
// Path must start and end with '/'.
throw new file_exception ( 'storedfileproblem' , 'Invalid file path' );
}
$filerecord -> filename = clean_param ( $filerecord -> filename , PARAM_FILE );
if ( $filerecord -> filename === '' ) {
// Path must start and end with '/'.
throw new file_exception ( 'storedfileproblem' , 'Invalid file name' );
}
$now = time ();
if ( isset ( $filerecord -> timecreated )) {
if ( ! is_number ( $filerecord -> timecreated )) {
throw new file_exception ( 'storedfileproblem' , 'Invalid file timecreated' );
}
if ( $filerecord -> timecreated < 0 ) {
// NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
$filerecord -> timecreated = 0 ;
}
} else {
$filerecord -> timecreated = $now ;
}
if ( isset ( $filerecord -> timemodified )) {
if ( ! is_number ( $filerecord -> timemodified )) {
throw new file_exception ( 'storedfileproblem' , 'Invalid file timemodified' );
}
if ( $filerecord -> timemodified < 0 ) {
// NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
$filerecord -> timemodified = 0 ;
}
} else {
$filerecord -> timemodified = $now ;
}
2012-05-22 13:51:04 +08:00
$transaction = $DB -> start_delegated_transaction ();
2012-05-12 04:14:53 +08:00
try {
2012-08-09 13:50:42 +08:00
$filerecord -> referencefileid = $this -> get_or_create_referencefileid ( $repositoryid , $reference );
2012-05-30 00:58:50 +02:00
} catch ( Exception $e ) {
throw new file_reference_exception ( $repositoryid , $reference , null , null , $e -> getMessage ());
2012-05-12 04:14:53 +08:00
}
2012-08-09 13:50:42 +08:00
if ( isset ( $filerecord -> contenthash ) && $this -> content_exists ( $filerecord -> contenthash )) {
// there was specified the contenthash for a file already stored in moodle filepool
if ( empty ( $filerecord -> filesize )) {
$filepathname = $this -> path_from_hash ( $filerecord -> contenthash ) . '/' . $filerecord -> contenthash ;
$filerecord -> filesize = filesize ( $filepathname );
} else {
$filerecord -> filesize = clean_param ( $filerecord -> filesize , PARAM_INT );
}
} else {
// atempt to get the result of last synchronisation for this reference
$lastcontent = $DB -> get_record ( 'files' , array ( 'referencefileid' => $filerecord -> referencefileid ),
'id, contenthash, filesize' , IGNORE_MULTIPLE );
if ( $lastcontent ) {
$filerecord -> contenthash = $lastcontent -> contenthash ;
$filerecord -> filesize = $lastcontent -> filesize ;
} else {
// External file doesn't have content in moodle.
// So we create an empty file for it.
list ( $filerecord -> contenthash , $filerecord -> filesize , $newfile ) = $this -> add_string_to_pool ( null );
}
}
2012-05-12 04:14:53 +08:00
$filerecord -> pathnamehash = $this -> get_pathname_hash ( $filerecord -> contextid , $filerecord -> component , $filerecord -> filearea , $filerecord -> itemid , $filerecord -> filepath , $filerecord -> filename );
try {
$filerecord -> id = $DB -> insert_record ( 'files' , $filerecord );
} catch ( dml_exception $e ) {
2012-08-09 13:50:42 +08:00
if ( ! empty ( $newfile )) {
2012-05-12 04:14:53 +08:00
$this -> deleted_file_cleanup ( $filerecord -> contenthash );
}
throw new stored_file_creation_exception ( $filerecord -> contextid , $filerecord -> component , $filerecord -> filearea , $filerecord -> itemid ,
$filerecord -> filepath , $filerecord -> filename , $e -> debuginfo );
}
$this -> create_directory ( $filerecord -> contextid , $filerecord -> component , $filerecord -> filearea , $filerecord -> itemid , $filerecord -> filepath , $filerecord -> userid );
2012-05-22 13:51:04 +08:00
$transaction -> allow_commit ();
2012-08-10 12:26:19 +08:00
// this will retrieve all reference information from DB as well
return $this -> get_file_by_id ( $filerecord -> id );
2012-05-12 04:14:53 +08:00
}
2008-09-13 19:38:44 +00:00
/**
* Creates new image file from existing .
2010-05-03 21:04:06 +00:00
*
2012-05-12 04:14:53 +08:00
* @ param stdClass | array $filerecord object or array describing new file
2012-02-15 12:48:57 +08:00
* @ param int | stored_file $fid file id or stored file object
2008-09-13 19:38:44 +00:00
* @ param int $newwidth in pixels
* @ param int $newheight in pixels
2012-02-15 12:48:57 +08:00
* @ param bool $keepaspectratio whether or not keep aspect ratio
2010-05-03 21:04:06 +00:00
* @ param int $quality depending on image type 0 - 100 for jpeg , 0 - 9 ( 0 means no compression ) for png
2012-02-15 12:48:57 +08:00
* @ return stored_file
2008-09-13 19:38:44 +00:00
*/
2012-05-12 04:14:53 +08:00
public function convert_image ( $filerecord , $fid , $newwidth = null , $newheight = null , $keepaspectratio = true , $quality = null ) {
2011-11-28 12:58:44 +08:00
if ( ! function_exists ( 'imagecreatefromstring' )) {
//Most likely the GD php extension isn't installed
//image conversion cannot succeed
throw new file_exception ( 'storedfileproblem' , 'imagecreatefromstring() doesnt exist. The PHP extension "GD" must be installed for image conversion.' );
}
2008-09-13 19:38:44 +00:00
if ( $fid instanceof stored_file ) {
$fid = $fid -> get_id ();
}
2012-05-12 04:14:53 +08:00
$filerecord = ( array ) $filerecord ; // We support arrays too, do not modify the submitted record!
2008-09-13 19:38:44 +00:00
2012-05-12 04:14:53 +08:00
if ( ! $file = $this -> get_file_by_id ( $fid )) { // Make sure file really exists and we we correct data.
2008-09-13 19:38:44 +00:00
throw new file_exception ( 'storedfileproblem' , 'File does not exist' );
}
if ( ! $imageinfo = $file -> get_imageinfo ()) {
throw new file_exception ( 'storedfileproblem' , 'File is not an image' );
}
2012-05-12 04:14:53 +08:00
if ( ! isset ( $filerecord [ 'filename' ])) {
$filerecord [ 'filename' ] = $file -> get_filename ();
2008-09-13 19:38:44 +00:00
}
2012-05-12 04:14:53 +08:00
if ( ! isset ( $filerecord [ 'mimetype' ])) {
2012-05-21 13:30:41 +08:00
$filerecord [ 'mimetype' ] = $imageinfo [ 'mimetype' ];
2008-09-13 19:38:44 +00:00
}
$width = $imageinfo [ 'width' ];
$height = $imageinfo [ 'height' ];
$mimetype = $imageinfo [ 'mimetype' ];
if ( $keepaspectratio ) {
if ( 0 >= $newwidth and 0 >= $newheight ) {
// no sizes specified
$newwidth = $width ;
$newheight = $height ;
} else if ( 0 < $newwidth and 0 < $newheight ) {
$xheight = ( $newwidth * ( $height / $width ));
if ( $xheight < $newheight ) {
$newheight = ( int ) $xheight ;
} else {
$newwidth = ( int )( $newheight * ( $width / $height ));
}
} else if ( 0 < $newwidth ) {
$newheight = ( int )( $newwidth * ( $height / $width ));
} else { //0 < $newheight
$newwidth = ( int )( $newheight * ( $width / $height ));
}
} else {
if ( 0 >= $newwidth ) {
$newwidth = $width ;
}
if ( 0 >= $newheight ) {
$newheight = $height ;
}
}
$img = imagecreatefromstring ( $file -> get_content ());
if ( $height != $newheight or $width != $newwidth ) {
$newimg = imagecreatetruecolor ( $newwidth , $newheight );
if ( ! imagecopyresized ( $newimg , $img , 0 , 0 , 0 , 0 , $newwidth , $newheight , $width , $height )) {
// weird
throw new file_exception ( 'storedfileproblem' , 'Can not resize image' );
}
imagedestroy ( $img );
$img = $newimg ;
}
ob_start ();
2012-05-12 04:14:53 +08:00
switch ( $filerecord [ 'mimetype' ]) {
2008-09-13 19:38:44 +00:00
case 'image/gif' :
imagegif ( $img );
break ;
case 'image/jpeg' :
if ( is_null ( $quality )) {
imagejpeg ( $img );
} else {
imagejpeg ( $img , NULL , $quality );
}
break ;
case 'image/png' :
2008-09-16 15:56:19 +00:00
$quality = ( int ) $quality ;
2008-09-13 19:38:44 +00:00
imagepng ( $img , NULL , $quality , NULL );
break ;
default :
throw new file_exception ( 'storedfileproblem' , 'Unsupported mime type' );
}
$content = ob_get_contents ();
ob_end_clean ();
imagedestroy ( $img );
if ( ! $content ) {
throw new file_exception ( 'storedfileproblem' , 'Can not convert image' );
}
2012-05-12 04:14:53 +08:00
return $this -> create_file_from_string ( $filerecord , $content );
2008-09-13 19:38:44 +00:00
}
2008-07-31 22:15:30 +00:00
/**
2010-05-03 21:04:06 +00:00
* Add file content to sha1 pool .
*
2008-07-31 22:15:30 +00:00
* @ param string $pathname path to file
2010-05-03 21:04:06 +00:00
* @ param string $contenthash sha1 hash of content if known ( performance only )
* @ return array ( contenthash , filesize , newfile )
2008-07-31 22:15:30 +00:00
*/
2010-05-03 21:04:06 +00:00
public function add_file_to_pool ( $pathname , $contenthash = NULL ) {
2008-07-31 22:15:30 +00:00
if ( ! is_readable ( $pathname )) {
2011-06-17 19:46:09 +01:00
throw new file_exception ( 'storedfilecannotread' , '' , $pathname );
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 {
2009-06-03 08:10:21 +00:00
if ( ! is_dir ( $hashpath )) {
if ( ! mkdir ( $hashpath , $this -> dirpermissions , true )) {
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 )) {
2011-06-17 19:46:09 +01:00
throw new file_exception ( 'storedfilecannotread' , '' , $pathname );
2008-07-31 22:15:30 +00:00
}
if ( filesize ( $hashfile ) !== $filesize ) {
@ unlink ( $hashfile );
throw new file_pool_content_exception ( $contenthash );
}
2009-06-03 08:10:21 +00:00
chmod ( $hashfile , $this -> filepermissions ); // fix permissions if needed
2008-07-31 22:15:30 +00:00
}
return array ( $contenthash , $filesize , $newfile );
}
/**
2010-05-03 21:04:06 +00:00
* Add string content to sha1 pool .
*
2008-07-31 22:15:30 +00:00
* @ param string $content file content - binary string
2010-05-03 21:04:06 +00:00
* @ return array ( contenthash , filesize , newfile )
2008-07-31 22:15:30 +00:00
*/
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 {
2009-06-03 08:10:21 +00:00
if ( ! is_dir ( $hashpath )) {
if ( ! mkdir ( $hashpath , $this -> dirpermissions , true )) {
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 );
}
2009-06-03 08:10:21 +00:00
chmod ( $hashfile , $this -> filepermissions ); // fix permissions if needed
2008-07-31 22:15:30 +00:00
}
return array ( $contenthash , $filesize , $newfile );
}
2012-04-29 01:16:53 +02:00
/**
* Serve file content using X - Sendfile header .
* Please make sure that all headers are already sent
* and the all access control checks passed .
*
* @ param string $contenthash sah1 hash of the file content to be served
* @ return bool success
*/
public function xsendfile ( $contenthash ) {
global $CFG ;
require_once ( " $CFG->libdir /xsendfilelib.php " );
$hashpath = $this -> path_from_hash ( $contenthash );
return xsendfile ( " $hashpath / $contenthash " );
}
2012-05-12 04:14:53 +08:00
/**
* Content exists
*
* @ param string $contenthash
* @ return bool
*/
public function content_exists ( $contenthash ) {
$dir = $this -> path_from_hash ( $contenthash );
$filepath = $dir . '/' . $contenthash ;
return file_exists ( $filepath );
}
2008-07-31 22:15:30 +00:00
/**
2010-05-03 21:04:06 +00:00
* Return path to file with given hash .
2008-07-31 22:15:30 +00:00
*
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
*
2012-02-15 12:48:57 +08:00
* @ param string $contenthash content hash
2008-07-31 22:15:30 +00:00
* @ 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 ];
2010-08-25 21:45:34 +00:00
return " $this->filedir / $l1 / $l2 " ;
2008-07-31 22:15:30 +00:00
}
2009-06-03 08:10:21 +00:00
/**
2010-05-03 21:04:06 +00:00
* Return path to file with given hash .
2009-06-03 08:10:21 +00:00
*
* NOTE : must not be public , files in pool must not be modified
*
2012-02-15 12:48:57 +08:00
* @ param string $contenthash content hash
2009-06-03 08:10:21 +00:00
* @ return string expected file location
*/
protected function trash_path_from_hash ( $contenthash ) {
$l1 = $contenthash [ 0 ] . $contenthash [ 1 ];
$l2 = $contenthash [ 2 ] . $contenthash [ 3 ];
2010-08-25 21:45:34 +00:00
return " $this->trashdir / $l1 / $l2 " ;
2009-06-03 08:10:21 +00:00
}
/**
2010-05-03 21:04:06 +00:00
* Tries to recover missing content of file from trash .
*
2012-02-15 12:48:57 +08:00
* @ param stored_file $file stored_file instance
2009-06-03 08:10:21 +00:00
* @ return bool success
*/
public function try_content_recovery ( $file ) {
$contenthash = $file -> get_contenthash ();
$trashfile = $this -> trash_path_from_hash ( $contenthash ) . '/' . $contenthash ;
if ( ! is_readable ( $trashfile )) {
if ( ! is_readable ( $this -> trashdir . '/' . $contenthash )) {
return false ;
}
// nice, at least alternative trash file in trash root exists
$trashfile = $this -> trashdir . '/' . $contenthash ;
}
if ( filesize ( $trashfile ) != $file -> get_filesize () or sha1_file ( $trashfile ) != $contenthash ) {
//weird, better fail early
return false ;
}
$contentdir = $this -> path_from_hash ( $contenthash );
$contentfile = $contentdir . '/' . $contenthash ;
if ( file_exists ( $contentfile )) {
//strange, no need to recover anything
return true ;
}
if ( ! is_dir ( $contentdir )) {
if ( ! mkdir ( $contentdir , $this -> dirpermissions , true )) {
return false ;
}
}
return rename ( $trashfile , $contentfile );
}
2008-07-31 22:15:30 +00:00
/**
2010-05-03 21:04:06 +00:00
* Marks pool file as candidate for deleting .
*
* DO NOT call directly - reserved for core !!
*
2008-07-31 22:15:30 +00:00
* @ param string $contenthash
*/
2009-06-03 08:10:21 +00:00
public function deleted_file_cleanup ( $contenthash ) {
2008-07-31 22:15:30 +00:00
global $DB ;
2009-06-03 08:10:21 +00:00
//Note: this section is critical - in theory file could be reused at the same
// time, if this happens we can still recover the file from trash
if ( $DB -> record_exists ( 'files' , array ( 'contenthash' => $contenthash ))) {
// file content is still used
return ;
}
//move content file to trash
$contentfile = $this -> path_from_hash ( $contenthash ) . '/' . $contenthash ;
if ( ! file_exists ( $contentfile )) {
//weird, but no problem
2008-07-31 22:15:30 +00:00
return ;
}
2009-06-03 08:10:21 +00:00
$trashpath = $this -> trash_path_from_hash ( $contenthash );
$trashfile = $trashpath . '/' . $contenthash ;
if ( file_exists ( $trashfile )) {
// we already have this content in trash, no need to move it there
unlink ( $contentfile );
return ;
}
if ( ! is_dir ( $trashpath )) {
mkdir ( $trashpath , $this -> dirpermissions , true );
}
rename ( $contentfile , $trashfile );
chmod ( $trashfile , $this -> filepermissions ); // fix permissions if needed
2008-07-31 22:15:30 +00:00
}
2012-05-12 04:14:53 +08:00
/**
* When user referring to a moodle file , we build the reference field
*
* @ param array $params
* @ return string
*/
public static function pack_reference ( $params ) {
$params = ( array ) $params ;
$reference = array ();
$reference [ 'contextid' ] = is_null ( $params [ 'contextid' ]) ? null : clean_param ( $params [ 'contextid' ], PARAM_INT );
$reference [ 'component' ] = is_null ( $params [ 'component' ]) ? null : clean_param ( $params [ 'component' ], PARAM_COMPONENT );
$reference [ 'itemid' ] = is_null ( $params [ 'itemid' ]) ? null : clean_param ( $params [ 'itemid' ], PARAM_INT );
$reference [ 'filearea' ] = is_null ( $params [ 'filearea' ]) ? null : clean_param ( $params [ 'filearea' ], PARAM_AREA );
2012-11-15 09:51:26 +08:00
$reference [ 'filepath' ] = is_null ( $params [ 'filepath' ]) ? null : clean_param ( $params [ 'filepath' ], PARAM_PATH );
2012-05-12 04:14:53 +08:00
$reference [ 'filename' ] = is_null ( $params [ 'filename' ]) ? null : clean_param ( $params [ 'filename' ], PARAM_FILE );
return base64_encode ( serialize ( $reference ));
}
/**
* Unpack reference field
*
* @ param string $str
2012-06-13 12:11:06 +08:00
* @ param bool $cleanparams if set to true , array elements will be passed through { @ link clean_param ()}
2012-06-22 15:22:27 +02:00
* @ throws file_reference_exception if the $str does not have the expected format
2012-05-12 04:14:53 +08:00
* @ return array
*/
2012-06-13 12:11:06 +08:00
public static function unpack_reference ( $str , $cleanparams = false ) {
2012-06-20 11:48:42 +02:00
$decoded = base64_decode ( $str , true );
if ( $decoded === false ) {
throw new file_reference_exception ( null , $str , null , null , 'Invalid base64 format' );
}
$params = @ unserialize ( $decoded ); // hide E_NOTICE
if ( $params === false ) {
throw new file_reference_exception ( null , $decoded , null , null , 'Not an unserializeable value' );
}
2012-06-13 12:11:06 +08:00
if ( is_array ( $params ) && $cleanparams ) {
$params = array (
'component' => is_null ( $params [ 'component' ]) ? '' : clean_param ( $params [ 'component' ], PARAM_COMPONENT ),
'filearea' => is_null ( $params [ 'filearea' ]) ? '' : clean_param ( $params [ 'filearea' ], PARAM_AREA ),
'itemid' => is_null ( $params [ 'itemid' ]) ? 0 : clean_param ( $params [ 'itemid' ], PARAM_INT ),
'filename' => is_null ( $params [ 'filename' ]) ? null : clean_param ( $params [ 'filename' ], PARAM_FILE ),
'filepath' => is_null ( $params [ 'filepath' ]) ? null : clean_param ( $params [ 'filepath' ], PARAM_PATH ),
'contextid' => is_null ( $params [ 'contextid' ]) ? null : clean_param ( $params [ 'contextid' ], PARAM_INT )
);
}
return $params ;
2012-05-12 04:14:53 +08:00
}
/**
2012-06-22 15:22:27 +02:00
* Returns all aliases that refer to some stored_file via the given reference
*
* All repositories that provide access to a stored_file are expected to use
* { @ link self :: pack_reference ()} . This method can ' t be used if the given reference
* does not use this format or if you are looking for references to an external file
* ( for example it can ' t be used to search for all aliases that refer to a given
* Dropbox or Box . net file ) .
2012-05-12 04:14:53 +08:00
*
2012-05-31 14:18:13 +02:00
* Aliases in user draft areas are excluded from the returned list .
*
* @ param string $reference identification of the referenced file
* @ return array of stored_file indexed by its pathnamehash
2012-05-12 04:14:53 +08:00
*/
2012-05-31 14:18:13 +02:00
public function search_references ( $reference ) {
2012-05-12 04:14:53 +08:00
global $DB ;
2012-05-31 14:18:13 +02:00
if ( is_null ( $reference )) {
throw new coding_exception ( 'NULL is not a valid reference to an external file' );
}
2012-06-22 15:22:27 +02:00
// Give {@link self::unpack_reference()} a chance to throw exception if the
// reference is not in a valid format.
self :: unpack_reference ( $reference );
2012-05-31 14:18:13 +02:00
$referencehash = sha1 ( $reference );
2012-05-24 01:35:13 -04:00
$sql = " SELECT " . self :: instance_sql_fields ( 'f' , 'r' ) . "
2012-05-12 04:14:53 +08:00
FROM { files } f
2012-05-31 14:18:13 +02:00
JOIN { files_reference } r ON f . referencefileid = r . id
JOIN { repository_instances } ri ON r . repositoryid = ri . id
WHERE r . referencehash = ?
AND ( f . component <> ? OR f . filearea <> ? ) " ;
2012-05-12 04:14:53 +08:00
2012-05-31 14:18:13 +02:00
$rs = $DB -> get_recordset_sql ( $sql , array ( $referencehash , 'user' , 'draft' ));
2012-05-12 04:14:53 +08:00
$files = array ();
foreach ( $rs as $filerecord ) {
2012-05-31 14:18:13 +02:00
$files [ $filerecord -> pathnamehash ] = $this -> get_file_instance ( $filerecord );
2012-05-12 04:14:53 +08:00
}
return $files ;
}
/**
2012-06-22 15:22:27 +02:00
* Returns the number of aliases that refer to some stored_file via the given reference
*
* All repositories that provide access to a stored_file are expected to use
* { @ link self :: pack_reference ()} . This method can ' t be used if the given reference
* does not use this format or if you are looking for references to an external file
* ( for example it can ' t be used to count aliases that refer to a given Dropbox or
* Box . net file ) .
2012-05-12 04:14:53 +08:00
*
2012-05-31 14:18:13 +02:00
* Aliases in user draft areas are not counted .
*
* @ param string $reference identification of the referenced file
2012-05-12 04:14:53 +08:00
* @ return int
*/
2012-05-31 14:18:13 +02:00
public function search_references_count ( $reference ) {
2012-05-12 04:14:53 +08:00
global $DB ;
2012-05-31 14:18:13 +02:00
if ( is_null ( $reference )) {
throw new coding_exception ( 'NULL is not a valid reference to an external file' );
}
2012-06-22 15:22:27 +02:00
// Give {@link self::unpack_reference()} a chance to throw exception if the
// reference is not in a valid format.
self :: unpack_reference ( $reference );
2012-05-31 14:18:13 +02:00
$referencehash = sha1 ( $reference );
2012-05-12 04:14:53 +08:00
$sql = " SELECT COUNT(f.id)
FROM { files } f
2012-05-31 14:18:13 +02:00
JOIN { files_reference } r ON f . referencefileid = r . id
JOIN { repository_instances } ri ON r . repositoryid = ri . id
WHERE r . referencehash = ?
AND ( f . component <> ? OR f . filearea <> ? ) " ;
2012-05-12 04:14:53 +08:00
2012-06-22 15:22:27 +02:00
return ( int ) $DB -> count_records_sql ( $sql , array ( $referencehash , 'user' , 'draft' ));
2012-05-12 04:14:53 +08:00
}
/**
2012-05-31 14:18:13 +02:00
* Returns all aliases that link to the given stored_file
*
* Aliases in user draft areas are excluded from the returned list .
2012-05-12 04:14:53 +08:00
*
* @ param stored_file $storedfile
2012-05-31 14:18:13 +02:00
* @ return array of stored_file
2012-05-12 04:14:53 +08:00
*/
2012-05-31 14:18:13 +02:00
public function get_references_by_storedfile ( stored_file $storedfile ) {
2012-05-12 04:14:53 +08:00
global $DB ;
$params = array ();
$params [ 'contextid' ] = $storedfile -> get_contextid ();
$params [ 'component' ] = $storedfile -> get_component ();
$params [ 'filearea' ] = $storedfile -> get_filearea ();
$params [ 'itemid' ] = $storedfile -> get_itemid ();
$params [ 'filename' ] = $storedfile -> get_filename ();
$params [ 'filepath' ] = $storedfile -> get_filepath ();
2012-05-31 14:18:13 +02:00
return $this -> search_references ( self :: pack_reference ( $params ));
2012-05-12 04:14:53 +08:00
}
/**
2012-05-31 14:18:13 +02:00
* Returns the number of aliases that link to the given stored_file
*
* Aliases in user draft areas are not counted .
2012-05-12 04:14:53 +08:00
*
* @ param stored_file $storedfile
* @ return int
*/
2012-05-31 14:18:13 +02:00
public function get_references_count_by_storedfile ( stored_file $storedfile ) {
2012-05-12 04:14:53 +08:00
global $DB ;
$params = array ();
$params [ 'contextid' ] = $storedfile -> get_contextid ();
$params [ 'component' ] = $storedfile -> get_component ();
$params [ 'filearea' ] = $storedfile -> get_filearea ();
$params [ 'itemid' ] = $storedfile -> get_itemid ();
$params [ 'filename' ] = $storedfile -> get_filename ();
$params [ 'filepath' ] = $storedfile -> get_filepath ();
2012-05-31 14:18:13 +02:00
return $this -> search_references_count ( self :: pack_reference ( $params ));
2012-05-12 04:14:53 +08:00
}
2012-07-31 09:02:13 +08:00
/**
* Updates all files that are referencing this file with the new contenthash
* and filesize
*
* @ param stored_file $storedfile
*/
public function update_references_to_storedfile ( stored_file $storedfile ) {
2012-09-11 14:23:12 -07:00
global $CFG , $DB ;
2012-07-31 09:02:13 +08:00
$params = array ();
$params [ 'contextid' ] = $storedfile -> get_contextid ();
$params [ 'component' ] = $storedfile -> get_component ();
$params [ 'filearea' ] = $storedfile -> get_filearea ();
$params [ 'itemid' ] = $storedfile -> get_itemid ();
$params [ 'filename' ] = $storedfile -> get_filename ();
$params [ 'filepath' ] = $storedfile -> get_filepath ();
$reference = self :: pack_reference ( $params );
$referencehash = sha1 ( $reference );
$sql = " SELECT repositoryid, id FROM { files_reference}
WHERE referencehash = ? and reference = ? " ;
$rs = $DB -> get_recordset_sql ( $sql , array ( $referencehash , $reference ));
$now = time ();
foreach ( $rs as $record ) {
require_once ( $CFG -> dirroot . '/repository/lib.php' );
$repo = repository :: get_instance ( $record -> repositoryid );
$lifetime = $repo -> get_reference_file_lifetime ( $reference );
$this -> update_references ( $record -> id , $now , $lifetime ,
$storedfile -> get_contenthash (), $storedfile -> get_filesize (), 0 );
}
$rs -> close ();
}
2012-05-12 04:14:53 +08:00
/**
* Convert file alias to local file
*
2012-07-31 10:50:05 +08:00
* @ throws moodle_exception if file could not be downloaded
*
2012-05-12 04:14:53 +08:00
* @ param stored_file $storedfile a stored_file instances
2012-07-31 10:50:05 +08:00
* @ param int $maxbytes throw an exception if file size is bigger than $maxbytes ( 0 means no limit )
2012-05-16 14:08:37 +08:00
* @ return stored_file stored_file
2012-05-12 04:14:53 +08:00
*/
2012-07-31 10:50:05 +08:00
public function import_external_file ( stored_file $storedfile , $maxbytes = 0 ) {
2012-05-12 04:14:53 +08:00
global $CFG ;
2012-07-31 10:50:05 +08:00
$storedfile -> import_external_file_contents ( $maxbytes );
2012-05-16 14:08:37 +08:00
$storedfile -> delete_reference ();
return $storedfile ;
2012-05-12 04:14:53 +08:00
}
2012-05-21 13:30:41 +08:00
/**
* Return mimetype by given file pathname
*
2012-05-23 14:51:55 +08:00
* If file has a known extension , we return the mimetype based on extension .
* Otherwise ( when possible ) we try to get the mimetype from file contents .
2012-05-21 13:30:41 +08:00
*
2012-05-28 15:19:41 +08:00
* @ param string $pathname full path to the file
* @ param string $filename correct file name with extension , if omitted will be taken from $path
2012-05-21 13:30:41 +08:00
* @ return string
*/
2012-05-28 15:19:41 +08:00
public static function mimetype ( $pathname , $filename = null ) {
if ( empty ( $filename )) {
$filename = $pathname ;
}
$type = mimeinfo ( 'type' , $filename );
2012-05-23 14:51:55 +08:00
if ( $type === 'document/unknown' && class_exists ( 'finfo' ) && file_exists ( $pathname )) {
2012-05-21 13:30:41 +08:00
$finfo = new finfo ( FILEINFO_MIME_TYPE );
2012-05-23 14:51:55 +08:00
$type = mimeinfo_from_type ( 'type' , $finfo -> file ( $pathname ));
2012-05-21 13:30:41 +08:00
}
2012-05-23 14:51:55 +08:00
return $type ;
2012-05-21 13:30:41 +08:00
}
2008-07-31 22:15:30 +00:00
/**
* Cron cleanup job .
*/
public function cron () {
2009-12-23 01:24:17 +00:00
global $CFG , $DB ;
2010-07-03 13:37:13 +00:00
2010-08-23 07:33:02 +00:00
// find out all stale draft areas (older than 4 days) and purge them
// those are identified by time stamp of the /. root dir
mtrace ( 'Deleting old draft files... ' , '' );
$old = time () - 60 * 60 * 24 * 4 ;
$sql = " SELECT *
FROM { files }
WHERE component = 'user' AND filearea = 'draft' AND filepath = '/' AND filename = '.'
AND timecreated < : old " ;
$rs = $DB -> get_recordset_sql ( $sql , array ( 'old' => $old ));
foreach ( $rs as $dir ) {
$this -> delete_area_files ( $dir -> contextid , $dir -> component , $dir -> filearea , $dir -> itemid );
}
2011-01-03 17:23:47 +01:00
$rs -> close ();
2010-12-21 12:02:09 +01:00
mtrace ( 'done.' );
2010-07-03 13:37:13 +00:00
2012-04-24 15:14:09 +02:00
// remove orphaned preview files (that is files in the core preview filearea without
// the existing original file)
mtrace ( 'Deleting orphaned preview files... ' , '' );
$sql = " SELECT p.*
FROM { files } p
LEFT JOIN { files } o ON ( p . filename = o . contenthash )
WHERE p . contextid = ? AND p . component = 'core' AND p . filearea = 'preview' AND p . itemid = 0
2012-04-25 13:44:36 +02:00
AND o . id IS NULL " ;
2012-04-24 15:14:09 +02:00
$syscontext = context_system :: instance ();
$rs = $DB -> get_recordset_sql ( $sql , array ( $syscontext -> id ));
foreach ( $rs as $orphan ) {
2012-04-25 13:44:36 +02:00
$file = $this -> get_file_instance ( $orphan );
if ( ! $file -> is_directory ()) {
$file -> delete ();
}
2012-04-24 15:14:09 +02:00
}
$rs -> close ();
mtrace ( 'done.' );
2009-06-03 08:10:21 +00:00
// remove trash pool files once a day
// if you want to disable purging of trash put $CFG->fileslastcleanup=time(); into config.php
if ( empty ( $CFG -> fileslastcleanup ) or $CFG -> fileslastcleanup < time () - 60 * 60 * 24 ) {
require_once ( $CFG -> libdir . '/filelib.php' );
2009-12-23 01:24:17 +00:00
// Delete files that are associated with a context that no longer exists.
mtrace ( 'Cleaning up files from deleted contexts... ' , '' );
$sql = " SELECT DISTINCT f.contextid
FROM { files } f
LEFT OUTER JOIN { context } c ON f . contextid = c . id
WHERE c . id IS NULL " ;
2011-01-03 17:23:47 +01:00
$rs = $DB -> get_recordset_sql ( $sql );
if ( $rs -> valid ()) {
2009-12-23 01:24:17 +00:00
$fs = get_file_storage ();
foreach ( $rs as $ctx ) {
$fs -> delete_area_files ( $ctx -> contextid );
}
}
2011-01-03 17:23:47 +01:00
$rs -> close ();
2009-12-23 01:24:17 +00:00
mtrace ( 'done.' );
2009-06-03 08:10:21 +00:00
mtrace ( 'Deleting trash files... ' , '' );
fulldelete ( $this -> trashdir );
set_config ( 'fileslastcleanup' , time ());
mtrace ( 'done.' );
2008-07-31 22:15:30 +00:00
}
}
2012-05-24 01:35:13 -04:00
/**
* Get the sql formated fields for a file instance to be created from a
* { files } and { files_refernece } join .
*
* @ param string $filesprefix the table prefix for the { files } table
* @ param string $filesreferenceprefix the table prefix for the { files_reference } table
* @ return string the sql to go after a SELECT
*/
private static function instance_sql_fields ( $filesprefix , $filesreferenceprefix ) {
// Note, these fieldnames MUST NOT overlap between the two tables,
// else problems like MDL-33172 occur.
$filefields = array ( 'contenthash' , 'pathnamehash' , 'contextid' , 'component' , 'filearea' ,
'itemid' , 'filepath' , 'filename' , 'userid' , 'filesize' , 'mimetype' , 'status' , 'source' ,
2012-08-10 12:26:19 +08:00
'author' , 'license' , 'timecreated' , 'timemodified' , 'sortorder' , 'referencefileid' );
2012-05-24 01:35:13 -04:00
2012-08-10 12:26:19 +08:00
$referencefields = array ( 'repositoryid' => 'repositoryid' ,
'reference' => 'reference' ,
'lastsync' => 'referencelastsync' ,
'lifetime' => 'referencelifetime' );
2012-05-24 01:35:13 -04:00
// id is specifically named to prevent overlaping between the two tables.
$fields = array ();
$fields [] = $filesprefix . '.id AS id' ;
foreach ( $filefields as $field ) {
$fields [] = " { $filesprefix } . { $field } " ;
}
2012-08-10 12:26:19 +08:00
foreach ( $referencefields as $field => $alias ) {
$fields [] = " { $filesreferenceprefix } . { $field } AS { $alias } " ;
2012-05-24 01:35:13 -04:00
}
return implode ( ', ' , $fields );
}
2010-05-03 21:04:06 +00:00
2012-05-30 00:58:50 +02:00
/**
* Returns the id of the record in { files_reference } that matches the passed repositoryid and reference
*
* If the record already exists , its id is returned . If there is no such record yet ,
* new one is created ( using the lastsync and lifetime provided , too ) and its id is returned .
*
* @ param int $repositoryid
* @ param string $reference
* @ return int
*/
private function get_or_create_referencefileid ( $repositoryid , $reference , $lastsync = null , $lifetime = null ) {
global $DB ;
$id = $this -> get_referencefileid ( $repositoryid , $reference , IGNORE_MISSING );
if ( $id !== false ) {
// bah, that was easy
return $id ;
}
// no such record yet, create one
try {
$id = $DB -> insert_record ( 'files_reference' , array (
'repositoryid' => $repositoryid ,
'reference' => $reference ,
2012-05-31 10:27:09 +02:00
'referencehash' => sha1 ( $reference ),
2012-05-30 00:58:50 +02:00
'lastsync' => $lastsync ,
'lifetime' => $lifetime ));
} catch ( dml_exception $e ) {
// if inserting the new record failed, chances are that the race condition has just
// occured and the unique index did not allow to create the second record with the same
// repositoryid + reference combo
$id = $this -> get_referencefileid ( $repositoryid , $reference , MUST_EXIST );
}
return $id ;
}
/**
* Returns the id of the record in { files_reference } that matches the passed parameters
*
* Depending on the required strictness , false can be returned . The behaviour is consistent
* with standard DML methods .
*
* @ param int $repositoryid
* @ param string $reference
* @ param int $strictness either { @ link IGNORE_MISSING }, { @ link IGNORE_MULTIPLE } or { @ link MUST_EXIST }
* @ return int | bool
*/
private function get_referencefileid ( $repositoryid , $reference , $strictness ) {
global $DB ;
2012-05-31 14:18:13 +02:00
return $DB -> get_field ( 'files_reference' , 'id' ,
array ( 'repositoryid' => $repositoryid , 'referencehash' => sha1 ( $reference )), $strictness );
2012-05-30 00:58:50 +02:00
}
2012-07-31 09:02:13 +08:00
/**
* Updates a reference to the external resource and all files that use it
*
* This function is called after synchronisation of an external file and updates the
* contenthash , filesize and status of all files that reference this external file
* as well as time last synchronised and sync lifetime ( how long we don ' t need to call
* synchronisation for this reference ) .
*
* @ param int $referencefileid
* @ param int $lastsync
* @ param int $lifetime
* @ param string $contenthash
* @ param int $filesize
* @ param int $status 0 if ok or 666 if source is missing
*/
public function update_references ( $referencefileid , $lastsync , $lifetime , $contenthash , $filesize , $status ) {
global $DB ;
$referencefileid = clean_param ( $referencefileid , PARAM_INT );
$lastsync = clean_param ( $lastsync , PARAM_INT );
$lifetime = clean_param ( $lifetime , PARAM_INT );
validate_param ( $contenthash , PARAM_TEXT , NULL_NOT_ALLOWED );
$filesize = clean_param ( $filesize , PARAM_INT );
$status = clean_param ( $status , PARAM_INT );
$params = array ( 'contenthash' => $contenthash ,
'filesize' => $filesize ,
'status' => $status ,
'referencefileid' => $referencefileid ,
'lastsync' => $lastsync ,
'lifetime' => $lifetime );
$DB -> execute ( ' UPDATE { files } SET contenthash = : contenthash , filesize = : filesize ,
status = : status , referencelastsync = : lastsync , referencelifetime = : lifetime
WHERE referencefileid = : referencefileid ' , $params );
$data = array ( 'id' => $referencefileid , 'lastsync' => $lastsync , 'lifetime' => $lifetime );
$DB -> update_record ( 'files_reference' , ( object ) $data );
}
2012-05-30 00:58:50 +02:00
}