Internet и CGI

Чего мы не сделали


Вот и все. Служба WebMail готова (см. рисунок). Как несложно заметить, мы всего лишь соединили готовые части - все наши шесть файлов не насчитывают и двух сотен строк - и получили почти настоящую почтовую программу. Конечно, с ней связаны и некоторые проблемы. Например, такие.

  1. Что будет, если с помощью нашей WebMail попробовать читать почту одновременно с двух компьютеров? При удалении письма на одном компьютере нумерация "съедет", и на втором начнут происходить весьма неприятные вещи.
  2. Как уже было замечено, на сервере с не полностью контролируемым содержанием использование нашей программы может привести к попаданию паролей в нечистые руки.
  3. Нет поддержки кодировок, отличных от KOI8-R, для почты (при том, что для Web-браузера благодаря Russian Apache поддерживаются все распространенные кодировки).
  4. Нет поддержки вложений.
  5. Нет записной книжки.
  6. Нет поддержки папок.
  7. Впрочем, мы и не ставили себе целью создать программу, способную сравниться с Eudora или Pegasus (но, кстати, программа Imap webMail Program - см. - очень близка к этому).

    Сделаем еще несколько замечаний по поводу возможных решений первой и второй проблемы. Эти проблемы связаны с обеспечением безопасности, а значит, требуют особого внимания. Для решения первой проблемы можно передавать в дополнение к номеру письма еще и идентификатор сообщения (MessageID); это, однако, повлечет существенное усложнение программы, так как нужно будет организовать подробное "разбирательство" в случае несовпадения идентификаторов, а также корректное обновление списка писем.

    Вторая проблема решается путем добавления еще одной формы на входе и передачи имени пользователя и пароля от сценария к сценарию через URL - так, как сейчас передается номер письма. Но тогда пароль будет появляться в адресной строке браузера. С этим можно бороться двумя способами - либо зашифровывая пароль перед посылкой и расшифровывая при получении, либо создав еще два фрейма: первый не используется никак (или в нем размещается реклама, что, в общем, то же самое), во втором происходит вся работа. Можно и скомбинировать названные способы. Дерзайте!

    ЛИСТИНГ 1 Файл counter.php3 (счетчик числа посещений Web-страницы)


    <html> <body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000"> <p> Число посещениий: <?PHP $filename = "counter.dat"; $fp = @fopen($filename,"r"); if ($fp) { $counter=fgets($fp,10); fclose($fp); } else { $counter=0; } $counter++; print $counter; $fp = fopen($filename,"w"); if ($fp) { $counter=fputs($fp,$counter); fclose($fp); } ?> </body> </html>



    ЛИСТИНГ 2 Файл index.php3 (идентификация пользователя, установление контакта с почтовым сервером и создание набора фреймов для вывода списка писем и текста текущего письма)


    <?PHP $REALM = "Web mail"; $POPSERVER = '127.0.0.1'; $LOGERRORS = 1; if(!isset($PHP_AUTH_USER)): Header( "WWW-Authenticate: Basic realm=\"$REALM\""); Header( "HTTP/1.0 401 Unauthorized"); echo "<H1>Authorization Required</H1>\n"; exit; else: if(!($imap_stream=@imap_open("{127.0.0.1:143}Inbox","$PHP_ AUTH_USER","$PHP_AUTH_PW",OP_READONLY))): Header( "WWW-Authenticate: Basic realm=\"$REALM\""); Header( "HTTP/1.0 401 Auth Required"); echo "<H1>Authorization Required</H1>\n"; exit; else: imap_close($imap_stream); ?> <html> <frameset border="0" framespacing="-2" rows="20%,80%"> <frame src="top.php3" name="top" marginwidth="1" marginheight="1" framespacing="0"> <frame src="main.php3" name="main" marginwidth="1" marginheight="1" framespacing="0"> </frameset> <noframes> <body> Sorry, but your browser does not support frames...<br> </body> </noframes> </html> <?PHP endif; endif; ?>



    ЛИСТИНГ 3 Файл top.php3 (формирование списка писем)

    <html> <body bgcolor="#C04040" text="#FFFFFF" link="#0000FF" vlink="#800080" alink="#FF0000"> <BASE TARGET="main"> <?PHP $imap_stream=imap_open("{127.0.0.1:143}Inbox","$PHP_AUTH_USER", "$PHP_AUTH_PW",OP_READONLY); $inbox=imap_mailboxmsginfo($imap_stream); ?> <CENTER><table border=3 width="100%"> <tr><th>NN</th><th>Subject</th><th>From</th><th>Date</th></tr> <tr><td> <?PHP for($i=1;$i<=$inbox->Nmsgs;$i++): $header=imap_header($imap_stream,$i,300,300,0); echo "<tr><td><B><a href=main.php3?mail=".$i. ">".$i. "</a></B></td><td><a href=main.php3?mail=".$i. ">".$header->Subject. "</a></td><td><a href=main.php3?mail=".$i. ">".$header->fromaddress. "</a></td><td><a href=main.php3?mail=".$i. ">".$header->Date. "</a></td></tr>"; endfor; imap_close($imap_stream); ?> </table> </CENTER> </body> </html>



    ЛИСТИНГ 4 Файл main.php3 ( проверка наличия писем и вывод кнопок)

    <html> <body bgcolor="#408080" text="#FFFFFF" link="#0000FF" vlink="#800080" alink="#FF0000"> <BASE TARGET="main"> <a href=mail.php3>New message</a> <?PHP if (isset($mail) && ($mail>=1)):?>| <a href=mail.php3?mail=<?PHP echo $mail;?>> Reply</a>| <a href=del.php3?mail=<?PHP echo $mail;?>target= _top>Delete</a><?PHP endif;?><br><br> <?PHP if(isset($mail) && ($mail>=1)): $imap_stream=imap_open("{127.0.0.1:143}Inbox","$PHP_AUTH_USER", "$PHP_AUTH_PW",OP_READONLY); $inbox=imap_mailboxmsginfo($imap_stream); $body=imap_fetchbody($imap_stream,$mail,1,0); print(nl2br(eregi_replace( "(http|https|ftp)://([-=%_ a-zA-Z0-9./~?:]+)", "<a href=\"\\1://\\2\" target=\"_blank\ ">\\1://\\2</a>", htmlspecialchars($body)))); imap_close($imap_stream); endif; ?> </body> </html>

    ЛИСТИНГ 5 Файл mail.php3 (создание письма)

    <html> <body bgcolor="#408080" text="#FFFFFF" link="#0000FF" vlink="#800080" alink="#FF0000"> <BASE TARGET="main"> <?PHP if (isset($mail) && ($mail>=1)): $imap_stream=imap_open("{127.0.0.1:143}Inbox","$PHP_AUTH_USER", "$PHP_AUTH_PW",OP_READONLY); $header=imap_header($imap_stream,$mail,300,300,0); endif; ?> <FORM ACTION='send.php3' METHOD='POST'> <table CELLSPACING=0 CELLPADDING=0 WIDTH=100%> <TR> <TD class=light WIDTH="150"> <B><b>Your name :</b></B> </TD><TD COLSPAN=2 class=light> <INPUT TYPE="text" NAME="sendername" VALUE="<?PHP echo $sendername;?>" SIZE=60 maxlength=70> </TD></TR> <TR> <TD class=light WIDTH="150"> <B><b>From :</b></B> </TD><TD COLSPAN=2 class=light> <INPUT TYPE="text" NAME="sender" VALUE="<?PHP echo $PHP_AUTH_USER."@host.some_domain.com";?>" SIZE=60 maxlength=70> </TD></TR> <TR> <TD class=light WIDTH="150"> <B><b>Subject :</b></B> </TD><TD COLSPAN=2 class=light> <INPUT TYPE="text" NAME="subject" VALUE="<?PHP if (isset($mail) && ($mail>=1)):?>Re: <?PHP echo eregi_replace("\"",""",$header->Subject); endif;?>" SIZE=60 maxlength=70> </TD></TR> <TR> <TD class=light WIDTH="150"> <B><b>To :</b></B> </TD><TD COLSPAN=2 class=light> <INPUT TYPE="text" NAME="mailto" VALUE="<?PHP if (isset($mail) && ($mail>=1)): echo eregi_replace ("\"",""",$header->fromaddress); endif;?>" SIZE=60 maxlength=70> </TD></TR> <TR> <TD class=light WIDTH="150"> <B>Message body : </TD><TD COLSPAN=2 class=light> <textarea name="text" rows=15 cols=59><?PHP if (isset($mail) && ($mail>=1)): echo "> ".eregi_replace ("\n","\n> ",htmlspecialchars(imap_fetchbody ($imap_stream,$mail,1,0))); endif;?></textarea> <center><input type=submit value="Send"></center><br> </TD></TR> </TABLE> </form> </body> </html> <?PHP if (isset($mail) && ($mail>=1)):imap_close($imap_stream);endif; ?>



    ЛИСТИНГ 6 Файл del.php (удаление письма)

    <html> <body bgcolor="#408080" text="#FFFFFF" link="#0000FF" vlink="#800080" alink="#FF0000"> <BASE TARGET="main"> <?PHP if (isset($mail) && ($mail>=1)): $imap_stream=imap_open("{127.0.0.1:143}Inbox","$PHP_AUTH_USER", "$PHP_AUTH_PW",OP_READONLY); $header=imap_header($imap_stream,$mail,300,300,0); endif; ?> <FORM ACTION='send.php3' METHOD='POST'> <table CELLSPACING=0 CELLPADDING=0 WIDTH=100%> <TR> <TD class=light WIDTH="150"> <B><b>Your name :</b></B> </TD><TD COLSPAN=2 class=light> <INPUT TYPE="text" NAME="sendername" VALUE="<?PHP echo $sendername;?>" SIZE=60 maxlength=70> </TD></TR> <TR> <TD class=light WIDTH="150"> <B><b>From :</b></B> </TD><TD COLSPAN=2 class=light> <INPUT TYPE="text" NAME="sender" VALUE="<?PHP echo $PHP_AUTH_USER."@host.some_domain.com";?>" SIZE=60 maxlength=70> </TD></TR> <TR> <TD class=light WIDTH="150"> <B><b>Subject :</b></B> </TD><TD COLSPAN=2 class=light> <INPUT TYPE="text" NAME="subject" VALUE="<?PHP if (isset($mail) && ($mail>=1)):?>Re: <? PHP echo eregi_replace ("\"",""",$header->Subject); endif;?>" SIZE=60 maxlength=70> </TD></TR> <TR> <TD class=light WIDTH="150"> <B><b>To :</b></B> </TD><TD COLSPAN=2 class=light> <INPUT TYPE="text" NAME="mailto" VALUE="<?PHP if (isset($mail) && ($mail>=1)): echo eregi_replace ("\"",""",$header->fromaddress); endif;?>" SIZE=60 maxlength=70> </TD></TR> <TR> <TD class=light WIDTH="150"> <B>Message body : </TD><TD COLSPAN=2 class=light> <textarea name="text" rows=15 cols=59><?PHP if (isset($mail) && ($mail>=1)): echo "> ".eregi_replace ("\n","\n> ",htmlspecialchars(imap_fetchbody ($imap_stream,$mail,1,0))); endif;?></textarea> <center><input type=submit value="Send"></center><br> </TD></TR> </TABLE> </form> </body> </html> <?PHP if (isset($mail) && ($mail>=1)):imap_close($imap_stream);endif; ?>



    ЛИСТИНГ 7 Файл send.php3 (отправка письма)

    <?PHP Header("Refresh: 5;url=main.php3"); ?> <html> <body bgcolor="#408080" text="#FFFFFF" link="#0000FF" vlink="#800080" alink="#FF0000"> <BASE TARGET="main"> <?PHP mail($mailto,$subject,$text, "From: $sendername <$sender>\nContent-Type: text/plain; charset=KOI8-R"); ?> Message was succesfully sent. </body> </html>

    1 Сценарий намеренно предельно упрощен: он не заботится о блокировке файлов, не обрабатывает ошибки записи на диск и т. п. Заметим, что наш счетчик, в отличие от большинства других, написан без использования тега <IMG>. Это позволяет сократить трафик и решает проблему неграфических браузеров (например, браузеров для слепых), но может создать проблемы, если нам нужен единый счетчик для нескольких "зеркал" основного узла. "Традиционная" реализация счетчика в PHP также не представляет проблемы, поскольку он имеет множество функций для порождения GIF-файлов (включая даже получение красивых надписей, выполненных шрифтами TrueType).

    2 Число 401 взято не с потолка, а из описания протокола HTTP.

    3 К сожалению, если в каком-либо другом подкаталоге указать realm="Web mail", то находящиеся в нем сценарии также получат соответствующую информацию. Поэтому данный метод неприемлем, если вы не можете контролировать содержимое всего узла.

    В конце статьи мы обсудим, как обойти это ограничение.


    Содержание раздела