moved code up one level to eliminate the docs subdirectory
[acontent.git] / include / classes / zipfile.class.php
1 <?php
2 /************************************************************************/
3 /* AContent                                                             */
4 /************************************************************************/
5 /* Copyright (c) 2010                                                   */
6 /* Inclusive Design Institute                                           */
7 /*                                                                      */
8 /* This program is free software. You can redistribute it and/or        */
9 /* modify it under the terms of the GNU General Public License          */
10 /* as published by the Free Software Foundation.                        */
11 /************************************************************************/
12
13 define('PCLZIP_TEMPORARY_DIR', TR_CONTENT_DIR.'export'.DIRECTORY_SEPARATOR);  //constant for the temp folder.
14 include_once(TR_INCLUDE_PATH.'lib/pclzip.lib.php');      //loads the pclzip library.
15 include_once(TR_INCLUDE_PATH.'classes/FileUtility.class.php');  //copy/delete folder
16
17 /**
18 * Class for creating and accessing an archive zip file.  Originally written by Joel Kronenberg,
19 * edited by Harris Wong to use the PCLZIP library (http://www.phpconcept.net)
20 *
21 * As of ATutor 2.0, this file will extend the pclzip library functions instead of using Joel's.  
22 * The function preconditions and postconditions will remain the same however. 
23 *
24 * @access       public
25 * @link         http://www.pkware.com/documents/casestudies/APPNOTE.TXT for the specs
26 * @author       Joel Kronenberg
27 */
28 class zipfile {
29
30         /**
31          * string $zipfile_dir - the actual system directory that stores the temporary files for archiving.
32          * @access      private
33          */
34         var $zipfile_dir;
35
36         /**
37         * boolean $is_closed - flag set to true if file is closed, false if still open
38         * @access  private
39         */
40         var $is_closed; 
41
42         /** 
43          * string $filename -   randomized filename of this zip instance.  It also shares the same name
44          *                                              as the folder under the export/ folder.  
45          */
46         var $filename; 
47
48
49         /**
50         * Constructor method.  Initialises variables.
51         * @access       public
52         * @author       Joel Kronenberg
53         */
54         function zipfile() {
55                 //create the temp folder for export if it hasn't been created.
56                 if (!is_dir(PCLZIP_TEMPORARY_DIR)){
57                         mkdir(PCLZIP_TEMPORARY_DIR);
58                         copy(PCLZIP_TEMPORARY_DIR.'../index.html', PCLZIP_TEMPORARY_DIR.'index.html');
59                 }
60
61                 //generate a random hash 
62                 $this->filename = substr(md5(rand()), 0, 5);
63
64                 //create a temporary folder for this zip instance
65                 $this->zipfile_dir = PCLZIP_TEMPORARY_DIR.$this->filename.DIRECTORY_SEPARATOR;
66                 mkdir($this->zipfile_dir);
67                 $this->is_closed = false;
68         }
69
70
71         /**
72         * Public interface for adding a dir and its contents recursively to zip file
73         * @access  public
74         * @param   string $dir                          the real system directory that contains the files to add to the zip              
75         * @param   string $zip_prefix_dir       the zip dir where the contents of $dir will be put in
76         * @param   string $pre_pend_dir         used during the recursion to keep track of the path, default=''
77         * @see     $_base_path                          in include/vitals.inc.php
78         * @see     priv_add_dir()                       in include/classes/zipfile.class.php
79         * @see     add_file()                           in include/classes/zipfile.class.php
80         * @author  Joel Kronenberg
81         */
82         function add_dir($dir, $zip_prefix_dir, $pre_pend_dir='') {
83                 if (!($dh = @opendir($dir.$pre_pend_dir))) {
84                         echo 'cant open dir: '.$dir.$pre_pend_dir;
85                         exit;           
86                 }
87                 //copy folder recursively into the temp folder.
88                 FileUtility::copys($dir, $this->zipfile_dir.DIRECTORY_SEPARATOR.$zip_prefix_dir);
89         }
90
91         /**
92         * Adding a dir to the archive 
93         * @access  private
94         * @param   string $name                         directory name
95         * @param   string $timestamp            time, default=''
96         * @author  Joel Kronenberg
97         */
98     function priv_add_dir($name, $timestamp = '') {   
99                 //deprecated as of ATutor 2.0
100     } 
101         
102         /**
103         * Public interface to create a directory in the archive.
104         * @access  public
105         * @param   string $name                         directory name
106         * @param   string $timestamp            time of creation, default=''
107         * @see     $_base_path                          in include/vitals.inc.php
108         * @see     priv_add_dir()                       in include/zipfile.class.php
109         * @author  Joel Kronenberg
110         */
111         function create_dir($name, $timestamp='') {
112                 $name = trim($name);
113                 //don't create a folder if it is itself
114                 if ($name=='' || $name=='.'){
115                         return;
116                 }
117
118                 $parent_folder = dirname($name);
119                 if (!is_dir($this->zipfile_dir.$name) && ($parent_folder=='.' || $parent_folder=='')){
120                         //base case
121                         mkdir($this->zipfile_dir.$name);
122                         return;
123                 } else {
124                         //recursion step
125                         $this->create_dir(dirname($name));
126                 }
127
128                 //returned stack. continue from where it left off.              
129                 if (!is_dir($this->zipfile_dir.$name)){
130                         //the parent folder should be created at this point, create itself
131                         mkdir($this->zipfile_dir.$name);
132                 }
133         }
134
135
136         /**
137         * Adds a file to the archive.
138         * @access  public
139         * @param   string $file_data            file contents
140         * @param   string $name                         name of file in archive (add path if your want)
141         * @param   string $timestamp            time of creation, default=''
142         * @see     $_base_path                          in include/vitals.inc.php
143         * @see     priv_add_dir()                       in include/zipfile.class.php
144         * @author  Joel Kronenberg
145         */
146     function add_file($file_data, $name, $timestamp = '') {
147         $name = str_replace("\\", "/", $name);
148
149                 //check if folder exists, if not, create it.
150                 if (!is_dir($this->zipfile_dir.dirname($name))){
151                         $this->create_dir(dirname($name));
152                 }
153
154                 //write to file
155                 $fp = fopen($this->zipfile_dir.$name, 'w');
156                 fwrite($fp, $file_data);
157                 fclose($fp);            
158     } 
159
160         /**
161         * Closes archive, sets $is_closed to true
162         * @access  public
163         * @param   none
164         * @author  Joel Kronenberg
165         */
166         function close() {
167                 //use pclzip to compress the file, and save it in the temp folder.
168                 $archive = new PclZip($this->zipfile_dir.$this->filename.'.zip');
169                 $v_list = $archive->create($this->zipfile_dir, 
170                                                         PCLZIP_OPT_REMOVE_PATH, $this->zipfile_dir);
171
172                 //error info
173                 if ($v_list == 0) {
174                 die ("Error: " . $archive->errorInfo(true));
175                 }
176                 
177                 $this->is_closed = true;
178         }
179
180     /**
181         * Gets size of new archive
182         * Only call this after calling close() - will return false if the zip wasn't close()d yet
183         * @access  public
184         * @return  int  size of file in byte.
185         * @author  Joel Kronenberg
186         */
187         function get_size() {
188                 if (!$this->is_closed) {
189                         return false;
190                 }
191
192                 //file path
193                 $filepath = $this->zipfile_dir.$this->filename.'.zip';
194                 if (file_exists($filepath)){
195                         return filesize($filepath);
196                 } 
197
198                 return false;
199         }
200
201
202     /**
203         * Returns binary file
204         * @access       public
205         * @see          get_size()              in include/classes/zipfile.class.php
206         * @author  Joel Kronenberg
207         */      
208         function get_file() {
209                 if (!$this->is_closed) {
210                         $this->close();
211                 }
212                 return file_get_contents($this->zipfile_dir.$this->filename.'.zip');
213     }
214
215         /**
216         * Writes the file to disk.
217         * Similar to get_file(), but instead of returning the file, it saves it to disk.
218         * @access  public
219         * @author  Joel Kronenberg
220         * @param  $file The full path and file name of the destination file.
221         */
222         function write_file($file) {
223                 if (!$this->is_closed) {
224                         $this->close();
225                 }               
226                 copy($this->zipfile_dir.$this->filename.'.zip', $file);
227         }
228
229
230     /**
231         * Outputs the file - sends headers to browser to force download
232         * Only call this after calling close() - will return false if the zip wasn't close()d yet
233         * @access       public
234         * @see          get_size()              in include/classes/zipfile.class.php
235         * @author  Joel Kronenberg
236         */
237         function send_file($file_name) {
238                 if (!$this->is_closed) {
239                         $this->close();
240                 }
241                 $file_name = str_replace(array('"', '<', '>', '|', '?', '*', ':', '/', '\\'), '', $file_name);
242
243                 header("Content-type: archive/zip");
244                 header("Content-disposition: attachment; filename=$file_name.zip");
245                 FileUtility::readfile_in_chunks($this->zipfile_dir.$this->filename.'.zip');
246                 exit;
247         }
248
249         /**
250          * Destructor - removes temporary folder and its content.
251          * Should self-destruct automatically for PHP 5.0+; otherwise developers should call this function
252          * to clean up.
253          * @access      public
254          * @author      Harris Wong
255          */
256         function __destruct(){
257                 FileUtility::clr_dir($this->zipfile_dir);
258         }
259 }
260
261 ?>