چند روز پیش یه پروژه ای به نام "KonkoorKill" رو شروع کردم که کارش استخراج کارنامه های کنکور سازمان سنجش بود. بعد از اون سعی کردم برم سراغ کنکور دانشگاه آزاد. انصافاً هم خیلی روش وقت گذاشتم. چند روز همه کارهامو کنسل کردم چسبیدم به این کار. اما اعتراف میکنم که واقعاً اشکم رو در آورد. یه جورایی به قول همون حسابرس باید بگم واقعاً مثه ماهی میموند، بدجوری توی دست لیز میخورد. هر جاشو میگرفتی یه جای دیگش در میرفت. درست درلحظه ای که خیال میکردم همه چیز درسته، با خطا مواجه میشدم. دست آخری درست در لحظه ای که دیگه قطع امید کرده بودم و تصمیم داشتم دستامو به نشانه تسلیم بالا ببرم، گفتم بزار یه ایمیل به اساتید فن بزنم و سوال کنم. خیلی طول نکشید که استاد و دوست عزیز و بامعرفتم "نیما شایافر" که همیشه بهم کمک کرده بهم ایمیل زد و وقتی که گفت بابا این که کاری نداره ...! کلی شاخ در آوردم! با اضافه کردن یه خط کوچولو به برنامه مشکل رو رفع کرد و برنامه جواب داد. واقعاً دستش درد نکنه، همینجا ازش تشکر میکنم. البته همچنین از "نیما جوهری زاده" عزیز که اون هم سعیش رو برای کمک کرد و باهم همفکری داشتیم.
در حال حاظر نسخه 2 و 3 برنامه حاظر شده که در زیر توضیحاتشون رو آوردم:
توضیح نسخه2: این نسخه مربوط به استخراج نتایج نهایی آزمون سراسری
سازمان سنجش است. مشابه نسخه شماره 1 ، امکان جستجوی موردی، جستجوی یک محدوده مشخص
و جستجو از روی فایل رو داره.
امکانی که در این نسخه اضافه شده امکان ذخیره کارنامه ها به صورت فایل و تفکیک شده
بر اساس شماره داوطلبی می باشه. برای اینکار کافیه در سورس فایل و چند خط ابتدای
فایل، مسیر شاخه ای که تمایل دارید کارنامه ها در اونجا ذخیره بشن رو به متغییر
logfile_results$ (سطح دسترسی شاخه بر روی سرور را بر
روی 777 تنظیم کنید.) بدید. و در غیر این صورت مقدار هیچی ""
رو بهش نسبت بدید.
همچنین اسم فایلی که تمایل دارید اطلاعات صحیح و یافت شده در اون ذخیره بشه رو به
متغییر logfile_found$ (سطح دسترسی فایل بر روی سرور را
بر روی 702 تنظیم کنید.) نسبت بدید و اسم فایلی که اطلاعات
اشتباه و کارنامه ای برای اونها پیدا نشده رو به فایل
logfile_notfound$ (سطح دسترسی فایل بر روی سرور را بر روی 702 تنظیم کنید.)
نسبت بدید. در صورتی که تمایل به ثبت log
file ها نداشتید مقدار هیچی "" رو به متغییرها نسبت بدید.
توضیح نسخه3: این نسخه مربوط به استخراج کارنامه های کنکور
دانشگاه آزاد است. و امکانات مشابه نسخه قبلی که توضیح داده شد رو داره.
تنها نکته مهم اینکه در بخش جستجو از روی فایل، فایل ورودی این نسخه، بر خلاف فایل
نسخه 1 و 2 کنکور دولتی که بایستی فورمت text ansi داشته
باشد. این نسخه یعنی نسخه 3 بایستی فورمت فایل ورودی از نوع
text utf-8 باشد. برای این منظور در Notepad در پنجره Save As ، گزينه
Encoding را بر روي UTF-8 تنظيم و فايل را ذخيره نمائيد.
و این هم لینک دون لود و نسخه نمایشی آنلاین تمام نسخه ها:
ضمناً برای آزمون های دیگه مثل کارشناسی ناپیوسته و فنی و حرفه ای سازمان سنجش و یا کارشناسی ارشد دانشگاه آزاد ... تا اونجایی که من بررسی کردم متوجه شدم تنها با عوض کردن url$ و referer$ ابتدای سورس فایل، میتونید برنامه رو برای اونها تعمیم بدید.
نسخه های آینده در همون لینک بالا قرار خواهند گرفت.
اما از اونجایی که این مطلب رو من در گروه PHP نوشتم، لازمه کمی در مورد سورس برنامه صحبت کنم. پس از اینجا به بعد صحبت تخصصی میشه.
این برنامه رو توسط PHP و HTTP_Request که از کتابخانه های مجموعه PEAR است نوشتم. پیش از این درمورد این کتابخانه در مطلبی که در مورد ارسال ایمیل نوشته بودم صحبت کرده بودم. پس توضیح اضافی نمیدم و بیشتر در مورد هسته اصلی برنامه صحبت میکنم.
سورس هسته اصلی برنامه بدین شکله:
<?php $drpExamCode = "نوع آزمون"; //options: 1 or 2 or 3 $txtName = "نام"; $txtFamily = "نام خانوادگی"; $txtFather = "نام پدر"; $txtIdNumbert = "شماره شناسنامه"; include('HTTP/Request.php'); $url = 'http://www.azmoon.com/Karshenasi/Year1386/Index1.aspx'; $req = &new HTTP_Request($url); $req->setMethod(HTTP_REQUEST_METHOD_POST); $req->_allowRedirects = true; $req->addPostData('drpExamCode', $drpExamCode); $req->addPostData('txtName', $txtName); $req->addPostData('txtFamily', $txtFamily); $req->addPostData('txtFather', $txtFather); $req->addPostData('txtIdNumbert', $txtIdNumbert); $req->addPostData('__VIEWSTATE', "/wEPDwUKMjAzOTYwNDI1MmRk"); $req->addPostData('__EVENTVALIDATION', "/wEWCgKqyZDNBALUkYGVAwLYkc2WAwLZkc2WAwLakc2WAwLEhISFCwLvhLKADgLJm+SFAgKRiee2DAKC3IeGDA=="); $req->addPostData('btnLogin', ""); $req->addCookie('ASP.NET_SessionId', "kn1ndx45pgfqfnav05zkkh3s"); $req->sendRequest(); echo $req->getResponseBody(); ?>
HTTP_Request یه کلاس قوی برای کار با URL هاست و امکان ارسال و دریافت داده ها به URL رو آسون میکنه، درواقع HTTP_Request از توابع داخلی PHP مخصوصاً تابع fsockopen استفاده میکنه. و هدر مورد نیاز برای ارسال داده به URL رو بسادگی و با پارامترهای ورودی میسازه و مقدار برگشتی رو به ما تحویل میده.
به نقل از سایت PHP، کلاس HTTP_Request از GET/POST/HEAD/TRACE/PUT/DELETE, Basic authentication, Proxy, Proxy Authentication, SSL, file uploads پشتیبانی میکنه.
سورسی که در بالا نوشتم، یک URL رو به عنوان ورودی دریافت میکنه و یک آبجکت از نوع کلاس HTTP_Request ایجاد میکنه. سپس با انتساب مقدار HTTP_REQUEST_METHOD_POST به متد setMethod مشخص میکنیم که داده ها به صورت POST ارسال بشن. به این ترتیب میتونیم فیلدهای فرم رو براحتی به URL پاس بدیم. با قرار دادن متد allowRedirects_ به true ، اجازه direct شدن url رو میدیم که در مورد این پروژه لازمه. سپس توسط متد addPostData کلیه پارامتر ها و فیلد های درون فرم مورد نظر رو مقدار دهی میکنیم. باید مراقب cookie ها و session ها نیز باشیم و در صورت نیاز اونها رو ست کنیم. در اینجا به دلیل اینکه سایت هدف توسط asp.net برنامه نویسی شده است. به صورت خودکار session یی ایجاد میشود که ما باید اون رو به همراه فرم ارسال کنیم. (این همون نکته ریزی بود که دوست خوبم نیما متوجه شد.) این عمل رو متد addCookie انجام خواهد داد. حال وقت ارسال داده هاست و منتظر پاسخ. توسط متد sendRequest داده ها ارسال میشود و نهایتاً توسط متد getResponseBody مقدار برگشتی URL رو به خروجی ارسال میکنیم. به همین سادگی.
کلاس HTTP_Request پارامترها و متد های دیگری دارد که در این پروژه نیازی به استفاده نداشتند. مثل getResponseCode, getResponseHeader, setBasicAuth, getResponseCookies, addFile, addHeader, setProxy و... که کاربرد هرکدوم از روی اسمش مشخصه. فهرست تموم این متدها و نحوه استفادشون رو میتونید در [اینجا] مشاهده کنید.
شخصاً خیلی به بسته PEAR علاقه پیدا کردم با اینکه فقط با چند تا از کلاس هاش بیشتر کار نکردم ولی چیز کامل و جالبیه. به همه PHP کارها پیشنهاد میکنم راهنمای PEAR رو با فورمت CHM از [این لینک] دون لود کنند تا همیشه راهنمای کامل و جامع اون رو بصورت offline دم دستشون داشته باشند. و البته راهنمای PHP را.
این بود داستان HTTP_Request. اما چند وقت پیش یکی دو تا از دوستان پرسیدند که آیا این برنامه رو توسط CURL هم میشه نوشت یا خیر. بعد از تحقیق متوجه شدم که قدرت دسته توابع CURL فراتر از این حرفهاست ! حتی با CURL میشه به پروتکل https وصل شد یا حتی فایل رو به سرور POST کرد و کارای جالب دیگه.
هسته اصلی ورژن 1 برنامه کنکور رو با CURL هم نوشتم که در زیر آوردم:
<?php $sds = "شماره داوطلبی"; $slns = "نام خانوادگی"; $sns = "نام"; $sshs = "شماره شناسنامه"; $stts = "دو رقم سمت راست سال تولد"; $data = array ( "sds" => $sds, "slns" => $slns, "sns" => $sns, "sshs" => $sshs, "stts" => $stts, ); $vars=null; foreach($data as $key=>$value) if($key && $value) $vars.=$key."=".urlencode($value)."&"; $url = "http://www.sanjesh.org/result_dav.php"; $ch = curl_init( $url ); curl_setopt($ch, CURLOPT_REFERER , "http://www.sanjesh.org/index.php"); curl_setopt($ch, CURLOPT_POST , 1); curl_setopt($ch, CURLOPT_POSTFIELDS , $vars); $content = curl_exec( $ch ); curl_close( $ch ); echo $content; ?>
همونطور که میبینید ، ابتدا داده هایی که باید ارسال بشن در آرایه قرار گرفتند و سپس توسط foreach تمام اندیس ها و مقادیر آرایه ها از urlencode عبور داده میشن و به یک رشته یکپارچه تبدیل میشن، در مورد HTTP_Request ، استفاده از urlencode نیازی نیست چون اینکار رو توابع داخلی این کلاس انجام میده، اما در مورد CURL اینکار لازمه. بعد از اینکه رشته حاوی فیلدها و مقادیر فرم مورد نظر جهت ارسال ساخته شد. توسط curl_init یک ارتباط به URL مورد نظر ایجاد شده. بعد از اون تموم کارها رو curl_setopt انجام میده، پارامتر اول این تابع همون اشاره گر به url است، پارامتر دوم نام option و پارامتر سوم مقدار اون است. در مورد این برنامه ما باید آدرس referer رو به CURLOPT_REFERER نسبت بدیم. مقدار 1 برای CURLOPT_POST مشخص میکنه که قصد داریم از متد POST استفاده کنیم. رشته ای که حاوی مقادیر فیلدهای فرم بود و ابتدا ساخته بودیم رو هم به CURLOPT_POSTFIELDS نسبت میدیم. حال وقت اجرای ارتباط ایجاد شده توسط curl_exec است، آن را درون متغییر content$ میریزیم و توسط curl_close ارتباط را قطع میکنیم. تنها کاری که باقی میمونه فرستادن متغییر content$ به خروجی است.
CURL دارای option های خیلی زیادی است. مثل CURLOPT_AUTOREFERER, CURLOPT_TIMEOUT, CURLOPT_USERAGENT, CURLOPT_HTTPHEADERو... [لیست کامل option ها] با نگاه به اسم این پارامترها، مورد استفاده اونها رو متوجه میشید. با این حال راهنمای CURL هم تمام این پارامترها رو باز کرده و همراه با مثال های متعدد توضیح داده.
یکی از امکانات جالبی که CURL داره و من باش حال کردم، پشتیبانی از SSL و ارسال داده ها به URL با پروتوکل HTTPS است. به این روش، میشه فرم سایتهایی که از این پروتکل استفاده میکنند و به اصطلاح ادعای امنیتشون میشه رو submit کرد. نمونه سورس جهت انجام اینکار رو در زیر آوردم:
<?php $user = ""; $pass = ""; $url = 'https://www.example.com/'; $params = "username=$user&password=$pass&"; $ch = curl_init(); curl_setopt ($ch, CURLOPT_POST, 1 ); curl_setopt ($ch, CURLOPT_POSTFIELDS, $params ); curl_setopt ($ch, CURLOPT_URL, $url ); curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE ); curl_setopt ($ch, CURLOPT_HEADER, 0 ); curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1 ); $result = curl_exec ($ch); curl_close ($ch); echo $result; ?>
پارامترهایی که برای انجام اینکار لازمه رو در بالا میبینید، همچنین پارامتر CURLOPT_SSL_VERIFYPEER که در اینجا نقش کلیدی ایفا میکنه.
همچنین پست داده ها به صورت multipart/form-data ، مثلا برای ارسال یک فایل به یک URL از دیگر امکانات جالب CURL است.
خب این هم گریزی کوتاه بود به CURL. که البته در مقایسه با HTTP_Request توانایی های اونها بسیار به هم نزدیک هستند.
منبع اصلی سورسها سایت رسمی PHP و PEAR بود. این رو هم اضافه کنم که تمام این مطالب رو در قالب چند مقاله هم میشد بنویسم، در هر صورت امیدوارم مورد استفاده قرار گرفته باشه.
+ پي نوشت: نکته بسیار مهم: الان که مدت زیادی از این مطلب میگذره، در مورد آزمون دانشگاه آزاد تست کردم و متوجه شدم برنامه کار نمیکنه، برای حل مشکل بایستی به صفحه اصلی اعلام نتایج یعنی آدرسی که در متغییر url$ قرار گرفته برید و view source کنید و مقادیر فیلدهای __VIEWSTATE و __EVENTVALIDATION رو با مقادیر جدید اون در سورس جایگزین کنید، در غیر این صورت برنامه کار نخواهد کرد.
+ تاريخ آخرين ويرايش: يکشنبه 16 تیر 1387 - 3:12:09 قبل از ظهر