Skip to content

Instantly share code, notes, and snippets.

@Hineynu
Created September 12, 2010 23:17
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hineynu/576593 to your computer and use it in GitHub Desktop.
Save Hineynu/576593 to your computer and use it in GitHub Desktop.
<%@ Page language="c#" EnableViewState="true" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script language="C#" runat="server">
// Handle file uploads via XMLHttpRequest
bool fLog = false;
string sLogFileFolder = string.Empty;
void Page_Load(Object Src, EventArgs E )
{
BindData();
}
private void BindData()
{
#region User Configuration
// list of valid extensions, ex. new string[]{"jpeg", "xml", "bmp"}
string[] allowedExtensions = new string[]{};
// max file size in bytes
int sizeLimit = 6 * 1024 * 1024;
// where to save the uploaded files
string uploadDirectory = Server.MapPath("~/images/EL/");
// used to return the url of the uploaded file
string serverPathToWebApplicationRoot = Server.MapPath("..");
// logging, you may also browse to this page with "configcheck=1" as the querystring to verify everything is setup correctly on the server
fLog = false;
sLogFileFolder = Server.MapPath("..\\Logs\\");
#endregion User Configuration
if (fLog)
{
if(Request.QueryString["qqfile"] != null)
WriteToLog("Upload Using UploadHandlerXhr" + Environment.NewLine);
else if(Request.Files.Count > 0)
WriteToLog("Upload Using UploadHandlerForm" + Environment.NewLine);
else
WriteToLog("No Files Uploaded" + Environment.NewLine);
WriteToLog("Request.QueryString[\"qqfile\"]: " + Request.QueryString["qqfile"] + Environment.NewLine);
WriteToLog("Request.Files.Count: " + Request.Files.Count.ToString() + Environment.NewLine);
int loop1 = 0;
string[] arr1 = Request.Files.AllKeys;
for (loop1 = 0; loop1 < arr1.Length; loop1++)
{
WriteToLog("\tRequest.Files.KeyName: " + arr1[loop1] + Environment.NewLine);
WriteToLog("\tRequest.Files[" + loop1.ToString() + "].FileName: " + Request.Files[loop1].FileName + Environment.NewLine);
WriteToLog("\tRequest.Files[" + loop1.ToString() + "].ContentLength: " + Request.Files[loop1].ContentLength + Environment.NewLine);
WriteToLog("\tRequest.Files[" + loop1.ToString() + "].ContentType: " + Request.Files[loop1].ContentType + Environment.NewLine);
}
WriteToLog("Request.ContentLength: " + Request.ContentLength.ToString() + Environment.NewLine);
WriteToLog(Environment.NewLine);
}
if((Request.QueryString["configcheck"] != null) && (Request.QueryString["configcheck"] == "1"))
{
Response.Write("uploadDirectory:<br /><b>" + uploadDirectory + "</b><br />&nbsp;&nbsp;&nbsp;&nbsp;Directory.Exists:&nbsp;&nbsp;" + (System.IO.Directory.Exists(uploadDirectory)).ToString() + "<br />");
if (System.IO.Directory.Exists(uploadDirectory))
{
string sPath = uploadDirectory;
// http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/be3880f0-355e-41f6-a126-cddfd7b7a5aa
System.Security.AccessControl.DirectorySecurity DS = System.IO.Directory.GetAccessControl(sPath);
bool WriteAccess = false;
foreach (System.Security.AccessControl.FileSystemAccessRule Rule in DS.GetAccessRules(true,true,typeof(System.Security.Principal.NTAccount)))
{
if ((Rule.FileSystemRights & System.Security.AccessControl.FileSystemRights.Write) != 0)
{
WriteAccess = true;
}
}
Response.Write("&nbsp;&nbsp;&nbsp;&nbsp;WriteAccess:&nbsp;&nbsp;" + WriteAccess.ToString() + "<br /><br />");
}
Response.Write("serverPathToWebApplicationRoot:<br /><b>" + serverPathToWebApplicationRoot + "</b><br />&nbsp;&nbsp;&nbsp;&nbsp;Directory.Exists:&nbsp;&nbsp;" + (System.IO.Directory.Exists(serverPathToWebApplicationRoot)).ToString() + "<br />");
if (System.IO.Directory.Exists(serverPathToWebApplicationRoot))
{
string sPath = serverPathToWebApplicationRoot;
// http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/be3880f0-355e-41f6-a126-cddfd7b7a5aa
System.Security.AccessControl.DirectorySecurity DS = System.IO.Directory.GetAccessControl(sPath);
bool WriteAccess = false;
foreach (System.Security.AccessControl.FileSystemAccessRule Rule in DS.GetAccessRules(true,true,typeof(System.Security.Principal.NTAccount)))
{
if ((Rule.FileSystemRights & System.Security.AccessControl.FileSystemRights.Write) != 0)
{
WriteAccess = true;
}
}
Response.Write("&nbsp;&nbsp;&nbsp;&nbsp;WriteAccess (optional):&nbsp;&nbsp;" + WriteAccess.ToString() + "<br /><br />");
}
Response.Write("sLogFileFolder:<br /><b>" + sLogFileFolder + "</b><br />&nbsp;&nbsp;&nbsp;&nbsp;Directory.Exists:&nbsp;&nbsp;" + (System.IO.Directory.Exists(sLogFileFolder)).ToString() + "<br />");
if (System.IO.Directory.Exists(sLogFileFolder))
{
string sPath = sLogFileFolder;
// http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/be3880f0-355e-41f6-a126-cddfd7b7a5aa
System.Security.AccessControl.DirectorySecurity DS = System.IO.Directory.GetAccessControl(sPath);
bool WriteAccess = false;
foreach (System.Security.AccessControl.FileSystemAccessRule Rule in DS.GetAccessRules(true,true,typeof(System.Security.Principal.NTAccount)))
{
if ((Rule.FileSystemRights & System.Security.AccessControl.FileSystemRights.Write) != 0)
{
WriteAccess = true;
}
}
Response.Write("&nbsp;&nbsp;&nbsp;&nbsp;WriteAccess:&nbsp;&nbsp;" + WriteAccess.ToString() + "<br /><br />");
}
}
string[] result = handleUpload(uploadDirectory, allowedExtensions, sizeLimit, serverPathToWebApplicationRoot);
if (fLog)
{
string resultstring = string.Empty;
if(result.Length > 3) // {success:true,url:url_to_file}
resultstring = "{\"" + result[0] + "\",\"" + result[1] + "\",\"" + result[2] + "\",\"" + result[3] + "\"}";
else if(result.Length > 1)
resultstring = "{\"" + result[0] + "\",\"" + result[1] + "\"}";
WriteToLog("result: " + resultstring + Environment.NewLine);
WriteToLog(Environment.NewLine);
}
// to pass data through iframe you will need to encode all html tags
//htmlspecialchars(json_encode($result), ENT_NOQUOTES);
if(result.Length > 3) // {success:true,url:url_to_file}
Response.Write("{\"" + result[0] + "\",\"" + result[1] + "\",\"" + result[2] + "\",\"" + result[3].Replace("&","&amp;").Replace(">","&gt;").Replace("<","&lt;") + "\"}");
else if(result.Length > 1)
Response.Write("{\"" + result[0] + "\",\"" + result[1].Replace("&","&amp;").Replace(">","&gt;").Replace("<","&lt;") + "\"}");
}
// Returns array('success'=>true) or array('error'=>'error message')
public string[] handleUpload(string uploadDirectory, string[] allowedExtensions, int sizeLimit, string serverPathToWebApplicationRoot){
if (!uploadDirectory.EndsWith("\\"))
uploadDirectory = uploadDirectory + "\\";
if (System.IO.Directory.Exists(uploadDirectory))
{
string sPath = uploadDirectory;
// http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/be3880f0-355e-41f6-a126-cddfd7b7a5aa
System.Security.AccessControl.DirectorySecurity DS = System.IO.Directory.GetAccessControl(sPath);
bool WriteAccess = false;
foreach (System.Security.AccessControl.FileSystemAccessRule Rule in DS.GetAccessRules(true,true,typeof(System.Security.Principal.NTAccount)))
{
if ((Rule.FileSystemRights & System.Security.AccessControl.FileSystemRights.Write) != 0)
{
WriteAccess = true;
}
}
if(!WriteAccess) {
return new string[] {"error", "Server error. Upload directory isn't writable."};
}
int fileSize = 0;
string fileName = string.Empty;
bool fUploadHandlerXhr = false;
if (Request.QueryString["qqfile"] != null)
{
#region UploadHandlerXhr
fUploadHandlerXhr = true;
fileSize = Request.ContentLength;
fileName = Request.QueryString["qqfile"];
#endregion UploadHandlerXhr
}
else
{
#region UploadHandlerForm
if (Request.Files.Count == 0)
{
return new string[] { "error", "No files were uploaded." };
}
HttpPostedFile thisFile = Request.Files["qqfile"];
if (thisFile == null)
{
return new string[] { "error", "No files were uploaded." };
}
fileSize = thisFile.ContentLength;
fileName = thisFile.FileName;
#endregion UploadHandlerForm
}
//int fileSize = ;
if (fileSize == 0) {
return new string[] {"error", "File is empty"};
}
if (fileSize > sizeLimit) {
return new string[] {"error", "File is too large"};
}
//string pathinfo = ;
string FileName = fileName;
string Extension = System.IO.Path.GetExtension(fileName).Replace(".",string.Empty); // GetExtension includes the . in the extension: .gif
if(allowedExtensions.Length > 0)
{
// http://msdn.microsoft.com/en-us/library/bb352880.aspx only >= .net 3.5
//if(! allowedExtensions.Contains<String>(Extension))
bool fContainsExtension = false;
foreach(string str in allowedExtensions)
{
if(str == Extension)
fContainsExtension = true;
}
if(! fContainsExtension)
{
return new string[] {"error", "File has an invalid extension, it should be one of " + String.Join(",", allowedExtensions) + "."};
}
}
string sLocalPath = uploadDirectory + FileName;
if (fLog)
WriteToLog("sLocalPath:" + sLocalPath + ", File.Exists: " + (System.IO.File.Exists(sLocalPath)).ToString() + Environment.NewLine + Environment.NewLine);
if (!System.IO.File.Exists(sLocalPath))
{
if (fUploadHandlerXhr)
{
// http://forums.asp.net/p/55127/106552.aspx
FileStream newFile = new FileStream(sLocalPath, FileMode.Create); // Create a file to store the stream
byte[] body = Request.BinaryRead(Request.TotalBytes); // read the file into byte array
newFile.Write(body, 0, body.Length); // write to stream
newFile.Flush();
newFile.Close();
}
else // UploadHandlerForm
{
Request.Files["qqfile"].SaveAs(sLocalPath);
}
// ApplicationPath only returns the url after the domain name
// This replaces the server path to the web application root with the url for the application root
string URL_To_File = sLocalPath.Replace(serverPathToWebApplicationRoot, Request.Url.GetLeftPart(UriPartial.Authority) + Request.ApplicationPath).Replace("\\","/");
return new string[] { "success","true","url", URL_To_File };
} else {
return new string[] {"error", "Could not save uploaded file. The uploaded file is already on the server."};
}
} // if (System.IO.Directory.Exists(uploadDirectory))
return new string[] {"error", "Could not save uploaded file. The upload was cancelled, or server error encountered"};
}
public void WriteToLog(string message)
{
string DefaultPath = sLogFileFolder + "\\AjaxUploadLog.txt";
TextWriter output = System.IO.TextWriter.Null;
try
{
// Open log file for appending
output = File.AppendText(DefaultPath);
// Insert Entry
output.Write(message.Replace("<br />", Environment.NewLine));
}
catch { }
finally
{
// Close File
output.Close();
}
}
</script>
@SeanJA
Copy link

SeanJA commented Sep 14, 2010

What about handling the other type of upload too? Or is that in here without a comment?

@Hineynu
Copy link
Author

Hineynu commented Sep 14, 2010

Hi Sean, both types of uploads (UploadHandlerXhr and UploadHandlerForm) are handled in the above code. It detects which is used and saves the file either way. There are #region's for each, sorry if I didn't explain it in the comments. What else should be commented better? I'm glad to add explanations.

@SeanJA
Copy link

SeanJA commented Sep 14, 2010

Sorry, its just that I am unfamiliar with C# so I was looking for another // Handle file uploads ... comment to see how it was done the other way, I see it now though, thanks!

@Hineynu
Copy link
Author

Hineynu commented Sep 15, 2010

I just posted an update with improved logging (including a "configcheck=1" querystring mode for testing the setup on a server) and I moved all the variables required to setup the file on a server into a "User Configuration" section at the top. This update also returns json encoded ('<' as '<', '>' as '>', and '&' as '&').

@SeanJA
Copy link

SeanJA commented Sep 15, 2010

Does it work if I upload a file with funny charcters in the name? ÎOâÂ¥.jpeg What about if I have a file called 2001.taxes.doc?

@Hineynu
Copy link
Author

Hineynu commented Sep 15, 2010

Hi Sean, The code will handle UTF-8 file names (I just uploaded a file with the name you posted ÎOâÂ¥.gif). I haven't tested uploading a Word doc, but I've uploaded a .zip file to test non-image binary files and it worked (I was able to open the uploaded zip file). Or was your concern a file name with two dots in it?

The only known issue is the returned json doesn't parse correctly in the browser. When I overload the onComplete event, the responseJSON is an object but not an array and I haven't been able to figure out what is wrong. I attempted to get the returned json from the hidden iframe but its innerText is empty, so I am unable to check for upload errors in the browser.

@SeanJA
Copy link

SeanJA commented Sep 15, 2010

My first concern was the two dots (just to see if I was reading the code right) apparently I was not, I misread FileName.LastIndexOf(".") as FileName.IndexOf("."). Though it does surprise me that there isn't an easier way to do it, in php we have pathinfo('/some/path/lib.inc.php') which breaks it apart nicely.

The second one I was just worried that you were cheating and using string replace instead of using a json encoding function with your latest modification (in doing this test though... I found out that the php one will fail every time because json_encode doesn't work so well with UTF8 characters and the return value for the filename is null).

The responseJSON should be an object (see here: http://www.json.org/js.html ). You should be able to do this: alert(responseJSON.success) or alert(responseJSON.error) and in your case: alert(responseJSON.url) (or console.log() if you are using chrome, safari or firefox with firebug installed).

@Hineynu
Copy link
Author

Hineynu commented Sep 15, 2010

Thank you Sean for pointing out the error with the code for getting a file extension. There was a bug in my code (it added 1 to the LastIndexOf return value, then checked if it was > -1 and not > 0), and I took your suggestion to look into the .NET documentation and found System.IO.Path.GetExtension! I changed the code to use that.

You're right that I'm not encoding the json as I should. .net handles UTF-8 very well but did not add json encoding until .net 3.5 and I'm running on .net 2.0. I probably should use the code at http://www.west-wind.com/weblog/posts/114530.aspx and will add it when I am able.

@SasSam
Copy link

SasSam commented Nov 25, 2010

An idea for "max file size" section:
// max file size in bytes
// Get the official size limit from Server
int sizeLimit = Convert.ToInt32(ConfigurationManager.OpenMachineConfiguration().SectionGroups["system.web"].Sections["httpRuntime"].ElementInformation.Properties["maxRequestLength"].Value) * 1024;

  // Try to get the custom settings from web.config
  HttpRuntimeSection section = ConfigurationManager.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
  if (section != null)
  {
    sizeLimit = section.MaxRequestLength * 1024;
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment