الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

كل ما تحتاجه لعرض الصور من قاعدة البيانات

بدأه Robatic في 4 فبراير 2010 · 6 رد · 7,287 مشاهدة · في ASP.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله وبركاته

أعزائي نظرا لتكرار الأسئلة المتعلقة بتخزين وإسترجاع الصور من قاعدة البيانات، قمت بكتابة هذا الموضوع (وأنا متأكد أن غيري قد وضح العملية مسبقا) لمحاولة محو أي تسائل أو غموض. قبل أن نبداء العملية دعونا نراجع بعض المفاهيم البدائية في تقنية أو ميكانيكية الويب بشكل عام.

أولا : Request & Response

عندما يقوم الزائر بإدخال عنوان لموقع ما أو عندما تقوم بالضغط على زر معين أو رابط معين، يقوم المتصفح بإرسال طلب (Request) إلى الخادم الذي يستضيف الموقع. بعد ذلك يقوم تطبيق الويب سواء كان ASP أو ASP.NET أو JSP أو PHP بمعاينة هذا الطلب ويبداء بإرسال الإستجابة Response لك (الزائر) وهي غالبا تكون على شاكلة HTML وهذا السبب الذي يجعلك تتصفح مواقع دون أن تحتاج لتتنصيب آلة إفتراضية (Virtual Machine) متطابقة مع اللغة التي أستخدمت لبناء هذه المواقع.بالنسبة لي ASP.NET يمكنك كتابة الـ Response بالشكل الذي تراه مناسبا لك ، فعلى سبيل المثال يمكنك إنشاء صفحة وفي حدث الـ Page_Load أكتب الكود التالي :

protected void Page_Load(object source, EventArgs e) {
	Response.Write("أهلا بك في موقعي");
}

نلاحظ أنه عندما يتم طلب على الصفحة المذكورة فوق سيكون الرد دائما هو عبارة "أهلا بك في موقعي"، بغض النظر عن كيفية عملية الطلب، هل هي عن طريق رابط أو عن Form أو ما إلى ذلك. دعونا نأخذ مثالا أكثر تعقيدا وهو عبارة عن عرض محتويات جدول مكون من حقلين ID و Name عن طريق إستخدام فقط الـ Response.Write:

protected void Page_Load(object source, EventArgs e) {
	DataTable dt = new DataTable();
	dt.Columns.Add("ID", typeof(string));
	dt.Columns.Add("Name", typeof(string));

	for(int i = 1; i <= 10; i++) 
	{
		DataRow newRow = dt.NewRow();
		newRow["ID"] = i;
		newRow["Name"] = "Name " + i;

		dt.Rows.Add(newRow);
	}

	// Here we will write our response without using GridView, ListView ... etc

	Response.Write("<table cellspacing='0' cellpadding='5' border='1' width='200px' style='margin: 0 auto;'>");
	Response.Write("<tr><td>ID</td><td>Name</td></tr>");

	foreach(DataRow row in dt.Rows)
		Response.Write(string.Format("<tr><td>{0}</td><td>{1}</td></tr>", row["ID"], row["Name"]));

	Response.Write("</table>");
}

لاحظوا أننا قمنا بتحديد شكل الرد عن طريق كتابة الـ HTML Tags المناسبة ويمكنك فعل ما تريد هنا والإحتمالات لا حصر لها، يمكنك أيضا كتابة محتوى ملف خارجي (موجود في نفس الخادم الذي يحوي تطبيق الويب). ولكن ماذا عن الصور ؟

ثانيا : كيفية عرض الصور في المواقع الإلكترونية بشكل عام

بشكل عام لعرض صورة ما في موقع إلكتروني معين نقوم بإستخدما الـ IMG Tag حيث أنه يحوي على Attribute خاص بإسم ملف الصورة المراد عرضها وهو src، فلنفرض أن هناك مجلد اسمه media ويحوي بداخله صورة باسم x.jpg، لكي نعرضها نكتب الـ HTML التالي

<img src="media/x.jpg" />

ولكن ماذا لو كانت الصورة مخزنة في قاعدة بينات أو في ملف XML (تخزين صورة داخل ملف XML ليس مستحيلا ولكنه لا يعد ممارسة جيدة) ؟

ثالثا : كيفية تخزين صورة داخل قاعدة بيانات

تخزين صورة داخل قاعدة بيانات ليس أمرا عسيرا كما يبدوا، كل ما عليك فعله هو تحديد نوع البيانات المناسب للحقل الذي سيحوي الصورة وهذا يختلف على حسب قاعدة البيانات، ففي MS SQL Server نوع الحقل هو image أو varbinary أما في Oracle و MySql هو blob بالنسبة للـ MS Access وغيرها لن أتطرق لها ولكن أود أن أشير إلى أن المبداء ينطبق على الجميع. بالنسبة للـ .NET لتخزين صورة في قاعدة البيانات يجب أولا تحويل الصورة إلى byte[] وهي مصفوفة من نوع byte ومن ثم إرسال المصفوفة أو إدخالها في جملة الـ INSERT، دعونا نفرض أن لدينا جدول باسم images وبداخلة حقلين id و image_content حيث أن الحقل image_content من نوع image وقاعدة البيانات هي MS SQL Server وأن هناك FileUpload Control باسم uploader، سيكون الكود كالتالي:

protected void InsertImageToDatabase() {
	if(uploader.HasFile) {
		using(SqlConnection con = new SqlConnectionString("your connection string")) {
			SqlCommand cmd = new SqlCommand("insert into images(image_content) values(@image_content)", con);
			cmd.Parameters.AddWithValue("image_content", uploader.FileBytes);

			con.Open();
			cmd.ExecuteNonQuery();
		}
	}
}

الكود السابق واضح ومباشر جدا.

رابعا : كيفية عرض الصور من قاعدة البيانات

لعمل ذلك يجب علينا الإستفادة مما تعلمناه في النقطة الأولى والثانية، في النقطة الأولى رأينا كيف يمكننا إستخدام Response.Write لتشكيل الرد من الخادم على ما نريد. سنقوم بنفس المبداْ ولكن بدلا من أن نستخدم Response.Write سوف نستخدم Response.BinaryWrite حيث أنها تقوم بكتابة بيانات ثنائية (byte) - هل تتذكر نوع البيانات التي حولنا الصورة إليها في النقطة الثالثة - ولكن قبل ذلك يجب علينا أن نعرف أن هناك في عالم الويب شيء اسمة Content Type وهو ما يحدد نوع البيانات للصفحة سواء كانت مجرد نص أو صورة أو ملف Excel أو ما إلى ذلك (لمزيد من المعلومات إذهب إلى google.com وقم بالبحث عن الموضوع http MIME). في النقطة الثانية رأينا كيفية عرض الصورة من ملف بإستخدام الـ IMG Tag، سوف نقوم بنفس الطريقة ولكن بدل من أن يحوي الـ src Attribute مسار ملف الصورة سوف يحوي مسار صفحة aspx ملصقا بها متغير =id? ومن ثم الرقم الخاص بالصورة والذي هو عبارة عن مفتاح أساسي (Primary Key) بحيث عن طريقة سنقوم بإستخلاص الصورة من قاعدة البيانات ومن ثم كتابتها في الصفحة بإستخدام Response.BinaryWrite. بالنسبة للـ =id? الذي تم إلصاقة في مصار صفحة aspx يسمة بـ Query String وهي عبارة عن بيانات إضافية يمكن إرسالها مع طلب (Request) صفحة معينة، كما هو الحال هنا، لاحظ في شريط العنوان في المتصفح الخاص بك وأنت تقراء هذا الموضوع هناك في آخر العنوان يوجد =showtopic? ومن ثم رقم معين، هذا الرقم هو الـ ID الخاص بهذا الموضوع حيث ان هذه الصفحة التي انت فيها الآن تأخذ هذا الرقم ثم تستعلم قاعدة البيانات ومن ثم تأتي بهذا الموضوع وكافة الردود المندرجة تحته. دعونا نستخدم نفس السيناريو الموجود في النقطة الثالثة ولكن هذه المرة سوف نقوم بعرض الصور:

كود الصفحة getimage.aspx والتي ستقوم بكتابة الصورة من قاعدة البيانات

protected void Page_Load(object source, EventArgs e) {

	// Check if 'id' is provided with the query string

	if(Request["id"] == null) return;

	using(SqlConnection con = new SqlConnection("your connection string")) {

		// fetching from database

		SqlCommand cmd = new SqlCommand("select image_content from images where id=@id", con);
		cmd.Parameters.AddWithValue("id", Request["id"]);

		con.Open();
		// Remeber to cast the data to byte[]

		byte[] image_buffer = (byte[])cmd.ExecuteScalar();

		// writing the image into the response

		Response.Clear();

		// setting the appropriate content type

		Resonse.ContentType = "image/pjpeg";

		// actual writing

		Response.BinaryWrite(image_buffer);

		// fluah the underlaying io stream

		Response.Flush();

		// have a nice day :>
	}
}

كود عرض الصور

<asp:GridView ID="imageGridView" runat="server" DataSourceID="imageDataSource"  AutoGenerateColumns="false">
	<Columns>
		<asp:TemplateField>
			<ItemTemplate>
				<img src='getimage.aspx?id=<%# Eval("id")' />
			</ItemTemplae>
		</asp:TemplateField>
	</Columns>
</asp:GridView>

<asp:SqlDataSource ID="imageDataSource" runat="server" ConnectionString="your connection string"
	SelectCommand="select id from images" />

خامسا: أبدا لا تأخذ مدخلات من المستخدم بشكل مسلم

في الواقع نلاحظ أن مدخلات المستخدم تلعب دورا كبير في أكثر الإختراقات المعروفة في عالم الويب ولكنني لن أتطرق إلى هذا حيث أنه خارج نطاق هذا الموضوع. ما يهمنا هنا هو تحديد الحجم الأقصى للصورة المراد رفعها وأن الملف الذي سيتم رفعة هو صورة وليس شيئا آخر. بالنسبة لحجم الصورة فهناك حد أقصى إفتراضي وهو 4MB وهذا هو سبب الـ Exception الذي يظهر لك في حالة رفع ملف أكثر من 4MB. يمكنك تغيير القيمة الإفتراضية عن طريق إدخال التالي في ملف web.config :

<system.web>
	.
	.
	.


	<httpRuntime maxRequestLength=[number in KB] />

	.
	.
	.
</system.web>

على كل حال يمكن فحص حجم الملف عن طريق إستخدام CustomValidator وذلك عن طريق ربطه بحدث في الـ Server من خلالة تقوم بفحص الـ ContentLength للملف المرفق في الـ FileUpload. اما بالنسبة للتأكد من الملف المراد رفعة هو عبارة عن صورة فقط فهناك طريقتين، الأولى إستخدام RegularExpressionValidator حيث أن الخاصية ValidationExpression ستكون بالشكل التالي

"^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))(.jpg|.JPG|.gif|.GIF)$" // you can add other extensions as well

والطريقة الثانية هي عبارة عن إستخدام CustomValidator بحيث يتم ربطة بحدث في الـ server من خلالة تقوم بفحص إمتداد اسم الملف الموجود في الـ FileUpload أو فحص الـ ContentType .

في المرفقات يوجد مشروع كامل يقوم برفع صورة وتخزينها بأبعادها الأصلية وأيضا يأخذ نسخة مصغرة منها بحجم 100 * 100 وذلك حتى يسهل ويخف عرضها وأيضا يتأكد من حجمها وأنها فقط صورة.

أتمنى أن أكون قد أصبت ولم أنسى شيئا وأسأل الله القدير أن يجعل هذا الشرح نافع غير وأن يوفق الجميع

Images.zip

2
#2

يعطيك العافيه اخويRobatic

ماقصرت شرح طيب وانا استفدت منه شخصياً

جزاك الله خير

ولكن اريد مساعدتك في القريد فيو اللي عندي

اعرض فيها الصور بشكل سليم ولكن اريد اضافة رابط على الصور بحيث اذا تم الضغط عليه يحوله الى صفحة iamglink.aspx مع حقل id للصوره

مثل الكود اللي عرضته انت لكن ماقدرتن اطبقه على القريد فيو اللي عندي

ياليت مساعدتك

وهذا كود العرض في القريد فيو عندي وشغال تمام لكن اريد اضيف اللي ذكرته لك

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="0">
                        <Columns>
                            <asp:TemplateField ShowHeader="False">
                                <EditItemTemplate>
                                    <asp:TextBox ID="TextBox1" runat="server" Text='<%# Eval("pic") %>'></asp:TextBox>
                                </EditItemTemplate>
                                <ItemTemplate>
                                    <asp:Image ID="Image1" runat="server" ImageUrl='<%# Eval("pic") %>' />
                                </ItemTemplate>
                                <ControlStyle Height="90px" Width="90px" />
                            </asp:TemplateField>
                        </Columns>
                    </asp:GridView>
#3

جهد رائع من رجل رائع ... جزاك الله كل خير أستاذي العزيز وأخي الكريم Robatic... كفيت ووفيت ... وإن شاء الله في ميزان حسناتك

ASP.NET Team Leader

moh_kin_mah@hotmail.com

--------------------------------

لو أعجبك أي من مشاركاتي ... برجاء قم بتقييم المشاركة عبر الأزرار الموجودة أسفل يسار كل مشاركة

#4

استفدت كتييير

جزاك الله خيرا

#5

منتظر ردك اخوي Robatic

#6

السلام عليكم ورحمة الله وبركاته

أولا أود أن أشكر الجميع على مرورهم الكريم

ثانيا بالنسبة لأخي العزيز / ضاري، أنا متأسف جدا على تأخري في الرد وأرجو منك العذر والسموحة

ألاحظ من الكود الي عندك في الـ GridView المعروضة في ردك إنه الصورة مخزنه في قاعدة البيانات على شكل رابط أو عنوان (path) وليس على شكل byte كما هو الحال في هذا الموضوع، إذا كان توقعي صحيح أكمل قراءة الرد ولا عليك أمر، أما إذا كان توقعي خاطيء يا ليت ترد عليا. المهم إذا الصورة كانت فعلا مخزنه على شكل عنوان في قاعدة البيانات فنحتاج نضيف صفحة لعرض الصورة كما أشرت والتي تحمل اسم imagelink.aspx وراح يكون الكود في حدث الـ Page_Load كالتالي :

protected void Page_Load(object source, EventArgs e) {
	if(Request["id"] != null) {
		using(SqlConnection con = new SqlConnection("your_connection_string")) {
			SqlCommand cmd = new SqlCommand("select pic from picture_table where id=@id", con) // change table name and column names to fit your table

			con.Open();
			string imagePath = cmd.ExecuteScalar();

			Response.Write(string.Format("<img border='0' src='{0}' />", imagePath));
		}
	}
}

وراح يكون التعديل في الـ GridView الموجوده في ردك في خانت الـ ItemTemplate بسيط جدا وهو عبارة عن وضع الـ asp:Image داخل رابط Anchor بحيث أن الرابط يشير إلى صفحة imagelink.aspx ملحوقا بالـ id الخاص بالصورة المراد عارضها، كما هو موضح في الكود التالي :

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="0">
        <Columns>
                 <asp:TemplateField ShowHeader="False">
                                <EditItemTemplate>
                                    <asp:TextBox ID="TextBox1" runat="server" Text='<%# Eval("pic") %>'></asp:TextBox>
                                </EditItemTemplate>
                                <ItemTemplate>
					<a href='imagelink.aspx?id=<%# Eval("id") %>'>
	                                    <asp:Image ID="Image1" runat="server" ImageUrl='<%# Eval("pic") %>' />
					</a>
                                </ItemTemplate>
                	 <ControlStyle Height="90px" Width="90px" />
        	 </asp:TemplateField>
	</Columns>
</asp:GridView>

أتمنى للجميع التوفيق والنجاح

#7

جزاك الله خير وجعله الله في ميزان حسناتك ورزق من حيث لاتدري ورحم والديك واعانك على اخرتك ودنياك ورزقك الجنة بلا حساب

ويعطيك العافيه

الحل فقط هو وضع هذا الكود في ال <ItemTemplate>

    <a href='imagelink.aspx?id=<%# Eval("id") %>'>

ومع اني كنت في محاولاتي اضع نفس الكود في نفس المكان ولكن كنت احطه بعد وليس قبل ولا يعمل

جزاك الله خير

لكن الان صرت انا طماع

هل ياترى استطيع في القريد فيو تكبير الصورة شي بسيط عن مرور الماوس عليه ؟

جزاك الله خير

مواضيع مشابهة