Архив за Август 2008

Сортировка результатов SQL-запроса

Сортировка результатов SQL-запроса производится при помощи конструкции ORDER BY, после которой указывается имя столбца, который подвергается сортировке. Если после имени столбца указано ключевое слово ASC, сортировка производится по возрастанию, если же указано ключевое слово DESC, то сортировка будет по убыванию. Таким образом, задача сводится к динамическому формированию SQL-запроса, в конструкцию ORDER BY которого подставлялись бы имена выбранных столбцов и порядок сортировки. Для этого будем использовать запрос вида

$query = "SELECT * FROM products WHERE 1 ORDER BY ".$orderby." ".$sort;

где переменная $orderby будет содержать имя столбца, а $sort принимать значение ASC или DESC, в зависимости от того, какой вид сортировки выбран.

<?php
$dblocation = "localhost";   // Имя сервера
$dbuser     = "root";        // Имя пользователя
$dbpswrd    = "";            // Пароль
$dbname     = "catalog";     // Имя базы данных

// Соединение с сервером базы данных
$dblink = mysql_connect( $dblocation, $dbuser, $dbpswrd );
mysql_query( 'SET NAMES cp1251' );
// Выбираем базу данных
mysql_select_db( $dbname, $dblink );

// По умолчанию сортировка по наименованию, по возрастанию
$orderby = 'title';
$sort = 'ASC';
if ( isset( $_GET['orderby'] ) and isset( $_GET['sort'] ) ) {
  if ( in_array( $_GET['orderby'], array( 'code', 'title', 'price' ) ) ) $orderby = $_GET['orderby'];
  if ( in_array( $_GET['sort'], array( 'ASC', 'DESC' ) ) ) $sort = $_GET['sort'];
}

$query = 'SELECT code, title, description, price
          FROM products
          ORDER BY '
.$orderby.' '.$sort;
$res = mysql_query( $query );
echo '<h1>Каталог продукции</h1>'."\n";
// Выводим "шапку" таблицы
echo '<table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; empty-cells: show">'."\n";
echo '<tr>';
if ( $sort == 'ASC' ) {
  $tmp = 'DESC';
  $image = 'down.gif';
} else {
  $tmp = 'ASC';
  $image = 'up.gif';
}
if ( $orderby == 'code' )
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=code&sort='.$tmp.'">Код</a>&nbsp;<img src="'.$image.'" alt="" /></th>';
else
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=code&sort=ASC">Код</a></th>';
if ( $orderby == 'title' )
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=title&sort='.$tmp.'">Наименование</a>&nbsp;<img src="'.$image.'" alt="" /></th>';
else
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=title&sort=ASC">Наименование</a></th>';
echo '<th>Описание</th>';
if ( $orderby == 'price' )
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=price&sort='.$tmp.'">Цена</a>&nbsp;<img src="'.$image.'" alt="" /></th>';
else
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=price&sort=ASC">Цена</a></th>';
echo '</tr>'."\n";
while( $prd = mysql_fetch_array( $res ) ) {
  echo '<tr>';
  echo '<td>'.$prd['code'].'</td>'."\n";
  echo '<td>'.$prd['title'].'</td>'."\n";
  echo '<td>'.$prd['description'].'</td>'."\n";
  echo '<td>'.$prd['price'].'</td>'."\n";   
  echo '</tr>'."\n";
}
echo '</table>'."\n";
?>

Посмотреть рабочий пример можно здесь.

Кто сейчас на сайте?

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

Для фиксирования времени обращения посетителей к страницам ресурса создадим таблицу MySQL session, в которой будем хранить имена пользователей и время их последнего обращения к странице.

CREATE TABLE session (
  id_session TINYTEXT NOT NULL,
  putdate DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  user TINYTEXT NOT NULL
) ENGINE=MyISAM;

Таблица содержит три поля:

  • id_session - идентификатор сессии;
  • putdate - время последнего обращения посетителя к страницам сайта;
  • user - имя пользователя.

Тогда для регистрации посетителей, которые находятся в данный момент на сайте, можно использовать следующий скрипт:

<?php
  // Начинаем сессию
  session_start();
  // Получаем уникальный id сессии
  $id_session = session_id();
  // Устанавливаем соединение с базой данных
  include 'connect.php';
  if ( isset( $_SESSION['user'] ) )
    $user = $_SESSION['user'];
  else
    $user = '';
  // Проверяем, присутствует ли такой id в базе данных
  $query = "SELECT * FROM session
            WHERE id_session = '"
.$id_session."'";
  $res = mysql_query($query);
  if ( $res ) {
    // Если сессия с таким номером уже существует,
    // значит пользователь online - обновляем время его
    // последнего посещения
    if( mysql_num_rows($res) > 0 ) {
      $query = "UPDATE session SET putdate = NOW(), user = '".$user."'
                WHERE id_session = '"
.$id_session."'";
      mysql_query($query);
    } else {
      // Иначе, если такого номера нет - посетитель только что
      // вошёл - помещаем в таблицу нового посетителя
      $query = "INSERT INTO session
              VALUES('"
.$id_session."', NOW(), '".$user."')";
      mysql_query($query);
    }
  } 
  // Будем считать, что пользователи, которые отсутствовали
  // в течении 20 минут - покинули ресурс - удаляем их
  // id_session из базы данных
  $query = "DELETE FROM session
            WHERE putdate < NOW() -  INTERVAL '20' MINUTE"
;
  mysql_query($query);
?>

В начале скрипта при помощи функции session_id() получается текущий идентификатор сессии. Если такой идентификатор отсутствует в таблице session, то происходит добавление новой записи, что эквивалентно приходу на ресурс нового посетителя. Если же идентификатор присутствует в таблице session, следовательно, данный посетитель уже зашел на ресурс и требуется обновить время его посещения и имя на тот случай, если он осуществил авторизацию только сейчас. В конце скрипта происходит удаление всех записей таблицы, время посещения для которых было обновлено более чем 20 минут назад - таким образом фиксируется уход посетителя с ресурса.

Этот скрипт следует подключить при помощи инструкции include ко всем страницам сайта, чтобы отслеживать присутствие посетителя на сайте.

Теперь не составит труда вывести список текущих посетителей:

<?php
  // Устанавливаем соединение с базой данных
  include 'connect.php';
  // Выводим имена всех посетителей, записи о которых имеются
  // в таблице session
  $query = 'SELECT * FROM session';
  $res = mysql_query($query);
  if ( $res ) {
    // Если хоть кто-то есть - выводим список
    if ( mysql_num_rows($res) > 0 )
    {  
      $guests = 0;
      while( $row = mysql_fetch_array($res) )
      {
        if ( empty( $row['user'] ) )
          $guests = $guests + 1;
        else
          $users[] = $row['user'];
      }
      if ( $guests > 0 or isset( $users ) ) {
        echo 'Сейчас на сайте: ';
        if ( isset( $users ) ) echo implode(',', $users);
        if ( $guests > 0 and isset( $users ) ) echo ' и ';
        if ( $guests > 0 ) echo $guests.' гостей';
      }
    }
  } 
?>

Извлечение названия HTML-страницы

Для решения этой задачи понадобится функция preg_match(), которая осуществляет поиск в строке по регулярному выражению и имеет следующий синтаксис:

int preg_match(string pattern, string subject, [, array matches [, int flags [, int offset]]])

Эта функция ищет в строке subject соответствие регулярному выражению pattern. Если задан необязательный параметр matches, то результаты поиска помещаются в массив. Элемент $matches[0] будет содержать часть строки, соответствующую вхождению всего шаблона, $matches[1] — часть строки, соответствующую первым круглым скобкам, $matches[2] — вторым и т.п.

Необязательный флаг $flag может принимать единственное значение PREG_OFFSET_CAPTURE, при указании которого изменяется формат возвращаемого масива $matches — каждое вхождение возвращается в виде массива, в нулевом элементе которого содержится найденная подстрока, а в первом — смещение. Поиск осуществляется слева направо, с начала строки.

Дополнительный параметр offset может быть использован для указания альтернативной начальной позиции для поиска. Функция preg_match() возвращает количество найденных соответствий. Это может быть 0 (совпадения не найдены) и 1, поскольку preg_match() прекращает свою работу после первого найденного совпадения.

$content = file_get_contents( "index.html" );
$pattern = "|<title>(.*?)</title>|si";
if ( preg_match( $pattern, $content, $out ) ) echo $out[1];