Реальные веб-проекты на PHP и MySQL. Разработка почтовой службы с веб-интерфейсом

Часть 2. Архитектура основного сценария

Comments

Серия контента:

Этот контент является частью # из серии # статей: Реальные веб-проекты на PHP и MySQL. Разработка почтовой службы с веб-интерфейсом

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Реальные веб-проекты на PHP и MySQL. Разработка почтовой службы с веб-интерфейсом

Следите за выходом новых статей этой серии.

1. Введение

В предыдущих статьях многократно описывались вопросы настройки и запуска в эксплуатацию самых разнообразных почтовых служб, - таких как sendmail, postfix, exim, Communigate, qmail, использующих в качестве платформы самый широкий спектр современных Linux- и BSD-систем. В настоящее время, по мере развития Всемирной Паутины все чаще возникает вопрос об актуальности использования услуг электронной почты, основанной на веб. В предыдущей, первой части цикла статей были рассмотрены вопросы относительно общего плана построения почтовой системы с веб-интерфейсом, создания базы данных под учебный проект и обзора общей библиотеки функций для решения задач обработки почты. Продолжение цикла мы посвятим вопросам общей архитектуры основного сценария, регулирующего работу всей почтовой системы.

Главный управляющий сценарий

<?php
// Этот файл служит основой приложения "Свежая почта".
// Он функционирует, главным образом, как конечный автомат,
// и генерирует для пользователей вывод в зависимости от
// выполняемых ими действий при вводе.

//*****************************************************************************
// Этап 1. Предварительная обработка
// Выполнение всех необходимых операций перед отправкой заголовка
// страницы и выбор информации, отображаемой в заголовках страницы
//*****************************************************************************

  include ('include_fns.php');
  session_start();

  // Создать короткие имена переменных
  $username = $_POST['username'];
  $passwd = $_POST['passwd'];
  $action = $_REQUEST['action'];
  $account = $_REQUEST['account'];
  $messageid = $_GET['messageid'];

  $to =  $_POST['to'];
  $cc =  $_POST['cc'];
  $subject =  $_POST['subject'];
  $message =  $_POST['message'];

  $buttons = array();

  // Добавлять к этой строке, если что-то выполняется перед выводом заголовка
  $status = '';

  // Необходимо сначала обработать запросы на вход и выход из системы
  if($username || $password)
  {
    if(login($username, $passwd))
    {
      $status .= '<p>Вы успешно вошли в систему.
      </p><br /><br /><br /><br />
                  <br /><br />';
      $_SESSION['auth_user'] = $username;
      if(number_of_accounts($_SESSION['auth_user']) == 1)
      {
        $accounts = get_account_list($_SESSION['auth_user']);
        $_SESSION['selected_account'] = $accounts[0];
      }
    }
    else
    {
      $status .= '<p>Извините, вход в систему с этим именем пользователя
            и паролем недопусим.
            </p><br /><br /><br /><br /><br /><br />';
    }
  }

  if($action == 'log-out')
  {
    session_destroy();
    unset($action);
    $_SESSION = array();
  }

  // Перед отображением заголовка необходимо обработать запросы
  // на выбор, удаление или сохранение учетных записей
  switch ( $action )
  {
    case 'delete-account' :
    {
      delete_account($_SESSION['auth_user'], $account);
      break;
    }
    case 'store-settings' :
    {
      store_account_settings($_SESSION['auth_user'], $_POST);
      break;
    }
    case 'select-account' :
    {
      // Если выбрана легитимная учетная запись, то
      // сохранить ее в переменной сеанса
      if($account&&account_exists($_SESSION['auth_user'], $account))
      {
        $_SESSION['selected_account'] = $account;
      }
    }
  }
  // Создать кнопки, которые будут выводиться в панели инструментов     //интерфейса
  $buttons[0] = 'view-mailbox';
  $buttons[1] = 'new-message';
  $buttons[2] = 'account-setup';
  // Кнопка выхода из системы нужна, только если был факт входа
  if(check_auth_user())
  {
    $buttons[4] = 'log-out';
  }
//*****************************************************************************
// Этап 2. Формирование заголовков
// Отправка HTML-заголовков и строки меню, соответствующих текущему действию
//*****************************************************************************
  if($action)
  {
    // Вывести заголовок с названием приложения и описанием страницы или действия
    do_html_header($_SESSION['auth_user'],
              "Безопасная и быстрая почта - ".format_action($action),
                   $_SESSION['selected_account']);
  }
  else
  {
    // Вывести заголовок с одним названием приложения и ничего более
    do_html_header($_SESSION['auth_user'], "Безопасная и быстрая почта",
                   $_SESSION['selected_account']);
  }

  display_toolbar($buttons);

//*****************************************************************************
// Этап 3. Скелет обработчика пользовательских действий
// Отображает соответствующее главное содержимое в зависимости от действия
//*****************************************************************************
  // Вывести любой текст, сгенерированный функциями,
  // которые вызваны до отображения заголовка
  echo $status;

  if(!check_auth_user())
  {
    echo '<p>Вы должны сначала войти в систему';
    if($action&&$action!='log-out')
      echo ' и затем переходить на '.format_action($action);
    echo '.</p><br /><br />';
    display_login_form($action);
  }
  else
  {
    switch ( $action )
    {
      // Если выбрана опция создания новой учетной записи,
      // либо учетная запись только что добавлена или удалена,
      // отобразить страницу создания учетных записей
      case 'store-settings' :
      case 'account-setup' :
      case 'delete-account' :
      {
        display_account_setup($_SESSION['auth_user']);
        break;
      }
      case 'send-message' :
      {
        if(send_message($to, $cc, $subject, $message))
          echo '<p>Сообщение отправлено.
          </p><br /><br /><br /><br /><br /><br />';
        else
          echo '<p>Невозможно отправить сообщение.
          </p><br /><br /><br /><br />
                <br /><br />';
        break;
      }
      case 'delete' :
      {
         delete_message($_SESSION['auth_user'],
                        $_SESSION['selected_account'], $messageid);
         // Здесь, примите во внимание, оператор 'break' опущен умышленно -
         // нужно перейти на следующий оператор case
      }
      case 'select-account' :
      case 'view-mailbox' :
      {
        // Если почтовый ящик только что выбран, отобразить его содержимое
        display_list($_SESSION['auth_user'],
                     $_SESSION['selected_account']);
        break;
      }
      case 'show-headers' :
      case 'hide-headers' :
      case 'view-message' :
      {
        // Если только что выбрано сообщение из списка, либо же
        // оно просматривается и выбрана опция сокрытия или
        // показа заголовков, загрузить сообщение
        $fullheaders = ($action=='show-headers');
        display_message($_SESSION['auth_user'],
                        $_SESSION['selected_account'],
                        $messageid, $fullheaders);
        break;
      }
      case 'reply-all' :
      {
        // Установить значение переменной cc равным строке cc текущего сообщения
        if(!$imap)
          $imap = open_mailbox($_SESSION['auth_user'],
                               $_SESSION['selected_account']);
        if($imap)
        {
          $header = imap_header($imap, $messageid);
          if($header->reply_toaddress)
            $to = $header->reply_toaddress;
          else
            $to = $header->fromaddress;
          $cc = $header->ccaddress;
          $subject = 'Re: '.$header->subject;
          $body = add_quoting(imap_body($imap, $messageid));
          imap_close($imap);

          display_new_message_form($_SESSION['auth_user'],
                                   $to, $cc, $subject, $body);
        }
        break;
      }
      case 'reply' :
      {
        // Установить значение переменной to равным полю reply-to
        // или from текущего сообщения
        if(!$imap)
          $imap = open_mailbox($_SESSION['auth_user'],
                               $_SESSION['selected_account']);
        if($imap)
        {
          $header = imap_header($imap, $messageid);
          if($header->reply_toaddress)
            $to = $header->reply_toaddress;
          else
            $to = $header->fromaddress;
          $subject = 'Re: '.$header->subject;
          $body = add_quoting(stripslashes(imap_body($imap, $messageid)));
          imap_close($imap);

          display_new_message_form($_SESSION['auth_user'],
                                   $to, $cc, $subject, $body);
        }

        break;
      }
      case 'forward' :
      {
        // Установить значение переменной body равным телу
        // текущего сообщения, взятого в кавычки
        if(!$imap)
          $imap = open_mailbox($_SESSION['auth_user'],
                               $_SESSION['selected_account']);

        if($imap)
        {
          $header = imap_header($imap, $messageid);
          $body = add_quoting(stripslashes(imap_body($imap, $messageid)));
          $subject = 'Fwd: '.$header->subject;
          imap_close($imap);

          display_new_message_form($_SESSION['auth_user'],
                                   $to, $cc, $subject, $body);
        }
        break;
      }
      case 'new-message' :
      {
        display_new_message_form($_SESSION['auth_user'],
                                 $to, $cc, $subject, $body);
        break;
      }
    }
  }
//*****************************************************************************
// Этап 4. Вывод нижнего колонтитула
//*****************************************************************************
  do_html_footer();
?>

В приведенном выше сценарии используется метод обработки событий. Он организован таким образом, что последовательно для каждого события выполняется соответствующая функция. В этом примере, как правило, все события генерирует пользователь, - именно он является отправной точкой, катализатором и проводником энергии механизма функционирования сайта. Выполняя щелчки по различным кнопкам имеющегося интерфейса, пользователь инициирует запуск тех или иных триггеров, которые в свою очередь дают «отмашку» для старта соответствующей функции. Большая часть кнопок порождается функцией display_button(), код которой приводится ниже:

 function display_button($button, $extra_parameters = '')
{
  // Отображает одну из наших стандартных кнопок в виде ссылки
  $url = "index.php?action=$button";
  if($extra_parameters)
    $url .= $extra_parameters;
  echo "<a href = '$url'>";
  echo "<img src = 'images/$button.gif' border = 0 ";
  echo 'width = 149 height = 43 ';
  echo 'alt = "'.format_action($button).'" /></a>';
}

а функция display_form_button() используется при выводе кнопок отправки формы:

function display_form_button($button)
{
  // Отображает на форме одну из наших стандартных кнопок
  echo '<input type = "image" src = "images/'.$button.'.gif" border = 0 ';
  echo 'width = 149 height = 43 ';
  echo 'alt = "'.format_action($button).'"></a>';
}

все они обеспечивают переход на URL index.php?action=log-out.

Значение переменной action, передаваемое в сценарий index.php, определят, какой именно триггер какого события должен быть запущен для вызова требуемой функции.

Функция вывода заголовка (верхней части сайта):

function do_html_header($auth_user, $title = '', $selected_account)
{
  // Выводит HTML-заголовок, включая крутой логотип :)

  global $table_width;

  // Выводит область заголовка 
?>
  <html>
  <head>
    <title><?php echo $title; ?></title>
    <style>
      h1 { font-family: 'Comic Sans MS',  sans-serif; font-size: 32; 
           font-weight: bold; color:  black; margin-bottom: 0}
      b { font-family: 'Arial', sans-serif; font-size: 13; 
          font-weight: bold; color: black }
      th { font-family: 'Comic Sans MS',  sans-serif; font-size: 18
           font-weight: bold; color:  black; }
      body, li, td { font-family: Arial, Helvetica, sans-serif; 
                     font-size: 12; margin = 5px }
      a { color: #000000 }
    </style>
  </head>
  <body>
  <table width = <?php echo $table_width; ?> cellspacing = 0 
  cellpadding = 3 bgcolor = "#ff6600" border = 0>
  <tr bgcolor = "#ff6600">
  <td bgcolor = "#ff6600" width = 103><img src = "images/warm-mail.gif" 
                 width = 103 height = 45 alt ="" valign = "middle" /></td>
  <td bgcolor = "#ff6600" width = <?php echo ($table_width-110);?>><h1>
  <?php echo $title;?></h1></td>
  <?php
  // Включать кнопку выбора учетной записи, 
  только если пользователь имеет их несколько
  if(number_of_accounts($auth_user)>1)
  {
    echo '<form target="index.php?action=open-mailbox" method="post">';
    echo '<td bgcolor = "#ff6600" align = "right" valign = "middle">';
    display_account_select($auth_user, $selected_account);
    echo '</td>';
    echo '</form>';
  }
  ?>
  </tr>
  </table>
  <table width = <?php echo $table_width;?> cellpadding = 0 cellspacing = 0 border = 0>
  <tr><td>
<?php
}

Функция вывода футера (нижней части сайта):

function do_html_footer()
{
  // Выводит завершающие HTML-дексрипторы
  global $table_width;
?>
  </td></tr>
  </table>
  <table width = <?php echo $table_width;?> cellspacing = 0 cellpadding = 6 border = 0>
  <tr>
  <td bgcolor = "#ff6600" align = right><img src = "images/warm-mail.gif"
                 width = 103 height = 45 alt ="" valign = "middle" />
  </td>
  </tr>
  </table>
  </body>
  </html>
<?php
}

Главный сценарий index.php состоит из четырех основных разделов, определяющих различные функциональные свойства:

  1. выполнение ряда операций до отправки заголовка страницы в браузер. К этим моментам относятся запуск сеанса, предварительная обработка для конкретного пользователя действия и определение внешнего вида заголовка;
  2. обработка и отправка требуемых заголовка и строки меню для выбранного пользователем действия;
  3. выбор части сценария для выполнения в зависимости от предпринимаемого действия. Выбор различного действия приводит к запуску различных функций;
  4. отправка нижних колонтитулов для формирования законченного вида страницы.

В последующих частях цикла каждая часть сценария будет рассмотрена более подробно.

Выводы

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

В следующей статье будет подробно изучена реализация механизма входа и выхода пользователей системы.


Ресурсы для скачивания


Похожие темы


Комментарии

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux, Open source
ArticleID=577044
ArticleTitle=Реальные веб-проекты на PHP и MySQL. Разработка почтовой службы с веб-интерфейсом: Часть 2. Архитектура основного сценария
publish-date=11092010