Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Приём почты
 
 автор: Lilu   (06.02.2007 в 10:21)   письмо автору
 
 

На почтовый ящик приходит письмо, значения кот. необходимо занести в базу данных в соотв-ие таблицы и поля.
Например, на ящик 12345@primer.ru пришло письмо с полями:
3258
Иванов И.В.
АСОИ
3
8,6
На веб страничке есть кнопка при нажатии на кот. эти данные должны попасть в базу данных "mgtu" в таблицу student c полями : N, fio, fakultet, kurs, sr_ball
Подскажите можно ли это как-то сделать....

   
 
 автор: ZuArt   (06.02.2007 в 10:26)   письмо автору
 
   для: Lilu   (06.02.2007 в 10:21)
 

Вообще - можно практически все =) но по конкретике - не буду прям приводить код, т.к. с ходу не напишу за минуту - дам общую концепцию...

Смотри в сторону темы - работа с сокетами + протокол POP3 - это тебе поможет забирать почту с любого почтового сервака, даже если он не на том-же хостинге.

Далее в сторону функций для работы с используемой БД + Transact SQL - это для внесения данных в БД.

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

Вот вкратце алгоритм работы.

   
 
 автор: ZuArt   (06.02.2007 в 10:29)   письмо автору
 
   для: ZuArt   (06.02.2007 в 10:26)
 

ЗЫ. В дополнение можно расширить функционал - если данные в письме не в нужном формате или нехватка данных - автоматизировать обработку или "ответное" письмо с текстом аля "некоректные данные" или просто считать письмо неформатом и пропустить...

   
 
 автор: Trianon   (06.02.2007 в 10:47)   письмо автору
 
   для: Lilu   (06.02.2007 в 10:21)
 

Как почтовый ящик связан с веб-страничкой?
Или это самое письмо и является веб-страницей?

   
 
 автор: ZuArt   (06.02.2007 в 11:01)   письмо автору
 
   для: Trianon   (06.02.2007 в 10:47)
 

[поправлено модератором]

   
 
 автор: Trianon   (06.02.2007 в 11:06)   письмо автору
 
   для: ZuArt   (06.02.2007 в 11:01)
 

Я ничего не утверждал. Я задал два вопроса, и оба - не в Ваш адрес.

[поправлено модератором]

   
 
 автор: ZuArt   (06.02.2007 в 11:22)   письмо автору
 
   для: Trianon   (06.02.2007 в 11:06)
 

[поправлено модератором]

   
 
 автор: lilu   (06.02.2007 в 11:27)   письмо автору
 
   для: Trianon   (06.02.2007 в 11:06)
 

Дело в том, что у меня есть программа служебная она емеет веб интерфейс и на ней есть кнопка "загрузить почту", при нажатии должна заполниться база, после успешной загрузки, например, появится надпись "обновление базы произошло успешно" и далее можно с этой же программы, открывая другой интерфейс пользоваться загруженными новыми данными....
Вот так...
Сокеты - для меня это совсем не знакомая степь, вот читаю, пытаюсь разобраться......

P.S. Я аж испугалась, чуть ли конфликт не возник на моей теме, вот это спросила :))))

   
 
 автор: ZuArt   (06.02.2007 в 11:41)   письмо автору
 
   для: lilu   (06.02.2007 в 11:27)
 

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


<?
function ToSend($fl$txt)
{
  
$ret "";
  
fwrite($fp$txt);
  while (!
feof($fp)) 
  {
    
$ret .= fgets($fp128);
  };
 return 
$ret;
};

$fp fsockopen("mail.primer.ru"110$errno$errstr30);
if (!
$fp)
 {
    echo 
"Ошибка подключения к почтовому серверу $errstr ($errno)<br />\n";
  return;
};

  
$ret ToSend($fp,"команда для подключения");
  
$ret ToSend($fp,"команда для логина");
  
$ret ToSend($fp,"команда для пасс");

  
$ret ToSend($fp,"запрос почты");

  
далее как-то в цикле или по условному оператору запрособработка и удаление писем...

  
$ret ToSend($fp,"закрытие ящика");
   
fclose($fp);
 echo 
"Почта обработана";
}
?>

   
 
 автор: Trianon   (06.02.2007 в 12:03)   письмо автору
 
   для: lilu   (06.02.2007 в 11:27)
 

>Дело в том, что у меня есть программа служебная она емеет веб интерфейс и на ней есть кнопка "загрузить почту", при нажатии должна заполниться база, после успешной загрузки, например, появится надпись "обновление базы произошло успешно" и далее можно с этой же программы, открывая другой интерфейс пользоваться загруженными новыми данными....
То есть, адрес, на который приходят эти письма - это некоторый служебный адрес этой системы, а не чей-то персональный?

И по нажатию кнопки скрипт должен пересмотреть письма в почтовом ящике, прочитать нужные, и переложить данные из них в таблицу БД?


>Вот так...
>Сокеты - для меня это совсем не знакомая степь, вот читаю, пытаюсь разобраться......

Придется работать с почтовым сервером по протоколу POP3. Для этого можно применить либо сокеты, либо php-расширение imap.


>P.S. Я аж испугалась, чуть ли конфликт не возник на моей теме, вот это спросила :))))

Не обращайте внимания, уж Вы-то явно повода не давали. :)

   
 
 автор: lilu   (06.02.2007 в 12:19)   письмо автору
 
   для: Trianon   (06.02.2007 в 12:03)
 

>То есть, адрес, на который приходят эти письма - это некоторый служебный адрес этой системы, а не чей-то персональный?
Ящик специально для этого созданный, личных писем нет там.
>И по нажатию кнопки скрипт должен пересмотреть письма в почтовом ящике, прочитать нужные, и переложить данные из них в таблицу БД?
Отфильтровывать данные не нужно, туда приходят только нужные и в таком виде, кот. представлен выше...Причём на каждого студента - отдельное письмо...

>Придется работать с почтовым сервером по протоколу POP3. Для этого можно применить либо сокеты, либо php-расширение imap.
что первый вариант, что второй - :( без примеров - Никак

   
 
 автор: ZuArt   (06.02.2007 в 12:22)   письмо автору
 
   для: lilu   (06.02.2007 в 12:19)
 

Хммм... как уже указал выше, пример более чем кустарный, но от него можно оттолкнуться в нужную сторону + ОБЯЗАТЕЛЬНО протокол POP3 - без него никак...
ну или как уже выше указывалось - воспользоваться более продвинутыми модулями - там наверняка все проще ;)

   
 
 автор: Trianon   (06.02.2007 в 12:24)   письмо автору
 
   для: lilu   (06.02.2007 в 12:19)
 

Вот пример.
Особое внимание обратите на то, что у сервера бывают запросы с однострочными ответами, и бывают с многострочными.


<?
define
('DEBUG'true); // debug mode
define('SMTP_TIMEOUT'10); // in seconds

function send($fs$data ='')
{
  if(
$data !== 0)
  {
    if(
constant('DEBUG'))
        echo 
'send: '.$data"<br>\r\n";
    
fwrite($fs$data."\r\n");
  }
}
function 
send_rcv($fs$data =''$list=false)
{
  
send($fs$data);
  if(
feof($fs))
     return 
false;
  
$n fgets($fs);
  if(
constant('DEBUG'))
        echo 
'recv: '.$n"<br>\r\n";

  if(
$n === false) return $n;
  if(
$n[0] !== '+') return '2 '.$n;
  if(
$list === false) return '1 '.$n;
  
$r = array($n);
  while((
$n fgets($fs)) !== false && !($n[0] == '.'&& $n[1] != '.'))
  {
  if(
constant('DEBUG'))
        echo 
'recv: '.$n"<br>\r\n";
   if(
$n[0]=='.' && $n[1]=='.'$n substr($n1);
   
$r[] = $n;
  }

  return 
$r;
}

function 
pop3_mail(
$server_host
                   
"pop3.primer.ru"   // адрес сервера pop3 
$login
                   
='12345' // имя пользователя почтового ящика
$password
                   
='password' // пароль почтового ящика
)
{
   
$fs fsockopen($server_host110$errno$errstrconstant('SMTP_TIMEOUT'));
   if(!
$fs)
   {
       echo 
"Cannot connect to $server_host: [$errno$errstr";
       return 
0;
   }
    if(
!= intval(($s send_rcv($fs,0)))) die("Status: $s");
    if(
!= intval(($s send_rcv($fs,$c="USER $login")))) die("Status $c$s");
    if(
!= intval(($s send_rcv($fs,$c="PASS $password")))) die("Status $c$s");

    
$s send_rcv($fs,$c="LIST"1);
    if(!
is_array($s)) die("Status $c : $s");
    
print_r($s);

    
$s send_rcv($fs,$c="UIDL"1);
    if(!
is_array($s)) die("Status $c : $s");
    
print_r($s);

    
$s send_rcv($fs,$c="TOP 1 1"1);
    if(!
is_array($s)) die("Status $c : $s");
    
print_r($s);

}
pop3_mail();
?>


Описание протокола POP3 можно поглядеть здесь

   
 
 автор: lilu   (06.02.2007 в 13:13)   письмо автору
 
   для: Trianon   (06.02.2007 в 12:24)
 

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

   
 
 автор: ZuArt   (06.02.2007 в 13:57)   письмо автору
 
   для: lilu   (06.02.2007 в 13:13)
 

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

   
 
 автор: lilu   (06.02.2007 в 14:07)   письмо автору
 
   для: ZuArt   (06.02.2007 в 13:57)
 

Буду оч признательна, а пока буду с примером разбираться....

   
 
 автор: ZuArt   (06.02.2007 в 18:07)   письмо автору
 
   для: lilu   (06.02.2007 в 14:07)
 

Не претендую на супер-код - написано практически "набело" на скорую руку - тестил не сильно...

<?php
class wspPop3
{
 var 
$fs;
 var 
$twt;
 var 
$Error;
 
 function 
wspPop3()
 {
  
$this->twt 5;
  
$this->fs false;
  
$this->Error '';
 }
 
 
// читать из потока
 
function Read(&$buff$lst=false$lim=4096)
 {
  
$this->Error 'Не открыт ящик';
  if (!
$this->fs)
   return 
false;
  
$this->Error 'Нет данных в потоке';
  if(
feof($this->fs))
   return 
false;
  while(!
preg_match("/\r\n/"$str))
   
$str fread($this->fs$lim);
  if(
$str[0] !== '+')
  {
   
$this->Error 'Ошибка: '.$str;
   return 
false;
  };
  if (!
$lst)
  {
   
$buff $str;
   return 
true;   
  };
  
  while(!
preg_match("/.*(\r\n\.\r\n).*/"$str))
   
$str $str.fread($this->fs$lim);
  
$buff explode("\r\n"$str);
  while((
count($buff) > 1)and($buff[count($buff)-1] != '.'))
   unset(
$buff[count($buff)-1]);
  if (
$buff[count($buff)-1] == '.')
   unset(
$buff[count($buff)-1]);
  return 
true;
 }
 
 
// запсись в поток и возврат вывода
 
function Write($snd, &$buff)
 {
  
$this->Error 'Не открыт ящик';
  if (!
$this->fs)
   return 
false;

  
$cmd explode(' '$snd);
  foreach(
$cmd as $key => $val)
   
$cmd[$key] = strtoupper(trim($val));
  
  
$buff '';
  
$snd trim($snd)."\r\n";
  if(!
fwrite($this->fs$snd))
  {
   
$this->Error 'Ошибка отсылки команды серверу';
   return 
false;
  };
  
  
$lst = ((($cmd[0] == "RETR")and(intval($cmd[1]) > 0))or
          ((
$cmd[0] == "LIST")and(!isset($cmd[1])))or
          ((
$cmd[0] == "TOP")and(intval($cmd[1]) > 0)and(intval($cmd[2]) > 0)));
  return 
$this->Read(&$buff$lst);   
 }
 
 
// открыть ящик
 
function Open($srv$usr$pwd$auto=true$port=110$tm=30)
 {
  if(
$this->fs)
  {
   if(!
$auto)
   {
    
$this->Error 'Подключение уже выполнено';
    return 
false;
   };
   
$this->Close();
  };

  
$this->fs fsockopen($srv$port$errno$errstr$tm);
  if(!
$this->fs)
  {
   
$this->Error 'Ошибка подключения к почтовому серверу '.$errstr.' ('.$errno.')';
   return 
false;
  };
  
$inf null;
  if (!
$this->Read(&$inf))
  {
   
$this->Close();
   
$this->Error 'Ошибка получения информации от сервера';
   return 
false;
  };
  
  
$buff null;
  
$snd "USER ".$usr;
  if(!
$this->Write($snd, &$buff))
   return 
false;

  
$snd "PASS ".$pwd;
  if(!
$this->Write($snd, &$buff))
   return 
false;
  
  
$this->Error "";
  return 
true
 }
 
// закрыть работу с ящиком
 
function Close()
 {
  
$buff null;
  
$this->Write("QUIT", &$buff);
  if(
$this->fs)
   
fclose($this->fs);
  
$this->fs false;
 }
 
 
// список писем
 
function Lst(&$lst)
 {
  
$this->Error 'Не открыт ящик';
  if (!
$this->fs)
   return 
false;
  
$buff null;
  if(!
$this->Write("LIST", &$buff))
   return 
false;  
  for(
$i=1$i<count($buff); $i++)
   
$lst[$i] = explode(' '$buff[$i], 2);
  return 
true;
 }
 
 
// чтение письма
 
function GetMail($id, &$head, &$text$del=false)
 {
  
$this->Error 'Не открыт ящик';
  if (!
$this->fs)
   return 
false;
  
$buff null;
  if(!
$this->Write("RETR ".$id, &$buff))
   return 
false;
  
  
$i 1;
  while(
strlen($buff[$i]) > 0)
   
$head[] = $buff[$i++];
  
$i++;
  while(
$i count($buff))
   
$text[] = $buff[$i++];
     
  if(
$del)
   
$this->Write("DELE ".$id, &$buff);
  return 
true;
 }
 
};


$pop3 = new wspPop3();
$opn $pop3->Open('сервер''юзер''пасс'); // !!! ПОСТАВИТЬ нужные данные
if ($opn)
{
 
$head null;
 
$text null;
 
$mls = array();
 
$pop3->Lst(&$mls);
 foreach(
$mls as $key => $val)
 {
  
$head null$text null;
  if(
$pop3->GetMail($key, &$head, &$textfalse))
   
ToBase($head$text);
  echo 
'<hr>';
 };

};

$pop3->Close();
unset(
$pop3);



// функция обработки письма - в частности - занесение в БД
function ToBase($head$text)
{
 
// сам процесс занесения информации в БД
 
$from null;
 foreach(
$head as $key => $val)
 {
  if (
preg_match("/From/i"$val))
   
$from htmlspecialchars($val);
 };
 echo 
'<b>'.$from.'</b> Внесено в БД<div style="border:1px solid #FF0000">'.nl2br(htmlspecialchars(implode("\r\n"$text)))."</div>";
};
?>


В класс даже не влезай пока - смысла нету... Посмотри концовку, в принципе все что тебе надо, так это массивы $head и $text - в цикле вызова GetMail($key, &$head, &$text, false)...
$key - это идентификатор письма, который получен предварительным $pop3->Lst(&$mls), $head - это заголовочная информация письма, $text - собственно сам текст письма - делай с ним что хочешь, и последний параметр false - это флаг удаления письма после считывания с сервака...

В случае возврата какой-то функцией значения false - смотри свойство Error объекта класса - там описание ошибки...

   
 
 автор: lilu   (09.02.2007 в 10:31)   письмо автору
 
   для: ZuArt   (06.02.2007 в 18:07)
 

ZuArt спасибо вам огромное - это просто супер, только вот письма с сервера не удаляются....или я что-то упустила. Ошибок не выдаёт.
Я создала кнопку "Загрузить почту" и при повторном нажатии выполняется дублирование содержимого писем в таблицу..

   
 
 автор: Trianon   (09.02.2007 в 10:45)   письмо автору
 
   для: lilu   (09.02.2007 в 10:31)
 

Вероятно, одно из двух:
Либо при вызове GetMail четвертый параметр не указан как true - признак удаления писем.
Либо не выполнен вызов Сlose() , который дает команду QUIT, завершающую POP3-транзакцию.

   
 
 автор: ZuArt   (09.02.2007 в 10:49)   письмо автору
 
   для: Trianon   (09.02.2007 в 10:45)
 

Абсолютно верно =))) забыл, что у меня в коде, када писал параметр оставлял false, чтобы не писать постоянно себе самому =)))
параметр в GetMail действительно должен быть true - он служит флагом удаления писем после их считывания =)))

   
 
 автор: lilu   (09.02.2007 в 10:50)   письмо автору
 
   для: Trianon   (09.02.2007 в 10:45)
 

Там там же целая функция закрывающая ящик ....

<?
 
function Close() 
 { 
  
$buff null
  
$this->Write("QUIT", &$buff); 
  if(
$this->fs
   
fclose($this->fs); 
  
$this->fs false
 } 
?>


P.S. Trianon спасибочки вам за пояснения - я теперь хоть примерно понимаю что к чему.. Хотя ещё разбираться и разбираться...:)

   
 
 автор: Trianon   (09.02.2007 в 10:52)   письмо автору
 
   для: lilu   (09.02.2007 в 10:50)
 

>Там там же целая функция закрывающая ящик

А Вы её вызываете?
Ну, собственно, автор точнее подскажет.

   
 
 автор: ZuArt   (09.02.2007 в 10:54)   письмо автору
 
   для: lilu   (09.02.2007 в 10:31)
 

вот в этой строчке

  if($pop3->GetMail($key, &$head, &$text, false))


поменяйте последний параметр на true =) - будут удаляться... Это флаг удаления писем после считывания =)))


  if($pop3->GetMail($key, &$head, &$text, true))


ЗЫ. Кстать, протокол РОР3 не удаляет письма сразу, а помечает на удаление... само удаление производится при ПРАВИЛЬНОМ отключении от сервера (командой "QUIT"). Это к тому, что метод класса Close() нужно ОБЯЗАТЕЛЬНО вызывать для корректного завершения работы и удаления обработанных писем =)

   
 
 автор: lilu   (09.02.2007 в 11:22)   письмо автору
 
   для: ZuArt   (09.02.2007 в 10:54)
 

Всё работает - ура - ну надо же, я бы так не написала ......, спасибочки вам ZuArt и Вам, Trianon..:))).

   
 
 автор: ZuArt   (09.02.2007 в 11:24)   письмо автору
 
   для: lilu   (09.02.2007 в 11:22)
 

Нзчт ;) обращайтесь, если что пишите... для индивидуальных вопросов все контакты в профиле есть =)))

   
 
 автор: ZuArt   (06.02.2007 в 12:28)   письмо автору
 
   для: lilu   (06.02.2007 в 12:19)
 

Надеюсь ссылки на другие ресурсы тут не считаются запрещенными - посмотри скрипты тут... по идее должны быть раскоментированы хорошо - сам скачать и посмотреть не могу - политика прокси запрещает =(

http://softsearch.ru/programs/18-274-getter-and-sender-download.shtml

А тут описание POP3 http://www.sources.ru/protocols/pop3_learning.shtml

   
 
 автор: lilu   (06.02.2007 в 14:21)   письмо автору
 
   для: ZuArt   (06.02.2007 в 12:28)
 

Trianon,
По поводу примера, вот что я поняла, если что-то не так - поправьте пож....

define('DEBUG', true); // debug mode
это я так понимаю отладчик включается

что функция send делает не совсем понятно, а вот функция send_rcv кажется формирует то самое сообщение(письмо), кот. в pop3 разделяется точкой.

$fs = fsockopen($server_host, 110, $errno, $errstr, constant('SMTP_TIMEOUT'));
тут всё понятно, имя сервера, 110 порт отправки почты, номер ошибки и номер строки с ошибкой, и истекшее время ожидания при неудачном соед. с сервером ...
А вот потом... начинаются непонятки...
можно как-то пояснить

   
 
 автор: Trianon   (06.02.2007 в 14:52)   письмо автору
 
   для: lilu   (06.02.2007 в 14:21)
 

Функция send_rcv() собственно и реализует обмен данными с сервером согласно протоколу POP3. Она выдает на сервер строки запроса и забирает ответ.
У нее три параметра: первый - сокет, подключенный к нужному серверу,
Второй - строка запроса, которую надо отправить.
И третий - признак запроса с многострочным ответом.
Помимо обмена данными с сервером через сокет, эта функция выводит "на экран" весь диалог в целях отладки, если, как Вы правильно заметили, включен отладочный режим.
Если строка define закомментарена, функция работает "молча".

Возвращать она может следющие вещи:

1)false - если соединение с сервером было неожиданно разорвано.
2) положительный ответ
Например, в ответ на указание имени пользователя в команде USER функция вернет что-то вроде

1 +OK

причем единичка слева приписана функцией sen_rcv() для того чтобы проще было оценивать успех/неудачу запроса.

3) отрицательный ответ
Например, в ответ на некорректный пароль в запросе PASS функция вернет что-то вроде

2 -ERR Authentication failed (bad password?) 

причем двойка слева приписана функцией sen_rcv() для того чтобы проще было оценивать успех/неудачу запроса.

4) многострочный положительный ответ

Возвращается массив с полученными от сервера строками.

Функция send() - внутренняя, ею пользуется функция send_rcv(). Вам применять её не нужно.


Начавшиеся непонятки это как раз вызовы функции send_rcv() , реализующие диалог.

   
 
 автор: Trianon   (06.02.2007 в 15:04)   письмо автору
 
   для: Trianon   (06.02.2007 в 14:52)
 

Конструкция

if(1 != intval(($s = send_rcv($fs,$c="USER $login")))) die("Status $c: $s"); 

представляет собой вызов send_rcv() с целью отправки однострочного запроса, и проверку на успех выполнения.
По шагам:
а) переменной $c присваивается строка, отправляемая клиентом:

$c="USER $login" 

б) результат, который вернул сервер, присваивается переменной $s :

$s = send_rcv($fs,$c...))

в) если результат начинается не с единицы

if(1 != intval($s ...)) 

г) ... то мы аварийно завершаем скрипт, печатая, что послал клиент, и что ответил сервер.

die("Status $c: $s"); 

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования