Pull to refresh

Как сделать автоматическую рассылку писем без cronа, имея в качестве сервера Windows Server 2008

В данной статье я постараюсь вам описать то, как мне на работе пришлось делать систему автоматической рассылки писем по расписанию, которое указал пользователь. Конечно, вы можете сказать, что не надо было городить весь этот бред и достаточно было иметь всего лишь *Unix сервер, но увы и ах, мне сказали что эта система нужна строго на Windows Server 2008. Поэтому немного пораскинув мозгами, мы с моим напарником-руководителем решили сделать автоматизацию через стандартный Windows Sheduler. Главный вопрос был в том, как сделать, чтобы пользователь мог управлять и создавать задачи для Windows Sheduler через стандартный Web-интерфейс.

Поползав по php мануалу, я нашёл несколько различных команд в php для отправки запроса в консоль сервера:
  • exec()
  • system()

В принципе две схожих по функционалу команды, exec() без дополнительных параметров ничего не выводит при выполнении программы, а system() выводит обратно последнюю строчку в консоли после выполнения программы. Следующим этапом я начал штрудить мануалы по консольным командам. Честно скажу, окончив универ и устроившись на работу, начал жалеть что многое упустил в плане обучения, поэтому приходилось с усилием навёрстывать то, что обычно знает каждый программист. Для тех, кто тоже как и я их плохо знает, вам полезная ссылочка. Там всё хорошо описано и с примерами, лучше чем первая ссылочка в гугле по запросу «список команд cmd». И я приступил к написанию кода, перейдя на интересующий меня раздел. Ниже я предоставлю вам кусок кода, идея которого заключается в следующем:
  1. Получаем данные введённые из заранее подготовленной формы, где указана почта или почты получателей (У нас так же была функция отправки по FTP, но это было для вложений в письмо)
  2. Заносим данные в подготовленную таблицу БД, где хранятся все пользователи, подписавшиеся на рассылку
  3. Создаём *.bat файл, для последующего запуска скрипта отправки письма (в моём случае это была генерация отчёта по определённым признакам, которые пользователь определил при вводе формы и отправки этого отчёта на почту в архиве)
  4. Создаём задачу в Windows Sheduler для запуска этого *.bat файла по тому расписанию, которое указал пользователь

Заранее хочу обговорить, что изначально вариантов подписки было всего три вида — ежедневно, еженедельно и ежемесячно. Соответственно создаётся форма, с которого, мы получаем вариант, который выбрал пользователь.
Пример создания подписки:
<?php
if(isset($_SESSION['query'])){
	if($periodSchedule==1){
		createCSVSubscription($_SESSION['idUser'],$_SESSION['query'][$subQuery],$emailSchedule,$periodSchedule);
		generateBatTxtFile($_SESSION['idUser']);
		exec('cmd /c schTasks /Create /SC DAILY /TN'.' '.$_SESSION['idUser'].' '.'/TR '.BATFiles.$_SESSION['idUser'].'.bat'.' /ST '.$timeSchedule.' /ru '.$systemUser.' /rp '.$systemPassword.'< '.DATAFiles.'key.txt');
		$subscription=TRUE;
	}elseif($periodSchedule==2){
		createCSVSubscription($_SESSION['idUser'],$_SESSION['query'][$subQuery],$emailSchedule,$periodSchedule);
		generateBatTxtFile($_SESSION['idUser']);
		exec('cmd /c schTasks /Create /SC WEEKLY /TN'.' '.$_SESSION['idUser'].' '.'/TR '.BATFiles.$_SESSION['idUser'].'.bat'.' /ST '.$timeSchedule.' /ru '.$systemUser.' /rp '.$systemPassword.'< '.DATAFiles.'key.txt');
		$subscription=TRUE;
	}elseif($periodSchedule==3){
		createCSVSubscription($_SESSION['idUser'],$_SESSION['query'][$subQuery],$emailSchedule,$periodSchedule);
		generateBatTxtFile($_SESSION['idUser']);
		exec('cmd /c schTasks /Create /SC MONTHLY /TN'.' '.$_SESSION['idUser'].' '.'/TR '.BATFiles.$_SESSION['idUser'].'.bat'.' /ST '.$timeSchedule.' /ru '.$systemUser.' /rp '.$systemPassword.'< '.DATAFiles.'key.txt');
		$subscription=TRUE;
	}elseif($periodSchedule==0){
		exec('cmd /c schTasks /Delete /TN'.' '.$_SESSION['idUser'].'< '.DATAFiles.'key.txt');
		unlink(BATFiles.$_SESSION['idUser'].".bat"."");
		unlink(BATFiles.$_SESSION['idUser'].".txt"."");
		$subscription=FALSE;
	}
	$_SESSION['query']=NULL;

	$HisEmails=$emailSchedule;
	include 'TPEmail.php';
}else{
	break;
}
?>

Переменная $periodSchedule содержит частоту рассылки писем, 1 — ежедневно, 2 — еженедельно и 3 — ежемесячно. Функция createCSVSubscription() получает данные от пользователя и записывает их в БД. Далее мы создаём *.bat файл, с названием в виде id пользователя и текстовый файл тоже с названием и содержанием id пользователя(Чуть ниже расскажу почему).
А теперь разберём одну из главных команд:
exec('cmd /c schTasks /Create /SC MONTHLY /TN'.' '.$_SESSION['idUser'].' '.'/TR '.BATFiles.$_SESSION['idUser'].'.bat'.' /ST '.$timeSchedule.' /ru '.$systemUser.' /rp '.$systemPassword.'< '.DATAFiles.'key.txt');
Первый параметр cmd /c делает так называемый — тихий запуск, не оставляя никаких окон и сразу закрывая все консольные процессы сразу же, после выполнения скрипта. Далее мы обращаемся к самому Scheduler, создаём задачу, выбираем частоту запуска, задаём название в виде того же id пользователя, вписываем какой батник запускать(прописывая путь к батнику, он у меня был заранее определён через define в переменной BATFiles), ставим время запуска, т.е. часы и минуты и наконец самое главное, из за чего я долго не понимал, почему запуская батник всё работало, а запуская php скрипт ничего не работало, мы прописываем от какого пользователя создастся задание. И ещё один немаловажный пункт, мы подаём на вход текстовый файл, с самым лаконичным содержанием: «y». На случай если пользователь захочет перезаписать время или частоту уведомления, консоль выкинет ему вопрос, уверены ли вы что хотите это перезаписать. К сожалению, как передать общение с консолью через php или тот же bat я так и не понял, единственный вариант, это подать на вход файл с содержимым ответа:
< '.DATAFiles.'key.txt'
Содержание *.bat файла:
C:\ПУТЬКPHP\php.exe C:\ПУТЬКСКРИПТУ\subscriptionCSV.php < C:\ПУТЬКФАЙЛУ\IDПользователя.txt
В результате, в нужное время запускается через php скрипт, который логинится, берет запросом параметры отчёта для письма из БД(id пользователя он берёт входным параметром из текстового файла) и отправляет его на почту.
Ниже приведу кусок кода, который позволяет php через консоль получать входные данные, путём диалогового окна, которое мы пропускаем автоматическим вводом данных:
<?php
$handle = fopen ("php://stdin","r");
$inputID = fgets($handle);
fclose($handle);
?>

Вот в принципе и все основные идеи при создании автоматического уведомления пользователей по почте. Если что то упустил, пишите в личку, исправлю, добавлю, допишу с радостью!
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.