* @package taoMediaManager */ class ZipImporter implements ServiceLocatorAwareInterface, TaoLoggerAwareInterface { use ImportHandlerHelperTrait; use LoggerAwareTrait; protected $directoryMap = []; /** * Starts the import based on the form values * * @param \core_kernel_classes_Class $class * @param \tao_helpers_form_Form|array $form * @param string|null $userId owner of the resource * @return \common_report_Report */ public function import($class, $form, $userId = null) { try { $uploadedFile = $this->fetchUploadedFile($form); $resource = new core_kernel_classes_Class($form instanceof Form ? $form->getValue('classUri') : $form['classUri']); // unzip the file try { $directory = $this->extractArchive($uploadedFile); } catch (\Exception $e) { $report = Report::createFailure(__('Unable to extract the archive')); $report->setData(['uriResource' => '']); return $report; } // get list of directory in order to create classes $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($directory, \RecursiveDirectoryIterator::CURRENT_AS_FILEINFO | \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY ); $service = MediaService::singleton(); $language = $form instanceof Form ? $form->getValue('lang') : $form['lang']; $this->directoryMap = [ rtrim($directory, DIRECTORY_SEPARATOR) => $resource->getUri() ]; $report = Report::createSuccess(__('Media imported successfully')); /** @var $file \SplFileInfo */ foreach ($iterator as $file) { if ($file->isFile()) { $this->logInfo('File ' . $file->getPathname()); if (isset($this->directoryMap[$file->getPath()])) { $classUri = $this->directoryMap[$file->getPath()]; } else { $classUri = $this->createClass($file->getPath()); } $mediaResourceUri = $service->createMediaInstance($file->getRealPath(), $classUri, $language, $file->getFilename(), null, $userId); $report->add(Report::createSuccess( __('Imported %s', substr($file->getRealPath(), strlen($directory))), ['uriResource' => $mediaResourceUri] // 'uriResource' key is needed by javascript in tao/views/templates/form/import.tpl )); } } } catch (\Exception $e) { $message = $e instanceof \common_exception_UserReadableException ? $e->getUserMessage() : __('An error has occurred. Please contact your administrator.'); $report = Report::createFailure($message); $this->logError($e->getMessage()); $report->setData(['uriResource' => '']); } return $report; } /** * @param $relPath * @return string * @throws \common_exception_Error */ protected function createClass($relPath) { $parentPath = dirname($relPath); if (isset($this->directoryMap[$parentPath])) { $parentUri = $this->directoryMap[$parentPath]; } else { $parentUri = $this->createClass($parentPath); } $parentClass = new \core_kernel_classes_Class($parentUri); $childClazz = MediaService::singleton()->createSubClass($parentClass, basename($relPath)); $this->directoryMap[$relPath] = $childClazz->getUri(); return $childClazz->getUri(); } /** * Unzip archive from the upload form * * @param string|File $archiveFile * @return string temporary directory zipfile was extracted to * * @throws \common_Exception */ protected function extractArchive($archiveFile) { helpers_TimeOutHelper::setTimeOutLimit(helpers_TimeOutHelper::LONG); if ($archiveFile instanceof File) { if (!$archiveFile->exists()) { throw new \common_Exception('Unable to open archive ' . '/' . $archiveFile->getPrefix()); } $tmpDir = \tao_helpers_File::createTempDir(); $tmpFilePath = $tmpDir . uniqid('sharedStimulus-import') . '.zip'; $tmpFile = fopen($tmpFilePath, 'w'); $originalPackage = $archiveFile->readStream(); stream_copy_to_stream($originalPackage, $tmpFile); fclose($originalPackage); fclose($tmpFile); $archiveFile = $tmpFilePath; } $archiveDir = \tao_helpers_File::createTempDir(); $archiveObj = new \ZipArchive(); if ($archiveFile instanceof File) { // get a local copy of zip $tmpName = \tao_helpers_File::concat([\tao_helpers_File::createTempDir(), $archiveFile->getBasename()]); if (($resource = fopen($tmpName, 'wb')) !== false) { stream_copy_to_stream($archiveFile->readStream(), $resource); fclose($resource); } $archiveFile = $tmpName; } $archiveHandle = $archiveObj->open($archiveFile); if (true !== $archiveHandle) { throw new \common_Exception('Unable to open archive ' . $archiveFile); } if (\tao_helpers_File::checkWhetherArchiveIsBomb($archiveObj)) { throw new \common_Exception(sprintf('Source "%s" seems to be a ZIP bomb', $archiveFile)); } if (!$archiveObj->extractTo($archiveDir)) { $archiveObj->close(); throw new \common_Exception('Unable to extract to ' . $archiveDir); } $archiveObj->close(); if (isset($tmpFilePath) && file_exists($tmpFilePath)) { unlink($tmpFilePath); } if (isset($tmpDir) && file_exists($tmpDir)) { rmdir($tmpDir); } helpers_TimeOutHelper::reset(); return $archiveDir; } }