Ноя 15

О невозможной CAPTCHA

Не так давно в блоге я показывал, как сделать капчу на собственном сайте, для того, чтобы защитить формы ввода информации от спама. Сегодня мне встретился потрясающий пример, того, как делать нельзя! Посмотрите на него:

На форуме игры Simutrans для того, чтобы зарегистрироваться или создать новую тему, надо заполнить аж четыре(!) строки. Распознать традиционный буквенный код + ответить на три вопроса, подбираемых случайным образом из некоторого набора. Такая captcha отобьет желание пользоваться сайтом не только у спам-ботов, но и у людей!

В веб-разработке предлагаю руководствоваться двумя правилами в отношении CAPTCHA:

  1. Где можно избежать использование CAPTCHA, следует его избегать;
  2. В каждой форме ввода на сайте не более одной строки для ввода CAPTCHA.

Хорошего кодинга!

Июл 30

Делаем форму обратной связи на сайт с защитой от спама

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

Самый простой способ защиты формы от спама - это использование CAPTCHA. Как сделать собственную CAPTCHA можно прочитать в моей статье "Скрипт текстовой CAPTCHA для защиты от спам-ботов". Но в данном примере мы используем проект KCAPTCHA - готовое решение, разработанное Сергеем Кругловым.

Скачаем содержимое KCAPTCHA с сайта автора и обязательно сохраним в корень сайта, в котором будет выполняться наш скрипт с формой.

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

<form method="post">
<input type="hidden" name="send" value="1"/>
<p>Уважаемый гость! Если Вам интересен наш проект, 
предложите, пожалуйста, тему, которую Вам было бы интересно
видеть разобранной на страницах нашего
сайта или блога:</p>
<textarea name="theme"></textarea>
<br/>
<img src="kindex.php?<?php echo session_name()?>=<?php echo session_id()?>" 
width="120" height="60"><br/>
Введите анти-спам код с картинки:<br/>
<input name="keystring"><br/>
<input type="submit" value="Отправить"/>
</table>
</form>

Форма приведена без какого-либо оформления и CSS-стилей.

Далее рассмотрим скрипт отправки письма:

// получение темы
$theme = htmlspecialchars($_REQUEST['theme'], ENT_QUOTES);

// отправка письма
$subject = 'Тема для разбора с сайта codething.ru';
$mailto = 'mike@pestr.ru';
$headers = "From: mike@pestr.ru";
$message = "Тема: $theme";
$message = iconv("utf-8", "koi8-r", $message);
mail($mailto, $subject, $message, $headers);

Не забывайте заменить мой почтовый адрес mike@pestr.ru на свой!

Перед отправкой функцией mail() сообщение перекодируется в кодировку KOI8-R (так исторически сложилось для электронной почты), в данном скрипте перекодировка идет из формата UTF-8, т.к. сами скрипты я всегда сохраняю в UTF-8, но если вы решите, что вам удобнее использовать windows-кодировку, то пожалуйста, только не забудьте заменить "UTF-8" на "CP1251" в вызове функции iconv() и перекодировка также будет проходить нормально.

Теперь осталось собрать всё в кучу и добавить проверку правильности ввода CAPTCHA для защиты от спама.

Получившийся в итоге программный код будет выглядеть так:

<?php
session_start();
if ($_REQUEST['send']!='')
{

  if(!isset($_SESSION['captcha_keystring']) || 
     $_SESSION['captcha_keystring'] != $_REQUEST['keystring'])
  {
    $message="<p>Форма не отправлена!</p>";
  }
  else
  {
    // получение темы
    $theme = htmlspecialchars($_REQUEST['theme'], ENT_QUOTES);

    // отправка письма
    $subject = 'Тема для разбора с сайта codething.ru';
    $mailto = 'mike@pestr.ru';
    $headers = "From: mike@pestr.ru";
    $message = "Тема: $theme";
    $message = iconv("utf-8", "koi8-r", $message);
    mail($mailto, $subject, $message, $headers);
    $message="<p>Форма отправлена!</p>";
  }
}

if ($message!="")
{
  echo $message;
}
else
{
?>
  <form method="post">
  <input type="hidden" name="send" value="1"/>
  <p>Уважаемый гость! Если Вам интересен наш проект,
  предложите, пожалуйста, тему, которую Вам было бы интересно
  видеть разобранной на страницах нашего сайта или блога:</p>
  <textarea name="theme" ></textarea>
  <br/>
  <img src="kindex.php?<?php echo session_name()?>=<?php echo session_id()?>"
  width="120" height="60"><br/>
  Введите анти-спам код с картинки:<br/>
  <input name="keystring"><br/>
  <input type="submit" value="Отправить"/>
  </table>
  </form>
<?
}
?>

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

Вставку этого кода к себе на сайт я сделал через тег <IFRAME>, можно посмотреть, как это работает на главной странице сайта codething.ru.

Мар 03

Скрипт увеличивающейся при наведении картинки

Скрипт увеличивающейся при наведении картинки

При наведении мышкой картинка увеличивается. Довольно часто необходимо решать эту задачу, особенно часто это используется в выдаче рекламных блоков. Желательно, также, чтобы картинка при наведении мышки увеличивалась, но не ломала верстку страницы.

Рассмотрим решение данной задачи с помощью JavaScript-скрипта и библиотеки jQuery.

<html>
 <head>
  <script src="jquery.js"></script>
 </head>
 <body>
  <img src='small.png' onmouseover='bigImage(this, "big.png");' align="left"/>
  <p>Какой-то текст, показывающий, что увеличенное изображение не ломает верстку, а размещается поверх содержимого страницы.</p>

  <div id="big" style="display: none; top: 0px; left: 0px; position: absolute; z-index: 1000;"></div>
  <script>
  function bigImage(obj, fname)
  {
   $("#big").css("left", $(obj).offset().left);
   $("#big").css("top", $(obj).offset().top);
   $("#big").html("<img src='"+fname+"' onmouseout='bigImageHide();'/><br/>");
   $("#big").show();
  }

  function bigImageHide()
  {
   $("#big").hide();
  }
  </script>
 </body>
</html>

Исходная картинка small.png загружается традиционно средствами HTML, но к ней мы добавим событие onmouseover (срабатывающее при наведении мышки), которое будет вызывать написанную нами функцию bigImage();

Для вывода увеличенной картинки на экран, создадим контейнер big, задав ему абсолютное позиционирование поверх других элементов сайта (z-index: 1000).

В функцию bigImage() передаются два параметра - информация о текущем элементе и название увеличенной картинки.

Функция bigImage() задает координаты контейнера big такими же, как и у уменьшенной картинки, после чего в контейнер размещается HTML-код увеличенного изображения. Увеличенное изображение содержит событие onmouseout (срабатывает, когда мышка ушла с объекта), по которому вызывается функция bigImageHide() - скрывающая с экрана контейнер big.

Полезный совет по использованию примера скрипта увеличения картинки:

  • Если вам надо передать ссылку, просто передавайте её третьим параметром в функции bigImage(). В саму функцию bigImage() также следует внести изменения, добавив в HTML-выдачу соответствующий тег <A> с параметром ссылки.

Скачать архив с примером скрипта увеличивающийся при наведении картинки, 54 Кб.

Июн 09

Скрипт для ротации баннеров

Решил сделать на своем сайте ротацию баннеров от различных партнерских программ. Сайт самописный и различные готовые решения, которые есть, например, для WordPress не подходят (кстати, в WordPress для этих же целей я использую плагин AdRotate, весьма удобный).

Поскольку простейшая ротация баннеров не требует слонжого программирования, то на создание скрипта и его тестирование отладку ушло ~20 минут.
Код баннерного ротатора выглядит следующим образом.

<? 
function rotator($filename)
 {
   if (file_exists($filename)) // проверяем наличие файла
    {
      $s=file_get_contents($filename); // читаем файл в строку
      $n = explode("###", $s);	// разделяем строку на отдельные баннеры
      $r = rand(0,count($n)-1); // выбираем случайное число (по кол-ву баннеров)
      echo $n[$r]; // выводим код баннера в поток вывода
     }
 }
?>

Для удобства использования ротатор реализован в виде функции, параметром которой является имя файла с HTML-кодом рекламных объявлений.
Файл с рекламными объявлениями выглядит следующим образом.

<a href="http://codething.ru/">Уголок веб-разработчика</a>
###
<a href="http://blog.codething.ru/">Блог веб-разработчика</a>
###
<a href="http://forum.codething.ru/">Форум о веб-разработке</a>

В качестве разделителя используется последовательность ###.

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

<?php
 include ("rotator.php");
 rotator("file"); // запускаем с именем файла, в котором код баннеров
?>

Задача ротации баннеров решена.

Июн 07

Формируем PDF файл из PHP

Столкнулся недавно с задачей формирования PDF файла из PHP.  Немного погуглив нашел два программных решения: FPDF и TCPDF. Первое значительно компактнее второго, но мне не подошло, т.к. там имелись проблемы с русскими шрифтами. Шрифты для него необходимо как-то обрабатывать и включать в состав продукта, после чего можно работать. С этим разбираться не хотелось и поэтому я стал смотреть второй вариант - TCPDF. В кодировке UTF-8 всё отображается сразу нормально.

PDF-файл может формироваться разными способами, самый простой из которых -  формирование из HTML кода.  Правда HTML поддерживается лишь частично, но все основное есть и работает. Можно задавать стили и цвета текста, размещать картинки и таблицы. Для моей задачи этого было более чем достаточно.

Весьма просто создать PDF-файл из HTML кода средствами TCPDF, вот пример:

1. сначала копируете файлы TCPDF в необходимую папку на хостинге.

2.  пишете программный код.

<?
require_once('tcpdf/config/lang/eng.php');
require_once('tcpdf/tcpdf.php');
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

// устанавливаем описание документа
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Test');
$pdf->SetTitle('Test');
$pdf->SetSubject('Test');
$pdf->SetKeywords('Test');

// выключаем заголовки, т.к. они нам не нужны
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);

// устанавливаем поля
$pdf->SetMargins(10,10,10,10);

// автоперенос на новую страницу
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);

// пропорционирование картинок
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);

// языковые настройки
$pdf->setLanguageArray($l);

// Устанавливаем шрифт
$pdf->setFontSubsetting(true);
$pdf->SetFont('dejavusans', '', 12, '', true);
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);

// Вывод данных из HTML в PDF
$pdf->AddPage();
$s= '<h1>Привет мир!</h1><p>Это тестовый пример!</p>';
$pdf->writeHTML($s, true, false, true, false, '');
$pdf->Output('test.pdf', 'I');
?>

ВАЖНО! Файл примера должен быть записан в кодировке UTF-8! Иначе ничего не увидите в сгенерированном PDF-файле.

На сайте TCPDF имеется множество других примеров.

P.S. Если при запуске примеров Вы видите ошибку:

TCPDF ERROR: Some data has already been output, can't send PDF file

необходимо перед строками

require_once('tcpdf/config/lang/eng.php');
require_once('tcpdf/tcpdf.php');

вызвать функцию ob_end_clean().

Помогает. Почему-то так было на хостинге от Мастерхост, а на jino.ru сразу все нормально.

P.P.S. TCPDF распространяется по лицензии LGPL, следовательно может встраиваться (при соблюдении лицензионных требований) даже в коммерческие продукты.