Restricting file types in the File Manager
I work as a developer for an EPiServer partner in the UK and also have the pleasure of running many of the CMS Developer training courses in the UK and Ireland. During these courses I am often asked questions that fall into one of two categories:
- A question that I’ve been asked several times previously;
- A question that has me stumped and needs a bit of research;
With that in mind I felt it would be a worthwhile exercise to try and make the answers and solutions to some of these questions available to the EPiServer community – so here goes!
This particular post relates to both a question I’ve been asked during a training course and a similar requirement on a recent EPiServer project I worked on.
The question I was asked was “is it possible to prevent certain file types from being uploaded into EPiServer’s File Manager?”. The client requirement was almost exactly the opposite – we needed to be able to specify which file types could be uploaded into a folder (i.e. Starting Point). I say the requirement was the opposite because in EPiServer it is possible to specify which types of files cannot be uploaded, not which file types can be uploaded.
Let’s deal with the question first. In short, in EPiServer it is very easy to restrict certain files from being uploaded, simply by altering the “illegalCharactersRegex” attribute on the “virtualPath” element in the EPiServer configuration file (episerver.config). The default regular expression is:
"%|&|\+|/COM[0-9]([/\.]|$)|/LPT[0-9]([/\.]|$)|/PRN([/\.]|$)|/CLOCK\$([/\.]|$)|/AUX([/\.]|$)|/NUL([/\.]|$)|/CON([/\.]|$)|/.+\.$|\.\."
To prevent additional file types from being uploaded you just need to add the extension to the regular expression. An example of preventing PDF files from being uploaded is:
"%|&|\+|/COM[0-9]([/\.]|$)|/LPT[0-9]([/\.]|$)|/PRN([/\.]|$)|/CLOCK\$([/\.]|$)|/AUX([/\.]|$)|/NUL([/\.]|$)|/CON([/\.]|$)|.pdf$ |/.+\.$|\.\."
More information can be found at http://world.episerver.com/Documentation/Items/Tech-Notes/EPiServer-CMS-6/EPiServer-CMS-60/Virtual-Path-Providers/.
This approach makes it possible to restrict file types from being uploaded, but imagine you wanted to ensure that only a handful of file types could be uploaded – this approach doesn’t help us because we would literally have to list every possible file type extension except for those we wanted to allow to be uploaded. This is where my client’s requirement becomes relevant – they wanted to ensure that only images could be uploaded to a particular folder i.e. Jpeg’s, Gif’s and PNG’s.
The solution
First of all we need somewhere to specify the file types i.e. extensions that are allowed for a particular starting point. We can achieve this by adding an attribute to the relevant starting point within the episerver.config file which contains a very simple regular expression, like so:
1: <add showInFileManager="true" virtualName="Images" virtualPath="~/Images/"
2: bypassAccessCheck="false" indexingServiceCatalog="Web" physicalPath="C:\EPiServer\VPP\AlloyTech-Custom\Images"
3: name="Images" type="EPiServer.Web.Hosting.VirtualPathVersioningProvider,EPiServer" allowedExtensions="jpg|jpeg|gif|png" />
Thankfully, EPiServer does not complain about adding attributes to the configuration that are not EPiServer specific. We now need a way of checking whether the file extension of the file being uploaded into our “Images” starting point has a file extension matching one of the options in our regular expression.
Within EPiServer there are a whole host of events that can be hooked into i.e. SavingPage, SavedPage, PublishingPage and relevant for this example UnifiedFileAdding and UnifiedFileMoving. These two events are raised when a file is added, or moved – these are the two places in which we need to check the type of file the user is attempting to add. We can register handlers for both of these events via a simple InitializationModule, like so:
1: using System;
2: using System.Configuration;
3: using System.Text.RegularExpressions;
4: using EPiServer.Configuration;
5: using EPiServer.Core;
6: using EPiServer.Framework;
7: using EPiServer.Framework.Initialization;
8: using EPiServer.Web.Hosting;
9:
10: namespace EPiServerLibrary.InitializationModules
11: {
12: [ModuleDependencyAttribute(typeof(EPiServer.Web.InitializationModule))]
13: public class RestrictFileTypes : IInitializableModule
14: {
15: Boolean _unifiedFileAddingEventAttached;
16: Boolean _unifiedFileMovingEventAttached;
17:
18: public void Initialize(InitializationEngine context)
19: {
20: //check whether event already attached before attempting to attach
21: if (!this._unifiedFileAddingEventAttached)
22: {
23: UnifiedDirectory.UnifiedFileAdding += new UnifiedDirectoryEventHandler(ValidateFileTypes);
24: this._unifiedFileAddingEventAttached = true;
25: }
26: if (!this._unifiedFileMovingEventAttached)
27: {
28: UnifiedFile.UnifiedFileMoving += new UnifiedFileEventHandler(ValidateFileTypes);
29: this._unifiedFileMovingEventAttached = true;
30: }
31: }
32:
33: private void ValidateFileTypes(UnifiedFile sender, UnifiedVirtualPathEventArgs e)
34: {
35: ValidateFileTypes(e, sender.Provider);
36: }
37:
38: private void ValidateFileTypes(UnifiedDirectory sender, UnifiedVirtualPathEventArgs e)
39: {
40: ValidateFileTypes(e, sender.Provider);
41: }
42:
43: private void ValidateFileTypes(UnifiedVirtualPathEventArgs e, VirtualPathUnifiedProvider provider)
44: {
45: //check whether the currentprovider i.e. the provider that the file is being uploaded to, has a property called allowedExtensions
46: PropertyInformation allowedExtensionsProperty = EPiServerSection.Instance.VirtualPathSettings.Providers[provider.ProviderName].ElementInformation.Properties["allowedExtensions"];
47: if (allowedExtensionsProperty != null)
48: {
49: //get the string value of the allowedExtensions i.e. the regular expression saved in the provider cofiguration element
50: string allowedExtensionsRegEx = allowedExtensionsProperty.DefaultValue.ToString();
51: Regex regex = new Regex(allowedExtensionsRegEx, RegexOptions.Compiled | RegexOptions.IgnoreCase);
52: //check whether the regular expression pattern matches the extension of the file being uploaded
53: if (!regex.IsMatch(e.NewVirtualPath.Substring(e.NewVirtualPath.LastIndexOf('.') + 1)))
54: {
55: e.Cancel = true;
56: e.Reason = String.Format(System.Globalization.CultureInfo.InvariantCulture, LanguageManager.Instance.TranslateFallback("/filemanager/illegalfiletype", "You cannot upload files of this type to this folder. Allowed file types are: {0}."), allowedExtensionsRegEx.Replace("|",", "));
57: }
58: }
59: }
60:
61: public void Preload(string[] parameters)
62: {
63:
64: }
65:
66: public void Uninitialize(InitializationEngine context)
67: {
68: //tidy up, detatch event handlers
69: if (this._unifiedFileAddingEventAttached)
70: {
71: UnifiedDirectory.UnifiedFileAdding -= ValidateFileTypes;
72: this._unifiedFileAddingEventAttached = false;
73: }
74: if (this._unifiedFileMovingEventAttached)
75: {
76: UnifiedFile.UnifiedFileMoving -= ValidateFileTypes;
77: this._unifiedFileMovingEventAttached = false;
78: }
79: }
80: }
81: }
Note, that what we are doing here within the main body is to check whether the “allowedExtensions” attribute exists for the current starting point i.e. the starting point that the user is uploading a file to, and if it does we are checking whether the extension of the file being uploaded matches an entry in the regular expression. If the regular expression is not matched it means that the type of file being uploaded is not one that we have specified as being “allowed” – in which case we can cancel the event and return a reason.
The end result is a starting point that only particular file types can be uploaded to. If the editor attempts to upload a file that does not match one of the entries in our regular expression they will be presented with the error message shown below.
If you would like to use this code, either copy and paste, or, download the following Zip file and deploy the assembly to the bin folder of your EPiServer project.
For now I have only tested this against CMS 6 R2.
Comments