просто о сложном


Своя капча на php без сторонних зависимостей за 10 минут

tags: php
captcha

Чаще всего изображения со случайным кодом (так называемая captcha) используются для защиты от флуда (автоматизированного ввода сообщений). Некоторые сервисы находят им применнение в качестве раздражителя (для перехода на платный вариант). В общем, может пригодиться.

В данном скрипте использована библиотека GD или Imagick, которые почти всегда (хотя бы одна) включённы по умолчанию в сборках php. Также понадобится любой шрифт ttf.

PHP код для GD:

$width = 120;				//ширина изображения
$height = 60;				//высота изображения
$font_size = 40;			//размер шрифта
$let_amount = 4;			//количество символов, которые нужно набрать
$fon_let_amount = 30;		//количество символов на фоне
$font = '/fonts/iris.ttf';	//путь к шрифту

//набор символов
$chars = array_flip(['a','b','c','d','e','f','g','h','i','j','k','m','n']);
//цвета
$colors = array_flip(['90','110','130','150','170','190','210']);

$captcha_chars = array_rand($chars, $let_amount);

$src = imagecreatetruecolor($width, $height);    //создаем изображение
$fon = imagecolorallocate($src, 255, 255, 255);  //создаем фон
imagefill($src, 0, 0, $fon);                     //заливаем изображение фоном

//добавляем на фон буковки
for ($i=0; $i < $fon_let_amount; ++$i)	{
	//случайный цвет
	$color = imagecolorallocatealpha($src,
		rand(0,255), rand(0,255), rand(0,255), rand(90, 110));
	//добавляем символ на картинку
	imagettftext(
		$src,
		rand($font_size / 2, $font_size - 5), //случайный размер
		rand(-45, 45), //случайный угол
		rand($width*0.1, $width - $width*0.1), //случайный x
		rand($height*0.2, $height), //случайный y
		$color,
		$font,
		array_rand($chars) //случайный символ
	);
}

//то же самое для основных букв
$letter_w = floor($width / $let_amount); //ширина символа
$y_padding = ($height - $font_size) / 2; //смещение символа по y

foreach ($captcha_chars as $k => $v) {
	$color = imagecolorallocatealpha(
		$src,
		array_rand($colors),
		array_rand($colors),
		array_rand($colors),
		0
	);
	imagettftext(
		$src,
		rand($font_size - 5, $font_size + 5),
		rand(-30, 30),
		($k * $letter_w) ?: 10,
		$font_size + rand(-$y_padding, $y_padding),
		$color,
		$font,
		$v
	);
}

//сохраняем код в сессию
$_SESSION['captcha'] = md5(implode($cod));

//выводим готовую картинку
header ('Content-type: image/gif');
imagegif($src);

PHP код для Imagick:

$width = 120;				//ширина изображения
$height = 60;				//высота изображения
$font_size = 40;			//размер шрифта
$let_amount = 4;			//количество символов, которые нужно набрать
$fon_let_amount = 30;		//количество символов на фоне
$font = '/fonts/iris.ttf';	//путь к шрифту

//набор символов
$chars = array_flip(['a','b','c','d','e','f','g','h','i','j','k','m','n']);
//цвета
$colors = array_flip(['90','110','130','150','170','190','210']);

$captcha_chars = array_rand($chars, $let_amount);

$src = new \imagick;
$src->newImage($width, $height, new \ImagickPixel('#fff'));

$draw = new \ImagickDraw;
$draw->setFont($font);

// background
for ($i = 0; $i < $fon_let_amount; $i++) {
	$draw->setFontSize(rand($font_size / 2, $font_size - 5));
	$draw->setFillColor(
		new \ImagickPixel('rgb('.rand(0, 255).','.rand(0, 255).','.rand(0, 255).')')
	);
	$draw->setFillOpacity(0.25);

	$src->annotateImage(
		$draw,
		rand(1, $width - 5),
		rand(1, $height + 5),
		rand(-30, 30),
		array_rand($chars)
	);
}

// main chars
$letter_w = floor($width / $let_amount);
$y_padding = ($height - $font_size) / 2;

foreach ($captcha_chars as $k => $v) {
	$draw->setFontSize(rand($font_size - 5, $font_size + 5));
	$draw->setFillColor(new \ImagickPixel('rgb('.implode(',', array_rand($colors, 3)).')'));
	$draw->setFillOpacity(1);

	$src->annotateImage(
		$draw,
		($k * $letter_w) ?: 10,
		$font_size + rand(-$y_padding, $y_padding),
		rand(-30, 30),
		$v
	);
}

// save captcha in session
$_SESSION['captcha'] = md5(implode($captcha_chars));

// display
$src->setImageFormat('gif');
header('Content-type: image/gif');
echo $src;

Это максимально упрощенный вариант с использованием только одного шрифта и небольшого количества символов и цветов, хотя и этого бывает достаточно, чтобы оградиться от незатейливых спамеров и флудеров.

В HTML такое изображение вызывается стандартно:
<img src="sec_pic.php" alt="captcha" />

UPDATE: кнопка обновления

Почему-то кнопка обновления капчи вызвала затруднения, хотя надо просто обновить src у img




captcha

Всем добра!

posted on february 25, 2008, updated on september 05, 2025

Комментарии

Картинка хорошая, спасибо.
Только объясните, пожалуйста, как принимающий скрипт узнает, что на ней нарисовано?

Mastik 15.03.2008 19:16 #

Через переменную сессии.
Когда генерируем изображение - $_SESSION['secpic'] = implode('',$cod);
Когда проверяем - if($_SESSION['secpic'] === strtolower($_POST['secpic']))

Alek Veritov 17.03.2008 06:53 #

Отличный скрипт, большое спасибо

Winxp 13.07.2008 14:08 #

в скрипте отличные буквы, мне оч понравился, а если еще и заработает у меня вообще отлично будет

seryjvolk 31.08.2008 00:41 #

Спасибо. СимпотишнЫе картинки. Будем ща прикручивать к фидбэку. Спасиб автору :)

pati 09.10.2008 01:08 #

Спасибо! Так лень было самому писать))

Faust 22.10.2008 19:48 #

Вставляю следующий код на свою страницу:
echo '<img src="captcha.php">';
echo <<<HTML
<form action="" method="post">
Secpic: <input type="text" maxlength="4" name="secpic" ><br />
<input type="submit" name="submit" value="Отправь меня!" />
</form>
HTML;
if ($_SESSION['secpic'] == $_POST["secpic"]) {echo "Код введен правельно.";}
Ввожу код ПРАВЕЛЬНО, но надпись "Код введен правельно." не появляется. Что делать ?

DRONNY 31.01.2009 19:10 #

У меня тоже самое, что и у DRONNY!
Объясните плиз!

drD0s 25.02.2009 15:10 #

выведите на экран $_SESSION['secpic'] и $_POST["secpic"], посмотрите что в них и будет вам счастье...

Alek Veritov 25.02.2009 15:48 #

Разобрался!
В самое начало страницы нужно воткнуть начало сессии!
<?php session_start(); ?>
...

drD0s 25.02.2009 17:18 #

Эмммм. А кто подскажет.
На Denwer капча работает нормально, а вот на сервере (CentOS)Apache не рисуется!
В чем проблема и как можно исправить?!

CaTacLYSM 03.03.2009 11:34 #

to CaTacLYSM: проверяйте правильность установки GD библиотеки на сервере

Alek Veritov 03.03.2009 23:31 #

Alek, молодец!) Кульный скрипт

Smile42RU 19.07.2009 17:41 #

А есть небольшая проблема с Кешированием. У меня почему-то сессии не совпадают немного. И когда неправильно введен код, то шаблонизатор заново отображает функцию, например, регистрации, а там код тот же, что и до этого. И при этом дико несоответствуют сессии друг другу. Запаздывают примерно на одно обновление. Как это можно исправиль. Прошу прощения за сумбур.

Динар 28.10.2009 16:01 #

добавляй случайный GET параметр к ссылке, что-нибудь типа
/captcha.php?rand=1234, чтобы браузер и прокси не кешировали

Alek Veritov 28.10.2009 22:53 #

Не получается, прошу разобраться.
В начале файла с формой ставлю старт сессии, но при вызове изображения переменная сессии не хочет запоминаться. Не могли бы вы выложить и примерный простой текст фала формы. Тоесть вы тут выложили пример но не полностью и поэтому применяя свою форму что-то да не получается.

Макс 29.11.2009 03:06 #

Картинки замечательные. К генератору никаких замечаний, всё работает, однако передачу значения кода с картинки через переменную сессии осуществить не удалось. Если можете, разъясните подробнее на рабочем примере "Форма+капча+обработчик формы и кода"

Андрей 19.01.2010 20:33 #

Таки заработало!
1. Включить куки (не уверен что нужно, но читал. что без этого может не работать);
2. Удалить из браузера всю историю, куки, посещённые адреса, кеш, можно отключить кеширование страниц и т.д.(пароли оставляем:));
3. session_star() пишем как в обработчеке формы, так и в скрипте генерации изображения.
4. Открываем "почищенный" браузер, а лучше какой-нибудь свежеустановленный альтернативный и пробуем там - должно заработать!

Андрей 19.01.2010 21:52 #

Здравствуйте!
Сделал все как тут, картинка генерируется, но проблема вот в чем:
пытаюсь на той же странице вывести из сессии ТЕКСТ картинки, а он выводит почему то СТАРЫЙ, а не тот который сейчас на картинке. Да и еще при первом запуске браузера он вообще бьет ошибку на строку вывода, а когда обновляю страницу то уже выводит, но выводит текст с предыдущей картинки.

Serega 17.04.2010 15:34 #

А вот код, как я это делаю:
<p>
<img src="secpic.php" alt="защитный код">
<?php
$a = $_SESSION['secpic'];
echo $a;
?>
</p>

Serega 17.04.2010 15:35 #

У меня проблемка, скрипт иногда выводит на картинку одно, а в переменную сессии другое, в чём может быть дело?
Кэширование точно не причем. После чистки всего, кэша, истории и кук, тестил на чистом браузере...

Александр 12.06.2010 07:28 #

День добрый!
Присоединяюсь к Александру. Тоже самое. Бьюсь второй день. Есть несовпадение с тем, что на картинке и с тем, что выводит $_SESSION['secpic']. В этой сессионной переменной почему то всегда значение которое было на предыдущей капче. Самое интересное что значения $_SESSION['secpic'] в скрипте моем, куда вставлена проверка и в скрипте который строит саму капчу (тот что в шапке этой статьи) РАЗНЫЕ. я это выяснил, когда добавил отсылку значения $_SESSION['secpic'] к себе на е-майл. Получилось что $_SESSION['secpic'] внутри скрипта построения капчи имеет ВЕРНОЕ значение (что и на текущей картинке), а при проверке и вызове этой переменной в своем скрипте, НЕВЕРНОЕ (предыдущее значение капчи). Помогите разобраться пожалуйста!

anonymous 07.07.2010 15:25 #

Скрипт и капча просто супер. Что бы все заработало нужно в принимающем файле вписать следующее.
$a = $_SESSION['secpic'];
$a = strtolower($a);
$b = $_POST['test'];
$b = strtolower($b);
$b = trim($b);
echo "В переменной а содержится: ".$a;
echo "<br>";
echo "В переменной b содержится: ".$b;
echo "<br>";
if ($a == $b) {
echo "куль";
}
else {
echo "некуль";
}
?>
<br><br><br>
<form name="news" method="post" action="hello.php">
<img src="blocks/secpic/secpic.php" alt="защитный код" /><br>
<input type="text" name="test">

<input type="submit" name="Submit" value="Изменить">
</form>

Set 31.08.2010 09:45 #

Цитата: "У меня проблемка, скрипт иногда выводит на картинку одно, а в переменную сессии другое, в чём может быть дело?"

Извиняюсь забыл уточнить, када писал это сообщение, что использовал русский алфавит, и вот он та даёт осечку такого типа. Как мне кажется эта проблема кроется в генераторе картинки. Где буквы в цикле перебираются.

При использовании английских символов осечек нету, у меня точно.

Set, на счёт вашего варианта попробую, может сканает :)

В чём суть моей проблемы, я хочу замутить капчу на русском, пока не решил проблему...

Александр 08.10.2010 19:45 #

Хорошая капча. Автору спасибо!

Беломор 06.02.2011 21:22 #

Как обновить картинку с новым кодом капTча ?

Jasperio 31.03.2011 00:26 #

Чтобы обновить изображение:

<span id="captcha"><img onclick="reload(); return false;" src="sec_pic.php" alt="защитный код" style="cursor:pointer;" /></span>

<script language="javascript" type="text/javascript">
function reload () {
var random_value = new Date().getTime();
document.getElementById('captcha').innerHTML = '<img onclick="reload(); return false;" src="sec_pic.php" alt="защитный код" style="cursor:pointer;" />';

};
</script>

MS 08.04.2011 23:20 #

Аналогичная проблема с сессией.
Переменная сессии показывает предыдущее значение с картинки.

ICEBERG 22.04.2011 02:27 #

в каптче сессия должна стартовать session_start();
а также сессия должна стартовать в Вашем php скрипте session_start();

в скрипте - обработчике сравниваем значения
$_SESSION['secpic'] и $_POST['captcha']

if ($_POST['captcha'] != $_SESSION['secpic'] OR !$_SESSION['secpic']) echo 'error';
else echo 'good';

MS 24.04.2011 11:33 #

Как перегрузить средствами php или js исходный файл(secpic.php), чтобы тот файл к которому прикручена капча не перегружался. Попробовал функцию в сообщении от 08.04.11 - не работает.

Дмитрий 28.04.2011 16:46 #

не дописал 1 строку, чтобы работало нужно заменить в сообщении от 08.04

<img onclick="reload(); return false;" src="sec_pic.php" alt="защитный код" style="cursor:pointer;" />

на

<img onclick="reload(); return false;" src="sec_pic.php?random_value=' + random_value + '" alt="защитный код" style="cursor:pointer;" />

MS 30.04.2011 16:03 #

Автору - опишите пожалуйста как Вы реализовали проверку на ввод защитного кода "Неправильный защитный код!".

Дмитрий 06.05.2011 14:57 #

Неплохо было бы автору обновить исходник и код вверху добавив к нему предоставленную возможность обнавления (очень полезная штука) но всеравно обоим авторам спс за скрипт

wcb-tezarius 14.05.2011 14:33 #

Отличный скрипт, спасибо.

Серей 16.05.2011 05:32 #

Картинка красивая, но выложите, кто-нить, пож., полностью работающую капчу с проверкой введенного кода и обновлением капчи.
Сенкс!

Раиса 06.06.2011 23:08 #

Не работает, на картинке и в переменной разные символы...:((

Alex 11.07.2011 01:19 #

Символы на картинке и в переменной разные пока вы сеанс не перезапустите,т.к. в том же сеансе данные извлечь нельзя.
Сделал свой вариант, капчу сделал ф-цией которая сразу возвращает значение кея и сохраняет картинку в гифку (имя картинки регеню по ид сессии), когда надо ф-ция вызывается, потом картинка вставляется и значение кода сразу известно.

Zakhar 25.08.2011 13:45 #

Такой вопрос:
как можно увеличить контрастность выводимых символов на картинке
к примеру символы в фоне покрасить черным цветом а нужные для проверки сделать поярче

TEZARIUS 18.10.2011 10:27 #

Цвета букв задаются как RGB тремя числами от 0 до 255. Для фона они выбираются случайно в соответствующей функции, для основных задаются варианты потемнее - см.код. И то и другое, естественно, можно поменять.

Alek Veritov 19.10.2011 10:03 #

Спасибо хороший скрипт!

pan_fx 16.11.2011 04:42 #

Спасибо! Целый день искал наконец нашел, установился без проблем

Алексей 29.11.2011 16:56 #

Можно еще и фон поменять, супер то что надо

Алексей 29.11.2011 17:00 #

Обалденный скрипт :))) Спасибо большое автору, все просто и без гемороя!!! и главное работает :))

Саша 26.12.2011 00:19 #

Применил данный пример, очень доволен, спасибо.

Заставить работать обновление картинки из постов от 08.04.11 и 24.04.11 не получилось
Зато я сочинил еще один похожий вариант с использованием библиотеки jQuery, который заработал у меня:

<div class='captcha'>
<img onclick='reload()' src='secpic.php'>
</div>

function reload() {
$(".captcha").empty();
$("<img onclick='reload()' src='secpic.php?"+ new Data().getTime() +"'/>").appendTo(".captcha");
}

Kapust 26.12.2011 15:12 #

Автор, большие благодарности за код! Работает идеально. Просто, стильно и со вкусом! Кликнул по рекламе :)

Black Diamond 26.01.2012 00:20 #

Fatal error: Call to undefined function imagecreatetruecolor() in F:serverwwwtestcommentssecpic.php on line 14
В моем php что нету такой функции?

От человека 27.02.2012 16:50 #

ну так и было, GD2 не было подключено! Спасибо за скрипт!

От человека 27.02.2012 16:59 #

в сессии находится предыдущие значение картинки,как быть?
только сравниваю не с с элементом массива post а то что введено в строку

Виталий 03.03.2012 21:12 #

Прекрасный скрипт. Но при использовании все равно валила куча спама пока в сессии не начал передавать не сам код в открытом виде, а md5 хэш. Видимо спам боты могут считывать переменные из сессии.

Константин 27.03.2012 10:31 #

Скрипт супер, спасибо, единственный трабл, ввожу все правельно, а пишет Регистрация невозможна: код подтверждения введен не верно
Из-за чего это?

от меня 15.05.2012 14:58 #

Подскажите пожалуйста. Как проверить $_SESSION['secpic'] на той же странице на которую выводим капчу (например явой). Ведь в этом случае переменная методом POST не передается и соответственно $_POST['secpic'] не существует и сравнивать переменную сессии не с чем.

Anar 20.07.2012 19:08 #

А для обновления именно этой капчи без перезагрузки страницы я использую этот простейший JavaScript код:

<img src="secpic.php?" title="Обновить картинку" onClick="this.src = 'secpic.php?'+Math.random();"/>

Не забывайте также экранировать кавычки если у вас ошибки php возникают, вот так например

<img src="secpic.php?" title="Обновить картинку" onClick="this.src = 'secpic.php?'+Math.random();"/>

DeepTDS 29.07.2012 23:51 #

Обратные слэши тут в комментариях вырезаются поэтому второй код без экранирования тоже)))
Ну думаю разобраться сможете)

DeepTDS 29.07.2012 23:54 #

Здравствуйте. А как можно передать данные случайной строки в captcha.php , или забрать оттуда, если session не используется, отключены куки? послать их при вызове GET? captcha.php/?randstr= ? это безопасно? по другому нельзя?

nikeddarn 21.08.2012 16:26 #

Код рабочий для тех у кого ручки не оттуда вот мной подправленный исходник
<?php
session_start();
echo "<img src='captcha.php' alt='защитный код' />";
echo <<<_END
<form action="test.php" method="post">
Secpic: <input type="text" maxlength="4" name="secpic" /><br />
<input type="submit" name="submit" value="Отправь меня!" />
</form>
_END;

if (isset($_POST['secpic'])) {
$secpic = $_POST['secpic'];

if ($_SESSION['secpic'] == $secpic) {
echo "Код введен правильно";
}
else {
echo "Код введен не правильно";
}
}
?>

Vi_ru_S 02.11.2012 14:07 #

Автору спасибо:) Кликнул по рекламке:)

Vi_ru_S 02.11.2012 14:14 #

Спасибо, очень круто

Андрей 19.12.2012 14:34 #

В конце не мешало бы еще поставить imagedestroy($src);

techncode 22.02.2013 14:10 #

Народ Session не обновляется, сравнение не срабатывает

Ростислав 16.03.2013 15:00 #

Большое спасибо! Отличный скрипт

Анатолий 30.03.2013 22:51 #

Не могу это приладить в Joomla 2.5. В сессии пусто. Подскажите, пожалуйста, как эту красивую штучку приладить в форму регистрации?

Сергей 01.04.2013 23:38 #

На хосте заработало! Пришлось добавить в верху secpic.php:
$mainframe = JFactory::getApplication('site');
$mainframe->initialise();

и внизу:
$s=implode('',$cod);
$session = JFactory::getSession();
$session->set('secpic', $s);
$_SESSION['secpic'] =$s;
Только так заработало (. Будем проверять. Автору - Спасибо!

Сергей 02.04.2013 02:49 #

Примного благодарен за скриптик

Василий Васильевич 12.04.2013 05:44 #

Спасибо большое за скрипт!
Очень полезная вещь!

userX 23.05.2013 15:00 #

Спам боты пробивают эту captch-у. Как можно защитить передачу правильного ответа от ботов?

Павел 01.06.2013 22:54 #

Пояснения к предыдущему комментарию:

У меня пробивали не через captcha, а SQL-запросами.
Проверил бесплатной программой NetSparker и нашел как боты обходят защиту код-картинка.

Павел 03.06.2013 07:12 #

Спасибо! То, что надо.

Андрей 05.09.2013 12:12 #

Все красиво и удобно, только проверка правильности ввода не работает. session_start(); на обоих страничках есть. На страничке с формой значение переменной $_SESSION['secpic'] недоступно, хотя в файле sess_ID значение сохраняется. Вот содержимое: secpic|s:5:"dbsp6"; В чем дело? Вторую неделю не могу ни чего сделать.

Михаил 16.10.2013 14:43 #

а вот бы еще REFRESH добавить надо
не подскажите?

ilma55 17.10.2013 18:50 #

ха ха. я сделал =)
<img src="<?=SITE_PATH?>views/script/kartinka.php?sid=<?php echo md5(time()) ?>" id="cap_img">
<a href="#"onclick="document.getElementById('cap_img').src = '<?=SITE_PATH?>views/script/kartinka.php?sid=' + Math.random(); return false">Refresh</a>

ilma55 17.10.2013 19:19 #

"ilma55 ха ха. я сделал =)"
------------------------------
А проверку на правильность ввода как делаете? Ведь без этого это бесполезная вещь, хоть как ее раскрась. Что интересно, здесь-то
проверка работает, специально проверил, а я не могу сделать.

Михаил 18.10.2013 16:33 #

В smarty интегрировать не получается, может кто знает как это делается?

Андрей 05.12.2013 18:44 #

Спасибо огромное, очень выручил своим скриптом, действительно классный ;)

ro$ven 14.12.2013 00:15 #

Вот спасибо большое за простой и красивый код.
Кстати чтоб при нажатии на картинку генерировалась новая нужно всего то добавить onClick, и стиль просто для отображения руки
<img src="sec_pic.php" onclick="this.src='sec_pic.php'" style="cursor:pointer;">

Иванов Михаил 14.11.2014 01:35 #

Спасибо, очень помогло!!!

Аликс 05.02.2015 21:53 #

Надо в файли генерации картинки вставить Session_start() и в самый верх вашего индексного файла (index.*) тоже самое. И всё :)

Crack1 25.02.2015 09:05 #

А это обновлять картинку:
<a href="javascript:void(0);" onclick="document.getElementById('capcha-image').src='captcha.php?rid=' + Math.random();">Обновить картинку</a>

Crack1 25.02.2015 09:07 #

А еще я заменил строку записи в сессию на $_SESSION['feedback']=md5(implode('',$cod));
это чтобы зашифрованная была сразу.
потом проверяем: if(trim(md5($_POST['code']))==$_SESSION["feedback"])...
---
а есчооооо я заметил, что при изменении размера (ширины) картинки буквы всё также толкутся у левого края. оптимально-красиво до 120px ширину делать. Возможно для красоты надо добавлять количество выводимых на картинку символов.
Крутой скрипт! красивый! какже я его раньше то не замечал! :)

Crack1 25.02.2015 09:13 #

Капча красивая и работает прекрасно. Спасибо!

Sanek_OS9 02.03.2015 13:22 #
Отправка новых комментариев временно отключена. Извините, работаем над этим.


tags cloud