در راستای مهاجرت به ویندوز 7، کار نصب و راه اندازی SVN و کلاینتهای آن باید مجددا انجام میشد. اگر برای بار اول است که به مبحث SVN برخورد میکنید، مطالعه این جزوه توصیه میشود. مطالب ذیل برای افرادی مفید است که قصد انتقال سیستم SVN موجود خود را به مکان و یا سیستم عامل دیگری در اسرع وقت دارند.
الف) دریافت و نصب Visual SVN server
یا میتوان SVN خالص را از سایت آن دریافت کرد و یا جهت سهولت کار و همچنین دسترسی به یک کنسول مدیریتی میتوان برنامهی رایگان Visual SVN server را از آدرس زیر دریافت و نصب کرد:
پس از نصب، ابتدا باید یا کاربر جدیدی را جهت استفاده از منابع آن تعریف کرد و یا از نحوهی اعتبار سنجی یکپارچه با ویندوز هم میتوان استفاده کرد که من از این روش دوم استفاده میکنم (شکل زیر، کلیک راست بر روی نود اصلی visual SVN server و سپس انتخاب خواص و مراجعه به برگهی اعتبار سنجی آن):
ب)دریافت و نصب TortoiseSVN
نصب آن نکتهی خاصی ندارد. اما یک سری نکتهی ریز پس از نصب آن بهتر است رعایت شود که در ادامه ذکر میشود:
ج) دریافت و نصب برنامهی WinMerge
برنامهی Diff پیش فرض TortoiseSVN آنچنان قوی نیست. به همین جهت میتوان برنامهی WinMerge را با آن یکپارچه کرد. برای این منظور ابتدا آنرا دریافت نمائید:
اگر پس از نصب TortoiseSVN آنرا نصب کنید، در حین نصب پیشنهاد یکپارچه سازی با TortoiseSVN را نیز میدهد. اگر ابتدا WinMerge را نصب کردهاید و سپس TortoiseSVN بر روی سیستم شما نصب شده، فقط کافی است مطابق شکل زیر ابتدا به قسمت Diff viewers آن مراجعه کرده و سپس با انتخاب گزینهی external ، دستور خط فرمان زیر را وارد نمائید:
بدیهی است مسیر WinMergeU.exe مطابق مسیر نصب در سیستم شما باید تنظیم شود.
د) تنظیم مسیر تحت نظر قرار گرفتن سیستم
TortoiseSVN به صورت پیش فرض کل سیستم را جهت مشاهدهی تغییرات تحت نظر قرار میدهد که گاهی باعث کاهش کارآیی آن خواهد شد. برای رفع این مشکل میتوان مسیرهایی را که پروژههای شما در آن قرار دارند را به آن معرفی نمود تا بار کلی سیستم کاهش یابد.
همانطور که در شکل نیز ملاحظه میکنید، Include path مقدار دهی شده است.
ه) مشخص سازی پسوندهایی که بهتر است از آنها صرفنظر شود
به برگهی general تنظیمات TortoiseSVN مراجعه کرده و در قسمت global ignore pattern آن، موارد زیر را وارد نمائید:
این موارد شامل پروژههای دات نت، دلفی ، VC و امثال آن است و همچنین یک سری فایل بایناری که عموما با پروژههای برنامه نویسی نیازی به ثبت نگارش آنها نیست.
در همین برگه، اگر هنوز از VS2003 استفاده میکنید، تیک مربوط به استفاده از _svn بجای .svn را قرار دهید تا VS.Net با پوشههای مدیریتی ذکر شده مشکل پیدا نکند.
و) نصب افزونههای SVN سازگار با VS.Net
یا میتوان از افزونهی Visual SVN استفاده کرد (که رایگان نیست) و یا AnkhSVN که رایگان و سورس باز است.
ولی در کل یک مورد را بیشتر نصب نکنید. علت هم کند شدن VS.Net است به دلیل فعالیتهای پشت صحنهی هر کدام از این افزونهها که زیاده روی در تعداد آنها گاها باعث کرش هم میشود. بنابراین همان یک مورد کافی است.
ز) Import مخزنهای قبلی
تا اینجا مقدمات کار فراهم شد. اکنون نوبت به import مخزنهای بجا مانده از سیستم قبلی است. برای اینکار مطابق شکل زیر، گزینهی import existing repositories را انتخاب کرده و مسیر مخزنهای قبلی خود را باید معرفی نمود (به ازای هر کدام یکبار باید این عملیات صورت گیرد).
پس از انجام این مراحل یکبار باید سیستم reboot شود و اکنون همه چیز مثل قبل خواهد شد!
نکته:
اگر مسیر ریشه مخزنهای جدید با مسیر آنها در سیستم قبلی متفاوت است، هنگام commit کارهای خود با خطای زیر متوقف خواهید شد:
Unable to open repository 'file:///C:/Repositories/tracking/trunk'
اشکالی ندارد! برای رفع آن باید از گزینهی relocate مربوط به TortoiseSVN استفاده کرد.
بر روی پوشه کاری پروژه خود کلیک راست کرده، انتخاب گزینهی TortoiseSVN و سپس انتخاب گزینهی Relocate آن باید صورت گیرد. در اینجا میتوان مسیر جدید ریشه اصلی مخزن را در سیستم جدید معرفی کرد.
این مساله تا به اینجا یک مزیت مهم را به همراه دارد: اگر شخصی مثلا فایل shell.aspx را در این پوشه ارسال کند، از طریق مرورگر قابل اجرا و دسترسی نخواهد بود و کسی نخواهد توانست به این طریق به سایت و سرور دسترسی پیدا کند.
برای ارائه این نوع فایلها به کاربر، معمولا از روش خواندن محتوای آنها و سپس flush این محتوا در مرورگر کاربر استفاده میشود. برای نمونه اگر به لینکهای سایت دقت کرده باشید مثلا لینکهای تصاویر آن به این شکل است:
File هم در اینجا کنترلر فایل است که نام فایل را دریافت کرده و سپس به کمک FilePathResult و return File آنرا به کاربر ارائه خواهد داد.
تا اینجا همه چیز طبیعی به نظر میرسد. اما ... مورد ذیل چطور؟!
لاگ خطاهای فوق مرتبط است به سعی و خطای شب گذشته یکی از دوستان جهت دریافت فایل web.config برنامه!
متدهای Server.MapPath یا متد return File و امثال آن تمامی به کاراکتر ویژه ~ (اشارهگر به ریشه سایت) به خوبی پاسخ میدهند. به عبارتی اگر این بررسی امنیتی انجام نشده باشد که کاربر چه مسیری را درخواست میکند، محتوای کامل فایل web.config برنامه به سادگی قابل دریافت خواهد بود (به علاوه هر آنچه که در سرور موجود است).
چطور میشود با این نوع حملات مقابله کرد؟
دو کار الزامی ذیل حتما باید انجام شوند:
الف) با استفاده از متد Path.GetFileName نام فایل را از کاربر دریافت کنید. به این ترتیب تمام زواید وارد شده حذف گردیده و فقط نام فایل به متدهای مرتبط ارسال میشود.
ب) بررسی کنید مسیری که قرار است به کاربر ارائه شود به کجا ختم شده. آیا به c:\windows اشاره میکند یا مثلا به c:\myapp\app_data ؟
اگر به لاگ فوق دقت کرده باشید تا چند سطح بالاتر از ریشه سایت هم جستجو شده.
نتیجه گیری:
اگر در برنامههای وب خود (فرقی نمیکند مرتبط به چه فناوری است)، نام فایلی را از کاربر جهت ارائه محتوایی به او دریافت و از این نام فایل بدون هیچ نوع بررسی خاصی، مستقیما در برنامه استفاده میکنید، برنامه شما به مشکل امنیتی Directory Traversal مبتلا است.
پ.ن.
1- این باگ امنیتی در سایت وجود داشت که توسط یکی از دوستان در روزهای اول آن گزارش شد؛ ضمن تشکر!
2- از این نوع اسکنها در لاگهای خطاهای سایت جاری زیاد است. برای مثال به دنبال فایلهایی مانند DynamicStyle.aspx و css.ashx یا theme.ashx میگردند. حدس من این است که در یکی از پرتالهای معروف یا افزونههای این نوع پرتالها فایلهای یاد شده دارای باگ فوق هستند. فایلهای ashx عموما برای flush یک فایل یا محتوا به درون مرورگر کاربر در برنامههای ASP.NET Web forms مورد استفاده قرار میگیرند.
پس از آن، برای تبدیل صفحات یک فایل PDF به تصویر، مراحل زیر باید طی شود:
الف) وهله سازی از شیء AcroExch.PDDoc
در صورتیکه SDK یاد شده بر روی سیستم نصب نباشد، این وهله سازی با شکست مواجه خواهد شد و همچنین باید دقت داشت که این SDK به همراه نگارش رایگان Adobe reader ارائه نمیشود.
ب) گشودن فایل PDF به کمک شیء Com وهله سازی شده (pdfDoc.Open)
ج) دریافت اطلاعات صفحه مورد نظر (pdfDoc.AcquirePage)
د) کپی این اطلاعات به درون clipboard ویندوز (pdfPage.CopyToClipboard)
به این ترتیب به یک تصویر Bmp قرار گرفته شده در clipboard ویندوز خواهیم رسید
ه) مرحله بعد تغییر ابعاد و ذخیره سازی این تصویر نهایی است.
کدهای زیر، روش انجام این مراحل را بیان میکنند:
using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; using Acrobat; //Add a Com Object ref. to "Adobe Acrobat 10.0 Type Library" => Program Files\Adobe\Acrobat 10.0\Acrobat\acrobat.tlb using Microsoft.Win32; namespace PdfThumbnail.Lib { public static class PdfToImage { const string AdobeObjectsErrorMessage = "Failed to create the PDF object."; const string BadFileErrorMessage = "Failed to open the PDF file."; const string ClipboardError = "Failed to get the image from clipboard."; const string SdkError = "This operation needs the Acrobat SDK(http://www.adobe.com/devnet/acrobat/downloads.html), which is combined with the full version of Adobe Acrobat."; public static byte[] PdfPageToPng(string pdfFilePath, int thumbWidth = 600, int thumbHeight = 750, int pageNumber = 0) { byte[] imageData = null; runJob((pdfDoc, pdfRect) => { imageData = pdfPageToPng(thumbWidth, thumbHeight, pageNumber, pdfDoc, pdfRect); }, pdfFilePath); return imageData; } public static void AllPdfPagesToPng(Action<byte[], int, int> dataCallback, string pdfFilePath, int thumbWidth = 600, int thumbHeight = 750) { runJob((pdfDoc, pdfRect) => { var numPages = pdfDoc.GetNumPages(); for (var pageNumber = 0; pageNumber < numPages; pageNumber++) { var imageData = pdfPageToPng(thumbWidth, thumbHeight, pageNumber, pdfDoc, pdfRect); dataCallback(imageData, pageNumber + 1, numPages); } }, pdfFilePath); } static void runJob(Action<CAcroPDDoc, CAcroRect> job, string pdfFilePath) { if (!File.Exists(pdfFilePath)) throw new InvalidOperationException(BadFileErrorMessage); var acrobatPdfDocType = Type.GetTypeFromProgID("AcroExch.PDDoc"); if (acrobatPdfDocType == null || !isAdobeSdkInstalled) throw new InvalidOperationException(SdkError); var pdfDoc = (CAcroPDDoc)Activator.CreateInstance(acrobatPdfDocType); if (pdfDoc == null) throw new InvalidOperationException(AdobeObjectsErrorMessage); var acrobatPdfRectType = Type.GetTypeFromProgID("AcroExch.Rect"); var pdfRect = (CAcroRect)Activator.CreateInstance(acrobatPdfRectType); var result = pdfDoc.Open(pdfFilePath); if (!result) throw new InvalidOperationException(BadFileErrorMessage); job(pdfDoc, pdfRect); releaseComObjects(pdfDoc, pdfRect); } public static byte[] ResizeImage(this Image image, int thumbWidth, int thumbHeight) { var srcWidth = image.Width; var srcHeight = image.Height; using (var bmp = new Bitmap(thumbWidth, thumbHeight, PixelFormat.Format32bppArgb)) { using (var gr = Graphics.FromImage(bmp)) { gr.SmoothingMode = SmoothingMode.HighQuality; gr.PixelOffsetMode = PixelOffsetMode.HighQuality; gr.CompositingQuality = CompositingQuality.HighQuality; gr.InterpolationMode = InterpolationMode.High; var rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); gr.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); using (var memStream = new MemoryStream()) { bmp.Save(memStream, ImageFormat.Png); return memStream.ToArray(); } } } } static bool isAdobeSdkInstalled { get { return Registry.ClassesRoot.OpenSubKey("AcroExch.PDDoc", writable: false) != null; } } private static Bitmap pdfPageToBitmap(int pageNumber, CAcroPDDoc pdfDoc, CAcroRect pdfRect) { var pdfPage = (CAcroPDPage)pdfDoc.AcquirePage(pageNumber); if (pdfPage == null) throw new InvalidOperationException(BadFileErrorMessage); var pdfPoint = (CAcroPoint)pdfPage.GetSize(); pdfRect.Left = 0; pdfRect.right = pdfPoint.x; pdfRect.Top = 0; pdfRect.bottom = pdfPoint.y; pdfPage.CopyToClipboard(pdfRect, 0, 0, 100); Bitmap pdfBitmap = null; var thread = new Thread(() => { var data = Clipboard.GetDataObject(); if (data != null && data.GetDataPresent(DataFormats.Bitmap)) pdfBitmap = (Bitmap)data.GetData(DataFormats.Bitmap); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(); Marshal.ReleaseComObject(pdfPage); return pdfBitmap; } private static byte[] pdfPageToPng(int thumbWidth, int thumbHeight, int pageNumber, CAcroPDDoc pdfDoc, CAcroRect pdfRect) { var pdfBitmap = pdfPageToBitmap(pageNumber, pdfDoc, pdfRect); if (pdfBitmap == null) throw new InvalidOperationException(ClipboardError); var pdfImage = pdfBitmap.GetThumbnailImage(thumbWidth, thumbHeight, null, IntPtr.Zero); // (+ 7 for template border) var imageData = pdfImage.ResizeImage(thumbWidth + 7, thumbHeight + 7); return imageData; } private static void releaseComObjects(CAcroPDDoc pdfDoc, CAcroRect pdfRect) { pdfDoc.Close(); Marshal.ReleaseComObject(pdfRect); Marshal.ReleaseComObject(pdfDoc); } } }
using System; using System.IO; using System.Windows.Forms; using PdfThumbnail.Lib; namespace PdfThumbnail { class Program { static void Main(string[] args) { var pdfPath = Application.StartupPath + @"\test.pdf"; PdfToImage.AllPdfPagesToPng((pageImageData, pageNumber, numPages) => { Console.WriteLine("Page {0}/{1}", pageNumber, numPages); File.WriteAllBytes(string.Format("{0}\\page-{1}.png", Application.StartupPath, pageNumber), pageImageData); }, pdfPath); } } }
کدهای این قسمت را از اینجا نیز میتوانید دریافت کنید:
PdfThumbnail.zip
یک سایت دیگر برای انجام کارهای تیمی
ReSharper 7.1 منتشر شد.
دریافت خروجی سایت
این خروجی هم صرفا برای کاربران فعال سایت درنظر گرفته شده است. کاربری در این سایت فعال نامیده میشود که حداقل یک مطلب جدید یا حداقل یک اشتراک جدید را ارسال کرده باشد.
پ.ن.
لطفا سعی نکنید برای رسیدن به این حد نصاب هر مطلب پیش پا افتاده یا هر لینک به سایتهای آشپزی که مطالب به نظر علمی را هم منتشر میکنند، ارسال کنید چون منجر به حذف اکانت شما خواهد شد.
و ساختار سرویس که SSIS به این ساختار نیاز دارد .
حال از محیط BIDS یک پروژه SSIS ایجاد میکنیم (برای آشنایی با BIDS به این پست مراجعه کنید) و یک Web Service Task به آن اضافه میکنیم :
سپس روی task دوبار کلیک کنید تا پنجره تنظیمات آن باز شود :
حال باید یک دیتا سورس کانکشن که همان سرویس ما میباشد تعریف کنیم :
دکمه تست را فشار دهید تا تاییدیه معتبر بودن سرویس را دریافت کنید ، OK را فشار دهید .
در قدم بعد SSIS به قالب فایل xml که در خروجی WSDL است نیاز دارد . اگر این فایل را دارید آدرس آن را باید در قسمت WSDL FIle وارد کنید در غیر این صورت (مانند شرایط فعلی این مثال) باید این فایل را از سرویس خود دانلود کنید . نکته اینکه در صورتی که این فایل را ندارید ، گزینه overwriteWSDLFile را True کنید و مسیر یک فایلی که در سیستم شما موجود نیست را در آدرس WSDLFile وارد کنید .
حال شما فایل مورد نظر را دارید :
اگر به تب input بازگردید میتوانید ادامه تنظیمات را انجام دهید :
حال باید خروجی مورد نظر از این سرویس را تعریف کنیم . دو نوع خروجی برای ما امکان پذیر است . یکی انتقال اطلاعات به یک فایل (مناسب برای مواردی که نیاز به دادههای offline دارید) و یکی منتقل کردن آنها به متغیرهای خود SSIS Package برای استفاده در کامهای بعدی flow (برای مواردی که نیاز به انجام تغییرات روی دادههای Online دارید) .
پس از انجام این تنظیمات باید کانکشن هایی مطابق زیر داشته باشید :
F5 را فشار دهید تا عملیات شروع شود :