Это мой первый пост на Хабре, по этому не судите строго.
Реализовать возможность загрузки фотографий в профайл или в фотоленту события посредством электронной почты, поместить их в заданную папку и сделать соответственную запись в БД.
Пользователь отправляет письмо с фотографиями на адрес типа userXXX_eventYYY@mysite.com, где eventYYY — ID события; userXXX — ID пользователя. Такого e-mail адреса НЕ СУЩЕСТВУЕТ. По этому все письма отправленные на несуществующие адреса перенаправляем на image_upload@mysite.com. Потом, при считывании почты с этого адреса, парсим заголовки и узнаем на какой адрес изначально было отправлено письмо. Распарсив полученный адрес, узнаем КУДА складывать файлы и кто их залил.
Для работы с POP3 сервером использовалась библиотека PEAR, в частности класс Net_POP3, который находится в файле path/to/pear/Net/POP3.php. Для его успешной работы необходим класс Net_Socket (path/to/pear/Net/Socket.php) и, собственно, PEAR.php. Все эти файлы находятся на сайте http://pear.php.net и доступны для скачивания.
Если PEAR у вас не установлена — просто скопируйте POP3.php и Socket.php в вашу папку с библиотеками и перепропишите пути в них. Файл PEAR.php есть в папке path/to/pear/.
Для обработки прикрепленных файлов мне понадобились еще несколько функций. Не буду приписывать себе их авторство. Они взяты с сайта http://webi.ru/webi_articles/6_12_f.html и немного переделаны (совсем немного).
В моем коде они выглядят так:
Теперь, когда все готово, пришло время писать скрипт для получения писем и их обработки.
Для начала, создадим объект $pop3 и подсоединимся к серверу.
Теперь все готово для получения списка писем и их обработки. Это и делаем
Пройдемся по всем письмам в цикле:
Собственно все. Модуль работает. Осталось только повесить этот файлик на CRON (например, каждый час).
Спасибо на внимание. Желаю удачи!
Задача.
Реализовать возможность загрузки фотографий в профайл или в фотоленту события посредством электронной почты, поместить их в заданную папку и сделать соответственную запись в БД.
Алгоритм
Пользователь отправляет письмо с фотографиями на адрес типа userXXX_eventYYY@mysite.com, где eventYYY — ID события; userXXX — ID пользователя. Такого e-mail адреса НЕ СУЩЕСТВУЕТ. По этому все письма отправленные на несуществующие адреса перенаправляем на image_upload@mysite.com. Потом, при считывании почты с этого адреса, парсим заголовки и узнаем на какой адрес изначально было отправлено письмо. Распарсив полученный адрес, узнаем КУДА складывать файлы и кто их залил.
Использование PEAR
Для работы с POP3 сервером использовалась библиотека PEAR, в частности класс Net_POP3, который находится в файле path/to/pear/Net/POP3.php. Для его успешной работы необходим класс Net_Socket (path/to/pear/Net/Socket.php) и, собственно, PEAR.php. Все эти файлы находятся на сайте http://pear.php.net и доступны для скачивания.
Если PEAR у вас не установлена — просто скопируйте POP3.php и Socket.php в вашу папку с библиотеками и перепропишите пути в них. Файл PEAR.php есть в папке path/to/pear/.
Дополнительные функции
Для обработки прикрепленных файлов мне понадобились еще несколько функций. Не буду приписывать себе их авторство. Они взяты с сайта http://webi.ru/webi_articles/6_12_f.html и немного переделаны (совсем немного).
В моем коде они выглядят так:
/* START FUNCTIONS BLOCK */
// Функция для выдергивания метки boundary из заголовка Content-Type
function get_boundary($ctype){
if(preg_match('/boundary[ ]?=[ ]?(["]?.*)/i',$ctype,$regs)) {
$boundary = preg_replace('/^\"(.*)\"$/', "\\1", $regs[1]);
return trim("--$boundary");
}
}
// если письмо будет состоять из нескольких частей (текст, файлы и т.д.)
// то эта функция разобьет такое письмо на части (в массив), согласно разделителю boundary
function split_parts($boundary,$body) {
$startpos = strpos($body,$boundary)+strlen($boundary)+2;
$lenbody = strpos($body,"\r\n$boundary--") - $startpos;
$body = substr($body,$startpos,$lenbody);
return explode($boundary."\r\n",$body);
}
// Эта функция отделяет заголовки от тела и возвращает массив с заголовками и телом
function fetch_structure($email) {
$ARemail = Array();
$separador = "\r\n\r\n";
$header = trim(substr($email,0,strpos($email,$separador)));
$bodypos = strlen($header)+strlen($separador);
$body = substr($email,$bodypos,strlen($email)-$bodypos);
$ARemail["header"] = $header;
$ARemail["body"] = $body;
return $ARemail;
}
// разбирает все заголовки и выводит массив, в котором каждый элемент является соответсвующим заголовком
function decode_header($header) {
$headers = explode("\r\n",$header);
$decodedheaders = Array();
foreach($headers as $header_item){
$thisheader = trim($header_item);
if(!empty($thisheader))
{
if(!ereg("^[A-Z0-9a-z_-]+:",$thisheader))
$decodedheaders[$lasthead] .= " $thisheader";
else {
$dbpoint = strpos($thisheader,":");
$headname = strtolower(substr($thisheader,0,$dbpoint));
$headvalue = trim(substr($thisheader,$dbpoint+1));
if($decodedheaders[$headname] != "")
$decodedheaders[$headname] .= "; $headvalue";
else
$decodedheaders[$headname] = $headvalue;
$lasthead = $headname;
}
}
}
return $decodedheaders;
}
// перекодировщик тела письма.
// Само письмо может быть закодировано и данная функция приводит тело письма в нормальный вид.
// Так же и вложенные файлы будут перекодироваться этой функцией.
function compile_body($body,$enctype,$ctype) {
$enctype = explode(" ",$enctype); $enctype = $enctype[0];
if(strtolower($enctype) == "base64")
$body = base64_decode($body);
elseif(strtolower($enctype) == "quoted-printable")
$body = quoted_printable_decode($body);
if(ereg("koi8", $ctype)) $body = convert_cyr_string($body, "k", "w");
return $body;
}
/* END FUNCTIONS BLOCK */
* This source code was highlighted with Source Code Highlighter.
Основной код (email_upload.php)
Теперь, когда все готово, пришло время писать скрипт для получения писем и их обработки.
Для начала, создадим объект $pop3 и подсоединимся к серверу.
$user='username';
$pass='secure';
$host='mysite.com';
$port="110";
// Создание объекта
$pop3 =& new Net_POP3();
// Соединение с сервером
if(PEAR::isError( $ret= $pop3->connect($host , $port ) )){
echo "ERROR: " . $ret->getMessage() . "\n";
exit();
}
// Авторизация на сервере
if(PEAR::isError( $ret= $pop3->login($user , $pass,'USER' ) )){
echo "ERROR: " . $ret->getMessage() . "\n";
exit();
}
* This source code was highlighted with Source Code Highlighter.
Теперь все готово для получения списка писем и их обработки. Это и делаем
$message_list=$pop3->getListing(); // Получаем массив писем.
* This source code was highlighted with Source Code Highlighter.
Пройдемся по всем письмам в цикле:
foreach($message_list as $message){
$filenames[] = array();
/* START GET PARSED HEADERS */
// Получаем ИД текущено сообщения
$message_id = $message['msg_id'];
// Парсим заголовки
$headers = $pop3->getParsedHeaders($message_id);
$type = $ctype = $headers['Content-Type'];
$ctype = split(";",$ctype);
$types = split("/",$ctype[0]);
$maintype = trim(strtolower($types[0]));
$subtype = trim(strtolower($types[1]));
/* END GET PARSED HEADERS */
/* START CREATE FILE LOCATION AND SQL DATA*/
// Получили данные с заголовка
$from_user_info = $headers['Delivered-To'];
// Далее получаем нужные АйДишники
preg_match('/(user[0-9]+)_(event[0-9]+)@mysite.com/', $from_user_info, $matches);
$user_id = str_replace("user","", $matches[1]);
$event_id = str_replace("event","", $matches[2]);
// Путь куда поместим файл
$file_location = "/path/to/upload";
// Помещаем данные для SQL запроса
$table_data = array(
'user_id' => $user_id,
'event_id' => $event_id
);
/* END CREATE FILE LOCATION AND SQL DATA*/
/* START GET BODY */
// Получаем тело сообщения
$message_text = htmlspecialchars($pop3->getBody($message_id));
// Проверяем его тип (на содержание прикрепленных файлов)
if($maintype=="multipart" && ereg($subtype,"signed,mixed,related")) // Если есть
{
// получаем метку-разделитель частей письма
$boundary=get_boundary($headers['Content-Type']);
// на основе этого разделителя разбиваем письмо на части
$part = split_parts($boundary,$message_text);
//Ищем файлы
foreach($part as $part_item){
// разбиваем текущую часть на тело и заголовки
$email = fetch_structure($part_item);
$header = $email["header"];
$body = $email["body"];
// разбираем заголовки на массив
$headers = decode_header($header);
$ctype = $headers["Content-Type"];
$cid = $headers["content-id"];
$Actype = split(";",$ctype);
$types = split("/",$Actype[0]);
$rctype = strtolower($Actype[0]);
// теперь проверяем, является ли эта часть прикрепленным файлом
$is_download = (ereg("name=",$headers["content-disposition"].$headers["content-type"]) || $headers["X-Attachment-Id"] != "" || $rctype == "message/rfc822");
if($is_download) {
// Имя файла можно выдернуть из заголовков Content-Type или Content-Disposition
$cdisp = $headers["content-disposition"];
$ctype = $headers["content-type"];
$ctype2 = explode(";",$ctype);
$ctype2 = $ctype2[0];
$Atype = split("/",$ctype);
$Acdisp = split(";",$cdisp);
$fname = $Acdisp[1];
if(ereg("filename=\"(.*)\"",$fname,$regs))
$filename = $regs[1];
if($filename == "" && ereg("name=(.*)",$ctype,$regs))
$filename = $regs[1];
$filename = ereg_replace("\"(.*)\"","\\1",$filename);
$filename = ereg_replace(""(.*)"","\\1",$filename);
//читаем файл в переменную.
$body = compile_body($body,$headers["content-transfer-encoding"],$ctype);
// Указываем КУДА записать файл
$filename = $file_location.trim($filename);
// Формируем список файлов для записи в базу
$filenames[] = $filename;
// Собственно сохраняем
$ft=fopen($filename,"wb");
fwrite($ft,$body);
fclose($ft);
}
}
}
// НА основе $filenames[] и $table_data создаем запросы и выполняем их.
$query = "INSERT INTO event_foto(event_id, user_id, image_name) VALUES ";
$total_fotos = count($filenames);
$current = 1;
foreach($filenames as $file){
$query .= "('$event_id','$user_id','$file')";
if($total_fotos>$current)
$query .= ", ";
$current++;
}
mysql_query($query);
//И не забываем удалить текущее письмо
$pop3->deleteMsg($message_id);
}
* This source code was highlighted with Source Code Highlighter.
Конец
Собственно все. Модуль работает. Осталось только повесить этот файлик на CRON (например, каждый час).
Спасибо на внимание. Желаю удачи!