Пишем простой авторегистратор. Часть 6 - пишем для RegSubmitter.

Содержание

  1. Инструментарий
  2. Основы
  3. Боремся с капчей
  4. Подключаем антикапчу
  5. Подтверждение по email
  6. Пишем модуль для RegSubmitter

В этой заключительной статье я покажу, как можно легко и аккуратно реализовать материал, изложенный в предыдущих статьях, при помощи RegSubmitter

Введение в предмет.

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

Сразу скажу, что в этой статье я буду пользоваться версией RegSubmitter 1.4.0, которая пока официально не зарелизена, но уже скоро будет Smile Впрочем, все нижеизложенное будет работать и в 1.3.6, за исключением подтверждения по email.

Структура модуля

Прежде всего, отмечу, что в RS есть два типа модулей: простые и "универсальные". Простые работают только с одним конкретным сервисом, и "универсальные" могут работать со многими сайтами на одинаковых движках. В рамках этой статьи мы каснемся только простых модулей и будем рассматривать все на примере memori.ru.

Модули в RegSubmitter разбиваются по категориям, и располагаются в папке modules/Category_Name/Module_ID/module_ID.php. Здесь module_ID - это буквенно-цифровой идентификатор модуля, который должен быть уникален для каждого модуля (впрочем, это не означает, что он должен быть нечитаем Wink ). Например, модуль, работающий с сервисом Memori.ru находится по адресу /modules/Rus/Memori/Memori.php.

В этом файле должен находиться класс с именем, совпадающим с Module_ID, и при этом унаследованным от класса Module.

Код модуля

Ниже я приведу полный код модуля с комментариями, но перед этим сделаю несколько заметок.

Первая состоит в том, что в начале класса идут параметры, задающие свойства модуля и то, как он будет обрабатываться RegSubmitter-ом. Во-вторых, я не буду отдельно описывать API RegSubmitter'a, но по ходу дела буду пояснять назначение тех или иных функций и их параметров.

 

<?php
class Memori extends Module
{
	// Параметры модуля
	var $name = 'Memori'; // Имя сервиса, отображаемое пользователю
	var $id = 'Memori'; // Все тот же Module_ID
	var $url = 'http://memori.ru/'; // URL сервиса. Настоятельно рекомендую указывать правильный :-)
	var $icon = 'memori.png'; // Имя иконки. Должна лежать в одной папке с файлом модуля.
	var $notice = ''; // Дополнительная информация, которую мы желаем сообщить пользователям
	var $email_confirm = true; // Требуется ли подтверждение по email
	var $core_version = 3; // Версия ядра, на которую рассчитан модуль, необходимо для проверки совместимости. Нынешняя, как не трудно догадаться - 3
	var $encoding = 'cp1251'; // Кодировка сайта.
	
	/**
	 * Функция, ответственная за загрузку капчи.
	 * Если ввод капчи не требуется, возвращает null. В противном случае возвращает массив данных, 
	 * которые понадобятся при отправке формы, в т. ч. имя временного файла с кукисами, различные токены и т. п.
	 * Обязательно в массиве должен быть элемент image_file, чтобы RegSubmitter мог отобразить капчу пользователю для ввода.
	 */
	function GetForm()
	{
		// Запрашиваем страницу регистрации.
		$page = $this->Get('http://memori.ru/registration/');
		// Извлекаем токен
		preg_match('#<input type="hidden" name="token" value="([0-9a-z]+)" />#is', $page, $matches);
		
		// Ноу-хау: допываем картинку из рекапчи
		$js = $this->Get('http://api.recaptcha.net/challenge?k=6LfV6wgAAAAAAF327mU7j7lzG6s-p1SolxPA2Wx2');
		preg_match("#challenge : '([^']+)'#", $js, $key);
		// Собственно скачиваем картинку
		$image = $this->Get("http://api.recaptcha.net/image?c=$key[1]");
		
		// Генерируем имена временных файлов для хранения кукисов и картинки. Параметр - префикс имени файла.
		$cookies_file = $this->TempFile('cookie');
		$image_file = $this->TempFile('image');
		
		$this->SaveCookies($cookies_file); // Сохраняем кукисы
		file_put_contents($image_file, $image); // Сохраняем картинку
		
		// Возвращаем данные, которые нам понадобятся потом.
		return array(
			'image_file'	=> $image_file, // Картинку капчи. ОБЯЗАТЕЛЬНО!
			'cookies_file'	=> $cookies_file, // Файл с кукисами
			'key'			=> $matches[1], // Токен формы, добытый в начале
			'recaptcha'		=> $key[1], // Токен рекапчи
		);
	}
	
	/**
	 * Эта функция занимается собственно произведением регистрации.
	 * Параметры:
	 * - $account массив из элеменитов login, password, email. Назначение, думаю, очевидно :)
	 * - $data тот самый массив, который мы вернули из функции GetForm()
	 * - $captcha текст, написанный по мнению пользователя на капче.
	 * Функция возвращает null в случае успеха или массив сообщений об ошибках, если они возникли.
	 */
	function SubmitReg($account, $data, $captcha)
	{
		// Собираем запрос
		$post_data = array(
			'login'			=> $account['login'], // Логин
			'email'			=> $account['email'], // Емейл
			'password'		=> $account['password'], // Пароль
			'password_confirm'	=> $account['password'], // И снова пароль
			'recaptcha_response_field'	=> $captcha, // Текст с картинки
			'recaptcha_challenge_field'	=> $data['recaptcha'], // Токен рекапчи
			'token'			=> $data['key'], // Токен формы
			'inviter'		=> '', // Просто пустое поле. Видимо, для какой-то реферральной системы
		);
		
		// Загружаем сохраненные кукисы с прошлого раза
		$this->LoadCookies($data['cookies_file']);
		// Отправляем запрос. Первый параметр - куда, второй - параметры запроса, 
		// третий (опциональный, по умолчанию - false) - надо ли преобразовывать страницу из кодировки сайта в родную для RS (utf-8)
		// Очевидно, что для веб-страниц его надо ставить true, а дял картинок - false. Аналогичный параметр есть и у метода $this->Get()
		$html_data = $this->Post("http://memori.ru/register/", $post_data, true);
		
		// Проверяем успешность регистрации
		if(strstr($html_data, 'На указанный Вами электронный адрес'))
		{
			return null;
		}
		else
		{
			// Если не прошло, добываем ошибки.
			preg_match_all('#<p class="error">([^<]+)</p>#mu', $html_data, $matches);
			return $matches[1];
		}
	}
	
	/**
	 * Функция подтверждения по почте.
	 * Параметр $account содержит те же данные о логине, пароле и email-e, что и в случае с методом SubmitReg.
	 * возвращает null в случае успеха или массив с сообщениями об ошибках в ином случае.
	 */
	function Confirm($account)
	{
		// Ищем письмо по отправителю. Кроме того, в теле письма должен упоминаться домен из поля $this->url
		$mail = $this->findMail('no-reply@memori.ru');

		// Загружаем тело сообщения
		$text = $this->getMailBody($mail['msg_id']);
		
		// Извлекаем ссылку подгверждения
		preg_match('#http://memori.ru/regconfirm/[0-9]+/[0-9a-z]+/#i', $text, $url);

		// Отправляем запрос
		$html_data = $this->Get($url[0], true);

		// Проверяем успешность
		if(strstr($html_data, '/logout/'))
		{
			return null;
		}
		else
		{
			// Если что не так - ругаемся.
			return array('Произошла ошибка активации или аккаунт уже был ранее подтвержден');
		}
	}
}
// Alles :-)
?>

Напоследок замечу, что в RS имеется очень удобная для отладки функция dbg($var). Будучи вызванная в любом месте кода она выведет дамп переменной var внизу страницы. Она особенно хороша тем, что работает в том числе и тогда, когда скрипт вызывается через AJAX.

Во вложении к посту полный архив модуля Memori. И, кстати, на этот раз в нем нет никаких ошибок Wink

Короткой строкой.

  • В процессе поиска хостинга для нового своего проекта нашел один недорогой хостинг. Между прочим, они являются спонсорами такого крупного ресурса, как phpbbguru.net, что есть хороший показатель.
  • Сегодня беседовал с хорошим товарищем на тему телефонов и брендов. Он утверждал, что яблочные телефоны - рабство Стива Джобса, хоть с джейлбрейком, хоть без него. И говорил что у нормальных производителей вроде нокии и тупых ограничений нет, и отзывы о nokia хорошие, не то что у яблофона, который с очередным обновлением прошивки грозит превратиться в кирпич. После долгих споров пришли к выводу, что пиво хорошее, но его мало. Вот так Smile.

Dimmu Borgir - The Sacrilegious Scorn



Trackback URL for this post:

http://nevkontakte.org.ru/trackback/379
Прикрепленный файлРазмер
Memori.zip3.34 кб
MyFreeWeb вт, 12/01/2010 - 00:57

"preg_match_all('#

([^<]+)

#mu', $html_data, $matches);"
напомнило http://b23.ru/s67l Smile
А вообще, почему PHP? Python же.

Alek$ вт, 12/01/2010 - 01:03

PHP потому как массовый потребитель с ним лучше знаком и ему проще объяснить, как это установить и заставить работать (Денвер тот же). Но в то же время это кроссплатформенно и вдобавок можно запускать на большинстве хостингов, что есть плюс.
Так что вот Smile

Просто Бомжик вт, 12/01/2010 - 21:33

Очнь подробно расписал. Спасибо.
Рекапча форева.

Alek$ вт, 12/01/2010 - 23:22

Пожалуйста Smile

Andipas чт, 18/02/2010 - 06:04

Может выложишь в свободный доступ функцию dbg($var), был бы оч. признателен =) Не пойму как она при AJAX запросе может что то выводить, разве только в лог файл.

Alek$ чт, 18/02/2010 - 22:53

Там все основано на фишке Котеровской AJAX библиотеки, которую я использую, перехватывающей весь вывод скрипта и передающей его в качестве отдельной переменной.
А код функции такой:

function dbg($var, $title = '')
{
	if(!defined('DEBUG') || DEBUG == false)
		return;
	
	global $template;
	if(empty($template))
	{
		echo "<h4>$title</h4><pre>";
		echo htmlspecialchars(var_export($var, true));
		echo "</pre></h4>";
	}
	else
	{
		static $n = 1;
		$template->set_row_vars('debug', array(
			'NUMBER'	=> $n,
			'TITLE'		=> $title,
			'CODE'		=> htmlspecialchars(var_export($var, true)),
		));
		$n++;
	}
}
Andipas пт, 19/02/2010 - 03:36

Ясно теперь. Я уж подумал про универсальное решение =) Но видимо такого нет. Здесь AJAX получает ответ и как он вычисляет, где нужные ему данные а где дебаг?

Alek$ пт, 19/02/2010 - 22:13

Не буду вдаваться в детали, дабы ненароком не исказить впечатление - лучше всего об этом прочитать на сайте автора Smile



Отправить комментарий

  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступны HTML теги: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <b> <s> <u> <p> <h3> <br> <strike> <sup> <pre> <h4> <hr>
  • Строки и параграфы переносятся автоматически.
  • You may use [inline:xx] tags to display uploaded files or images inline.
  • Текстовые смайлы будут заменены на графические.
CAPTCHA
Вы точно не бот?
9 + 9 =
Without JavaScript you won't pass captcha test, sorry. Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.