PDA

View Full Version : FileUpload چطور کار میکنه؟



مهدی رحیم زاده
چهارشنبه 11 بهمن 1391, 09:20 صبح
با سلام خدمت تمامی دوستان و اساتید عزیز
من چند وقتیه دارم روی یک موضوعی کار می کنم . یکی از نتایجی که بنده به اون رسیدم اینه که مرورگر ها برای امنیت آدرس فایلی که از سمت کلاینت انتخاب میشه ، مثلا توی کنترل Fileupload رو نشون نمیدون و اون رو یک جایی نگهداری می کنن . حالا این موضوع مطرح میشه که این اطلاعات کجا ذخیره میشن که saveas کنترل fileupload اون رو میشناسه؟ یکی از دوستان میگفتن که این توی یکی از لایه های شبکه ذخیره میشه . میخواستم اگر دوستان اطلاعاتی تو این زمینه دارن و میتونن در اختیار بنده قرار بدن ، لطف کنن و بنده رو راهنمایی کنن
با تشکر

اوبالیت به بو
چهارشنبه 11 بهمن 1391, 10:01 صبح
درود بر شما

من فکر می کنم متدی یا پراپرتی درون FileUpload وجود داره که کپسوله سازی شده و وقتی درخواست به سرور ارسال میشه این پراپرتی مقدارش رو ارسال می کنه.

fakhravari
چهارشنبه 11 بهمن 1391, 13:15 عصر
[Designer("System.Web.UI.Design.WebControls.PreviewControlDes igner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), ControlValueProperty("FileBytes"), ValidationProperty("FileName")]
public class FileUpload : WebControl
{
// Fields
private static readonly IList<HttpPostedFile> _emptyFileCollection;
private IList<HttpPostedFile> _postedFiles;

// Methods
static FileUpload();
public FileUpload();
protected override void AddAttributesToRender(HtmlTextWriter writer);
protected internal override void OnPreRender(EventArgs e);
protected internal override void Render(HtmlTextWriter writer);
public void SaveAs(string filename);

// Properties
[DefaultValue(false), Browsable(true), WebCategory("Behavior"), WebSysDescription("FileUpload_AllowMultiple")]
public virtual bool AllowMultiple { get; set; }
[Browsable(false), Bindable(true), DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden)]
public byte[] FileBytes { get; }
[DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden), Browsable(false)]
public Stream FileContent { get; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden)]
public string FileName { get; }
[DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden), Browsable(false)]
public bool HasFile { get; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden)]
public bool HasFiles { get; }
[Browsable(false), DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden)]
public HttpPostedFile PostedFile { get; }
[DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden), Browsable(false)]
public IList<HttpPostedFile> PostedFiles { get; }
}


:متفکر:

public sealed class HttpPostedFile
{
// Fields
private string _contentType;
private string _filename;
private HttpInputStream _stream;

// Methods
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
internal HttpPostedFile(string filename, string contentType, HttpInputStream stream);
public void SaveAs(string filename);

// Properties
public int ContentLength { get; }
public string ContentType { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; }
public string FileName { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; }
public Stream InputStream { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; }
}


:متفکر:

meisam3322
چهارشنبه 11 بهمن 1391, 18:36 عصر
فخرآوری جان میتونی توضیح بدی که این کدها چیه ؟

fakhravari
چهارشنبه 11 بهمن 1391, 22:45 عصر
سلام
اطلاعات زیادی ندارم .
متد های داخلی فایل اپلود.
گزاشتم شاید به دوستان کمکی کرد.:لبخندساده:

Himalaya
پنج شنبه 12 بهمن 1391, 01:52 صبح
سلام
پراپرتی FileName از کلاس FileUpload رو ببینیم



/// A string that specifies the name of a file on a client to upload using the <see cref="T:System.Web.UI.WebControls.FileUpload"/>.
///
/// </returns>
[DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden)]

public string FileName
{
get
{
HttpPostedFile postedFile = this.PostedFile;
string str = string.Empty;
if (postedFile != null)
{
string fileName = postedFile.FileName;
try
{
str = Path.GetFileName(fileName);
}
catch
{
str = fileName;
}
}
return str;
}
}


همونطور که مشخصه تو بلاک try، نام و پسوند فایل از فیلد fileName بدست میاد و تو متغیر str قرار میگیره و برگشت داده میشه
پس مسیر کامل فایل انتخابی باید مربوط به پراپرتی FileName از کلاس HttpPostedFile باشه (نه FileName از کلاس FileUpload)
پراپرتی FileName از کلاس HttpPostedFile رو هم ببینیم


/// <summary>
/// Gets the fully qualified name of the file on the client.
///
/// </summary>
///
/// <returns>
/// The name of the client's file, including the directory path.
///
/// </returns>
public string FileName
{
get
{
return this._filename;
}
}

تو بخش summary و returns توضیحات لازم رو داده (Gets the fully qualified name of the file on the client) و (The name of the client's file, including the directory path)

واسه تست هم میشه از کد زیر استفاده کرد

Label1.Text = "FullPath: " + FileUpload1.PostedFile.FileName + "<br />Filename And Extension: " + FileUpload1.FileName;
اما اگه تو IE تست کردید و مسیر کامل توسط PostedFile.FileName برگشت داده شد و تو مثلا فایرفاکس این دستور فقط نام و پسوند رو برگشت داد، متن زیر رو هم بهش توجه داشته باشید


FileUpload1.PostedFile.FileName This actually gives you path of the uploaded file.

But in all the newer browsers (FF 3.6 series, Chrome, IE7+) this feature has been disabled due to security reasons. Any website should not need path of a file stored in client's systems because that gives the directory structure and may expose other important things to website owner.

So in your case, the above code returned only the file name.
و این

If you upload the file from Firefox browser, you will get [B]only the file name (Without any path) in the fileName variable (Say, AutoPlay.jpg)

But, if you upload the file from IE, you will get the File name along with the path in the user's computer from where the file is uploaded (Say, "C:\Users\shubho\Desktop\AutoPlay.png"). Note that, this path is not the path in the web server, this is the file path in client's PC.

مهدی رحیم زاده
پنج شنبه 12 بهمن 1391, 08:58 صبح
با سلام و تشکر از تمامی دوستانی که توی بحث شرکت کردن


FileUpload1.PostedFile.FileName This actually gives you path of the uploaded file.

But in all the newer browsers (FF 3.6 series, Chrome, IE7+) this feature has been disabled due to security reasons. Any website should not need path of a file stored in client's systems because that gives the directory structure and may expose other important things to website owner.

So in your case, the above code returned only the file name.
و این
If you upload the file from Firefox browser, you will get only the file name (Without any path) in the fileName variable (Say, AutoPlay.jpg)

But, if you upload the file from IE, you will get the File name along with the path in the user's computer from where the file is uploaded (Say, "C:\Users\shubho\Desktop\AutoPlay.png"). Note that, this path is not the path in the web server, this is the file path in client's PC
تمامی گفته های شما درسته . بنده هم توی عرایضم گفتم این موضوع رو که مرورگر های جدید به دلیل افزایش امنیت اطلاعات کلاینت ، فقط نام رو برمیگردونن و آدرس رو نمیدن . اما خوب اینجا یک نکته هست و اون هم اینه که بدون داشتن این آدرس عملا امکان بارگزاری فایل وجود نداره .پس قاعدتا باید این آدرس یک جایی ذخیره بشه که مثلا کنترل FileUpload میتونه اون رو بدست بیاره و فایل رو از اون آدرس آپلود کنه . حالا به عنوان مثال اگر شما بخوایید یک فایل رو توی FTP بارگذاری کنید به این آدرس نیاز دارید.یعنی آدرس اولیه فایل ، مطمئنا راهی باید باشه که این آدرس رو مثل کنترل Fileupload بدست آورد.

اوبالیت به بو
پنج شنبه 12 بهمن 1391, 10:20 صبح
با سلام و تشکر از تمامی دوستانی که توی بحث شرکت کردن

تمامی گفته های شما درسته . بنده هم توی عرایضم گفتم این موضوع رو که مرورگر های جدید به دلیل افزایش امنیت اطلاعات کلاینت ، فقط نام رو برمیگردونن و آدرس رو نمیدن . اما خوب اینجا یک نکته هست و اون هم اینه که بدون داشتن این آدرس عملا امکان بارگزاری فایل وجود نداره .پس قاعدتا باید این آدرس یک جایی ذخیره بشه که مثلا کنترل FileUpload میتونه اون رو بدست بیاره و فایل رو از اون آدرس آپلود کنه . حالا به عنوان مثال اگر شما بخوایید یک فایل رو توی FTP بارگذاری کنید به این آدرس نیاز دارید.یعنی آدرس اولیه فایل ، مطمئنا راهی باید باشه که این آدرس رو مثل کنترل Fileupload بدست آورد.

درود بر شما

خیلی موضوع خوبی هست، این پست رو چندین بار نوشتم و پاک کردم چون هر دفعه یک سوالی به ذهنم می رسید. اما اول با این سوال شروع کردم:

چرا باید راهی باشه تا این آدرس رو از FileUpload بدست آورد؟ چون صفحه به صورت HTML کد می شود.

من فکر می کنم این آدرس به همراه متد Post ارسال میشه و در اونجا کد میشه. آیا دسترسی به اون قسمت امکان پذیر هست؟

مهدی رحیم زاده
پنج شنبه 12 بهمن 1391, 11:06 صبح
لطف دارید دوست من

چرا باید راهی باشه تا این آدرس رو از FileUpload بدست آورد؟ چون صفحه به صورت HTML کد می شود.
بنده هم همین رو دارم میگم من FileUpload رو مثال زدم . منظورم این نبود که از اون بدست بیاریمش . منظورم این بود وقتی اون میتونه از مرورگر آدرس فایل رو بگیره و توی متد saveas ذخیره کنه پس راهی احتمالا باشه برای این که ما هم بتونیم بخونیمش.

من فکر می کنم این آدرس به همراه متد Post ارسال میشه و در اونجا کد میشه
بنده هم به همین موضوع دارم فک می کنم . ولی نمیدونم این در سطحی هست که Application ما بتونه به اون دسترسی داشته باشه یا نه!
با تشکر بسیار از دوستان بابت مشارکت توی بحث

Himalaya
پنج شنبه 12 بهمن 1391, 15:56 عصر
سلام

من فکر می کنم این آدرس به همراه متد Post ارسال میشه و در اونجا کد میشه. آیا دسترسی به اون قسمت امکان پذیر هست؟
منظورم این بود وقتی اون میتونه از مرورگر آدرس فایل رو بگیره و توی متد saveas ذخیره کنه پس راهی احتمالا باشه برای این که ما هم بتونیم بخونیمش. ببینید متد SaveAs برای ذخیره یه فایل روی سرور نیازی به داشتن آدرس فایل روی کامپیوتر کلاینت نداره. منظورم اینکه سمت سرور اصلا نیازی به این آدرس نیست.
FileUpload فایل انتخابی رو به صورت Stream برای سرور ارسال میکنه.
فرض کنید از متد زیر برای ذخیره فایل استفاده میکنیم
متد 1:


FileUpload1.SaveAs("SavePath");
کدی که اجرا میشه اینه (البته نمیخوام زیاد وارد جزئیات بشم)

public void SaveAs(string filename)
{
HttpPostedFile postedFile = this.PostedFile;
if (postedFile == null)
return;
postedFile.SaveAs(filename);
}


و اگه از متد زیر برای ذخیره فایل استفاده کنیم
متد 2:

FileUpload1.PostedFile.SaveAs("SavePath");
کدی که اجرا میشه اینه

public void SaveAs(string filename)
{
if (!Path.IsPathRooted(filename) && RuntimeConfig.GetConfig().HttpRuntime.RequireRoote dSaveAsPath)
{
throw new HttpException(SR.GetString("SaveAs_requires_rooted_path", new object[1]
{
(object) filename
}));
}
else
{
FileStream fileStream = new FileStream(filename, FileMode.Create);
try
{
this._stream.WriteTo((Stream) fileStream);
fileStream.Flush();
}
finally
{
fileStream.Close();
}
}
}

کاملا مشخصه که متد 1 تو پشت صحنه داره متد 2 رو برای ذخیره سازی صدا میکنه. یعنی هردوی اونا نهایتا به کد زیر میرسن

this._stream.WriteTo((Stream) fileStream);
fileStream فایلی هستش که رو سرور داره ایجاد میشه. (تو مسیری که به عنوان پارامتر ورودی تابع SaveAs دادیم)

FileStream fileStream = new FileStream(filename, FileMode.Create);
اما محتویات این فایل چیه؟ محتویاتش میشه this._stream. حالا خود این چیه؟ این دقیقا هموم استریمی هستش که فابل آپلود با متد Post برای سرور فرستاده (نه مسیر فایل روی کلاینت). کدای زیر رو ببینیم

/// <summary>
/// Gets a <see cref="T:System.IO.Stream"/> object that points to an uploaded file to prepare for reading the contents of the file.
///
/// </summary>
///
/// <returns>
/// A <see cref="T:System.IO.Stream"/> pointing to a file.
///
/// </returns>
public Stream InputStream
{
get
{
return (Stream) this._stream;
}
}

internal HttpPostedFile(string filename, string contentType, HttpInputStream stream)
{
this._filename = filename;
this._contentType = contentType;
this._stream = stream;
}
HttpInputStream تو ورودی سازنده کلاس HttpPostedFile میشه همون پراپرتی InputStream که از طریق FileUpload1.PostedFile.InputStream قابل دسترسی هستش.
توضیحاتش هم تو بخش summary اومده
Gets a System.IO.Stream object that points to an uploaded file to prepare for reading the contents of the file.
پس برای ذخیره سازی سمت سرور نیازی به مسیر فایل رو کامپیوتر کلاینت نیست.
اگه توسط Firebug، بعد از ارسال یه فایل به سرور، تب Post رو ببنیم، مشخصه که فایل آپلود فایل رو به صورت استریم میفرسته برای سرور و هیچ نیازی به مسیر کامل فایل نیست

Content-Disposition: form-data; name="FileUpload1"; filename="test.txt"
Content-Type: text/plain
salam
اون کلمه salam هم همون محتوای فایل انتخابی هستش (یه فایل تکست ساده آپ کردم تا محتوا مشخص باشه. اگه تصور میفرستادم اونوقت این محتوا میشد یه سری کاراکتر نامفهوم)

حالا شاید بگید خوب اینا سمت سرور بود. بالاخره خود فایل آپلود هم واسه تبدیل اون فایل انتخابی به استریم و فرستادنش برای سرور، نیاز به مسیر فایل داره دیگه. درسته داره ولی این به نظرم مربوط میشه به نحوه تعامل مرورگر با تگ زیر

<input type="file" name="FileUpload1" id="FileUpload1" />
و اصلا ارتباطی به کدای سمت سرور کنترل asp:FileUpload نداره که قرار باشه ما مسیر کامل فایل رو روی کامپیوتر کلاینت از طریق اون بدست بیاریم
ضمن اینکه همین IE هم که داره مسیر کامل رو میفرسته سمت سرور (هرچند که هیچ نیازی بهش نیست و همون اسم و پسوند کفایت میکنه) بعضی جاها ازش به عنوان باگ اسم بردن

مهدی رحیم زاده
پنج شنبه 12 بهمن 1391, 17:24 عصر
با سلام و تشکر بسیار از جناب karaji333 بابت توضیحات بسیار کاملتون
حالا یک سوال دیگه به همین فایل استریم چطور میشه دسترسی داشت؟
میشه اون رو به عنوان یک ورودی به یک وب سرویس ارسال کرد؟منظورم اینه که میشه با jquery اون رو به یک وب سرویس ارسال کرد تا یک سری پردازش ها روی اون انجام بشه؟

Himalaya
پنج شنبه 12 بهمن 1391, 18:12 عصر
سلام


میشه اون رو به عنوان یک ورودی به یک وب سرویس ارسال کرد؟منظورم اینه که میشه با
jquery اون رو به یک وب سرویس ارسال کرد تا یک سری پردازش ها روی اون انجام
بشه؟
اگه منظورتون بدون PostBack هستش تو حالت معمول نه. تاحالا زیاد شنیدیم که فایل آپلود تو UpdatePanel کار نمیکنه. کنجکاو نشدید بدونید چرا؟ دلیلش کد زیره

[DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden)]
[Browsable(false)]
public HttpPostedFile PostedFile
{
get
{
if (this.Page != null && this.Page.IsPostBack)
return this.Context.Request.Files[this.UniqueID];
else
return (HttpPostedFile) null;
}
}
یه قسمت از شرط مربوط به پست بک میشه که اگه نباشه null برگشت داده میشه و چیزی آپ نمیشه
گفتم تو حالت معمول نمیشه. ولی خوب میتونید از راههایی که بعضی پلاگینهای جاوا اسکریپت استفاده میکنن برای آپلود (بدون Postback) استفاده کنید. روشش هم به این صورت بود که
یه تگ iframe اضافه میکنن به صفحه و تگ فرم و بقیه تگهای لازم رو به صورت داینامیک توسط جاوا اسکریپت اضافه میکنن به اون و توسط این iframe فایل رو ارسال میکنن واسه یه HttpHandler و
تو اونجا عملیات برسی کردن پسوند و ContentType و حجم فایل رو انجام میدن و اگه همه چیز ok بود فایل رو ذخیره میکنن (توسط iframe میان عملیات PostBack رو شبیه سازی میکنن)

WebService که ازش اسم بردید نقشه همین HttpHandler رو میتونه برای شما بازی میکنه
مثلا یه نمونه Handler میتونه به صورت زیر باشه

using System;
using System.Web;
using System.IO;

public class Upload : IHttpHandler
{

public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Expires = -1;
try
{
HttpPostedFile file = context.Request.Files["Filedata"];
string targetDirectory = context.Server.MapPath(context.Request["folder"].ToString());
string renameFile = (new Random(DateTime.Now.Millisecond).Next(100, 1000)).ToString() + DateTime.Now.Millisecond.ToString() + file.FileName;
string targetFilePath = Path.Combine(targetDirectory, renameFile);
if (!Directory.Exists(targetDirectory))
Directory.CreateDirectory(targetDirectory);
if (File.Exists(targetFilePath))
{
context.Response.Write("0:Error");
}
else
{
file.SaveAs(targetFilePath);
context.Response.Write("1:" + renameFile);
}
context.Response.StatusCode = 200;
}
catch (Exception)
{
context.Response.Write("0:Error");
}
}

public bool IsReusable
{
get
{
return false;
}
}
}


و اسکریپتی هم که این هندلر رو فراخونی میکنه و بقیه تنظیمات رو انجام میده

$(document).ready(function () {
$("#filePhoto").fileUpload({
'uploader': '../Swf/uploader.swf',
'cancelImg': '../Photo/Other/CancelUp.png',
'buttonText': 'picture file',
'script': '../Upload.ashx',
'folder': '../UpFile/EditorImage',
'fileDesc': 'Image File',
'fileExt': '*.jpg;*.jpeg;*.gif;*.png',
'multi': false,
'auto': true,
'height': 22,
'width': 110,
'sizeLimit': 30720,
'onComplete': function (event, ID, fileObj, response, data) {
jsonParam = null;
$('#WinHiddenLayer').css({ 'visibility': 'visible' });
jsonParam = { "Num": 44, "Index": 1 };
AjaxProcess($.toJSON(jsonParam), handleMessage, handleError, false);
}
});
});
که اینجا از پلاگین uploadify.js استفاده شده و اضافه شدن اون iframe و بقیه تگ های لازم توسط این پلاگین خودکار انجام میشه

مهدی رحیم زاده
جمعه 13 بهمن 1391, 12:37 عصر
پس با توجه به گفته های شما ما اگر بخواییم فایلی رو روی اف تی پی آپلود کنیم ، می تونیم از این stream استفاده کنیم درسته؟

Himalaya
جمعه 13 بهمن 1391, 16:35 عصر
سلام



اگر بخواییم فایلی رو روی اف تی پی آپلود کنیم

من فقط در مورد fileupload توضیح دادم. حالا اینکه این کار شدنی هست یا نه رو باید خودتون تست کنید

مهدی رحیم زاده
شنبه 14 بهمن 1391, 17:52 عصر
با سلام خدمت دوستان عزیز
خوب هدف اصلی من از راه اندازی این تاپیک این بود که بتونیم یک فایل رو روی FTP از طریق وب فرم آپلود کنم . نکته اینجاست که برای آپلود فایل توی FTP ما نیاز داریم که آدرس فایل روی کلاینت رو هم داشته باشیم . بر اساس گفته های دوست عزیزمون جناب karaji333 و سایر دوستانی که توی این تاپیک توضیحات دادن و بررسی هایی که بنده انجام دادم ، فک میکنم عملا استفاده از این موضوع توی وب شاید نشدنی باشه! چون بر اساس گفته های دوستان این فایل Stream هم با پروتکل http داره سمت سرور ارسال میشه. پس عملا آپلود فایل با Ftp در وب فرم ها شاید نشدنی باشه.
دوستان اگر لطف کنن و بگن که گفته های بنده درسته یا نه ممنون میشم .
با تشکر

mehdi8400
شنبه 14 بهمن 1391, 21:58 عصر
سلام دوست عزیز

system.net در ویژوال استدیو را مطالعه کن به همه سئوالاتت پاسخ داده می شه . تو msdn کامل توضیح داده شده .

Himalaya
شنبه 14 بهمن 1391, 23:42 عصر
سلام.
یه نگاه به اینجا بنداز شاید مشکلت با این حل بشه (http://stackoverflow.com/questions/838584/upload-to-ftp-asp-net)
یا این


private bool UploadToFtp(HttpPostedFile fileToUpload)
{
try
{
const string uploadUrl = @"ftp://demo.myFtpServer.com/UploadFles";
var uploadFileName = fileToUpload.FileName;

var streamObj = fileToUpload.InputStream;
var buffer = new Byte[fileToUpload.ContentLength];
streamObj.Read(buffer, 0, buffer.Length);
streamObj.Close();
streamObj = null;

var ftpUrl = string.Format("{0}/{1}", uploadUrl, uploadFileName);
var requestObj = FtpWebRequest.Create(ftpUrl) as FtpWebRequest;
requestObj.Method = WebRequestMethods.Ftp.UploadFile;
requestObj.Credentials = new NetworkCredential("userid", "password");
var requestStream = requestObj.GetRequestStream();
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Flush();
requestStream.Close();
requestObj = null;
return true;
}
catch
{
return false;
}
}