Рубрика «PHP»

Класс для работы с zip-архивами

В PHP 5.2.0 был добавлен встроенный класс для работы с zip архивами на запись и чтение. Сегодня мы рассмотрим несколько примеров его использования. Прежде всего, убедитесь, что включена поддержка библиотеки php_zip.dll. Для этого в файле php.ini нужно убрать символ комментария (;) в начале строки

extension=php_zip.dll

и перезапустить Apache.

Теперь переходим к созданию архива. Все операции с архивом выполняются с помощью объекта ZipArchive. После создания экземпляра класса создаем файл архива с помощью метода open(), который в качестве параметров принимает имя архива и константу, указывающую способ открытия.

Чтобы добавить в архив файл, используем метод addFile(), который принимает два параметра: имя исходного файла и имя, под которым файл будет добавлен в архив. Завершает работу с архивом метод close().

<?php
// Создаем архив
$zip = new ZipArchive;
$res = $zip -> open("archive.zip", ZIPARCHIVE::CREATE);
if ( $res === true ) {
    $zip -> addFromString("string.txt", "Это строка, которая будет записана в файл string.txt, а сам файл помещен в архив");
    // Файл file.txt будет помещен в архив под именем file_zip.txt
    $zip -> addFile("file.txt", "file_zip.txt");
    $zip -> close();
    echo "<p>Файлы добавлены в архив</p>";
} else {
    echo "<p>Ошибка</p>";
}
?>

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

<?php
// Создаем архив и добавляем в него все файлы из директории
$zip = new ZipArchive;
$res = $zip -> open("images.zip", ZIPARCHIVE::CREATE);
if ($res === true) {
    $dir = opendir( "./images" );
    chdir( "./images" );
   
    while( $d = readdir( $dir ) ) {
        if( is_file( $d ) ) {
            echo "Добавляем в архив файл ".$d." размером ".filesize( $d )."<br />";
            $zip -> addFile( $d, $d);       
        }
    }
    closedir( $dir );
    $zip -> close();
    echo "<p>Файлы добавлены в архив</p>";
} else {
    echo "<p>Ошибка</p>";
}
?>

Извлечение файла из архива выполняется в три этапа:

  • открываем архив с помощью метода open()
  • извлекаем файлы (метод extractTo())
  • закрываем архив методом close().
<?php
// Извлекаем файлы из архива
$zip = new ZipArchive;
if ( $zip -> open("archive.zip") === true ) {
   $zip -> extractTo("testunzip");
   $zip -> close();
   echo "<p>Архив распакован</p>";
} else {
   echo "<p>Ошибка при извлечении файлов из архива</p>";
}
?>

Обратите внимание, что здесь используется тот же метод open(), что и при создании архива, но константа ZIPARCHIVE::CREATE не указывается. Мы собираемся что-то извлечь из архива, значит, он должен существовать.

Метод extractTo() принимает два параметра: имя папки, в которую будет извлечено содержимое архива и имена объектов, которые необходимо извлечь. В нашем примере второй параметр не задан. Это означает, что будет распаковано все содержимое архива.

С помощью методов объекта ZipArchive можно не только добавлять и извлекать файлы, но и получить информацию об архиве:

// читаем сведения об архиве
echo "Number of files: ".$zip->numFiles."<br/>";
echo "status: ".$zip->status."<br/>";
echo "statusSys: ".$zip->statusSys."<br/>";
echo "filename: ".$zip->filename."<br/>";
echo "comment: ".$zip->comment."<br/>";

Отправка письма с вложением. Часть 1

Для отправки почтового сообщения создадим HTML-форму, состоящую из трех текстовых полей для имени автора name, его e-mail адреса email, темы сообщения subject, текстовой области message для ввода содержимого письма и поля типа file для выбора файла отправки.

Письмо будем отправлять по адресу администратора сайта $admin = ‘admin@mail.ru’

<?php
session_start();
$admin = 'admin@mail.ru';

if ( isset( $_POST['sendMail'] ) ) {
  $name  = substr( $_POST['name'], 0, 64 );
  $email   = substr( $_POST['email'], 0, 64 );
  $subject = substr( $_POST['subject'], 0, 64 );
  $message = substr( $_POST['message'], 0, 250 );
 
  $error = '';
  if ( empty( $name ) ) $error = $error.'<li>Не заполнено поле "Имя"</li>';
  if ( empty( $email ) ) $error = $error.'<li>Не заполнено поле "E-mail"</li>';
  if ( empty( $subject ) ) $error = $error.'<li>Не заполнено поле "Тема"</li>';
  if ( empty( $message ) ) $error = $error.'<li>Не заполнено поле "Сообщение"</li>';
  if ( !empty( $email ) and !preg_match( "#^[0-9a-z_\-\.]+@[0-9a-z\-\.]+\.[a-z]{2,6}$#i", $email ) )
    $error = $error.'<li>поле "E-mail" должно соответствовать формату somebody@somewhere.ru</li>';
  if ( !empty( $error ) ) {
    $_SESSION['sendMailForm']['error']   = '<p>При заполнении формы были допущены ошибки:</p><ul>'.$error.'</ul>';
    $_SESSION['sendMailForm']['name']    = $name;
    $_SESSION['sendMailForm']['email']   = $email;
    $_SESSION['sendMailForm']['subject'] = $subject;
    $_SESSION['sendMailForm']['message'] = $message;
    header( 'Location: '.$_SERVER['PHP_SELF'] );
    die();
  }

  if ( !empty( $_FILES['file']['tmp_name'] ) and $_FILES['file']['error'] == 0 ) {
    $filepath = $_FILES['file']['tmp_name'];
    $filename = $_FILES['file']['name'];
  } else {
    $filepath = '';
    $filename = '';
  }
 
  $body = "АВТОР:\r\n".$name."\r\n\r\n";
  $body .= "E-MAIL:\r\n".$email."\r\n\r\n";
  $body .= "ТЕМА:\r\n".$subject."\r\n\r\n";
  $body .= "СООБЩЕНИЕ:\r\n".$message;
 
  if ( send_mail($admin, $body, $email, $filepath, $filename) )
    $_SESSION['success'] = true;
  else
    $_SESSION['success'] = false;
  header( 'Location: '.$_SERVER['PHP_SELF'] );
  die();
}

// Вспомогательная функция для отправки почтового сообщения с вложением
function send_mail($admin, $body, $email, $filepath, $filename)
{
  $subject = '=?windows-1251?B?'.base64_encode('Заполнена форма на сайте').'?=';
  $boundary = "--".md5(uniqid(time())); // генерируем разделитель
  $headers = "From: ".strtoupper($_SERVER['SERVER_NAME'])." <".$email.">\r\n";   
  $headers .= "Return-path: <".$email.">\r\n";
  $headers .= "MIME-Version: 1.0\r\n";
  $headers .="Content-Type: multipart/mixed; boundary=\"".$boundary."\"\r\n";
  $multipart = "--".$boundary."\r\n";
  $multipart .= "Content-type: text/plain; charset=\"windows-1251\"\r\n";
  $multipart .= "Content-Transfer-Encoding: quoted-printable\r\n\r\n";

  $body = quoted_printable_encode( $body )."\r\n\r\n";
 
  $multipart .= $body;
 
  $file = '';
  if ( !empty( $filepath ) ) {
    $fp = fopen($filepath, "r");
    if ( $fp ) {
      $content = fread($fp, filesize($filepath));
      fclose($fp);
      $file .= "--".$boundary."\r\n";
      $file .= "Content-Type: application/octet-stream\r\n";
      $file .= "Content-Transfer-Encoding: base64\r\n";
      $file .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
      $file .= chunk_split(base64_encode($content))."\r\n";
    }
  }
  $multipart .= $file."--".$boundary."--\r\n";

  if( mail($admin, $subject, $multipart, $headers) )
    return true;
  else
    return false;
}

function quoted_printable_encode ( $string ) {
   // rule #2, #3 (leaves space and tab characters in tact)
   $string = preg_replace_callback (
   '/[^\x21-\x3C\x3E-\x7E\x09\x20]/',
   'quoted_printable_encode_character',
   $string
   );
   $newline = "=\r\n"; // '=' + CRLF (rule #4)
   // make sure the splitting of lines does not interfere with escaped characters
   // (chunk_split fails here)
   $string = preg_replace ( '/(.{73}[^=]{0,3})/', '$1'.$newline, $string);
   return $string;
}

function quoted_printable_encode_character ( $matches ) {
   $character = $matches[0];
   return sprintf ( '=%02x', ord ( $character ) );
}
?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Отправить письмо</title>
<link rel="StyleSheet" type="text/css" href="/style/screen.css">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
</head>
<body>

<?php
if ( isset( $_SESSION['sendMailForm'] ) ) {
  echo $_SESSION['sendMailForm']['error'];
  $name    = htmlspecialchars ( $_SESSION['sendMailForm']['name'] );
  $email   = htmlspecialchars ( $_SESSION['sendMailForm']['email'] );
  $subject = htmlspecialchars ( $_SESSION['sendMailForm']['subject'] );
  $message = htmlspecialchars ( $_SESSION['sendMailForm']['message'] );
  unset( $_SESSION['sendMailForm'] );
} else {
  $name  = '';
  $email   = '';
  $subject = '';
  $message = '';
}

if ( isset( $_SESSION['success'] ) ) {
  if ( $_SESSION['success'] )
    echo '<p>Письмо успешно отправлено</p>';
  else
    echo '<p>Ошибка при отправке письма</p>';
  unset( $_SESSION['success'] );
}
?>

<form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="POST" enctype="multipart/form-data">
<table>
<tr><td>Имя:</td><td><input type="text" name="name" maxlength="64" value="<?php echo $name ?>" /></td></tr>
<tr><td>E-mail:</td><td><input type="text" name="email" maxlength="64" value="<?php echo $email ?>" /></td></tr>
<tr><td>Тема:</td><td><input type="text" name="subject" maxlength="64" value="<?php echo $subject ?>" /></td></tr>
<tr><td>Сообщение:</td><td><textarea name="message" rows="5" cols="30"><?php echo $message ?></textarea></td></tr>
<tr><td>Файл:</td><td><input type="file" name="file" /></td></tr>
<tr><td>&nbsp;</td><td><input type="submit" name="sendMail" value="Отправить" /></td></tr>
</table>
</form>

</body>
</html>

Письмо, содержащее вложенный файл, несколько отличается от простого. Одна из особенностей - наличие заголовка MIME-Version: 1.0. Этот заголовок указывает стандарт, которому соответствует тело сообщения.

Если мы хотим отослать письмо с прикрепленным файлом, то необходимо использовать заголовок Content-type: multipart/mixed, который обозначает, что письмо состоит из нескольких частей, каждая из которых содержит свой заголовок Content-type.

Для обозначения границы этих частей необходимо использовать параметр boundary, который еще называется маркером границы. Значением этого параметра может служить любая строка. Но надо учесть, что она должна быть уникальной и не встречалась в теле письма. Иначе письмо может быть неправильно разбито на части.

При разделении письма на части перед маркером должны стоять два знака дефиса. А последний маркер, который обозначает конец письма, должен содержать в конце два знака дефиса.

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

Если у нас идет часть с текстом, то заголовоку Content-Transfer-Encoding надо присвоить значение quoted-printable, либо 7bit, либо 8bit. Для части с файлом этот заголовок должен быть равен base64.

Заголовок Content-Disposition, присутствующий во второй части, указывает, как почтовой программе следует отобразить данную часть письма. Он может принимать значение attachment (этот участок не является частью письма, а просто прикреплен к нему в виде файла) и inline (включение, которое используется непосредственно в письме, например, картинка, вставляемая в HTML).

В первой части заголовком Content-type: text/plain; charset=”windows-1251″ указали, что это простой текст в кодировке Windows-1251. Во второй же части заголовком Content-Type: application/octet-stream указали, что заранее не известно, какой тип файла будет отправлен.

Прикрепленный файл должен быть размещен в письме в формате base64. Преобразовать файл в этот формат можно при помощи PHP-функции base64_encode().

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

Создание файлов Excel средствами PHP

Возникла нужда создавать Excel-файлы средствами PHP. О существовании PEAR::Spreadsheet_Excel_Writer я уже знал - видел статью Создание таблиц Excel средствами PHP на http://phpclub.ru. Поиск в Google помог установить PEAR и Spreadsheet_Excel_Writer. Пример использования класса:

<?php
require_once 'Spreadsheet/Excel/Writer.php';

// We give the path to our file here
$workbook = new Spreadsheet_Excel_Writer('test.xls');

$worksheet =& $workbook->addWorksheet('My first worksheet');

$worksheet->write(0, 0, 'Name');
$worksheet->write(0, 1, 'Age');
$worksheet->write(1, 0, 'John Smith');
$worksheet->write(1, 1, 30);
$worksheet->write(2, 0, 'Johann Schmidt');
$worksheet->write(2, 1, 31);
$worksheet->write(3, 0, 'Juan Herrera');
$worksheet->write(3, 1, 32);

// We still need to explicitly close the workbook
$workbook->close();
?>

Для создания и чтения данных из файлов формата OpenXML (который используется в MS Excel 2007) можно использовать набор библиотек PHPExcel. Для их работы требуется версия PHP 5.2 или выше, с установленными библиотеками Zip, XML и GD2. Пример кода:

<?php
/** Error reporting */
error_reporting(E_ALL);
 
/** Include path **/
ini_set('include_path', ini_get('include_path').';../Classes/');
 
/** PHPExcel */
include 'PHPExcel.php';
 
/** PHPExcel_Writer_Excel2007 */
include 'PHPExcel/Writer/Excel2007.php';
 
// Create new PHPExcel object
echo date('H:i:s') . " Create new PHPExcel object\n";
$objPHPExcel = new PHPExcel();
 
// Set properties
echo date('H:i:s') . " Set properties\n";
$objPHPExcel->getProperties()->setCreator("Maarten Balliauw");
$objPHPExcel->getProperties()->setLastModifiedBy("Maarten Balliauw");
$objPHPExcel->getProperties()->setTitle("Office 2007 XLSX Test Document");
$objPHPExcel->getProperties()->setSubject("Office 2007 XLSX Test Document");
$objPHPExcel->getProperties()->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.");
 
// Add some data
echo date('H:i:s') . " Add some data\n";
$objPHPExcel->setActiveSheetIndex(0);
$objPHPExcel->getActiveSheet()->SetCellValue('A1', 'Hello');
$objPHPExcel->getActiveSheet()->SetCellValue('B2', 'world!');
$objPHPExcel->getActiveSheet()->SetCellValue('C1', 'Hello');
$objPHPExcel->getActiveSheet()->SetCellValue('D2', 'world!');
 
// Rename sheet
echo date('H:i:s') . " Rename sheet\n";
$objPHPExcel->getActiveSheet()->setTitle('Simple');
    
// Save Excel 2007 file
echo date('H:i:s') . " Write to Excel2007 format\n";
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$objWriter->save(str_replace('.php', '.xlsx', __FILE__));
 
// Echo done
echo date('H:i:s') . " Done writing file.\r\n";
?>

Наконец, друзья из Индии нам выложили класс Excel Writer. Вот пример его работы:

<?php
    include("excelwriter.inc.php");
   
    $excel=new ExcelWriter("myXls.xls");
   
    if($excel==false)   
        echo $excel->error;
       
    $myArr=array("Name","Last Name","Address","Age");
    $excel->writeLine($myArr);

    $myArr=array("Sriram","Pandit","23 mayur vihar",24);
    $excel->writeLine($myArr);
   
    $excel->writeRow();
    $excel->writeCol("Manoj");
    $excel->writeCol("Tiwari");
    $excel->writeCol("80 Preet Vihar");
    $excel->writeCol(24);
   
    $excel->writeRow();
    $excel->writeCol("Harish");
    $excel->writeCol("Chauhan");
    $excel->writeCol("115 Shyam Park Main");
    $excel->writeCol(22);

    $myArr=array("Tapan","Chauhan","1st Floor Vasundhra",25);
    $excel->writeLine($myArr);
   
    $excel->close();
    echo "data is write into myXls.xls Successfully.";
?>