<?php //$Id$
+/**
+ * Utility class - handles all zipping and unzipping operations.
+ */
class file_packer {
+ public function zip_files_to_pathname($files, $zipfile) {
+ error('todo');
+ }
+
+ public function zip_files_to_storage($files, $contextid, $filearea, $itemid, $filepath, $filename) {
+ error('todo');
+ }
+
+ /**
+ * Unzip file to given file path (real OS filesystem), existing files are overwrited
+ * @param mixed $zipfile full pathname of zip file or stored_file instance
+ * @param string $path target directory
+ * @return mixed list of processed files; false if error
+ */
+ public function unzip_files_to_pathname($zipfile, $pathname) {
+ global $CFG;
+
+ if (!is_string($zipfile)) {
+ return $zipfile->unzip_files_to_pathname($pathname);
+ }
+
+ $processed = array();
+
+ $pathname = rtrim($pathname, '/');
+ if (!is_readable($zipfile)) {
+ return false;
+ }
+ $zip = new ZipArchive();
+ if (!$zip->open($zipfile, ZIPARCHIVE::FL_NOCASE)) {
+ return false;
+ }
+
+ for ($i=0; $i<$zip->numFiles; $i++) {
+ $index = $zip->statIndex($i);
+
+ $size = clean_param($index['size'], PARAM_INT);
+ $name = clean_param($index['name'], PARAM_PATH);
+ $name = ltrim($name, '/');
+
+ //TODO: add $name encoding conversions magic here
+
+ if ($name === '' or array_key_exists($name, $processed)) {
+ //probably filename collisions caused by filename cleaning/conversion
+ continue;
+ }
+
+ if ($size === 0 and $name[strlen($name)-1] === '/') {
+ $newdir = "$pathname/$name";
+ // directory
+ if (is_file($newdir) and !unlink($newdir)) {
+ $processed[$name] = 'Can not create directory, file already exists'; // TODO: localise
+ continue;
+ }
+ if (is_dir($newdir)) {
+ //dir already there
+ $processed[$name] = true;
+ } else {
+ if (mkdir($newdir, $CFG->directorypermissions, true)) {
+ $processed[$name] = true;
+ } else {
+ $processed[$name] = 'Can not create directory'; // TODO: localise
+ }
+ }
+ continue;
+ }
+
+ $parts = explode('/', trim($name, '/'));
+ $filename = array_pop($parts);
+ $newdir = rtrim($pathname.'/'.implode('/', $parts), '/');
+
+ if (!is_dir($newdir)) {
+ if (!mkdir($newdir, $CFG->directorypermissions, true)) {
+ $processed[$name] = 'Can not create directory'; // TODO: localise
+ continue;
+ }
+ }
+
+ $newfile = "$newdir/$filename";
+ if (!$fp = fopen($newfile, 'wb')) {
+ $processed[$name] = 'Can not write target file'; // TODO: localise
+ continue;
+ }
+ if (!$fz = $zip->getStream($index['name'])) {
+ $processed[$name] = 'Can not read file from zip archive'; // TODO: localise
+ fclose($fp);
+ continue;
+ }
+
+ while (!feof($fz)) {
+ $content = fread($fz, 262143);
+ fwrite($fp, $content);
+ }
+ fclose($fz);
+ fclose($fp);
+ if (filesize($newfile) !== $size) {
+ $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise
+ // something went wrong :-(
+ @unlink($newfile);
+ continue;
+ }
+ $processed[$name] = true;
+ }
+ $zip->close();
+ return $processed;
+ }
+
+ /**
+ * Unzip file to given file path (real OS filesystem), existing files are overwrited
+ * @param mixed $zipfile full pathname of zip file or stored_file instance
+ * @param int $contextid
+ * @param string $filearea
+ * @param int $itemid
+ * @param string $filepath
+ * @return mixed list of processed files; false if error
+ */
+ public function unzip_files_to_storage($zipfile, $contextid, $filearea, $itemid, $pathbase, $userid=null) {
+ global $CFG;
+
+ if (!is_string($zipfile)) {
+ return $zipfile->unzip_files_to_pathname($contextid, $filearea, $itemid, $pathbase, $userid);
+ }
+
+ check_dir_exists($CFG->dataroot.'/temp/unzip', true, true);
+
+ $pathbase = trim($pathbase, '/');
+ $pathbase = ($pathbase === '') ? '/' : '/'.$pathbase.'/';
+ $fs = get_file_storage();
+
+ $processed = array();
+
+ $zip = new ZipArchive();
+ if (!$zip->open($zipfile, ZIPARCHIVE::FL_NOCASE)) {
+ return false;
+ }
+
+ for ($i=0; $i<$zip->numFiles; $i++) {
+ $index = $zip->statIndex($i);
+
+ $size = clean_param($index['size'], PARAM_INT);
+ $name = clean_param($index['name'], PARAM_PATH);
+ $name = ltrim($name, '/');
+
+ //TODO: add $name encoding conversions magic here
+
+ if ($name === '' or array_key_exists($name, $processed)) {
+ //probably filename collisions caused by filename cleaning/conversion
+ continue;
+ }
+
+ if ($size === 0 and $name[strlen($name)-1] === '/') {
+ $newfilepath = $pathbase.$name.'/';
+ $fs->create_directory($contextid, $filearea, $itemid, $newfilepath, $userid);
+ $processed[$name] = true;
+ continue;
+ }
+
+ $parts = explode('/', trim($name, '/'));
+ $filename = array_pop($parts);
+ $filepath = $pathbase;
+ if ($parts) {
+ $filepath .= implode('/', $parts).'/';
+ }
+
+ if ($size < 2097151) {
+ // small file
+ if (!$fz = $zip->getStream($index['name'])) {
+ $processed[$name] = 'Can not read file from zip archive'; // TODO: localise
+ continue;
+ }
+ $content = '';
+ while (!feof($fz)) {
+ $content .= fread($fz, 262143);
+ }
+ fclose($fz);
+ if (strlen($content) !== $size) {
+ $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise
+ // something went wrong :-(
+ unset($content);
+ continue;
+ }
+
+ if ($file = $fs->get_file($contextid, $filearea, $itemid, $filepath, $filename)) {
+ if (!$file->delete()) {
+ $processed[$name] = 'Can not delete existing file'; // TODO: localise
+ continue;
+ }
+ }
+ $file_record = new object();
+ $file_record->contextid = $contextid;
+ $file_record->filearea = $filearea;
+ $file_record->itemid = $itemid;
+ $file_record->filepath = $filepath;
+ $file_record->filename = $filename;
+ $file_record->userid = $userid;
+ if ($fs->create_file_from_string($file_record, $content)) {
+ $processed[$name] = true;
+ } else {
+ $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise
+ }
+ unset($content);
+ continue;
+
+ } else {
+ // large file, would not fit into memory :-(
+ $tmpfile = tempnam($CFG->dataroot.'/temp/unzip');
+ if (!$fp = fopen($tmpfile, 'wb')) {
+ $processed[$name] = 'Can not write temp file'; // TODO: localise
+ continue;
+ }
+ if (!$fz = $zip->getStream($index['name'])) {
+ $processed[$name] = 'Can not read file from zip archive'; // TODO: localise
+ continue;
+ }
+ while (!feof($fz)) {
+ $content = fread($fz, 262143);
+ fwrite($fp, $content);
+ }
+ fclose($fz);
+ fclose($fp);
+ if (strlen($tmpfile) !== $size) {
+ $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise
+ // something went wrong :-(
+ @unlink($tmpfile);
+ continue;
+ }
+
+ if ($file = $fs->get_file($contextid, $filearea, $itemid, $filepath, $filename)) {
+ if (!$file->delete()) {
+ $processed[$name] = 'Can not delete existing file'; // TODO: localise
+ continue;
+ }
+ }
+ $file_record = new object();
+ $file_record->contextid = $contextid;
+ $file_record->filearea = $filearea;
+ $file_record->itemid = $itemid;
+ $file_record->filepath = $filepath;
+ $file_record->filename = $filename;
+ $file_record->userid = $userid;
+ if ($fs->create_file_from_pathname($file_record, $tmpfile)) {
+ $processed[$name] = true;
+ } else {
+ $processed[$name] = 'Unknown error during zip extraction'; // TODO: localise
+ }
+ @unlink($tmpfile);
+ continue;
+ }
+ }
+ return $processed;
+ }
}
\ No newline at end of file
/**
* Protected - developers must not gain direct access to this function
+ * NOTE: do not make this public, we must not modify or delete the pool files directly! ;-)
+ * @return ful path to pool file with file content
**/
protected function get_content_file_location() {
- // NOTE: do not make this public, we must not modify or delete the pool files directly! ;-)
- $hashpath = $this->fs->path_from_hash($this->file_record->contenthash);
- return $hashpath.'/'.$this->file_record->contenthash;
+ global $CFG;
+ if (isset($CFG->filedir)) {
+ $filedir = $CFG->filedir;
+ } else {
+ $filedir = $CFG->dataroot.'/filedir';
+ }
+ $contenthash = $this->file_record->contenthash;
+ $l1 = $contenthash[0].$contenthash[1];
+ $l2 = $contenthash[2].$contenthash[3];
+ $l3 = $contenthash[4].$contenthash[5];
+ return "$filedir/$l1/$l2/$l3/$contenthash";
}
/**
/**
* Copy content of file to give npathname
- * @param string $pathnema rela path to new file
+ * @param string $pathnema rela path to new file
* @return bool success
*/
public function copy_content_to($pathname) {
return copy($path, $pathname);
}
+ /**
+ * Unzip file to given file path (real OS filesystem), existing files are overwrited
+ * @param string $path target directory
+ * @return mixed list of processed files; false if error
+ */
+ public function unzip_files_to_pathname($path) {
+ $packer = get_file_packer();
+ $zipfile = $this->get_content_file_location();
+ return $packer->unzip_files_to_pathname($path, $path);
+ }
+
+ /**
+ * Unzip file to given file path (real OS filesystem), existing files are overwrited
+ * @param int $contextid
+ * @param string $filearea
+ * @param int $itemid
+ * @param string $pathbase
+ * @param int $userid
+ * @return mixed list of processed files; false if error
+ */
+ public function unzip_files_to_storage($contextid, $filearea, $itemid, $pathbase, $userid=null) {
+ $packer = get_file_packer();
+ $zipfile = $this->get_content_file_location();
+ return $packer->unzip_files_to_storage($zipfile, $contextid, $filearea, $itemid, $pathbase);
+ }
+
public function get_contextid() {
return $this->file_record->contextid;
}