Moodle 2.0 - how to create file (from string)

Moodle 2.0 - how to create file (from string)

by Łukasz Sanokowski -
Number of replies: 8

Hello

I am developing block called "block_mindmap". Block was working very well in Moodle 1.9.x. I am now migrating it to Moodle 2.0. I have a problem with creating file from string.

Code of my function is following:

function block_mindmap_create_file($filename){
global $CFG, $COURSE;
require_once($CFG->dirroot.'/lib/filelib.php');
require_once($CFG->dirroot.'/lib/datalib.php');

$context = get_context_instance(CONTEXT_COURSE, $COURSE->id);

$content = "somecontent";

//HERE IS OLD FUNCTION WHICH CREATES FILE
//$file = fopen($CFG->dataroot.'/'.$COURSE->id.'/'.$filename, "w");
//fwrite($file, $content);
//fclose($file);

$fs = get_file_storage();
$fileinfo = array(
'contextid' => $context->id, // ID of context
'component' => 'block_mindmap',     // usually = table name
'filearea' => 'maps',     // usually = table name
'itemid' => 0,               // usually = ID of row in table
'filepath' => '/path/',           // any path beginning and ending in /
'filename' => '$filename'); // any filename

$fs->create_file_from_string($fileinfo, $content);
}

When I invoke this function with uniqe $filename (diffrent from filename which was set on previous invoking) the function works propertly, I think. But I don't know where to find created file.
When I invoke this function with $filename equal two times in a row, i recieve error message:

Can not create file "829/block_mindmap/maps/0//path//mapY.mm"

So the file was created properly, because function create_file_from_string() can not override file.

I am not sure if I set parameters of $fileinfo array properly. I don't understand using $context in file API either. Notice double "/" in path to file around 'filepath' parameter.

The documentation of migrating code to Moodle 2.0 needs to be improved I think.

Can anybody help me to find created file, or improve my function?

Regards, Łukasz

Average of ratings: -
In reply to Łukasz Sanokowski

Re: Moodle 2.0 - how to create file (from string)

by Oleg Sychev -
Picture of Core developers Picture of Plugin developers
Why you need to create file form string? That's a rare thing to do.
In reply to Łukasz Sanokowski

Re: Moodle 2.0 - how to create file (from string)

by sam marshall -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

I agree there are totally lots of reasons to create files from strings...!

1) The context id is necessasry because your files are stored associated with a context. For example they could be associated with a course or with a block. In your case you are storing the files in the course context, which seems weird, since you're working on a block. Why not use the block context? Unless this is some kind of shared thing where there could be multiple blocks and they need to all have the same file.

2) Here is some code I wrote that you may be able to figure out another way to do what you're trying, but I'm not sure. Note that the comments etc will not make sense. Also the code is a bit weird in that it sometimes uses system context. Also the API has changed slightly since this was written (note 'component' field is missing from my code) and it doesn't run any more but I think that's just to do with extra parameters or something (sorry we are going to update this but haven't done it yet). Just hoping it might help.

/**
* Obtains a file info array for a document file (as distinct from user file).
* @param object $oucontent OU content object
* @param string $path Path within area (e.g. '/')
* @param string $name Filename
* @return object File info object
*/
function oucontent_get_documentfile_info($oucontent, $path, $name) {
$fileinfo = new stdClass;
$fileinfo->filearea = 'oucontent';
$fileinfo->itemid = $oucontent->id;
if ($oucontent->course) {
$cm = oucontent_get_cm($oucontent);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
} else {
$context = get_context_instance(CONTEXT_SYSTEM);
}
$fileinfo->contextid = $context->id;
$fileinfo->filepath = $path;
$fileinfo->filename = $name;
return $fileinfo;
}

/**
* Gets a file from its file info object.
* @param object $fileinfo File info object
* @return stored_file Actual file
* @throws moodle_exception If file does not exist
*/
function oucontent_get_file($fileinfo) {
$fs = get_file_storage();
$file = $fs->get_file($fileinfo->contextid, $fileinfo->filearea,
$fileinfo->itemid, $fileinfo->filepath, $fileinfo->filename);
if (!$file) {
throw new moodle_exception('fileerror', 'oucontent', '', '',
"{$fileinfo->contextid}, {$fileinfo->filearea}, {$fileinfo->itemid},{$fileinfo->filepath}{$fileinfo->filename}" );
}
return $file;
}

/**
* Checks if a file exists from its file info object.
* @param object $fileinfo File info object
* @return bool True if file exists
*/
function oucontent_file_exists($fileinfo) {
$fs = get_file_storage();
return $fs->file_exists($fileinfo->contextid, $fileinfo->filearea,
$fileinfo->itemid, $fileinfo->filepath, $fileinfo->filename);
}

/**
* Saves a file in the appropriate area.
* @param object $oucontent OU content object
* @param string $path Path within area (e.g. '/')
* @param string $name Filename
* @param string $content Content to save into file
*/
function oucontent_documentfile_save($oucontent, $path, $name, $content) {
$fs = get_file_storage();
$fs->create_file_from_string(oucontent_get_documentfile_info(
$oucontent, $path, $name), $content);
}

--sam

Average of ratings: Useful (1)
In reply to sam marshall

Re: Moodle 2.0 - how to create file (from string)

by Oleg Sychev -
Picture of Core developers Picture of Plugin developers

If you need to pass string to the external app, the file is a good way. But sometimes people create files to read them from PHP script, that is a case where phpstringstream code may be better. Writing this just in case it could help someone.

In reply to Oleg Sychev

Odp: Re: Moodle 2.0 - how to create file (from string)

by Łukasz Sanokowski -

Thank You for Your response. I do need  to create file from string because I pass this file to external application.

I changed my code in accordance with Your instructions.  Now code of my function is:


function block_mindmap_create_file($filename, $block_instance_id){
global $CFG, $COURSE, $USER;
require_once($CFG->dirroot.'/lib/filelib.php');
require_once($CFG->dirroot.'/lib/datalib.php');

$context = get_context_instance(CONTEXT_BLOCK, $block_instance_id);

$content = "some content";

//Old code which created file in Moodle 1.9.x
//$file = fopen($CFG->dataroot.'/'.$COURSE->id.'/'.$filename, "w");
//fwrite($file, $content);
//fclose($file);

$fs = get_file_storage();
$fileinfo = array(
'contextid' => $context->id, //
'component' => 'block_mindmap',     //
'filearea' => 'maps',     //
'itemid' => $USER->id,               // each user has his own mindmap
'filepath' => '/',           //
'filename' => 'map17.mm'); //

$fs->create_file_from_string($fileinfo, $content);

}

I think that file is created correctly, when I invoke this function first time with a single filename. When I invoke this function second time with the same filename I reveive error message (file exists and it can not be overriden):

Can not create file "5786/block_mindmap/maps/2///map17.mm"

More information about this error

Stack trace:
  • line 886 of /lib/filestorage/file_storage.php: stored_file_creation_exception thrown
  • line 53 of /blocks/mindmap/lib.php: call to file_storage->create_file_from_string()
  • line 31 of /blocks/mindmap/view.php: call to block_mindmap_create_file()

So i created hyperlink:

http://my.domain.pl/moodle2/pluginfile.php/5786/block_mindmap/maps/2///map17.mm

but when I go to page from this hyperlink i receive error:

Sorry, the requested file could not be found

More information about this error

Stack trace:
  • line 421 of /lib/setuplib.php: moodle_exception thrown
  • line 1474 of /lib/filelib.php: call to print_error()
  • line 732 of /pluginfile.php: call to send_file_not_found()

When i change $fileinfo->filepath variable to, for example '/folder/' and create file to times in a row (to receive error of overwriting) the error is:

Can not create file "5786/block_mindmap/maps/2//folder//map17.mm"

Please notice bolded double backslash in path above. System is forcing $fileinfo->filepath variable to be starting and ending with '/' character, so the path is weird.

 

Please, can somebody write simplest block example function which create file from string in Moodle 2.x file API?

I would like to continue my contribution of Moodle by developing and publishing subsequent applications, but I need to solve this problem first.

In reply to Łukasz Sanokowski

Re: Odp: Re: Moodle 2.0 - how to create file (from string)

by Anthony Borrow -
Picture of Core developers Picture of Plugin developers Picture of Testers

Have you had a chance to read Development:Using_the_file_API to see if that might help you. I've not done much with creating files from strings so I am not sure about how the 2.0 file api will handle it. Peace - Anthony

In reply to Anthony Borrow

Odp: Re: Odp: Re: Moodle 2.0 - how to create file (from string)

by Łukasz Sanokowski -

Hello

Maybe now somebody has a knowledge how to create file from string in Moodle 2 file API?

Regards

In reply to Łukasz Sanokowski

Re: Odp: Re: Odp: Re: Moodle 2.0 - how to create file (from string)

by David Upson -

I have run into this problem myself using the Certificate module. The File API documentation states under "Create File":

"Unlike with ordinary files, this method will not automatically overwrite an existing file. If you wish to overwrite a file, you must first get the file and (if it exists) delete it, and only then create it again."

http://docs.moodle.org/en/Development:Using_the_file_API

So, it appears that one needs to test whether the file already exists and if so then delete it before writing out the new file.

In reply to Łukasz Sanokowski

Re: Odp: Re: Odp: Re: Moodle 2.0 - how to create file (from string)

by Nick Boss -

Here's how to create a file whose contents will be a text string. This is the equivalent of the PHP function file_put_contents.

$fs = get_file_storage();
 
// Prepare file record object
$fileinfo = array(
'contextid' => $context->id, // ID of context
'component' => 'mod_mymodule', // usually = table name
'filearea' => 'myarea', // usually = table name
'itemid' => 0, // usually = ID of row in table
'filepath' => '/', // any path beginning and ending in /
'filename' => 'myfile.txt'); // any filename
 
// Create file containing text 'hello world'
$fs->create_file_from_string($fileinfo, 'hello world');
Average of ratings: Useful (1)