Скрипт для проверки e-mail и сбора ссылок активации (PHP+Human Emulator)

Решил я все таки написать пост про то как мы хуманом собираем почту, раз уж сегодня у меня выдался вынужденный выходной. Скрипт сам написан на PHP и вроде бы как может работать и без хуман эмулятора (не проверял). Сразу хочу сказать — основная идея данного поста описать наш алгоритм проверки почты при многопотоке, а выложенные ниже скрипт — это бонус. Я не гарантирую что он у вас будет работать и не буду отвечать на вопросы типа «Почему у меня не работает?», я слишком хреновый кодер чтобы разбирать почему кого-то что-то не работает.

Итак, приступим. Начнем с того что всю почту мы шлем на один ящик на своем домене, назовем его human@domain.com. Если вы хотите регать аккаунты на гмейлы с точками — просто делаете форвардинг всей почты на ваш ящик на вашем домене. Мы же регаем в основном на свои домены, на рендомные ящики типа name@domain.com. Делается это примерно так (на примере панели ISPManger). Идем в раздел «Домены«->»Почтовые домены» и добавляем новый почтовый домен, заполняем поля вот так:isp_mail1

понятное дело, что вместо domain.com — ваш домен.

Далее, «Учетные записи«->»Почтовые ящики» и добавляем новый ящик:

isp_mail2Если хотите слать с двух доменов, например, то добавляете как на первой картинке еще один домен domain2.com, но перенаправляем все равно на human@domain.com, ну и ящик добавлять не надо, будет у вас с двух доменов идти все в один ящик. Причем ящики можно теперь делать совершенно случайные:

sfhajh@domain.com
ksyyn@domain.com
vasya@domain.com
395483875@domain2.com
daitedeneg@domain2.com

Все письма с этих и любых других ящиках окажутся в одном ящике — human@domain.com.

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

Допустим у нас есть 10 потоков регера какого нибудь блогсервиса, каждый регается на свое мыло в формате логин@domain.com (где логин — уникальное слово для каждого аккаунта). И все сваливается в ящик human@domain.com. У нам имеется папка mail_tmp, куда мы складываем все письма, и временный файл mail_lock. Итак, запустили мы скрипт, первый поток доходит до проверки почты, и проверяет наличие нужного файла в папке mail_tmp. Нужный файл — это файл имя которого логин@domain.com.txt, то есть для каждого потока этот файл будет свой.

Так как поток первый — то в папке пусто, поэтому поток создает файл mail_lock, это означает что другие потоки, дойдя до проверки почты, будут стоять на паузе пока файл существует. Далее поток переходит к проверке почты и циклически, указанное количество раз, пытается проверить почту. В почте мы ищем все письма заголовок которых содержит нужные нам данные (ну что то вроде: «Сервис ВасяПупкин и ко приветствует вас»). И все найденные письма сохраняются в папку mail_tmp, каждое под своим именем (имя файла, как я уже говорил — равно почтовому ящику на который регаем аккаунт). Выглядеть папка будет как-то так:

mails_list1

Письма наши удаляются с ящика при скачивании, то есть то письмо которое забираем себе в папку — удаляем. После чего поток завершает работу с почтовым сервером, удаляет файл mail_lock и продолжает свою работу. Второй поток, увидев что файла нету — проверяет папку mail_tmp на наличие своего письма, с большой вероятностью оно уже там будет, если да — то почту он даже не проверяет, а забирает письмо и работает себе дальше. Если же письма нет то создается файл mail_lock и повторяется вышеописанная процедура.

Входящие данные

 

Сейчас будет огромный кусок кода сразу с комментариями что для чего, код вырезал как есть.


$DEF_xhe_path = "G:\\XWeb\\Human Emulator MT\\"; //путь к уставновленному хуман эмулятору, обязательно с экранированными слешами
$DEF_script_path = $DEF_xhe_path."My Scripts\\tramplins v4.0\\"; //путь к скрипту, обязательно с экранированными слешами
$DEF_data_path = $DEF_script_path."data\\"; //путь к обновляемым данным для переменных, обязательно с экранированными слешами
$DEF_const_data_path = $DEF_data_path."const data\\"; //путь к данным котоыре не удаляются из файла, обязательно с экранированными слешами
$DEF_mail_tmp_dir = $DEF_script_path."mail_tmp\\"; //путь к папке куда сохраняем почту

$DEF_register_attempts = 3; //количество попыток регистрации с одинаковыми данными
$DEF_attempts_fails_to_stop = 7; //количество попыток регистрации с разными данными
/* количество попыток регистрации влияет на циклы, то есть пробуем регнуться $DEF_register_attempts раз с одинаковыми данными,
если не выходит то меняем данные и пробуем еще $DEF_register_attempts раз, данные меняются $DEF_attempts_fails_to_stop раз
данные органичения позволяют не слить весь баланс с антигейта за ночь из-за случайной ошибки в скрипте либо изменений в сервисе
*/

$DEF_wait_for_mail_recheck = 5; //секунд, время ожидания для перепроверки почты
$DEF_mail_recheck_attempts = 12; //количество перепроверок почты
$DEF_mail_full_recheck_attempts = 3; //количество циклов проверок почты
/* используется при проверке почты, каждые $DEF_wait_for_mail_recheck секунд скрипт пытается проверить почту на наличие нужных писем
количество попыток использования равно $DEF_mail_recheck_attempts,
при рекомендуемых значениях ($DEF_wait_for_mail_recheck = 5 и $DEF_mail_recheck_attempts = 12) максимальное время ожидания письма составляет минуту,
после чего цикл повторяется еще $DEF_mail_full_recheck_attempts раз и в случае неудачи рега поулчает статус фейла и должна пробовать регнуться заново
*/

$DEF_max_mail_lock_time = 300; //секунд
/*максимальное время жизни файла mail_lock, данный файл нужен при многопотоке, когда один из потоков проверяет ящик - создается этот файл
если файл существует то остальные потоки ждут
вообще логика проверки почты у нас такая:
1. поток №1  хочет проверить почту, видит что файла нет, создает файл, приступает к проверке почты
алго проверки почты:
- почта проверяется до тех пор пока в папке mail_tmp не появится файл с именем ящика на который должно прийти письмо, либо пока не пройдет время заданное переменными $DEF_wait_for_mail_recheck и $DEF_mail_recheck_attempts
- перед первой проверкой ящика ВСЕГДА проверяется наличие в папке mail_tmp нужного файла
2. пока создан файл mail_lock (находится в корневой папке софта) потоки №2, №3...№50 ждут
3. как только поток №1 завершит работу - он удаляет файл mail_lock, и следующий в очереди поток идет в алгоритм проверки почты, зачастую бывает что первый поток уже скачал все нужные письма,
поэтому перед проверкой почты кажыдй поток всегда проверяет сначала наличие файла в папке, и если файл есть то проверка почты не запускается для этого потока
4. обычно время проверки ящика у нас равно 1 минуте (задаем в $DEF_wait_for_mail_recheck и $DEF_mail_recheck_attempts), однако бывают случаи когда првоеряющий почту поток вылетел или мы сами его закрыли,
тогда остальные потоки будут ждать $DEF_max_mail_lock_time от времени СОЗДАНИЯ файла(по дефолту 5 минут, 300 сек), после чего файл удаляется и следующий в очереди поток начинает алгоритм проверки почты
*/

Функция сбора почты

Не забываем поменять domain.com на ваш домен.

 //поулчаем с ящика ВСЮ почту с указанным сабжектом (тема письма) и создаем по указанному пути файл имя которого равно имени ящика на который было ОТПРАВЛЕНО письмо(обычно это не тот ящик который мы првоеряем)
function libGetAllMailWithSubj($host="{mail.domain.com:143/novalidate-cert}INBOX",$login="human@domain.com",$pass="qwerty",$path_to_mail_tmp,$subj_str,$txt_decode=0){
    imap_timeout(1,120);
    $mbox = imap_open ($host,$login,$pass);

    for($i=1;$i<=imap_num_msg($mbox);$i++){

        $header = imap_header($mbox,$i,0,200);

//        sleep(3);    

//        $to_address = $header->toaddress;

        $arr_to_address = $header->to;
        $to_address = $arr_to_address[0]->mailbox."@".$arr_to_address[0]->host;

        $mail_filename = $path_to_mail_tmp.$to_address.".txt";

    //    $subject = imap_utf8($header->fetchsubject);
        $subject = $header->fetchsubject;

        if(!is_file($mail_filename)){

//                $mail_text = imap_body($mbox,$i); // перестало рабоать хз почему
            $mail_text = imap_fetchbody($mbox,$i,1);

            if($txt_decode==1){
                $mail_text = imap_qprint($mail_text);
            }
            if($txt_decode==2){
                $mail_text = imap_base64($mail_text);
            }
//                echo $i.": ".$subject." ~ ".$subj_str." - ".strstr($subject,$subj_str)."<br>";
            if(strstr($subject,$subj_str)){
                libCreateFile($mail_filename,$mail_text);
                imap_delete ($mbox, $i);
            }

        }
    }
    imap_expunge($mbox);
    imap_close($mbox);

}

 

Модуль проверки почты

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

<?php

clearstatcache();
if((time()-filemtime("mail_lock")) >$DEF_max_mail_lock_time){
    @unlink("mail_lock");
    clearstatcache();
}

$pro_url_res = 0;
$mail_check_fail =0 ;
$mail_check_count = 0;

sleep(5);
do{
    clearstatcache();    
    if(!is_file($DEF_mail_tmp_dir.$user_mail.".txt")){
        $mail_read = 0;
        $mail_lock  = 0;
        $mail_check_num = 0;
            
        do{
            clearstatcache();
            $mlock_file = $DEF_script_path."mail_lock";
            $mail_lock = is_file($mlock_file);

            if($mail_lock == 0){

                libCreateFile("mail_lock",$argv[1]);
                libGetAllMailWithSubj("{".$mail_server.":143/novalidate-cert}INBOX",$mail_login,$mail_pass,$DEF_mail_tmp_dir,$mail_subj_to_check,$mail_subj_encode);
                unlink($mlock_file);
                if(is_file($DEF_mail_tmp_dir.$user_mail.".txt")) $mail_read = 1;
                else{

                    sleep($DEF_wait_for_mail_recheck);
                    $mail_check_num++;
                }
            }
            else{
                sleep($DEF_wait_for_mail_recheck);
                $mail_check_num++;

                if(is_file($DEF_mail_tmp_dir.$user_mail.".txt")) $mail_read = 1;
            }
            if($mail_check_num>=$DEF_mail_recheck_attempts) $mail_read = 1;
        }while($mail_read == 0);    
    }
    else{    
        $pro_url_res = 1;
    }
    
    $mail_check_count++;
    if($mail_check_count>$DEF_mail_full_recheck_attempts){
        $mail_check_fail = 1;
    }
    
}while($pro_url_res == 0||$mail_check_fail == 1);

?>

 

А следующий это уже вызов модуля в регере:

//--------------READING MAIL----------------------
$mail_server = "mail.domain.com";
$mail_login = "human@domain.com";
$mail_pass = "qwerty";
$mail_subj_to_check = "=?iso-8859-11?B?ZGVrLWQuY29tIC0gwtS5tNW06c25w9G6ytnoysHSqtShIOC056G01bTN?= =?iso-8859-11?B?t6TNwQ==?=";
$mail_subj_encode = 0; //если сабжект зашифрован пробуем вместо 0 подставить1 или 2

include($DEF_script_path."lib\\modules\\read_mail.php"); //сохраняет письмо в файл, в случае фейла выдает переменную $mail_check_fail равную 1

/*
    если почта проверена успешно - вытягиваем из текста письма урл активации и переходим по нему
    если же во время проверки почты произошла ошибка то ставим $i_attempts=$DEF_register_attempts,
        чтобы скрипт больше не пытался регнуться с этими данными
*/

$mail_subj_to_check — это наш сабжект письма, иногда, когда язык какой то типа испанского — он выглядит вот так, смотреть его нужно в исходнике письма, ну либо в фукнции была строка

echo $i.": ".$subject." ~ ".$subj_str." - ".strstr($subject,$subj_str)."<br>";

Если ее раскомментировать — то окно дебага хумана выдаст сначала реальный сабжект письма, а потом тот что у нас в переменной, и останется только в переменную подставить реальный сабжект. Главное чтобы письмо в ящике во время дебага было одно, а то офигеете от количества инфы.

После отработки модуль выдает переменную $mail_check_fail, равную 0 если все ок и 1 если письма нет. Ну и в конце всей это радости регуляркой вытягиваем урл активации, естественно http://www.blogservis.com/register/ меняем на ваши значения, иногда регулярка нужна чуть посложнее.

        if(!$mail_check_fail){
            $mail_text = file_get_contents($DEF_mail_tmp_dir.$user_mail.".txt");                
            preg_match_all('|http://www.blogservis.com/register/(.*?)\n|',$mail_text,$pro_url_arr);
            $pro_url = "http://www.blogservis.com/register/".$pro_url_arr[1][0];            
    
            $browser->navigate($pro_url);        
            $browser->wait_for(90,2);    
         ...

        }

 

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

P.S. еще в коде используется функция libCreateFile, вот её исходник

    //создаем файл $path со строкой $txt_data
    function libCreateFile($path,$txt_data){
        $file=fopen($path,"w+");
        flock ($file,LOCK_EX);
        fputs($file,$txt_data);
        fflush ($file);
        flock ($file,LOCK_UN);
        // close out file
        fclose($file);
    }

Добавить комментарий

Вход: