Постраничный вывод из MySQL

Как сделать постраничный вывод из MySQL: по 10 (20, 30) записей на страницу, а внизу - ссылки на остальные страницы?

Чтобы получить нужные записи, воспользуемся оператором LIMIT, который вызывается с двумя параметрами - с какой записи начинать, и сколько выводить:

SELECT id, title FROM items LIMIT 0, 10;

Этот запрос вернет записи с первой по 10, поскольку нумерация начинается с 0. Cоответственно, запросы для второй и третьей страницы будут выглядеть

SELECT id, title FROM items LIMIT 10, 10;
SELECT id, title FROM items LIMIT 20, 10;

Как видите, нам надо лишь передать в скрипт число, которое потом подставить в запрос.

Для построения постраничной навигации нам еще понадобится общее число записей в таблице. Это можно сделать с помощью запроса

SELECT COUNT(*) FROM items;
$query = "SELECT COUNT(*) FROM items";
$res = mysql_query( $query );
$total = mysql_result( $res, 0, 0 );

Далее определим, сколько всего получится страниц:

$cnt_pages = ceil( $total / ITEMS_PER_PAGE );

Здесь используется константа ITEMS_PER_PAGE, в которой хранится количество выводимых на странице записей.

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

DEFINE('ITEMS_PER_PAGE', 5);

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

// Выбираем из БД общее количество записей
$query = "SELECT COUNT(*) FROM products WHERE 1";
$res = mysql_query( $query );
$total = mysql_result( $res, 0, 0 );
   
// Проверяем передан ли номер текущей страницы
if ( isset($_GET['page']) ) {
  $page = (int)$_GET['page'];
  if ( $page < 1 ) $page = 1;
} else {
  $page = 1;
}

// Сколько всего получится страниц
$cnt_pages = ceil( $total / ITEMS_PER_PAGE );
if ( $page > $cnt_pages ) $page = $cnt_pages;
// Начальная позиция
$start = ( $page - 1 ) * ITEMS_PER_PAGE;

$query = "SELECT id, title, price
          FROM products
          ORDER BY price ASC
          LIMIT "
.$start.", ".ITEMS_PER_PAGE;
$res = mysql_query( $query );

// Выводим "шапку" таблицы
echo '<table border="1" cellpadding="5" cellspacing="0">';
echo '<tr>';
echo '<th>ID</th>';
echo '<th>Наименование</th>';
echo '<th>Цена</th>';
echo '</tr>';

while( $prd = mysql_fetch_array( $res ) )
{
    echo '<tr>';
    echo '<td>'.$prd['id'].'</td>';
    echo '<td>'.$prd['title'].'</td>';
    echo '<td>'.$prd['price'].'</td>';   
    echo '</tr>';
}

echo '</table>';

// Строим постраничную навигацию
if ( $cnt_pages > 1 )
{
    echo '<div style="margin:1em 0">&nbsp;Страницы: ';
    // Проверяем нужна ли стрелка "В начало"
    if ( $page > 3 )
        $startpage = '<a href="'.$_SERVER['PHP_SELF'].'?page=1"><<</a> ... ';
    else
        $startpage = '';
    // Проверяем нужна ли стрелка "В конец"
    if ( $page < ($cnt_pages - 2) )
        $endpage = ' ... <a href="'.$_SERVER['PHP_SELF'].'?page='.$cnt_pages.'">>></a>';
    else
        $endpage = '';

    // Находим две ближайшие станицы с обоих краев, если они есть
    if ( $page - 2 > 0 )
        $page2left = ' <a href="'.$_SERVER['PHP_SELF'].'?page='.($page - 2).'">'.($page - 2).'</a> | ';
    else
        $page2left = '';
    if ( $page - 1 > 0 )
        $page1left = ' <a href="'.$_SERVER['PHP_SELF'].'?page='.($page - 1).'">'.($page - 1).'</a> | ';
    else
        $page1left = '';
    if ( $page + 2 <= $cnt_pages )
        $page2right = ' | <a href="'.$_SERVER['PHP_SELF'].'?page='.($page + 2).'">'.($page + 2).'</a>';
    else
        $page2right = '';
    if ( $page + 1 <= $cnt_pages )
        $page1right = ' | <a href="'.$_SERVER['PHP_SELF'].'?page='.($page + 1).'">'.($page + 1).'</a>';
    else
        $page1right = '';

    // Выводим меню
    echo $startpage.$page2left.$page1left.'<strong>'.$page.'</strong>'.$page1right.$page2right.$endpage;

    echo '</div>';
}
?>

Тут есть проблема, о которой стоит упомянуть: кроме переменной $page нашему скрипту могут быть переданы и другие переменные. Решается это просто:

$uri = strtok($_SERVER['REQUEST_URI'],"?")."?";
if (count($_GET)) {
  foreach ($_GET as $k => $v) {
    if ($k != "page") $uri.=urlencode($k)."=".urlencode($v)."&";
  }
}

и полученную переменную $uri подставляем в код вместо $_SERVER['PHP_SELF']

Как отправить файл на сервер

Задача: отправить с сайта first.com на сайт second.com файл без использования формы. Для этого на сервере first.com формируем POST-запрос, который в себе содержит название и содержимое файла, который нужно передать, и посылаем на сервер second.com. На сайте second.com POST-запрос принимается, и в указанный файл пишется переданное содержимое.

Для того, чтобы передать данные методом POST, требуется сформировать строку, содержащую заголовки запроса и непосредственно сами данные. Строка, отсылаемая на сервер second.com, выглядит примерно так:

POST /getfile.php HTTP/1.1
Host: second.com
Content-type: application/x-www-form-urlencoded
Content-Length: 2501

file=image.gif&amp;content=GIF89a%3C%00%3C%00%D5%00%00%F4...%5E%10%00%3B

Для передачи POST-запроса будем использовать сокеты:

<?php
$hostname = 'second.com';
$path = '/getfile.php';
// Устанавливаем соединение с сервером $hostname
$fp = fsockopen($hostname, 80, $errno, $errstr, 30);
// Проверяем успешность установки соединения
if (!$fp) die($errstr.' ('.$errno.')');

// Содержимое файла
$file = 'image.gif';
$f = fopen($file, 'r');
$content = fread($f, filesize($file));
fclose($f);
// Данные HTTP-запроса
$data = 'file='.urlencode($file).'&amp;content='.urlencode($content);
// Заголовок HTTP-запроса
$headers = 'POST '.$path." HTTP/1.1\r\n";
$headers .= 'Host: '.$hostname."\r\n";
$headers .= "Content-type: application/x-www-form-urlencoded\r\n";
$headers .= 'Content-Length: '.strlen($data)."\r\n\r\n";
// Отправляем HTTP-запрос серверу second.com
fwrite($fp, $headers.$data);
// Получаем ответ
$result = '';
while ( !feof($fp) ) $result .= fgets($fp, 1024);
// Закрываем соединение
fclose($fp);
// Выводим ответ в браузер
echo $result;
?>

В результате работы скрипта с сайта first.com уходит POST-запрос на сайт second.com, а именно в скрипт getfile.php, находящийся в корне сайта second.com. Скрипту getfile.php будет доступен массив $_POST, содержащий переменные file и content.

Все, что нам нужно, так это открыть на запись файл с именем $_POST['file'], и записать туда данные из переменной $_POST['content']:

<?php
$f = fopen($_POST['file'], 'w+');
fwrite($f, $_POST['content']);
fclose($f);
echo '<p>Файл получен</p>';
?>

Ссылки по теме:

Фотогалерея: просмотр файлов в каталоге с постраничной навигацией

Пусть у нас есть каталог (директория), содержащий файлы изображений и мы хотим создать удобный интерфейс для их просмотра. Было бы неудобно выводить все файлы изображений в каталоге - ведь их может быть очень много. Следовательно, необходимо сделать постраничный вывод: по 10 (20, 30) изображений на страницу, а внизу - ссылки на остальные страницы.


Для этого мы должны прочитать все содержимое каталога (исключив директории и файлы, не являющиеся картинками), записать в массив, отсортировать, а потом просто вывести не все содержимое массива, а только нужные элементы (например, с 0 до 9 или с 10 по 19).

<?php
// количество изображений на странице
define( 'PERPAGE', 10 );
$directory = 'small';
$dir = new DirectoryItems($directory);
// Отфильтровываем все файлы, которые не являются изображениями
$dir->filter();
// Сортируем картинки
$dir->indexOrder();
// Общее количество изображений в директории
$totalCount = $dir->getCount();
// Текущая страница
if ( isset( $_GET['page'] ) )
  $page = $_GET['page'];
else
  $page = 1;
$numPages = ceil($totalCount/PERPAGE);
if ( $page < 1 ) $page = 1;
if ( $page > $numPages ) $page = $numPages;
// Получаем часть массива
$filearray = $dir->getFileArraySlice( ($page-1)*PERPAGE, PERPAGE);

foreach( $filearray as $value) {
  $path = $dir->getDirectoryName().'/'.$value;
  echo '<img src="'.$path.'" alt="" />'."\n";
}

// Создавать постраничную навигацию есть смысл, только если
// есть больше одной страницы
if($numPages > 1) {
  // Создаем навигатор
  $nav = new PageNavigator($totalCount, PERPAGE, $page);
  echo $nav->getNavigator();
}

class DirectoryItems {
  private $filearray = array();
  private $directory;

  public function __construct($directory) {
    $this->directory = $directory;
    if ( is_dir($directory) ) {
      $d = opendir( $directory ) or die("Failed to open directory.");
      while ( false !== ($f = readdir($d)) ) {
        if( is_file($directory.'/'.$f) ) {
          $this->filearray[] = $f;
        }
      }
      closedir($d);
    } else {
      die("Must pass in a directory.");
    }
  }

  public function __destruct(){
    unset($this->filearray);
  }

  public function getDirectoryName(){
    return $this->directory;
  }
   
  public function indexOrder(){
    sort($this->filearray);
  }

  public function getCount() {
    return count($this->filearray);
  }

  public function getFileArray() {
    return $this->filearray;
  }
   
  public function getFileArraySlice($start, $numberitems) {
    return array_slice($this->filearray, $start, $numberitems);
  }

  // исключить из массива все элементы с недопустимым расширением
  public function filter(){
    $extensions = array("jpg", "jpeg", "gif", "png");
    foreach ($this->filearray as $key => $value) {
      $ext = substr($value,(strpos($value, ".")+1));
      $extstrtolower($ext);
      if(!in_array($ext, $extensions)){
        unset($this->filearray[$key]);
      }
    }
  }   
}

class PageNavigator {
  // общее число страниц, необходимых для вывода всего списка изображений
  private $totalpages;
  // число изображений на одной странице
  private $recordsperpage;
  // текущая страница
  private $currentpage
  // текст для навигации
  private $strfirst = 'Первая';
  private $strlast = 'Последняя';
 
  public function __construct($totalrecords, $recordsperpage = 10, $currentpage = 1){
    $this->totalrecords = $totalrecords;
    $this->recordsperpage = $recordsperpage;
    $this->currentpage = $currentpage;   
    $this->setTotalPages($totalrecords, $recordsperpage);
  }
  // Возвращает HTML код навигатора
  public function getNavigator(){
    $strnavigator = '<div>'."\n";
    // Ссылка "Первая страница"   
    if($this->currentpage != 1) {
      $strnavigator .= $this->createLink(1, $this->strfirst);
      $strnavigator .= ' ... ';
    }
    // Две страницы назад + текущая страница + две страницы вперед
    for($i = $this->currentpage - 2; $i <= $this->currentpage + 2; $i++) {
      if($i < 1 or $i > $this->totalpages) continue;
      if($i == $this->currentpage) {
        $strnavigator .= '<b>';
        $strnavigator .= $i;
        $strnavigator .= '</b>'."\n";
      } else {
        $strnavigator .= $this->createLink($i, $i);
      }
      if ($i != $this->totalpages) $strnavigator .= ' | ';
    }
    // Ссылка "Последняя страница"   
    if($this->currentpage != $this->totalpages){
      $strnavigator .= ' ... ';
      $strnavigator .= $this->createLink($this->totalpages, $this->strlast);
    }
    $strnavigator .= '</div>'."\n";
    return $strnavigator;
  }
 
  private function createLink($offset, $strdisplay ){
    $strtemp = '<a href="'.$_SERVER['PHP_SELF'].'?page='.$offset.'">'.$strdisplay.'</a>'."\n";
    return $strtemp;
  }
  // всего страниц
  private function setTotalPages($totalrecords, $recordsperpage){
    $this->totalpages = ceil($totalrecords/$recordsperpage);
  }
}
?>