-
-
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 /> Directory.Exists: " + (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(" WriteAccess: " + WriteAccess.ToString() + "<br /><br />"); | |
} | |
Response.Write("serverPathToWebApplicationRoot:<br /><b>" + serverPathToWebApplicationRoot + "</b><br /> Directory.Exists: " + (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(" WriteAccess (optional): " + WriteAccess.ToString() + "<br /><br />"); | |
} | |
Response.Write("sLogFileFolder:<br /><b>" + sLogFileFolder + "</b><br /> Directory.Exists: " + (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(" WriteAccess: " + 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("&","&").Replace(">",">").Replace("<","<") + "\"}"); | |
else if(result.Length > 1) | |
Response.Write("{\"" + result[0] + "\",\"" + result[1].Replace("&","&").Replace(">",">").Replace("<","<") + "\"}"); | |
} | |
// 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> |
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.
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!
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 '&').
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
?
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.
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).
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.
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;
}
What about handling the other type of upload too? Or is that in here without a comment?