У нас на корпоративном портале есть календарь:
Он работает с MySQL, таблица представляет из себя:
CREATE TABLE `inventory` ( `id` int(6) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `opisanie` varchar(100) DEFAULT NULL, `login` varchar(20) DEFAULT NULL, `loginapt` varchar(20) DEFAULT NULL, `sotrudniki` varchar(50) DEFAULT NULL, `complect` varchar(40) DEFAULT NULL, `start` datetime DEFAULT NULL, `end` datetime DEFAULT NULL, `users` varchar(150) DEFAULT NULL, `buh` varchar(60) DEFAULT NULL, `colcomp` varchar(1) DEFAULT NULL, `close` varchar(5) DEFAULT '0', `dateclose` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`), KEY `login` (`login`) ) ENGINE=InnoDB AUTO_INCREMENT=295 DEFAULT CHARSET=utf8;
Задача — организовать выгрузку этого календаря в файл, для возможности импорта в другие календари(например google).
Наиболее распространенным форматом является iCalendar(.ics), его и будем использовать. Как это не смешно, но самое адекватное описание формата можно получить на википедии, а также экспортировав календарь из того же google(или microsoft outlook) и открыв блокнотом.
Для начала отобьём все запросы вне сессии(хотя секретной информации нет, но пусть будет небольшая безопасность):
if(!isset($_SESSION['login'])){ //если обращение вне сессии завершаем скрипт exit; }
Следующим шагом подключимся к БД:
$mysqli = new mysqli("****", "*****", "*******", "*******"); if ($mysqli->connect_errno) { echo "Не удалось подключиться к MySQL:".$mysqli->connect_error; exit; }
Отберем последние 100 записей инвентаризации(т.к. торговых объектов ~60, то больше нам не нужно) в массив $arraydb:
$mysqli->query("SET NAMES utf8"); $result = $mysqli->query("SELECT * FROM inventory ORDER BY id DESC LIMIT 100"); //для экономии памяти отрываем 100 последних записей $i=0; while( $row = $result->fetch_assoc() ){ if(strtotime($row['start']) >= time()) { //выбираем в массив актуальные даты начала $arraydb[$i]= $row; $i++; } } $result->close();
Т.к. сотрудники у нас в отдельной таблице:
CREATE TABLE `apt_users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(160) DEFAULT NULL, `fio` varchar(80) DEFAULT NULL, `dol` varchar(110) DEFAULT NULL, `date` datetime DEFAULT NULL, `active` int(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1772 DEFAULT CHARSET=utf8;
Соответственно нам понадобится выборка сотрудников, вытянем ее в массив $arraysotr:
$result = $mysqli->query("SELECT id, fio FROM apt_users"); //вытягиваем список сотрудников while( $row = $result->fetch_assoc() ){ $arraysotr[$row['id']]= $row['fio']; } $result->close(); $mysqli->close();
Т.к. нам еще пригодится адрес и время работы, а они в другой базе , то подключемся к ней, вытянем данные в массив $arrayadr, и закроем соединение:
$mysqli = new mysqli("**********", "********", "********", "********"); if ($mysqli->connect_errno) { echo "Не удалось подключиться к MySQL:".$mysqli->connect_error; exit; } $mysqli->query("SET NAMES utf8"); $result = $mysqli->query("SELECT LOGIN, ADR, TIME FROM `search.apt`"); //вытягиваем адреса объектов while( $row = $result->fetch_assoc() ){ $arrayadr[$row['LOGIN']]['ADR'] = $row['ADR']; $arrayadr[$row['LOGIN']]['TIME'] = $row['TIME']; } $result->close(); $mysqli->close();
Т.к. генерация файла будет осуществляться сразу в скрипте, то добавим хидеры для выгрузки файла в браузер:
header("Content-type: application/ics"); header('Content-Disposition: attachment; filename="pereuchet.ics"');
В качестве отладки можно выводить текст генерируемого календаря в браузер, для чего закомментируем хидеры выше и добавим новый:
header("Content-type: text/text; charset=UTF-8"); //вывод в браузер
Соответственно, чтобы выгрузить файл, закомментируем этот и раскомментируем предыдущие. Далее выведем текст, который меняться не будет(заголовок календаря):
echo 'BEGIN:VCALENDAR VERSION:2.0 PRODID:-//by name dudko X-WR-CALNAME:Переучет на аптеках CALSCALE:GREGORIAN BEGIN:VTIMEZONE TZID:Europe/Minsk TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Minsk X-LIC-LOCATION:Europe/Minsk BEGIN:STANDARD TZOFFSETFROM:+0300 TZOFFSETTO:+0300 TZNAME:MSK DTSTART:19700101T000000 END:STANDARD END:VTIMEZONE';
Далее в цикле создадим ивенты:
for($i=count($arraydb)-1;$i>=0;$i--){ $sotrudniki = explode(';',$arraydb[$i]['sotrudniki']); echo ' BEGIN:VEVENT DTSTAMP:'.date('Ymd').'T'.date('His').'Z UID:'.date('Ymd').'T'.date('His').'Z-'.md5($arraydb[$i]['start'].$arraydb[$i]['end'].$arraydb[$i]['name']).'@sergdudko.tk DTSTART;VALUE=DATE:'.date_format(date_create($arraydb[$i]['start']), 'Ymd').' DTEND;VALUE=DATE:'; $dateend = date_create($arraydb[$i]['end']); $dateend->modify('+1 day'); echo date_format($dateend, 'Ymd'); echo ' SUMMARY:Переучет:'.$arraydb[$i]['name'].' DESCRIPTION:Бухгалтер: '.explode(';', $arraydb[$i]['buh'])[0].'\n\n Участники переучета: '; for($j=0;$j < count($sotrudniki);$j++){ echo $arraysotr[$sotrudniki[$j]]; if($j+2 < count($sotrudniki)){ echo ', '; } } echo '\n\n Комплекты: '.$arraydb[$i]['complect'].'\n\n Описание: '.$arraydb[$i]['opisanie'].'\n\n Рабочее время: '.$arrayadr[$arraydb[$i]['loginapt']]['TIME']; echo ' LOCATION:'.$arrayadr[$arraydb[$i]['loginapt']]['ADR'].' END:VEVENT'; }
По генерации в цикле:
UID — должен быть уникальным, иначе он просто перезапишет события одно на другое.
DTSTART и DTEND — время начала и окончания события, соответственно. Не забываем, что если событие весь день, то DTEND — это не 23:59:59указанного числа, а 00:00:00(т.е. +1 день).
SUMMARY — наименование события.
DESCRIPTION — описание события.
LOCATION — адрес для google maps.
Далее закроем календарь:
echo ' END:VCALENDAR'; exit; ?>
В качестве отладки, открываем блокнотом(я использую notepad++) сгенерированный календарь и проверяем его соответствия с тем, который экспортировали из google(у меня, например, были проблемы с переносами строк). Проверяем его импорт в гугл и microsoft outlook.
Ну и для самой выгрузки нам нужно просто сделать ссылку на соответствующий скрипт.
<a href="php/saveicall.php" type="application/file">Скачать iCalendar файл</a>