diff --git a/lib/filelib.php b/lib/filelib.php
index 60560e3455e..cbd218576b1 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -928,7 +928,7 @@ function file_remove_editor_orphaned_files($editor) {
// Find those draft files included in the text, and generate their hashes.
$context = context_user::instance($USER->id);
$baseurl = $CFG->wwwroot . '/draftfile.php/' . $context->id . '/user/draft/' . $editor['itemid'] . '/';
- $pattern = "/" . preg_quote($baseurl, '/') . "(.+?)[\?\"']/";
+ $pattern = "/" . preg_quote($baseurl, '/') . "(.+?)[\?\"'<>\s:\\\\]/";
preg_match_all($pattern, $editor['text'], $matches);
$usedfilehashes = [];
foreach ($matches[1] as $matchedfilename) {
diff --git a/lib/tests/filelib_test.php b/lib/tests/filelib_test.php
index 4fd35c47d1e..2cd8159526c 100644
--- a/lib/tests/filelib_test.php
+++ b/lib/tests/filelib_test.php
@@ -1725,25 +1725,30 @@ EOF;
$filerecord['filename'] = 'file 3.png';
self::create_draft_file($filerecord);
+ $filerecord['filename'] = 'file4.png';
+ self::create_draft_file($filerecord);
+
// Confirm the user drafts area lists 3 files.
$fs = get_file_storage();
$usercontext = \context_user::instance($USER->id);
$draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'itemid', 0);
- $this->assertCount(3, $draftfiles);
+ $this->assertCount(4, $draftfiles);
// Now, spoof some editor text content, referencing 2 of the files; one requiring name encoding, one not.
$editor = [
'itemid' => $draftitemid,
- 'text' => '
-
-
'
+ 'text' => "
+
wwwroot}/draftfile.php/{$usercontext->id}/user/draft/{$draftitemid}/file%203.png\" alt=\"\">
+
wwwroot}/draftfile.php/{$usercontext->id}/user/draft/{$draftitemid}/file1.png\" alt=\"\">
+ {$CFG->wwwroot}/draftfile.php/{$usercontext->id}/user/draft/{$draftitemid}/file4.png"
];
// Run the remove orphaned drafts function and confirm that only the referenced files remain in the user drafts.
- $expected = ['file1.png', 'file 3.png']; // The drafts we expect will not be removed (are referenced in the online text).
+ // The drafts we expect will not be removed (are referenced in the online text).
+ $expected = ['file1.png', 'file 3.png', 'file4.png'];
file_remove_editor_orphaned_files($editor);
$draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'itemid', 0);
- $this->assertCount(2, $draftfiles);
+ $this->assertCount(3, $draftfiles);
foreach ($draftfiles as $file) {
$this->assertContains($file->get_filename(), $expected);
}