xpdo =& $xpdo; $this->_filename = is_string($filename) ? $filename : ''; $this->_options = is_array($options) ? $options : array(); $this->_archive = new ZipArchive(); if (!empty($this->_filename) && file_exists(dirname($this->_filename))) { if (file_exists($this->_filename)) { if ($this->getOption(xPDOZip::OVERWRITE, null, false) && is_writable($this->_filename)) { if ($this->_archive->open($this->_filename, ZIPARCHIVE::OVERWRITE) !== true) { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOZip: Error opening archive at {$this->_filename} for OVERWRITE"); } } else { if ($this->_archive->open($this->_filename) !== true) { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOZip: Error opening archive at {$this->_filename}"); } } } elseif ($this->getOption(xPDOZip::CREATE, null, false) && is_writable(dirname($this->_filename))) { if ($this->_archive->open($this->_filename, ZIPARCHIVE::CREATE) !== true) { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOZip: Could not create archive at {$this->_filename}"); } } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOZip: The location specified is not writable: {$this->_filename}"); } } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOZip: The location specified does not exist: {$this->_filename}"); } } /** * Pack the contents from the source into the archive. * * @todo Implement custom file filtering options * * @param string $source The path to the source file(s) to pack. * @param array $options An array of options for the operation. * @return array An array of results for the operation. */ public function pack($source, array $options = array()) { $results = array(); if ($this->_archive) { $target = $this->getOption(xPDOZip::ZIP_TARGET, $options, ''); if (is_dir($source)) { if ($dh = opendir($source)) { if ($source[strlen($source) - 1] !== '/') $source .= '/'; $targetDir = rtrim($target, '/'); if (!empty($targetDir)) { if ($this->_archive->addEmptyDir($targetDir)) { $results[$target] = "Successfully added directory {$target} from {$source}"; } else { $results[$target] = "Error adding directory {$target} from {$source}"; $this->_errors[] = $results[$target]; } } while (($file = readdir($dh)) !== false) { if (is_dir($source . $file)) { if (($file !== '.') && ($file !== '..')) { $results = $results + $this->pack($source . $file . '/', array_merge($options, array(xPDOZip::ZIP_TARGET => $target . $file . '/'))); } } elseif (is_file($source . $file)) { if ($this->_archive->addFile($source . $file, $target . $file)) { $results[$target . $file] = "Successfully packed {$target}{$file} from {$source}{$file}"; } else { $results[$target . $file] = "Error packing {$target}{$file} from {$source}{$file}"; $this->_errors[] = $results[$target . $file]; } } else { $results[$target . $file] = "Error packing {$target}{$file} from {$source}{$file}"; $this->_errors[] = $results[$target . $file]; } } } } elseif (is_file($source)) { $file = basename($source); if ($this->_archive->addFile($source, $target . $file)) { $results[$target . $file] = "Successfully packed {$target}{$file} from {$source}"; } else { $results[$target . $file] = "Error packing {$target}{$file} from {$source}"; $this->_errors[] = $results[$target . $file]; } } else { $this->_errors[]= "Invalid source specified: {$source}"; } } return $results; } /** * Unpack the compressed contents from the archive to the target. * * @param string $target The path of the target location to unpack the files. * @param array $options An array of options for the operation. * @return bool|array An array of results for the operation. */ public function unpack($target, $options = array()) { $results = false; if ($this->_archive) { if (is_dir($target) && is_writable($target)) { if ($this->getOption('check_filetype', $options, false)) { $fileIndex = array(); for ($i = 0; $i < $this->_archive->numFiles; $i++) { $filename = $this->_archive->getNameIndex($i); if ($this->checkFiletype($filename)) { $fileIndex[] = $filename; } } $results = $this->_archive->extractTo($target, $fileIndex); } else { $results = $this->_archive->extractTo($target); } } } return $results; } /** * Close the archive. */ public function close() { if ($this->_archive) { $this->_archive->close(); } } /** * Get an option from supplied options, the xPDOZip instance options, or xpdo itself. * * @param string $key Unique identifier for the option. * @param array $options A set of explicit options to override those from xPDO or the * xPDOZip instance. * @param mixed $default An optional default value to return if no value is found. * @return mixed The value of the option. */ public function getOption($key, $options = null, $default = null) { $option = $default; if (is_array($key)) { if (!is_array($option)) { $default= $option; $option= array(); } foreach ($key as $k) { $option[$k]= $this->getOption($k, $options, $default); } } elseif (is_string($key) && !empty($key)) { if (is_array($options) && !empty($options) && array_key_exists($key, $options)) { $option = $options[$key]; } elseif (is_array($this->_options) && !empty($this->_options) && array_key_exists($key, $this->_options)) { $option = $this->_options[$key]; } else { $option = $this->xpdo->getOption($key, null, $default); } } return $option; } /** * Detect if errors occurred during any operations. * * @return boolean True if errors exist, otherwise false. */ public function hasError() { return !empty($this->_errors); } /** * Return any errors from operations on the archive. */ public function getErrors() { return $this->_errors; } /** * Check that the filename has a file type extension that is allowed * * @param $filename * @return bool */ private function checkFiletype($filename) { if ($this->xpdo->getOption('allowedFileTypes')) { $allowedFileTypes = $this->getOption('allowedFileTypes'); $allowedFileTypes = (!is_array($allowedFileTypes)) ? explode(',', $allowedFileTypes) : $allowedFileTypes; } else { $allowedFiles = $this->xpdo->getOption('upload_files') ? explode(',', $this->xpdo->getOption('upload_files')) : array(); $allowedImages = $this->xpdo->getOption('upload_images') ? explode(',', $this->xpdo->getOption('upload_images')) : array(); $allowedMedia = $this->xpdo->getOption('upload_media') ? explode(',', $this->xpdo->getOption('upload_media')) : array(); $allowedFlash = $this->xpdo->getOption('upload_flash') ? explode(',', $this->xpdo->getOption('upload_flash')) : array(); $allowedFileTypes = array_unique(array_merge($allowedFiles, $allowedImages, $allowedMedia, $allowedFlash)); $this->xpdo->setOption('allowedFileTypes', $allowedFileTypes); } $ext = pathinfo($filename, PATHINFO_EXTENSION); $ext = strtolower($ext); if (!empty($allowedFileTypes) && !in_array($ext, $allowedFileTypes)) { $this->xpdo->log(XPDO::LOG_LEVEL_WARN, $filename .' can\'t be extracted, because the file type is not allowed'); return false; } return true; } }