توسعهدهندگان هر روز در تلاشاند تا فرآیندهای مختلف برنامهنویسی را خودکار کنند. طبق این واقعیت که کامپیوترها بسیار سریعتر و دقیقتر از انسان هستند، پس به ما امکان میدهند بسیاری از کارهای پیچیده روزمره را سادهتر کنیم. اما متأسفانه از همین تواناییها میتوان برای برنامهریزی کامپیوترها در جهت انجام کارهای مخرب مانند ارسال هرزنامه (spam) یا حدس زدن رمزهای عبور استفاده کرد.
فرض کنید یک وبسایت با فرم تماس دارید تا از طریق آن کاربران با شما در ارتباط باشند. تنها کاری که آنها باید انجام دهند این است که فرم را پر کنند و دکمه ارسال را بزنند تا مشکل یا درخواستی که دارند را به شما اطلاع دهند. این یکی از ویژگیهای مهم وبسایتهای عمومی است، اما فرآیند پر کردن مقادیر فرم میتواند توسط کاربران مخرب خودکار شود تا هرزنامههای زیادی برای شما ارسال گردد. هر چند این نوع تکنیک ارسال هرزنامه تنها به فرمهای تماس محدود نمیشود. چرا که رباتها همچنین میتوانند برای پر کردن انجمنهای شما با پستهای هرزنامه یا نظراتی که به لینکهای مخرب مربوط میشود، به کار گرفته شوند.
یکی از راههای حل این مشکل، قرار دادن آزمایشی است که میتواند بین رباتهایی که سعی در انتشار هرزنامه دارند و افرادی که به طور قانونی میخواهند با شما تماس بگیرند، تمایز قائل شود. این همان جایی است که CAPTCHA وارد عمل میشود. آنها معمولا از تصاویری با ترکیب تصادفی پنج یا شش حرفی که روی پس زمینه رنگی نوشته شدهاند، تشکیل میشوند. ایده این است که یک انسان میتواند متن داخل تصویر را بخواند، اما یک ربات نمیتواند. بررسی مقدار CAPTCHA پر شده توسط کاربر در برابر نسخه اصلی میتواند به شما کمک کند رباتها را از انسان تشخیص دهید. CAPTCHA مخفف عبارت:
“completely automated public Turing test to tell computers and humans apart“
تست تورینگ عمومی کاملا خودکار برای تشخیص کامپیوترها و انسانهاست.
نحوه ایجاد کپچا در فرم با PHP
برای این کار از کتابخانه PHP GD استفاده خواهیم کرد.همچنین باید کمی کد بنویسیم که رشته تصادفی خود را ایجاد کنیم تا روی تصویر ساخته شده نوشته شود.
مرحله نخست: ایجاد یک رشته تصادفی
برای اینکار یک فایل با عنوان captcha.php ایجاد می کنیم.سپس دستورات php خود را برای تولید یک رشته تصادفی وارد می کنیم.
ابتدا یک متغیر با نام permitted_chars ایجاد می کنیم که این متغیر حاوی کاراکترهای انگلیسی است.
مثال:
1 2 3 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; ?> |
حال طول رشته ای که قرار است تولید کنیم را تعیین می کنیم.برای مثال مقدار ۶
مثال:
1 2 3 4 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $string_length = 6; ?> |
حال یک تابع به نام generate_string ایجاد می کنیم که دارای دو پارامتر است.
- پارامتر اول کاراکترهای موردنظر
- پارامتر دوم تعداد پارامتر که پیش فرض برابر با عدد ۵ قرار می دهیم
مثال:
1 2 3 4 5 6 7 8 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $string_length = 6; function generate_string($input, $strength = 5) { } ?> |
حال در تابع خود مقدار طول کاراکتر نخست را بدست می آوریم.
مثال:
1 2 3 4 5 6 7 8 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $string_length = 6; function generate_string($input, $strength = 5) { $input_length = strlen($input) } ?> |
سپس یک متغیر به نام random_string تعریف می کنیم که دارای رشته خالی است.
مثال:
1 2 3 4 5 6 7 8 9 10 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $string_length = 6; function generate_string($input, $strength = 5) { $input_length = strlen($input); $random_string = ''; } ?> |
حال یک حلقه با دستور for به تعداد پارامتر دوم بر روی کاراکتر وارد شده ایجاد می کنیم.
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $string_length = 6; function generate_string($input, $strength = 5) { $input_length = strlen($input); $random_string = ''; for($i=0;$i < $strength;$i++){ } } ?> |
در هر بار حلقه یک مقدار تصادفی با استفاده از متد mt_rand که بین عدد ۰ تا طول رشته (input_length) از پارامتر input بدست آورده و به متغیر random_char تخصیص داده سپس به متغیر random_string اضافه می کنیم.
در آخر مقدار random_char را برگشت می دهیم.
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $string_length = 6; function generate_string($input, $strength = 5) { $input_length = strlen($input); $random_string = ''; for($i=0;$i < $strength;$i++){ $random_char = $input[mt_rand(0,$input_length-1)]; $random_string .= $random_char; } return $random_string; } ?> |
حال تابع generate_string را فراخوانی می کنیم.
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $string_length = 6; function generate_string($input, $strength = 5) { $input_length = strlen($input); $random_string = ''; for($i=0;$i < $strength;$i++){ $random_char = $input[mt_rand(0,$input_length-1)]; $random_string .= $random_char; } return $random_string; } generate_string($permitted_chars,$string_length); ?> |
میتوانید از توابع امن رمزنگاری برای تولید رشتههای تصادفی استفاده کرده و بدین صورت حدس زدن CAPTCHA را سختتر کنید.
در این مورد خاص، میتوانیم از تابع ()random_int به جای ()mt_rand کمک بگیریم. این متد همانند قبلی دو پارامتر یکسان را میپذیرد اما اعداد تصادفی ایمن رمزنگاری شده تولید میکند. در زیر کد اصلاح شده ما برای تولید رشتههای تصادفی آورده شده است.
برای اینکار در تابع خود پارامتر سومی به نام secure ایجاد می کنیم که دارای یک مقدار بولین است.مقدار پیش فرض آن برابر با false است. در صورت true بودن از تابع ()random_int استفاده می شود.
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $string_length = 6; function generate_string($input, $strength = 5,$secure = true) { $input_length = strlen($input); $random_string = ''; for($i=0;$i < $strength;$i++){ if($secure){ $random_char = $input[random_int(0,$input_length-1)]; }else{ $random_char = $input[mt_rand(0,$input_length-1)]; } $random_string .= $random_char; } return $random_string; } generate_string($permitted_chars,$string_length); ?> |
مرحله دوم: ایجاد تصویر CAPTCHA
در این مرحله می بایست تصویر خود را براساس رشته تولید شده ایجاد کنیم به همین منظور ابتدا یک تصویر با طول ۲۰۰ و عرض ۵۰ ایجاد می کنیم.
مثال:
1 2 3 |
<?php $image = imagecreatetruecolor(200,50); ?> |
پس از ایجاد تصویر ویژگی فعال شدن امکان ترسیم خطوط را با تابع imageantialias فعال می کنیم.
مثال:
1 2 3 4 |
<?php $image = imagecreatetruecolor(200,50); imageantialias($image,true); ?> |
حال میتوان رنگ خود را برای قرار گرفتن بر روی تصویر بسازیم.به همین منظور ابتدا یک آرایه خالی به نام colors ایجاد می کنیم.
همانطور که میدانیم رنگ از سه واحد قرمز،سبز و آبی تولید می شود. بنابراین رنگ خود را بصورت تصادفی بین عدد ۱۲۵ تا ۱۷۵ انتخاب می کنیم.
سپس یک حلقه به تعداد ۵ آیتم ایجاد می کنیم که بتوانیم ۵ واحد رنگ مختلف تولید کنیم.
روشنترین رنگ اولین عنصر آرایه colors$ ماست و تیرهترین رنگ هم آخرین عنصر است.
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php $image = imagecreatetruecolor(200,50); imageantialias($image,true); $colors = []; $red = rand(125,175); $green = rand(125,175); $blue = rand(125,175); imagecolorallocate($image,140,130,150); for ($i=0;$i < 5; $i++){ $colors[] = imagecolorallocate($image,$red - 20 * $i,$green - 20 * $i,$blue - 20 * $i); } ?> |
حال رنگ خود را با استفاده از تابع imagefill بر روی تصویر خود قرار می دهیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php $image = imagecreatetruecolor(200,50); imageantialias($image,true); $colors = []; $red = rand(125,175); $green = rand(125,175); $blue = rand(125,175); imagecolorallocate($image,140,130,150); for ($i=0;$i < 5; $i++){ $colors[] = imagecolorallocate($image,$red - 20 * $i,$green - 20 * $i,$blue - 20 * $i); } imagefill($image,0,0,$colors[0]); ?> |
برای ترسیم اشکال مختلف بر روی تصویر می توانیم از اشکال مربع استفاده کنیم. به همین منظور یک حلقه به تعداد مثلا ۵ عدد ایجاد می کنیم و در هر بار پیمایش یک شکل در یک نقطه و براساس ضخامت مختلف تولید می کنیم.
برای تعریف ضخامت اشکال از تابع imagesetthickness و برای خود شکل مربع از تابع imagerectangle استفاده می کنیم.
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php $image = imagecreatetruecolor(200,50); imageantialias($image,true); $colors = []; $red = rand(125,175); $green = rand(125,175); $blue = rand(125,175); imagecolorallocate($image,140,130,150); for ($i=0;$i < 5; $i++){ $colors[] = imagecolorallocate($image,$red - 20 * $i,$green - 20 * $i,$blue - 20 * $i); } imagefill($image,0,0,$colors[0]); for($i=0;$i<5;$i++){ imagesetthickness($image,rand(2,5)); imagerectangle($image,rand(-10,190),rand(-10,10),rand(-10,190),rand(40, 60),$colors[rand(1,4)]); } ?> |
قرار دادن متن تولید شده بر روی تصویر
حال در این بخش پس از تولید متن و عکس باید متن را در قالب تصویر ایجاد کرد.
به همین منظور برای رنگ کاراکترها می توانیم ابتدا دو رنگ با استفاده از imagecolorallocate را در قالب آرایه ذخیره سازی کنیم.
مثال:
1 2 3 4 5 |
<?php $color_white = imagecolorallocate($image,255,255,255); $color_black = imagecolorallocate($image,0,0,0); $color_text = [$color_white,$color_black]; ?> |
حال فونت یا فونت ها خود را در اسکریپت خود لود می کنیم.در صورتی که چندین فونت دارید آنها را درون یک آرایه به نام fonts قرار دهید.
برای خواندن فایل های فونت که با پسوند ttf هستند می بایست مسیر پروژه را با استفاده از ثابت __FILE__ و تابع dirname بدست بیاوریم.
مثال:
1 2 3 4 5 6 |
<?php $color_white = imagecolorallocate($image,255,255,255); $color_black = imagecolorallocate($image,0,0,0); $color_text = [$color_white,$color_black]; $fonts = [dirname(__FILE__).'\fonts\RubikDirt-Regular.ttf',dirname(__FILE__).'\fonts\RubikMarkerHatch-Regular.ttf']; ?> |
برای ایجاد فاصله بین کاراکترها یک متغیر ایجاد کرده و مقدار آن را تعدادکاراکتر تصادفی قرار می دهیم.در اینجا تعداد کاراکتر ما ۶ است.
مثال:
1 2 3 4 5 6 7 8 |
<?php $color_white = imagecolorallocate($image,255,255,255); $color_black = imagecolorallocate($image,0,0,0); $color_text = [$color_white,$color_black]; $fonts = [dirname(__FILE__).'\fonts\RubikDirt-Regular.ttf',dirname(__FILE__).'\fonts\RubikMarkerHatch-Regular.ttf']; $string_length = 6; ?> |
برای قرار دادن فاصله بین کاراکترها یک حلقه به تعداد string_length ایجاد می کنیم.در این حلقه برای ایجاد متن بر روی تصویر براساس فونت و سایز مورد نظر از تابع imagettftext استفاده کرده ایم.این تابع پارامترهای مختلفی را دریافت کرده که عبارتند از:
- سورس تصویر
- سایز فونت برابر با ۲۰
- زاویه متن که تصادفی بین ۱۵- و ۱۵ قرار دارد
- فاصله کاراکترها که در هر بار مقدارش با توجه به ضرب شدن در مقدار i$ افزایش می یابد
- انتخاب رنگ متن بین سفید و سیاه
- انتخاب فونت
- متن نهایی تولید شده
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php $color_white = imagecolorallocate($image,255,255,255); $color_black = imagecolorallocate($image,0,0,0); $color_text = [$color_white,$color_black]; $fonts = [dirname(__FILE__).'\fonts\RubikDirt-Regular.ttf',dirname(__FILE__).'\fonts\RubikMarkerHatch-Regular.ttf']; $string_length = 6; $text_out = generate_string($permitted_chars,$string_length); for($i=0;$i<$string_length;$i++){ $letter_space = 170/$string_length; $initial = 15; imagettftext($image,20,rand(-15,15),$initial + $i * $letter_space,rand(20,40),$color_text[rand(0,1)],$fonts[rand(0,1)],$text_out[$i]); } ?> |
خروجی گرفتن از تصویر
برای خروجی گرفتن می بایست نوع header سند خود را image/png قرار دهیم.
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php $color_white = imagecolorallocate($image,255,255,255); $color_black = imagecolorallocate($image,0,0,0); $color_text = [$color_white,$color_black]; $fonts = [dirname(__FILE__)."\fonts\RubikDirt-Regular.ttf",dirname(__FILE__)."\fonts\RubikMarkerHatch-Regular.ttf"]; $string_length = 6; $text_out = generate_string($permitted_chars,$string_length); for($i=0;$i<$string_length;$i++){ $letter_space = 170/$string_length; $initial = 15; imagettftext($image,20,rand(-15,15),$initial + $i * $letter_space,rand(20,40),$color_text[rand(0,1)],$fonts[rand(0,1)],$text_out); } header('Content-type: image/png'); ?> |
برای ارسال تصویر نهایی به خروجی مرورگر از تابع imagepng استفاده می کنیم.
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php $color_white = imagecolorallocate($image,255,255,255); $color_black = imagecolorallocate($image,0,0,0); $color_text = [$color_white,$color_black]; $fonts = [dirname(__FILE__)."\fonts\RubikDirt-Regular.ttf",dirname(__FILE__)."\fonts\RubikMarkerHatch-Regular.ttf"]; $string_length = 6; $text_out = generate_string($permitted_chars,$string_length); for($i=0;$i<$string_length;$i++){ $letter_space = 170/$string_length; $initial = 15; imagettftext($image,20,rand(-15,15),$initial + $i * $letter_space,rand(20,40),$color_text[rand(0,1)],$fonts[rand(0,1)],$text_out); } header('Content-type: image/png'); imagepng($image); ?> |
در آخر برای آزادسازی حافظه تصویر را با استفاده از تابع imagedestroy حذف می کنیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php $color_white = imagecolorallocate($image,255,255,255); $color_black = imagecolorallocate($image,0,0,0); $color_text = [$color_white,$color_black]; $fonts = [dirname(__FILE__)."\fonts\RubikDirt-Regular.ttf",dirname(__FILE__)."\fonts\RubikMarkerHatch-Regular.ttf"]; $string_length = 6; $text_out = generate_string($permitted_chars,$string_length); for($i=0;$i<$string_length;$i++){ $letter_space = 170/$string_length; $initial = 15; imagettftext($image,20,rand(-15,15),$initial + $i * $letter_space,rand(20,40),$color_text[rand(0,1)],$fonts[rand(0,1)],$text_out); } header('Content-type: image/png'); imagepng($image); imagedestroy($image); ?> |
فایل نهایی کپچا در فرم با PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?php $permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $string_length = 6; function generate_string($input, $strength = 5,$secure = true) { $input_length = strlen($input); $random_string = ''; for($i=0;$i < $strength;$i++){ if($secure){ $random_char = $input[random_int(0,$input_length-1)]; }else{ $random_char = $input[mt_rand(0,$input_length-1)]; } $random_string .= $random_char; } return $random_string; } $image = imagecreatetruecolor(200,50); imageantialias($image,true); $colors = []; $red = rand(125,175); $green = rand(125,175); $blue = rand(125,175); imagecolorallocate($image,140,130,150); for ($i=0;$i < 5; $i++){ $colors[] = imagecolorallocate($image,$red - 20 * $i,$green - 20 * $i,$blue - 20 * $i); } imagefill($image,0,0,$colors[0]); for($i=0;$i<5;$i++){ imagesetthickness($image,rand(2,5)); imagerectangle($image,rand(-10,190),rand(-10,10),rand(-10,190),rand(40, 60),$colors[rand(1,4)]); } $color_white = imagecolorallocate($image,255,255,255); $color_black = imagecolorallocate($image,0,0,0); $color_text = [$color_white,$color_black]; $fonts = [dirname(__FILE__)."\fonts\RubikDirt-Regular.ttf",dirname(__FILE__)."\fonts\RubikMarkerHatch-Regular.ttf"]; $string_length = 6; $text_out = generate_string($permitted_chars,$string_length); for($i=0;$i<$string_length;$i++){ $letter_space = 170/$string_length; $initial = 15; imagettftext($image,20,rand(-15,15),$initial + $i * $letter_space,rand(20,40),$color_text[rand(0,1)],$fonts[rand(0,1)],$text_out); } header('Content-type: image/png'); imagepng($image); imagedestroy($image); ?> |
خروجی نهایی: