/** * Handles view events for latex files * * @param \Hubzero\Filesystem\Collection $collection The file collection to view * @return void **/ public function onHandleView(\Hubzero\Filesystem\Collection $collection) { if (!$this->canHandle($collection)) { return false; } $file = $collection->findFirstWithExtension('tex'); // Create view $view = new \Hubzero\Plugin\View(['folder' => 'handlers', 'element' => 'latex', 'name' => 'latex', 'layout' => 'view']); // Build path for storing temp previews $outputDir = PATH_APP . DS . trim($this->params->get('compile_dir', 'site/latex/compiled'), DS); $adapter = Manager::adapter('local', ['path' => $outputDir]); $uniqid = md5(uniqid()); $temp = File::fromPath($uniqid . '.tex', $adapter); // Clean up data from Windows characters - important! $data = preg_replace('/[^(\\x20-\\x7F)\\x0A]*/', '', $file->read()); // Store file locally $temp->write($data); // Build the command $command = DS . trim($this->params->get('texpath', '/usr/bin/pdflatex'), DS); $command .= ' -output-directory=' . $outputDir . ' -interaction=batchmode ' . escapeshellarg($temp->getAbsolutePath()); // Exec and capture output exec($command, $out); $compiled = File::fromPath($uniqid . '.pdf', $adapter); $log = File::fromPath($uniqid . '.log', $adapter); if (!$compiled->size()) { $view->setError(Lang::txt('PLG_HANDLERS_LATEX_ERROR_COMPILE_TEX_FAILED')); } // Read log (to show in case of error) if ($log->size()) { $view->log = $log->read(); } $view->compiled = $compiled; return $view; }
/** * Expand archive * * @param bool $cleanup Whether or not to clean up after expansion (i.e. removing known OS files, etc...) * @return bool */ public function expand($cleanup = true) { // Create local tmp copy of the archive that's being expanded $temp = Manager::getTempPath($this->getName()); $this->copy($temp); $archive = new \PharData($temp->getAbsolutePath()); foreach ($archive as $file) { // Add 7 to the length for the 'phar://' prefix to the file $path = substr($file, strlen($temp->getAbsolutePath()) + 7); $entity = Entity::fromPath($this->getParent() . $path, $this->getAdapter()); if ($entity->isFile()) { // Open $item = fopen($file, 'r'); // Write stream $entity->putStream($item); // Close fclose($item); } else { // Create the directory $entity->create(); } } // Clean up $temp->delete(); return parent::expand($cleanup); }
/** * Expand archive * * @param bool $cleanup Whether or not to clean up after expansion (i.e. removing known OS files, etc...) * @return bool */ public function expand($cleanup = true) { // Create local tmp copy of the archive that's being expanded $temp = Manager::getTempPath($this->getName()); $this->copy($temp); $zip = new \ZipArchive(); // Open the temp archive (we use the absolute path because we're on the local filesystem) if ($zip->open($temp->getAbsolutePath()) === true) { // We don't actually have to extract the archive, we can just read out of it and copy over to the original location for ($i = 0; $i < $zip->numFiles; $i++) { $filename = $zip->getNameIndex($i); $entity = Entity::fromPath($this->getParent() . '/' . $filename, $this->getAdapter()); if ($entity->isFile()) { // Open $item = fopen('zip://' . $temp->getAbsolutePath() . '#' . $filename, 'r'); // Write stream $entity->putStream($item); // Close fclose($item); } else { // Create the directory $entity->create(); } } // Clean up $zip->close(); $temp->delete(); return parent::expand($cleanup); } return false; }
/** * Compiles PDF/image preview for any kind of file * * @return string */ public function compile() { // Combine file and folder data $items = $this->getCollection(); // Incoming $download = Request::getInt('download', 0); // Check that we have compile enabled // @FIXME: why are latex and compiled preview tied together? // presumedly we are also 'compiling' pdfs? if (!$this->params->get('latex')) { $this->setError(Lang::txt('PLG_PROJECTS_FILES_COMPILE_NOTALLOWED')); return; } // Output HTML $view = new \Hubzero\Plugin\View(['folder' => 'projects', 'element' => 'files', 'name' => 'connected', 'layout' => 'compiled']); // Make sure we have an item if (count($items) == 0) { $view->setError(Lang::txt('PLG_PROJECTS_FILES_ERROR_NO_FILES_TO_COMPILE')); $view->loadTemplate(); return; } // We can only handle one file at a time $file = $items->first(); // Build path for storing temp previews $imagePath = trim($this->model->config()->get('imagepath', '/site/projects'), DS); $outputDir = DS . $imagePath . DS . strtolower($this->model->get('alias')) . DS . 'compiled'; // Make sure output dir exists if (!is_dir(PATH_APP . $outputDir)) { if (!Filesystem::makeDirectory(PATH_APP . $outputDir)) { $this->setError(Lang::txt('PLG_PROJECTS_FILES_UNABLE_TO_CREATE_UPLOAD_PATH')); return; } } // Get LaTeX helper $compiler = new \Components\Projects\Helpers\Compiler(); // Tex compiler path $texPath = DS . trim($this->params->get('texpath'), DS); // Set view args and defaults $view->file = $file; $view->oWidth = '780'; $view->oHeight = '460'; $view->url = $this->model->link('files'); $cExt = 'pdf'; // Tex file? $tex = $compiler->isTexFile($file->getName()); // Build temp name $tempBase = $tex ? 'temp__' . \Components\Projects\Helpers\Html::takeOutExt($file->getName()) : $file->getName(); $tempBase = str_replace(' ', '_', $tempBase); $view->data = $file->isImage() ? NULL : $file->read(); // LaTeX file? if ($tex && !empty($view->data)) { // Clean up data from Windows characters - important! $view->data = preg_replace('/[^(\\x20-\\x7F)\\x0A]*/', '', $view->data); // Store file locally $tmpfile = PATH_APP . $outputDir . DS . $tempBase; file_put_contents($tmpfile, $view->data); // Compile and get path to PDF $contentFile = $compiler->compileTex($tmpfile, $view->data, $texPath, PATH_APP . $outputDir, 1, $tempBase); // Read log (to show in case of error) $logFile = $tempBase . '.log'; if (file_exists(PATH_APP . $outputDir . DS . $logFile)) { $view->log = Filesystem::read(PATH_APP . $outputDir . DS . $logFile); } if (!$contentFile) { $this->setError(Lang::txt('PLG_PROJECTS_FILES_ERROR_COMPILE_TEX_FAILED')); } $cType = Filesystem::mimetype(PATH_APP . $outputDir . DS . $contentFile); } else { // Make sure we can handle preview of this type of file if ($file->hasExtension('pdf') || $file->isImage() || !$file->isBinary()) { $origin = $this->connection->provider->alias . '://' . $file->getPath(); $dest = 'compiled://' . $tempBase; // Do the copy Manager::adapter('local', ['path' => PATH_APP . $outputDir . DS], 'compiled'); Manager::copy($origin, $dest); $contentFile = $tempBase; } } // Parse output if (!empty($contentFile) && file_exists(PATH_APP . $outputDir . DS . $contentFile)) { // Get compiled content mimetype $cType = Filesystem::mimetype(PATH_APP . $outputDir . DS . $contentFile); // Is image? if (strpos($cType, 'image/') !== false) { // Fix up object width & height list($width, $height, $type, $attr) = getimagesize(PATH_APP . $outputDir . DS . $contentFile); $xRatio = $view->oWidth / $width; $yRatio = $view->oHeight / $height; if ($xRatio * $height < $view->oHeight) { // Resize the image based on width $view->oHeight = ceil($xRatio * $height); } else { // Resize the image based on height $view->oWidth = ceil($yRatio * $width); } } // Download compiled file? if ($download) { $pdfName = $tex ? str_replace('temp__', '', basename($contentFile)) : basename($contentFile); // Serve up file $server = new \Hubzero\Content\Server(); $server->filename(PATH_APP . $outputDir . DS . $contentFile); $server->disposition('attachment'); $server->acceptranges(false); $server->saveas($pdfName); $result = $server->serve(); if (!$result) { // Should only get here on error throw new Exception(Lang::txt('PLG_PROJECTS_FILES_SERVER_ERROR'), 404); } else { exit; } } // Generate preview image for browsers that cannot embed pdf if ($cType == 'application/pdf') { // GS path $gspath = trim($this->params->get('gspath'), DS); if ($gspath && file_exists(DS . $gspath . DS . 'gs')) { $gspath = DS . $gspath . DS; $pdfName = $tex ? str_replace('temp__', '', basename($contentFile)) : basename($contentFile); $pdfPath = PATH_APP . $outputDir . DS . $contentFile; $exportPath = PATH_APP . $outputDir . DS . $tempBase . '%d.jpg'; exec($gspath . "gs -dNOPAUSE -sDEVICE=jpeg -r300 -dFirstPage=1 -dLastPage=1 -sOutputFile={$exportPath} {$pdfPath} 2>&1", $out); if (is_file(PATH_APP . $outputDir . DS . $tempBase . '1.jpg')) { $hi = new \Hubzero\Image\Processor(PATH_APP . $outputDir . DS . $tempBase . '1.jpg'); if (count($hi->getErrors()) == 0) { $hi->resize($view->oWidth, false, false, true); $hi->save(PATH_APP . $outputDir . DS . $tempBase . '1.jpg'); } else { return false; } } if (is_file(PATH_APP . $outputDir . DS . $tempBase . '1.jpg')) { $image = $tempBase . '1.jpg'; } } } } elseif (!$this->getError()) { $this->setError(Lang::txt('PLG_PROJECTS_FILES_ERROR_COMPILE_PREVIEW_FAILED')); } $view->file = $file; $view->outputDir = $outputDir; $view->embed = $contentFile; $view->cType = $cType; $view->subdir = $this->subdir; $view->option = $this->_option; $view->image = !empty($image) ? $image : NULL; $view->model = $this->model; $view->repo = $this->repo; $view->connection = $this->connection; if ($this->getError()) { $view->setError($this->getError()); } return $view->loadTemplate(); }
/** * Compresses/archives entities in collection * * @param bool $structure Whether or not to retain directory location of files being zipped * @param bool $upload Whether or not to reupload compressed to filesystem location * @return string|bool */ public function compress($structure = false, $upload = false) { if (!extension_loaded('zip')) { return false; } // Get temp directory $adapter = null; $temp = sys_get_temp_dir(); $tarname = uniqid() . '.zip'; $zip = new \ZipArchive(); if ($zip->open($temp . DS . $tarname, \ZipArchive::OVERWRITE) === true) { foreach ($this->_data as $entity) { if ($entity->isFile()) { $zip->addFromString($structure ? $entity->getPath() : $entity->getName(), $entity->read()); } else { if ($entity->isDir() && $structure) { $zip->addEmptyDir($entity->getPath()); } } // Set some vars in case we need them later $adapter = $adapter ?: $entity->getAdapter(); } $zip->close(); $local = Manager::getTempPath(); if ($upload) { // @FIXME: use manager copy? $entity = Entity::fromPath($tarname, $adapter); $entity->put($local->readAndDelete()); return $entity; } else { return $local; } } else { return false; } }
/** * Generates the filesystem adapter for the given provider * * @param array $options extra params to include with defaults * @return object **/ public function adapter($options = []) { $params = (array) json_decode($this->params); $params = array_merge($params, $options); return Manager::adapter($this->provider->alias, $params); }
/** * Copies the entity * * @param string|object $to What/where to copy the entity to * @return bool **/ public function copy($to) { if (is_string($to)) { return $this->hasAdapterOrFail()->adapter->copy($this->getPath(), $to); } else { return Manager::copy($this, $to); } }
/** * Save incoming file selection * * @return boolean */ public function save($element, $elementId, $pub, $blockParams, $toAttach = array()) { // Incoming selections if (empty($toAttach)) { $selections = Request::getVar('selecteditems', ''); $toAttach = explode(',', $selections); } // Get configs $configs = $this->getConfigs($element, $elementId, $pub, $blockParams); // Cannot make changes if ($configs->freeze) { return false; } // Nothing to change if (empty($toAttach)) { return false; } // Git helper include_once PATH_CORE . DS . 'components' . DS . 'com_projects' . DS . 'helpers' . DS . 'githelper.php'; $this->_git = new \Components\Projects\Helpers\Git($configs->path); // Counter $i = 0; $a = 0; // Attach/refresh each selected item foreach ($toAttach as $identifier) { if (!trim($identifier)) { continue; } $identifier = urldecode($identifier); // Catch items coming in from connections if (preg_match('/^([0-9]*):\\/\\//', $identifier, $matches)) { if (isset($matches[1])) { require_once PATH_CORE . DS . 'components' . DS . 'com_projects' . DS . 'models' . DS . 'orm' . DS . 'connection.php'; // Grab the connection id $connection = $matches[1]; // Reset identifier $identifier = str_replace($matches[0], '', $identifier); $connection = Connection::oneOrFail($connection); // Create file objects $conFile = Entity::fromPath($identifier, $connection->adapter()); if (!$conFile->isLocal()) { // Create a temp file and write to it $tempFile = Manager::getTempPath($conFile->getName()); Manager::copy($conFile, $tempFile); } else { $tempFile = $conFile; } // Insert the file into the repo $result = $pub->_project->repo()->insert(['subdir' => $conFile->getParent(), 'dataPath' => $tempFile->getAbsolutePath(), 'update' => false]); if (!$conFile->isLocal()) { $tempFile->delete(); } } } $a++; $ordering = $i + 1; if ($this->addAttachment($identifier, $pub, $configs, User::get('id'), $elementId, $element, $ordering)) { $i++; } } // Success if ($i > 0 && $i == $a) { Event::trigger('filesystem.onAfterSaveFileAttachments', [$pub, $configs, $elementId, $element]); $message = $this->get('_message') ? $this->get('_message') : Lang::txt('Selection successfully saved'); $this->set('_message', $message); } return true; }