Своя капча на php без сторонних зависимостей за 10 минут
Чаще всего изображения со случайным кодом (так называемая 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
Всем добра!
Картинка хорошая, спасибо.
Только объясните, пожалуйста, как принимающий скрипт узнает, что на ней нарисовано?
Через переменную сессии.
Когда генерируем изображение - $_SESSION['secpic'] = implode('',$cod);
Когда проверяем - if($_SESSION['secpic'] === strtolower($_POST['secpic']))
Отличный скрипт, большое спасибо
в скрипте отличные буквы, мне оч понравился, а если еще и заработает у меня вообще отлично будет
Спасибо. СимпотишнЫе картинки. Будем ща прикручивать к фидбэку. Спасиб автору :)
Спасибо! Так лень было самому писать))
Вставляю следующий код на свою страницу:
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!
Объясните плиз!
выведите на экран $_SESSION['secpic'] и $_POST["secpic"], посмотрите что в них и будет вам счастье...
Разобрался!
В самое начало страницы нужно воткнуть начало сессии!
<?php session_start(); ?>
...
Эмммм. А кто подскажет.
На Denwer капча работает нормально, а вот на сервере (CentOS)Apache не рисуется!
В чем проблема и как можно исправить?!
to CaTacLYSM: проверяйте правильность установки GD библиотеки на сервере
Alek, молодец!) Кульный скрипт
А есть небольшая проблема с Кешированием. У меня почему-то сессии не совпадают немного. И когда неправильно введен код, то шаблонизатор заново отображает функцию, например, регистрации, а там код тот же, что и до этого. И при этом дико несоответствуют сессии друг другу. Запаздывают примерно на одно обновление. Как это можно исправиль. Прошу прощения за сумбур.
добавляй случайный GET параметр к ссылке, что-нибудь типа
/captcha.php?rand=1234, чтобы браузер и прокси не кешировали
Не получается, прошу разобраться.
В начале файла с формой ставлю старт сессии, но при вызове изображения переменная сессии не хочет запоминаться. Не могли бы вы выложить и примерный простой текст фала формы. Тоесть вы тут выложили пример но не полностью и поэтому применяя свою форму что-то да не получается.
Картинки замечательные. К генератору никаких замечаний, всё работает, однако передачу значения кода с картинки через переменную сессии осуществить не удалось. Если можете, разъясните подробнее на рабочем примере "Форма+капча+обработчик формы и кода"
Таки заработало!
1. Включить куки (не уверен что нужно, но читал. что без этого может не работать);
2. Удалить из браузера всю историю, куки, посещённые адреса, кеш, можно отключить кеширование страниц и т.д.(пароли оставляем:));
3. session_star() пишем как в обработчеке формы, так и в скрипте генерации изображения.
4. Открываем "почищенный" браузер, а лучше какой-нибудь свежеустановленный альтернативный и пробуем там - должно заработать!
Здравствуйте!
Сделал все как тут, картинка генерируется, но проблема вот в чем:
пытаюсь на той же странице вывести из сессии ТЕКСТ картинки, а он выводит почему то СТАРЫЙ, а не тот который сейчас на картинке. Да и еще при первом запуске браузера он вообще бьет ошибку на строку вывода, а когда обновляю страницу то уже выводит, но выводит текст с предыдущей картинки.
А вот код, как я это делаю:
<p>
<img src="secpic.php" alt="защитный код">
<?php
$a = $_SESSION['secpic'];
echo $a;
?>
</p>
У меня проблемка, скрипт иногда выводит на картинку одно, а в переменную сессии другое, в чём может быть дело?
Кэширование точно не причем. После чистки всего, кэша, истории и кук, тестил на чистом браузере...
День добрый!
Присоединяюсь к Александру. Тоже самое. Бьюсь второй день. Есть несовпадение с тем, что на картинке и с тем, что выводит $_SESSION['secpic']. В этой сессионной переменной почему то всегда значение которое было на предыдущей капче. Самое интересное что значения $_SESSION['secpic'] в скрипте моем, куда вставлена проверка и в скрипте который строит саму капчу (тот что в шапке этой статьи) РАЗНЫЕ. я это выяснил, когда добавил отсылку значения $_SESSION['secpic'] к себе на е-майл. Получилось что $_SESSION['secpic'] внутри скрипта построения капчи имеет ВЕРНОЕ значение (что и на текущей картинке), а при проверке и вызове этой переменной в своем скрипте, НЕВЕРНОЕ (предыдущее значение капчи). Помогите разобраться пожалуйста!
Скрипт и капча просто супер. Что бы все заработало нужно в принимающем файле вписать следующее.
$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, на счёт вашего варианта попробую, может сканает :)
В чём суть моей проблемы, я хочу замутить капчу на русском, пока не решил проблему...
Хорошая капча. Автору спасибо!
Как обновить картинку с новым кодом капTча ?
Чтобы обновить изображение:
<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>
Аналогичная проблема с сессией.
Переменная сессии показывает предыдущее значение с картинки.
в каптче сессия должна стартовать session_start();
а также сессия должна стартовать в Вашем php скрипте session_start();
в скрипте - обработчике сравниваем значения
$_SESSION['secpic'] и $_POST['captcha']
if ($_POST['captcha'] != $_SESSION['secpic'] OR !$_SESSION['secpic']) echo 'error';
else echo 'good';
Как перегрузить средствами php или js исходный файл(secpic.php), чтобы тот файл к которому прикручена капча не перегружался. Попробовал функцию в сообщении от 08.04.11 - не работает.
не дописал 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;" />
Автору - опишите пожалуйста как Вы реализовали проверку на ввод защитного кода "Неправильный защитный код!".
Неплохо было бы автору обновить исходник и код вверху добавив к нему предоставленную возможность обнавления (очень полезная штука) но всеравно обоим авторам спс за скрипт
Отличный скрипт, спасибо.
Картинка красивая, но выложите, кто-нить, пож., полностью работающую капчу с проверкой введенного кода и обновлением капчи.
Сенкс!
Не работает, на картинке и в переменной разные символы...:((
Символы на картинке и в переменной разные пока вы сеанс не перезапустите,т.к. в том же сеансе данные извлечь нельзя.
Сделал свой вариант, капчу сделал ф-цией которая сразу возвращает значение кея и сохраняет картинку в гифку (имя картинки регеню по ид сессии), когда надо ф-ция вызывается, потом картинка вставляется и значение кода сразу известно.
Такой вопрос:
как можно увеличить контрастность выводимых символов на картинке
к примеру символы в фоне покрасить черным цветом а нужные для проверки сделать поярче
Цвета букв задаются как RGB тремя числами от 0 до 255. Для фона они выбираются случайно в соответствующей функции, для основных задаются варианты потемнее - см.код. И то и другое, естественно, можно поменять.
Спасибо хороший скрипт!
Спасибо! Целый день искал наконец нашел, установился без проблем
Можно еще и фон поменять, супер то что надо
Обалденный скрипт :))) Спасибо большое автору, все просто и без гемороя!!! и главное работает :))
Применил данный пример, очень доволен, спасибо.
Заставить работать обновление картинки из постов от 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");
}
Автор, большие благодарности за код! Работает идеально. Просто, стильно и со вкусом! Кликнул по рекламе :)
Fatal error: Call to undefined function imagecreatetruecolor() in F:serverwwwtestcommentssecpic.php on line 14
В моем php что нету такой функции?
ну так и было, GD2 не было подключено! Спасибо за скрипт!
в сессии находится предыдущие значение картинки,как быть?
только сравниваю не с с элементом массива post а то что введено в строку
Прекрасный скрипт. Но при использовании все равно валила куча спама пока в сессии не начал передавать не сам код в открытом виде, а md5 хэш. Видимо спам боты могут считывать переменные из сессии.
Скрипт супер, спасибо, единственный трабл, ввожу все правельно, а пишет Регистрация невозможна: код подтверждения введен не верно
Из-за чего это?
Подскажите пожалуйста. Как проверить $_SESSION['secpic'] на той же странице на которую выводим капчу (например явой). Ведь в этом случае переменная методом POST не передается и соответственно $_POST['secpic'] не существует и сравнивать переменную сессии не с чем.
А для обновления именно этой капчи без перезагрузки страницы я использую этот простейший 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();"/>
Обратные слэши тут в комментариях вырезаются поэтому второй код без экранирования тоже)))
Ну думаю разобраться сможете)
Здравствуйте. А как можно передать данные случайной строки в captcha.php , или забрать оттуда, если session не используется, отключены куки? послать их при вызове GET? captcha.php/?randstr= ? это безопасно? по другому нельзя?
Код рабочий для тех у кого ручки не оттуда вот мной подправленный исходник
<?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 "Код введен не правильно";
}
}
?>
Автору спасибо:) Кликнул по рекламке:)
Спасибо, очень круто
В конце не мешало бы еще поставить imagedestroy($src);
Народ Session не обновляется, сравнение не срабатывает
Большое спасибо! Отличный скрипт
Не могу это приладить в Joomla 2.5. В сессии пусто. Подскажите, пожалуйста, как эту красивую штучку приладить в форму регистрации?
На хосте заработало! Пришлось добавить в верху secpic.php:
$mainframe = JFactory::getApplication('site');
$mainframe->initialise();
и внизу:
$s=implode('',$cod);
$session = JFactory::getSession();
$session->set('secpic', $s);
$_SESSION['secpic'] =$s;
Только так заработало (. Будем проверять. Автору - Спасибо!
Примного благодарен за скриптик
Спасибо большое за скрипт!
Очень полезная вещь!
Спам боты пробивают эту captch-у. Как можно защитить передачу правильного ответа от ботов?
Пояснения к предыдущему комментарию:
У меня пробивали не через captcha, а SQL-запросами.
Проверил бесплатной программой NetSparker и нашел как боты обходят защиту код-картинка.
Спасибо! То, что надо.
Все красиво и удобно, только проверка правильности ввода не работает. session_start(); на обоих страничках есть. На страничке с формой значение переменной $_SESSION['secpic'] недоступно, хотя в файле sess_ID значение сохраняется. Вот содержимое: secpic|s:5:"dbsp6"; В чем дело? Вторую неделю не могу ни чего сделать.
а вот бы еще REFRESH добавить надо
не подскажите?
ха ха. я сделал =)
<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 ха ха. я сделал =)"
------------------------------
А проверку на правильность ввода как делаете? Ведь без этого это бесполезная вещь, хоть как ее раскрась. Что интересно, здесь-то
проверка работает, специально проверил, а я не могу сделать.
В smarty интегрировать не получается, может кто знает как это делается?
Спасибо огромное, очень выручил своим скриптом, действительно классный ;)
Вот спасибо большое за простой и красивый код.
Кстати чтоб при нажатии на картинку генерировалась новая нужно всего то добавить onClick, и стиль просто для отображения руки
<img src="sec_pic.php" onclick="this.src='sec_pic.php'" style="cursor:pointer;">
Спасибо, очень помогло!!!
Надо в файли генерации картинки вставить Session_start() и в самый верх вашего индексного файла (index.*) тоже самое. И всё :)
А это обновлять картинку:
<a href="javascript:void(0);" onclick="document.getElementById('capcha-image').src='captcha.php?rid=' + Math.random();">Обновить картинку</a>
А еще я заменил строку записи в сессию на $_SESSION['feedback']=md5(implode('',$cod));
это чтобы зашифрованная была сразу.
потом проверяем: if(trim(md5($_POST['code']))==$_SESSION["feedback"])...
---
а есчооооо я заметил, что при изменении размера (ширины) картинки буквы всё также толкутся у левого края. оптимально-красиво до 120px ширину делать. Возможно для красоты надо добавлять количество выводимых на картинку символов.
Крутой скрипт! красивый! какже я его раньше то не замечал! :)
Капча красивая и работает прекрасно. Спасибо!