Статьи

Как архивировать и распаковывать файлы в CodeIgniter

В первой половине этого руководства объясняются различные способы создания файла zip с использованием встроенных API-интерфейсов CodeIgniter. Мы увидим, как создавать и сохранять ZIP-файлы на сервере и как вы можете сделать их доступными для загрузки конечным пользователям.

Вторая половина включает обсуждение того, как вы можете разархивировать файл. Чтобы продемонстрировать это, мы создадим пользовательскую страницу, которая позволяет пользователям загружать zip-файлы, которые будут извлечены на сервер после успешной загрузки файла. Для достижения желаемой функциональности, PHP-расширение ZipArchive приходит нам на помощь!

Прежде чем мы продолжим и углубимся в процесс разработки, я перечислю файлы, которые мы собираемся разработать в ходе этого урока:

  • application/controllers/Zip.php : это файл контроллера, который демонстрирует различные способы создания zip-файла.
  • application/controllers/Unzip.php : это файл контроллера, который содержит код, используемый для распаковки загруженного пользователем файла.
  • application/views/file_upload_form.php : это файл представления, который содержит довольно простой код формы загрузки HTML-файла.
  • application/views/file_upload_result.php : это файл представления, который показывает результат загруженного пользователем файла; в основном он сообщает вам, был ли файл успешно разархивирован.
  • application/libraries/Extractor.php : этот файл демонстрирует концепцию пользовательской библиотеки в CodeIgniter.

Со всем на месте, мы готовы перейти к следующему разделу!

Идем дальше и создаем файл application/controllers/Zip.php со следующим содержимым.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<?php
// application/controllers/Zip.php
defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
 
class Zip extends CI_Controller {
    private function _load_zip_lib()
    {
        $this->load->library(‘zip’);
    }
     
    private function _archieve_and_download($filename)
    {
        // create zip file on server
        $this->zip->archive(FCPATH.’/uploads/’.$filename);
         
        // prompt user to download the zip file
        $this->zip->download($filename);
    }
 
    public function data()
    {
        $this->_load_zip_lib();
         
        $this->zip->add_data(‘name.txt’, ‘Sajal Soni’);
        $this->zip->add_data(‘profile.txt’, ‘Web Developer’);
         
        $this->_archieve_and_download(‘my_info.zip’);
    }
 
    public function data_array()
    {
        $this->_load_zip_lib();
         
        $files = array(
                ‘name.txt’ => ‘Sajal Soni’,
                ‘profile.txt’ => ‘Web Developer’
        );
         
        $this->zip->add_data($files);
         
        $this->_archieve_and_download(‘my_info.zip’);
    }
 
    public function data_with_subdirs()
    {
        $this->_load_zip_lib();
         
        $this->zip->add_data(‘info/name.txt’, ‘Sajal Soni’);
        $this->zip->add_data(‘info/profile.txt’, ‘Web Developer’);
         
        $this->_archieve_and_download(‘my_info.zip’);
    }
 
    public function files()
    {
        $this->_load_zip_lib();
         
        // pass second argument as TRUE if want to preserve dir structure
        $this->zip->read_file(FCPATH.’/uploads/1.jpg’);
        $this->zip->read_file(FCPATH.’/uploads/2.jpg’);
         
        $this->_archieve_and_download(‘images.zip’);
    }
     
    public function dir()
    {
        $this->_load_zip_lib();
         
        // pass second argument as FALSE if want to ignore preceding directories
        $this->zip->read_dir(FCPATH.’/uploads/images/’);
         
        $this->_archieve_and_download(‘dir_images.zip’);
    }
}

Это довольно стандартный файл контроллера, с которым вы уже знакомы. Он содержит несколько методов, и каждый из них показывает вам свой способ создания zip-файла.

Кроме того, он предоставляет два закрытых метода, _load_zip_lib и _archieve_and_download , которые вызываются из остальных методов. Конечно, вам не нужно реализовывать эти методы, но мы только что провели рефакторинг нашего кода, чтобы вы не повторили тот же код в других методах. Давайте сначала пройдемся по этим двум методам.

Вот как выглядит метод _load_zip_lib .

1
2
3
4
private function _load_zip_lib()
{
    $this->load->library(‘zip’);
}

Он загружает встроенную zip-библиотеку платформы CodeIgniter, чтобы вы могли использовать возможности этой библиотеки в остальной части кода. Теперь вы можете получить доступ к библиотеке zip с помощью соглашения $this->zip .

Далее есть метод _archieve_and_download .

1
2
3
4
5
6
7
8
private function _archieve_and_download($filename)
{
    // create zip file on server
    $this->zip->archive(FCPATH.’/uploads/’.$filename);
         
    // prompt user to download the zip file
    $this->zip->download($filename);
}

Поскольку мы загрузили библиотеку zip, вы можете использовать методы, предоставляемые ею. Метод архивирования позволяет вам создать zip-файл по пути, указанному в качестве первого аргумента. С другой стороны, метод загрузки запрашивает загрузку файла.

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

Все на месте, поэтому мы готовы к работе!

Давайте возьмем код метода data . Этот метод показывает, как создавать файлы на лету и оборачивать их в zip-файл.

1
2
3
4
5
6
7
8
9
public function data()
{
    $this->_load_zip_lib();
         
    $this->zip->add_data(‘name.txt’, ‘Sajal Soni’);
    $this->zip->add_data(‘profile.txt’, ‘Web Developer’);
         
    $this->_archieve_and_download(‘my_info.zip’);
}

Для начала мы _load_zip_lib метод _load_zip_lib который загружает библиотеку zip. Далее мы использовали метод add_data класса zip, который позволяет вам создать файл и одновременно заполнить его содержимым! Конечно, он добавлен и в архив!

Первый аргумент должен быть именем файла, а второй аргумент содержит содержимое файла.

Как видите, мы добавили два файла, name.txt и profile.txt , с некоторым демонстрационным содержимым. Наконец, мы вызываем _archieve_and_download с my_info.zip в качестве аргумента этого метода. Что оно делает?

  • Это создаст zip-файл my_info.zip в вашем каталоге загрузок.
  • Он также предложит пользователю загрузить файл, и имя, под которым будет сохранен файл, — my_info.zip .

Поэтому убедитесь, что вы создали каталог для uploads в корне вашего сайта. Кроме того, сделайте его доступным для записи пользователем веб-сервера. Теперь идите вперед и запустите « http: // my-codeingiter-site / zip / data », чтобы увидеть все в действии!

Если у вас возникли проблемы, вы можете спросить меня в комментариях!

Далее есть метод data_array .

01
02
03
04
05
06
07
08
09
10
11
12
13
public function data_array()
{
    $this->_load_zip_lib();
     
    $files = array(
        ‘name.txt’ => ‘Sajal Soni’,
        ‘profile.txt’ => ‘Web Developer’
    );
     
    $this->zip->add_data($files);
     
    $this->_archieve_and_download(‘my_info.zip’);
}

Этот метод идентичен последнему, который мы только что обсуждали, за исключением того, что мы предоставили массив файлов для метода add_data вместо отдельных файлов!

data_with_subdirs метода data_with_subdirs .

1
2
3
4
5
6
7
8
9
public function data_with_subdirs()
{
    $this->_load_zip_lib();
         
    $this->zip->add_data(‘info/name.txt’, ‘Sajal Soni’);
    $this->zip->add_data(‘info/profile.txt’, ‘Web Developer’);
         
    $this->_archieve_and_download(‘my_info.zip’);
}

На случай, если вы захотите организовать свои файлы в определенных каталогах, метод add_data позволяет вам создавать их. Результирующий вывод описанного выше метода не будет отличаться, за исключением того, что name.txt и profile.txt будут размещены в info каталоге.

Хотя метод add_data предоставляет замечательную функцию, которая позволяет создавать файлы на лету, чаще всего вам понадобится архивировать существующие файлы на сервере. Во всяком случае, это именно та тема нашей следующей пары методов.

Давайте быстро посмотрим, как выглядит наш следующий метод files . Это создаст почтовый файл в каталоге uploads .

01
02
03
04
05
06
07
08
09
10
public function files()
{
    $this->_load_zip_lib();
         
    // pass second argument as TRUE if want to preserve dir structure
    $this->zip->read_file(FCPATH.’/uploads/1.jpg’);
    $this->zip->read_file(FCPATH.’/uploads/2.jpg’);
         
    $this->_archieve_and_download(‘images.zip’);
}

Цель метода read_file — прочитать существующий файл на сервере и добавить его в архив. Как видите, мы добавили в архив два файла 1.jpg и 2.jpg . Конечно, эти два файла должны присутствовать в каталоге uploads в корне вашего сайта.

Если вы передадите TRUE в качестве второго аргумента метода read_file , результирующий zip-файл сохранит точную структуру каталогов, в которую он был помещен.

Попробуйте запустить http: // my-codeingiter-site / zip / files и проверьте результат!

Последний метод в этом сегменте — метод dir . Это создаст zip-архив всего каталога.

1
2
3
4
5
6
7
8
9
public function dir()
{
    $this->_load_zip_lib();
         
    // pass second argument as FALSE if want to ignore preceding directories
    $this->zip->read_dir(FCPATH.’/uploads/images/’);
         
    $this->_archieve_and_download(‘dir_images.zip’);
}

Вы можете использовать метод read_dir если хотите создать zip-архив всего каталога вместо определенных файлов. В нашем примере выше, он создаст файл dir_images.zip который содержит все файлы в каталоге /uploads/images/ .

Здесь важно отметить, что вся структура каталогов будет сохранена по умолчанию в zip-файле. Но, если вы хотите игнорировать это, просто передайте FALSE как второй аргумент метода read_dir . В этом случае он будет создавать только каталог images в zip-файле.

На этом наша история о том, как создать zip-архив, используя различные методы, предоставляемые встроенным zip-классом, заканчивается.

К сожалению, нет встроенной библиотеки CodeIgniter, которая позволяла бы нам разархивировать zip-архив. Но расширение ZipArchive PHP делает его быстрым, как мы увидим через мгновение.

Мы создадим довольно простой пример, который демонстрирует, как разархивировать загруженные пользователем файлы.

Идем дальше и создаем файл application/controllers/Unzip.php со следующим содержимым.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
// application/controllers/Unzip.php
defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
 
class Unzip extends CI_Controller {
    public function __construct()
    {
        parent::__construct();
        $this->load->helper(array(‘form’, ‘url’));
    }
 
    public function index()
    {
        $this->load->view(‘file_upload_form’);
    }
 
    public function upload()
    {
        $config[‘upload_path’] = ‘./uploads/’;
        $config[‘allowed_types’] = ‘zip’;
         
        $this->load->library(‘upload’, $config);
         
        if ( ! $this->upload->do_upload(‘zip_file’))
        {
            $params = array(‘error’ => $this->upload->display_errors());
        }
        else
        {
            $data = array(‘upload_data’ => $this->upload->data());
            $full_path = $data[‘upload_data’][‘full_path’];
             
            /**** without library ****/
            $zip = new ZipArchive;
 
            if ($zip->open($full_path) === TRUE)
            {
                $zip->extractTo(FCPATH.’/uploads/’);
                $zip->close();
            }
 
            $params = array(‘success’ => ‘Extracted successfully!’);
        }
         
        $this->load->view(‘file_upload_result’, $params);
    }
}

Давайте также создадим наши шаблоны представления, и затем мы увидим, как это работает в целом.

Создайте файл шаблона представления application/views/file_upload_form.php со следующим содержимым.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
<?php
// application/views/file_upload_form.php
defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
?><!DOCTYPE html>
<html lang=»en»>
<head>
    <meta charset=»utf-8″>
    <title>Welcome to CodeIgniter</title>
 
    <style type=»text/css»>
 
    ::selection { background-color: #E13300;
    ::-moz-selection { background-color: #E13300;
 
    body {
        background-color: #fff;
        margin: 40px;
        font: 13px/20px normal Helvetica, Arial, sans-serif;
        color: #4F5155;
    }
 
    a {
        color: #003399;
        background-color: transparent;
        font-weight: normal;
    }
 
    h1 {
        color: #444;
        background-color: transparent;
        border-bottom: 1px solid #D0D0D0;
        font-size: 19px;
        font-weight: normal;
        margin: 0 0 14px 0;
        padding: 14px 15px 10px 15px;
    }
 
    code {
        font-family: Consolas, Monaco, Courier New, Courier, monospace;
        font-size: 12px;
        background-color: #f9f9f9;
        border: 1px solid #D0D0D0;
        color: #002166;
        display: block;
        margin: 14px 0 14px 0;
        padding: 12px 10px 12px 10px;
    }
 
    #body {
        margin: 0 15px 0 15px;
    }
 
    p.footer {
        text-align: right;
        font-size: 11px;
        border-top: 1px solid #D0D0D0;
        line-height: 32px;
        padding: 0 10px 0 10px;
        margin: 20px 0 0 0;
    }
 
    #container {
        margin: 10px;
        border: 1px solid #D0D0D0;
        box-shadow: 0 0 8px #D0D0D0;
    }
     
    div {
      padding: 10px;
    }
     
    .error {
      color: #F00;
    }
     
    .success {
      color: #00F;
    }
    </style>
</head>
<body>
 
<div id=»container»>
    <h1>Upload File</h1>
 
    <div id=»body»>
      <div class=»success»><?php if (isset($success)) {echo $success;}?></div>
      <div class=»error»><?php if (isset($error)) {echo $error;}?></div>
 
        <?php echo form_open_multipart(‘unzip/upload’);?>
          <div>
              <input name=»zip_file» type=»file»/>
            </div>
            <div>
              <input type=»submit» value=»Upload Zip File» />
            </div>
        </form>
    </div>
</div>
 
</body>
</html>

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

Далее, давайте создадим файл шаблона представления application/views/file_upload_result.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
// application/views/file_upload_result.php
defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
?><!DOCTYPE html>
<html lang=»en»>
<head>
    <meta charset=»utf-8″>
    <title>Welcome to CodeIgniter</title>
 
    <style type=»text/css»>
 
    ::selection { background-color: #E13300;
    ::-moz-selection { background-color: #E13300;
 
    body {
        background-color: #fff;
        margin: 40px;
        font: 13px/20px normal Helvetica, Arial, sans-serif;
        color: #4F5155;
    }
 
    a {
        color: #003399;
        background-color: transparent;
        font-weight: normal;
    }
 
    h1 {
        color: #444;
        background-color: transparent;
        border-bottom: 1px solid #D0D0D0;
        font-size: 19px;
        font-weight: normal;
        margin: 0 0 14px 0;
        padding: 14px 15px 10px 15px;
    }
 
    code {
        font-family: Consolas, Monaco, Courier New, Courier, monospace;
        font-size: 12px;
        background-color: #f9f9f9;
        border: 1px solid #D0D0D0;
        color: #002166;
        display: block;
        margin: 14px 0 14px 0;
        padding: 12px 10px 12px 10px;
    }
 
    #body {
        margin: 0 15px 0 15px;
    }
 
    p.footer {
        text-align: right;
        font-size: 11px;
        border-top: 1px solid #D0D0D0;
        line-height: 32px;
        padding: 0 10px 0 10px;
        margin: 20px 0 0 0;
    }
 
    #container {
        margin: 10px;
        border: 1px solid #D0D0D0;
        box-shadow: 0 0 8px #D0D0D0;
    }
     
    div {
      padding: 10px;
    }
     
    .error {
      color: #F00;
    }
     
    .success {
      color: #00F;
    }
    </style>
</head>
<body>
 
<div id=»container»>
    <h1>Upload File Result</h1>
 
    <div id=»body»>
      <div class=»success»><?php if (isset($success)) {echo $success;}?></div>
      <div class=»error»><?php if (isset($error)) {echo $error;}?></div>
      <a href=»<?php echo site_url(‘unzip/index’); ?>»>&lt;&lt;
    </div>
</div>
 
</body>
</html>

Как только файл загружен и распакован, пользователю будет показан вышеуказанный шаблон.

Теперь вернемся к нашему контроллеру и рассмотрим каждый метод.

В конструктор нашего контроллера мы загрузили встроенную форму и помощники CodeIgniter для URL , чтобы мы могли использовать вспомогательные функции, такие как form_open_multipart , site_url и тому подобное.

Далее, давайте посмотрим на метод index .

1
2
3
4
public function index()
{
    $this->load->view(‘file_upload_form’);
}

Это нуждается в каком-либо объяснении? Он вызывает представление file_upload_form и отображает страницу. Поэтому, когда вы открываете http: // my-codeingiter-site / unzip , он должен отображать простую форму загрузки файла, как показано ниже.

Также обратите внимание, что действие нашей формы — unzip/upload где данные будут опубликованы. Мы использовали помощник form_open_multipart для создания тега составной формы!

Страница загрузки

Далее нам нужно реализовать метод действия upload который будет обрабатывать загрузку и извлечение файлов. Unzip.php код этого от контроллера Unzip.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public function upload()
{
    $config[‘upload_path’] = ‘./uploads/’;
    $config[‘allowed_types’] = ‘zip’;
         
    $this->load->library(‘upload’, $config);
         
    if ( ! $this->upload->do_upload(‘zip_file’))
    {
        $params = array(‘error’ => $this->upload->display_errors());
    }
    else
    {
        $data = array(‘upload_data’ => $this->upload->data());
        $full_path = $data[‘upload_data’][‘full_path’];
             
        $zip = new ZipArchive;
 
        if ($zip->open($full_path) === TRUE)
        {
            $zip->extractTo(FCPATH.’/uploads/’);
            $zip->close();
        }
 
        $params = array(‘success’ => ‘Extracted successfully!’);
    }
         
    $this->load->view(‘file_upload_result’, $params);
}

Если вы знакомы с загрузкой файлов в CodeIgniter, код не должен выглядеть для вас чуждым. Для тех, кто не знаком, не о чем беспокоиться, поскольку встроенные API загрузки в CodeIgniter делают это проще простого.

Следующий код загружает библиотеку загрузки с некоторой начальной конфигурацией, предоставленной переменной массива $config .

1
$this->load->library(‘upload’, $config);

Мы настроили его так, чтобы загруженный файл был помещен в каталог uploads в корне приложения, и пользователю будет разрешено загружать только zip-файлы.

Далее мы проверили, не удалось ли загрузить файл, и в этом случае мы извлечем полезное сообщение об ошибке и назначим его в $params чтобы мы могли отобразить его в шаблоне.

1
$params = array(‘error’ => $this->upload->display_errors());

В этом случае файл успешно загружен, поэтому следующим шагом является получение пути к файлу загруженного файла.

1
2
$data = array(‘upload_data’ => $this->upload->data());
$full_path = $data[‘upload_data’][‘full_path’];

Наконец, мы создаем экземпляр объекта ZipArchive, открываем наш zip-файл и распаковываем его в каталог uploads .

1
2
3
4
5
6
7
$zip = new ZipArchive;
 
if ($zip->open($full_path) === TRUE)
{
    $zip->extractTo(FCPATH.’/uploads/’);
    $zip->close();
}

Разве это не просто?

Единственное, что нам осталось, это вызвать представление file_upload_result , и вот как оно должно выглядеть!

Страница результатов загрузки

Итак, это другая часть истории!

Вы бы заметили, что метод upload содержит код ZipArchive, который извлекает загруженный файл. Что если вам нужно использовать этот код в нескольких местах? У вас может возникнуть желание скопировать и вставить код по мере необходимости.

Действительно, есть лучший способ, с помощью которого CodeIgniter позволяет вам централизовать код, который можно использовать во всем приложении. Вы можете создать собственную библиотеку.

Продолжайте и создайте файл application/libraries/Extractor.php со следующим содержимым.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
<?php
// application/libraries/Extractor.php
class Extractor {
    private $CI = NULL;
    private $zip = NULL;
     
    public function __construct($params = array())
    {
        $this->CI =& get_instance();
        $this->zip = new ZipArchive;
    }
     
    public function extract($source_file, $dest_dir)
    {
        if ($this->zip->open($source_file) === TRUE)
        {
            $this->zip->extractTo($dest_dir);
            $this->zip->close();
        }
    }
}

Теперь перейдите и замените метод upload в вашем контроллере Unzip.php следующим.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function upload()
{
    $config[‘upload_path’] = ‘./uploads/’;
    $config[‘allowed_types’] = ‘zip’;
         
    $this->load->library(‘upload’, $config);
         
    if ( ! $this->upload->do_upload(‘zip_file’))
    {
        $params = array(‘error’ => $this->upload->display_errors());
    }
    else
    {
        $data = array(‘upload_data’ => $this->upload->data());
        $full_path = $data[‘upload_data’][‘full_path’];
 
        $this->load->library(‘extractor’);
        $this->extractor->extract($full_path, FCPATH.’/uploads/’);
        $params = array(‘success’ => ‘Extracted successfully!’);
    }
         
    $this->load->view(‘file_upload_result’, $params);
}

Как видите, мы загрузили нашу пользовательскую библиотеку и использовали ее для извлечения содержимого!

1
2
$this->load->library(‘extractor’);
$this->extractor->extract($full_path, FCPATH.’/uploads/’);

Довольно круто, а?

И да, это конец этой статьи.

Надеюсь, вам понравилась эта статья, в которой мы начали исследовать базовую zip-библиотеку инфраструктуры CodeIgniter и различные способы создания zip-архива. Во второй части я объяснил, как вы можете разархивировать загруженные пользователем файлы, используя расширение ZipArchive PHP.

В ходе этого процесса мы также получили возможность преобразовать наш код в пользовательскую библиотеку CodeIgniter, и я бы сказал, что это что-то вроде вишни!

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