|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00018 00028 defined('MOODLE_INTERNAL') || die(); 00029 00030 require_once("$CFG->libdir/filestorage/file_packer.php"); 00031 require_once("$CFG->libdir/filestorage/zip_archive.php"); 00032 00041 class zip_packer extends file_packer { 00042 00055 public function archive_to_storage($files, $contextid, $component, $filearea, $itemid, $filepath, $filename, $userid = NULL) { 00056 global $CFG; 00057 00058 $fs = get_file_storage(); 00059 00060 check_dir_exists($CFG->tempdir.'/zip'); 00061 $tmpfile = tempnam($CFG->tempdir.'/zip', 'zipstor'); 00062 00063 if ($result = $this->archive_to_pathname($files, $tmpfile)) { 00064 if ($file = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename)) { 00065 if (!$file->delete()) { 00066 @unlink($tmpfile); 00067 return false; 00068 } 00069 } 00070 $file_record = new stdClass(); 00071 $file_record->contextid = $contextid; 00072 $file_record->component = $component; 00073 $file_record->filearea = $filearea; 00074 $file_record->itemid = $itemid; 00075 $file_record->filepath = $filepath; 00076 $file_record->filename = $filename; 00077 $file_record->userid = $userid; 00078 $file_record->mimetype = 'application/zip'; 00079 00080 $result = $fs->create_file_from_pathname($file_record, $tmpfile); 00081 } 00082 @unlink($tmpfile); 00083 return $result; 00084 } 00085 00092 public function archive_to_pathname($files, $archivefile) { 00093 if (!is_array($files)) { 00094 return false; 00095 } 00096 00097 $ziparch = new zip_archive(); 00098 if (!$ziparch->open($archivefile, file_archive::OVERWRITE)) { 00099 return false; 00100 } 00101 00102 foreach ($files as $archivepath => $file) { 00103 $archivepath = trim($archivepath, '/'); 00104 00105 if (is_null($file)) { 00106 // empty directories have null as content 00107 $ziparch->add_directory($archivepath.'/'); 00108 00109 } else if (is_string($file)) { 00110 $this->archive_pathname($ziparch, $archivepath, $file); 00111 00112 } else if (is_array($file)) { 00113 $content = reset($file); 00114 $ziparch->add_file_from_string($archivepath, $content); 00115 00116 } else { 00117 $this->archive_stored($ziparch, $archivepath, $file); 00118 } 00119 } 00120 00121 return $ziparch->close(); 00122 } 00123 00124 private function archive_stored($ziparch, $archivepath, $file) { 00125 $file->archive_file($ziparch, $archivepath); 00126 00127 if (!$file->is_directory()) { 00128 return; 00129 } 00130 00131 $baselength = strlen($file->get_filepath()); 00132 $fs = get_file_storage(); 00133 $files = $fs->get_directory_files($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_itemid(), 00134 $file->get_filepath(), true, true); 00135 foreach ($files as $file) { 00136 $path = $file->get_filepath(); 00137 $path = substr($path, $baselength); 00138 $path = $archivepath.'/'.$path; 00139 if (!$file->is_directory()) { 00140 $path = $path.$file->get_filename(); 00141 } 00142 $file->archive_file($ziparch, $path); 00143 } 00144 } 00145 00146 private function archive_pathname($ziparch, $archivepath, $file) { 00147 if (!file_exists($file)) { 00148 return; 00149 } 00150 00151 if (is_file($file)) { 00152 if (!is_readable($file)) { 00153 return; 00154 } 00155 $ziparch->add_file_from_pathname($archivepath, $file); 00156 return; 00157 } 00158 if (is_dir($file)) { 00159 if ($archivepath !== '') { 00160 $ziparch->add_directory($archivepath); 00161 } 00162 $files = new DirectoryIterator($file); 00163 foreach ($files as $file) { 00164 if ($file->isDot()) { 00165 continue; 00166 } 00167 $newpath = $archivepath.'/'.$file->getFilename(); 00168 $this->archive_pathname($ziparch, $newpath, $file->getPathname()); 00169 } 00170 unset($files); //release file handles 00171 return; 00172 } 00173 } 00174 00181 public function extract_to_pathname($archivefile, $pathname) { 00182 global $CFG; 00183 00184 if (!is_string($archivefile)) { 00185 return $archivefile->extract_to_pathname($this, $pathname); 00186 } 00187 00188 $processed = array(); 00189 00190 $pathname = rtrim($pathname, '/'); 00191 if (!is_readable($archivefile)) { 00192 return false; 00193 } 00194 $ziparch = new zip_archive(); 00195 if (!$ziparch->open($archivefile, file_archive::OPEN)) { 00196 return false; 00197 } 00198 00199 foreach ($ziparch as $info) { 00200 $size = $info->size; 00201 $name = $info->pathname; 00202 00203 if ($name === '' or array_key_exists($name, $processed)) { 00204 //probably filename collisions caused by filename cleaning/conversion 00205 continue; 00206 } 00207 00208 if ($info->is_directory) { 00209 $newdir = "$pathname/$name"; 00210 // directory 00211 if (is_file($newdir) and !unlink($newdir)) { 00212 $processed[$name] = 'Can not create directory, file already exists'; // TODO: localise 00213 continue; 00214 } 00215 if (is_dir($newdir)) { 00216 //dir already there 00217 $processed[$name] = true; 00218 } else { 00219 if (mkdir($newdir, $CFG->directorypermissions, true)) { 00220 $processed[$name] = true; 00221 } else { 00222 $processed[$name] = 'Can not create directory'; // TODO: localise 00223 } 00224 } 00225 continue; 00226 } 00227 00228 $parts = explode('/', trim($name, '/')); 00229 $filename = array_pop($parts); 00230 $newdir = rtrim($pathname.'/'.implode('/', $parts), '/'); 00231 00232 if (!is_dir($newdir)) { 00233 if (!mkdir($newdir, $CFG->directorypermissions, true)) { 00234 $processed[$name] = 'Can not create directory'; // TODO: localise 00235 continue; 00236 } 00237 } 00238 00239 $newfile = "$newdir/$filename"; 00240 if (!$fp = fopen($newfile, 'wb')) { 00241 $processed[$name] = 'Can not write target file'; // TODO: localise 00242 continue; 00243 } 00244 if (!$fz = $ziparch->get_stream($info->index)) { 00245 $processed[$name] = 'Can not read file from zip archive'; // TODO: localise 00246 fclose($fp); 00247 continue; 00248 } 00249 00250 while (!feof($fz)) { 00251 $content = fread($fz, 262143); 00252 fwrite($fp, $content); 00253 } 00254 fclose($fz); 00255 fclose($fp); 00256 if (filesize($newfile) !== $size) { 00257 $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise 00258 // something went wrong :-( 00259 @unlink($newfile); 00260 continue; 00261 } 00262 $processed[$name] = true; 00263 } 00264 $ziparch->close(); 00265 return $processed; 00266 } 00267 00278 public function extract_to_storage($archivefile, $contextid, $component, $filearea, $itemid, $pathbase, $userid = NULL) { 00279 global $CFG; 00280 00281 if (!is_string($archivefile)) { 00282 return $archivefile->extract_to_pathname($this, $contextid, $component, $filearea, $itemid, $pathbase, $userid); 00283 } 00284 00285 check_dir_exists($CFG->tempdir.'/zip'); 00286 00287 $pathbase = trim($pathbase, '/'); 00288 $pathbase = ($pathbase === '') ? '/' : '/'.$pathbase.'/'; 00289 $fs = get_file_storage(); 00290 00291 $processed = array(); 00292 00293 $ziparch = new zip_archive(); 00294 if (!$ziparch->open($archivefile, file_archive::OPEN)) { 00295 return false; 00296 } 00297 00298 foreach ($ziparch as $info) { 00299 $size = $info->size; 00300 $name = $info->pathname; 00301 00302 if ($name === '' or array_key_exists($name, $processed)) { 00303 //probably filename collisions caused by filename cleaning/conversion 00304 continue; 00305 } 00306 00307 if ($info->is_directory) { 00308 $newfilepath = $pathbase.$name.'/'; 00309 $fs->create_directory($contextid, $component, $filearea, $itemid, $newfilepath, $userid); 00310 $processed[$name] = true; 00311 continue; 00312 } 00313 00314 $parts = explode('/', trim($name, '/')); 00315 $filename = array_pop($parts); 00316 $filepath = $pathbase; 00317 if ($parts) { 00318 $filepath .= implode('/', $parts).'/'; 00319 } 00320 00321 if ($size < 2097151) { 00322 // small file 00323 if (!$fz = $ziparch->get_stream($info->index)) { 00324 $processed[$name] = 'Can not read file from zip archive'; // TODO: localise 00325 continue; 00326 } 00327 $content = ''; 00328 while (!feof($fz)) { 00329 $content .= fread($fz, 262143); 00330 } 00331 fclose($fz); 00332 if (strlen($content) !== $size) { 00333 $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise 00334 // something went wrong :-( 00335 unset($content); 00336 continue; 00337 } 00338 00339 if ($file = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename)) { 00340 if (!$file->delete()) { 00341 $processed[$name] = 'Can not delete existing file'; // TODO: localise 00342 continue; 00343 } 00344 } 00345 $file_record = new stdClass(); 00346 $file_record->contextid = $contextid; 00347 $file_record->component = $component; 00348 $file_record->filearea = $filearea; 00349 $file_record->itemid = $itemid; 00350 $file_record->filepath = $filepath; 00351 $file_record->filename = $filename; 00352 $file_record->userid = $userid; 00353 if ($fs->create_file_from_string($file_record, $content)) { 00354 $processed[$name] = true; 00355 } else { 00356 $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise 00357 } 00358 unset($content); 00359 continue; 00360 00361 } else { 00362 // large file, would not fit into memory :-( 00363 $tmpfile = tempnam($CFG->tempdir.'/zip', 'unzip'); 00364 if (!$fp = fopen($tmpfile, 'wb')) { 00365 @unlink($tmpfile); 00366 $processed[$name] = 'Can not write temp file'; // TODO: localise 00367 continue; 00368 } 00369 if (!$fz = $ziparch->get_stream($info->index)) { 00370 @unlink($tmpfile); 00371 $processed[$name] = 'Can not read file from zip archive'; // TODO: localise 00372 continue; 00373 } 00374 while (!feof($fz)) { 00375 $content = fread($fz, 262143); 00376 fwrite($fp, $content); 00377 } 00378 fclose($fz); 00379 fclose($fp); 00380 if (filesize($tmpfile) !== $size) { 00381 $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise 00382 // something went wrong :-( 00383 @unlink($tmpfile); 00384 continue; 00385 } 00386 00387 if ($file = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename)) { 00388 if (!$file->delete()) { 00389 @unlink($tmpfile); 00390 $processed[$name] = 'Can not delete existing file'; // TODO: localise 00391 continue; 00392 } 00393 } 00394 $file_record = new stdClass(); 00395 $file_record->contextid = $contextid; 00396 $file_record->component = $component; 00397 $file_record->filearea = $filearea; 00398 $file_record->itemid = $itemid; 00399 $file_record->filepath = $filepath; 00400 $file_record->filename = $filename; 00401 $file_record->userid = $userid; 00402 if ($fs->create_file_from_pathname($file_record, $tmpfile)) { 00403 $processed[$name] = true; 00404 } else { 00405 $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise 00406 } 00407 @unlink($tmpfile); 00408 continue; 00409 } 00410 } 00411 $ziparch->close(); 00412 return $processed; 00413 } 00414 00419 public function list_files($archivefile) { 00420 if (!is_string($archivefile)) { 00421 return $archivefile->list_files(); 00422 } 00423 00424 $ziparch = new zip_archive(); 00425 if (!$ziparch->open($archivefile, file_archive::OPEN)) { 00426 return false; 00427 } 00428 $list = $ziparch->list_files(); 00429 $ziparch->close(); 00430 return $list; 00431 } 00432 00433 }