/** * {@inheritdoc} * * @SuppressWarnings(PHPMD.LongVariable) */ public function handle(\Input $input) { $packageName = $input->get('install'); if ($packageName == 'contao/core') { $this->redirect('contao/main.php?do=composer'); } if ($input->post('version')) { $version = base64_decode(rawurldecode($input->post('version'))); // make a backup copy(TL_ROOT . '/' . $this->configPathname, TL_ROOT . '/' . $this->configPathname . '~'); // update requires $json = new JsonFile(TL_ROOT . '/' . $this->configPathname); $config = $json->read(); if (!array_key_exists('require', $config)) { $config['require'] = array(); } $config['require'][$packageName] = $version; ksort($config['require']); $json->write($config); Messages::addInfo(sprintf($GLOBALS['TL_LANG']['composer_client']['added_candidate'], $packageName, $version)); $_SESSION['COMPOSER_OUTPUT'] .= $this->io->getOutput(); $this->redirect('contao/main.php?do=composer'); } $installationCandidates = $this->searchPackage($packageName); if (empty($installationCandidates)) { Messages::addError(sprintf($GLOBALS['TL_LANG']['composer_client']['noInstallationCandidates'], $packageName)); $_SESSION['COMPOSER_OUTPUT'] .= $this->io->getOutput(); $this->redirect('contao/main.php?do=composer'); } $template = new \BackendTemplate('be_composer_client_install'); $template->composer = $this->composer; $template->packageName = $packageName; $template->candidates = $installationCandidates; return $template->parse(); }
/** * {@inheritdoc} */ public function handle(\Input $input) { $this->handleRunOnce(); // PATCH if ($input->post('FORM_SUBMIT') == 'database-update') { $count = 0; $sql = deserialize($input->post('sql')); if (is_array($sql)) { foreach ($sql as $key) { if (isset($_SESSION['sql_commands'][$key])) { $this->Database->query(str_replace('DEFAULT CHARSET=utf8;', 'DEFAULT CHARSET=utf8 COLLATE ' . $GLOBALS['TL_CONFIG']['dbCollation'] . ';', $_SESSION['sql_commands'][$key])); $count++; } } } $_SESSION['sql_commands'] = array(); Messages::addConfirmation(sprintf($GLOBALS['TL_LANG']['composer_client']['databaseUpdated'], $count)); $this->reload(); } /** @var \Contao\Database\Installer $installer */ $installer = \System::importStatic('Database\\Installer'); $form = $installer->generateSqlForm(); if (empty($form)) { Messages::addInfo($GLOBALS['TL_LANG']['composer_client']['databaseUptodate']); $this->redirect('contao/main.php?do=composer'); } $form = preg_replace('#(<label for="sql_\\d+")>(CREATE TABLE)#', '$1 class="create_table">$2', $form); $form = preg_replace('#(<label for="sql_\\d+")>(ALTER TABLE `[^`]+` ADD)#', '$1 class="alter_add">$2', $form); $form = preg_replace('#(<label for="sql_\\d+")>(ALTER TABLE `[^`]+` DROP)#', '$1 class="alter_drop">$2', $form); $form = preg_replace('#(<label for="sql_\\d+")>(DROP TABLE)#', '$1 class="drop_table">$2', $form); $template = new \BackendTemplate('be_composer_client_update'); $template->composer = $this->composer; $template->form = $form; return $template->parse(); }
/** * {@inheritdoc} */ public function handle(\Input $input) { if (Runtime::clearComposerCache()) { Messages::addConfirmation($GLOBALS['TL_LANG']['composer_client']['composerCacheCleared']); } $this->redirect('contao/main.php?do=composer'); }
/** * {@inheritdoc} */ public function handle(\Input $input) { $removeNames = $input->post('packages') ? explode(',', $input->post('packages')) : array($input->post('remove')); // filter undeletable packages $removeNames = array_filter($removeNames, function ($removeName) { return !in_array($removeName, InstalledController::$UNDELETABLE_PACKAGES); }); // skip empty if (empty($removeNames)) { $this->redirect('contao/main.php?do=composer'); } // make a backup copy(TL_ROOT . '/' . $this->configPathname, TL_ROOT . '/' . $this->configPathname . '~'); // update requires $json = new JsonFile(TL_ROOT . '/' . $this->configPathname); $config = $json->read(); if (!array_key_exists('require', $config)) { $config['require'] = array(); } foreach ($removeNames as $removeName) { unset($config['require'][$removeName]); } $json->write($config); Messages::addInfo(sprintf($GLOBALS['TL_LANG']['composer_client']['removeCandidate'], implode(', ', $removeNames))); $_SESSION['COMPOSER_OUTPUT'] .= $this->io->getOutput(); $this->redirect('contao/main.php?do=composer'); }
/** * {@inheritdoc} */ public function handle(\Input $input) { $configFile = new \File($this->configPathname); if ($input->post('save')) { $tempPathname = $this->configPathname . '~'; $tempFile = new \File($tempPathname); $config = $input->postRaw('config'); $config = html_entity_decode($config, ENT_QUOTES, 'UTF-8'); $tempFile->write($config); $tempFile->close(); $validator = new ConfigValidator($this->io); list($errors, $publishErrors, $warnings) = $validator->validate(TL_ROOT . '/' . $tempPathname); if (!$errors && !$publishErrors) { Messages::addConfirmation($GLOBALS['TL_LANG']['composer_client']['configValid']); $this->import('Files'); $this->Files->rename($tempPathname, $this->configPathname); } else { $tempFile->delete(); $_SESSION['COMPOSER_EDIT_CONFIG'] = $config; if ($errors) { foreach ($errors as $message) { Messages::addError('Error: ' . $message); } } if ($publishErrors) { foreach ($publishErrors as $message) { Messages::addError('Publish error: ' . $message); } } } if ($warnings) { foreach ($warnings as $message) { Messages::addWarning('Warning: ' . $message); } } $this->reload(); } if (isset($_SESSION['COMPOSER_EDIT_CONFIG'])) { $config = $_SESSION['COMPOSER_EDIT_CONFIG']; unset($_SESSION['COMPOSER_EDIT_CONFIG']); } else { $config = $configFile->getContent(); } $template = new \BackendTemplate('be_composer_client_editor'); $template->composer = $this->composer; $template->config = $config; return $template->parse(); }
/** * {@inheritdoc} */ public function handle(\Input $input) { // get installed packages $localRepository = $this->composer->getRepositoryManager()->getLocalRepository(); $packages = $localRepository->getPackages(); // find contao composer plugin $plugins = $this->composer->getPluginManager()->getPlugins(); $plugin = null; foreach ($plugins as $temp) { if ($temp instanceof Plugin) { $plugin = $temp; } } // plugin not found -> abort if (!$plugin) { Messages::addError($GLOBALS['TL_LANG']['composer_client']['pluginNotFound']); $this->redirect('contao/main.php?do=composer&tools=dialog'); } // create installer $config = $this->composer->getConfig(); if ($config->get('preferred-install') == 'dist') { $installer = new CopyInstaller($this->io, $this->composer, $plugin); } else { $installer = new SymlinkInstaller($this->io, $this->composer, $plugin); } /** @var PackageInterface[] $packages */ /** @var Plugin $plugin */ foreach ($packages as $package) { if ($package instanceof AliasPackage) { continue; } try { $this->io->write(sprintf($GLOBALS['TL_LANG']['composer_client']['resyncPackage'], $package->getName())); $installer->updateContaoFiles($package); Messages::addInfo(sprintf($GLOBALS['TL_LANG']['composer_client']['resyncedPackage'], $package->getName())); } catch (\RuntimeException $e) { Messages::addError(sprintf($GLOBALS['TL_LANG']['composer_client']['resyncFailed'], $package->getName(), $e->getMessage())); } } $_SESSION['COMPOSER_OUTPUT'] .= $this->io->getOutput(); $this->redirect('contao/main.php?do=composer&update=database'); }
/** * {@inheritdoc} */ public function handle(\Input $input) { $keyword = $input->get('keyword'); $tokens = explode(' ', $keyword); $tokens = array_map('trim', $tokens); $tokens = array_filter($tokens); $searchName = count($tokens) == 1 && strpos($tokens[0], '/') !== false; if (empty($tokens)) { $_SESSION['COMPOSER_OUTPUT'] .= $this->io->getOutput(); $this->redirect('contao/main.php?do=composer'); } $packages = $this->searchPackages($tokens, $searchName ? RepositoryInterface::SEARCH_NAME : RepositoryInterface::SEARCH_FULLTEXT); if (empty($packages)) { Messages::addError(sprintf($GLOBALS['TL_LANG']['composer_client']['noSearchResult'], $keyword)); $_SESSION['COMPOSER_OUTPUT'] .= $this->io->getOutput(); $this->redirect('contao/main.php?do=composer'); } $template = new \BackendTemplate('be_composer_client_search'); $template->composer = $this->composer; $template->keyword = $keyword; $template->packages = $packages; return $template->parse(); }
/** * {@inheritdoc} * * @SuppressWarnings(PHPMD.LongVariable) */ public function handle(\Input $input) { $packageName = $input->get('solve'); $version = base64_decode(rawurldecode($input->get('version'))); if ($input->post('mark') || $input->post('install')) { // make a backup copy(TL_ROOT . '/' . $this->configPathname, TL_ROOT . '/' . $this->configPathname . '~'); // update requires $json = new JsonFile(TL_ROOT . '/' . $this->configPathname); $config = $json->read(); if (!array_key_exists('require', $config)) { $config['require'] = array(); } $config['require'][$packageName] = $version; $json->write($config); Messages::addInfo(sprintf($GLOBALS['TL_LANG']['composer_client']['added_candidate'], $packageName, $version)); $_SESSION['COMPOSER_OUTPUT'] .= $this->io->getOutput(); if ($input->post('install')) { $this->redirect('contao/main.php?do=composer&update=packages'); } $this->redirect('contao/main.php?do=composer'); } /** @var RootPackage $rootPackage */ $rootPackage = $this->composer->getPackage(); $installedRootPackage = clone $rootPackage; $installedRootPackage->setRequires(array()); $installedRootPackage->setDevRequires(array()); $repositoryManager = $this->getRepositoryManager(); $localRepository = $repositoryManager->getLocalRepository(); $platformRepo = new PlatformRepository(); $installedRepository = new CompositeRepository(array($localRepository, new InstalledArrayRepository(array($installedRootPackage)), $platformRepo)); $versionParser = new VersionParser(); $constraint = $versionParser->parseConstraints($version); $stability = $versionParser->parseStability($version); $aliases = $this->getRootAliases($rootPackage); $this->aliasPlatformPackages($platformRepo, $aliases); $stabilityFlags = $rootPackage->getStabilityFlags(); $stabilityFlags[$packageName] = BasePackage::$stabilities[$stability]; $pool = $this->getPool($rootPackage->getMinimumStability(), $stabilityFlags); $pool->addRepository($installedRepository, $aliases); $policy = new DefaultPolicy($rootPackage->getPreferStable()); $request = new Request($pool); // add root package $rootPackageConstraint = $this->createConstraint('=', $rootPackage->getVersion()); $rootPackageConstraint->setPrettyString($rootPackage->getPrettyVersion()); $request->install($rootPackage->getName(), $rootPackageConstraint); // add requirements $links = $rootPackage->getRequires(); /** @var Link $link */ foreach ($links as $link) { if ($link->getTarget() != $packageName) { $request->install($link->getTarget(), $link->getConstraint()); } } /** @var PackageInterface $package */ foreach ($installedRepository->getPackages() as $package) { $request->install($package->getName(), $this->createConstraint('=', $package->getVersion())); } $operations = array(); try { $solver = new Solver($policy, $pool, $installedRepository); $beforeOperations = $solver->solve($request); $request->install($packageName, $constraint); $operations = $solver->solve($request); /** @var \Composer\DependencyResolver\Operation\SolverOperation $beforeOperation */ foreach ($beforeOperations as $beforeOperation) { /** @var \Composer\DependencyResolver\Operation\InstallOperation $operation */ foreach ($operations as $index => $operation) { if ($operation->getPackage()->getName() != $packageName && $beforeOperation->__toString() == $operation->__toString()) { unset($operations[$index]); } } } } catch (SolverProblemsException $e) { Messages::addError(sprintf('<span style="white-space: pre-line">%s</span>', trim($e->getMessage()))); } $template = new \BackendTemplate('be_composer_client_solve'); $template->composer = $this->composer; $template->packageName = $packageName; $template->packageVersion = $version; $template->operations = $operations; return $template->parse(); }
/** * Load composer and the composer class loader. */ protected function loadComposer() { // search for composer build version $composerDevWarningTime = Runtime::readComposerDevWarningTime(); $incompatibleVersion = false === $composerDevWarningTime || mktime(11, 0, 0, 6, 5, 2014) > $composerDevWarningTime - 30 * 86400; // Update if allowed or composer version is incompatible. if ($incompatibleVersion || $GLOBALS['TL_CONFIG']['composerAutoUpdateLibrary'] && time() > $composerDevWarningTime) { Runtime::updateComposer(); Messages::addConfirmation($GLOBALS['TL_LANG']['composer_client']['composerUpdated']); } if ($composerDevWarningTime && !$GLOBALS['TL_CONFIG']['composerAutoUpdateLibrary'] && $incompatibleVersion) { Messages::addError($GLOBALS['TL_LANG']['composer_client']['composerUpdateNecessary']); } // register composer class loader Runtime::registerComposerClassLoader(); // define pathname to config file $this->configPathname = COMPOSER_DIR_RELATIVE . '/' . Factory::getComposerFile(); // create io interface $this->io = new BufferIO('', $this->getDebugLevel(), new HtmlOutputFormatter()); // create composer $this->composer = Runtime::createComposer($this->io); }
/** * Check if SNI is available and disable remote host checking if not. * * @param string $url The url. * * @param resource $curl The curl resource. * * @return void */ private static function checkSNI($url, $curl) { if ('https' !== substr($url, 0, 5)) { return; } $curlVersion = curl_version(); // Curl 7.18.1 - March 30 2008 supports server name indication (RFC 4366), aka SNI // (http://curl.haxx.se/changes.html) if (version_compare(trim($curlVersion['version']), '7.18.1', '<')) { curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); Messages::addWarning('SNI support not available, curl version too old. Host verification has been deactivated.'); return; } // We only check for OpenSSL. $ssl = explode('/', trim($curlVersion['ssl_version'])); if (count($ssl) !== 2 || $ssl[0] !== 'OpenSSL') { return; } // OpenSSL 0.9.8f support SNI, 0.9.8k and later has this enabled by default // (https://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI) if (version_compare($ssl[1], '0.9.8f', '<')) { curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); Messages::addWarning('SNI support not available, OpenSSL version too old. Host verification has been deactivated.'); } }
/** * {@inheritdoc} * * @SuppressWarnings(PHPMD.LongVariable) */ public function handle(\Input $input) { if (\Database::getInstance()->tableExists('tl_repository_installs')) { $oldPackageCount = \Database::getInstance()->execute('SELECT COUNT(*) AS count FROM tl_repository_installs')->count; $commercialPackages = \Database::getInstance()->execute('SELECT * FROM tl_repository_installs WHERE lickey!=\'\'')->fetchEach('extension'); $commercialPackages = count($commercialPackages) ? implode(', ', $commercialPackages) : false; } else { $oldPackageCount = 0; $commercialPackages = ''; } $smhEnabled = Runtime::isSafeModeHackEnabled(); $allowUrlFopenEnabled = ini_get('allow_url_fopen'); $pharSupportEnabled = false; $apcOpcodeCacheEnabled = ini_get('apc.enabled') && ini_get('apc.cache_by_default'); try { if (class_exists('Phar', false)) { new \Phar(TL_ROOT . '/system/modules/!composer/config/test.phar'); $pharSupportEnabled = true; } } catch (\Exception $e) { } $composerSupported = !$smhEnabled && $allowUrlFopenEnabled && $pharSupportEnabled; $gitAvailable = Runtime::testProcess('git --version'); $hgAvailable = Runtime::testProcess('hg --version'); $svnAvailable = Runtime::testProcess('svn --version'); $mode = 'upgrade'; $setup = 'production'; if ($composerSupported && $input->post('FORM_SUBMIT') == 'tl_composer_migrate') { $target = 'contao/main.php?do=composer'; $mode = $input->post('mode'); $setup = $input->post('setup'); // load config $json = new JsonFile(TL_ROOT . '/' . $this->configPathname); $config = $json->read(); if ($input->post('skip')) { // mark migration skipped $config['extra']['contao']['migrated'] = 'skipped'; Messages::addConfirmation($GLOBALS['TL_LANG']['composer_client']['migrationSkipped']); } else { if (\Database::getInstance()->tableExists('tl_repository_installs')) { switch ($mode) { case 'upgrade': $this->removeER2Files(); $install = \Database::getInstance()->query('SELECT * FROM tl_repository_installs WHERE lickey=""'); while ($install->next()) { // skip the composer package if ($install->extension == 'composer') { continue; } $packageName = 'contao-legacy/' . $install->extension; /* $packageName = preg_replace( '{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $packageName ); */ $packageName = strtolower($packageName); $oldVersion = $install->version; $stability = $oldVersion % 10; $oldVersion = (int) ($oldVersion / 10); $oldVersion = (int) ($oldVersion / 1000); $minor = $oldVersion % 1000; $major = (int) ($oldVersion / 1000); $version = sprintf('~%d.%d%s', $major, $minor, static::$versionNames[$stability]); $config['require'][$packageName] = $version; } $target = 'contao/main.php?do=composer&update=packages'; break; case 'clean': $this->removeER2Files(); break; } } switch ($setup) { case 'production': $config['minimum-stability'] = 'dev'; $config['prefer-stable'] = true; $config['config']['preferred-install'] = 'dist'; break; case 'development': $config['minimum-stability'] = 'dev'; $config['prefer-stable'] = true; $config['config']['preferred-install'] = 'source'; break; } // mark migration done $config['extra']['contao']['migrated'] = 'done'; Messages::addConfirmation($GLOBALS['TL_LANG']['composer_client']['migrationDone']); } // write config $json->write($config); $this->redirect($target); } $template = new \BackendTemplate('be_composer_client_migrate'); $template->composer = $this->composer; $template->smhEnabled = $smhEnabled; $template->allowUrlFopenEnabled = $allowUrlFopenEnabled; $template->pharSupportEnabled = $pharSupportEnabled; $template->composerSupported = $composerSupported; $template->apcOpcodeCacheEnabled = $apcOpcodeCacheEnabled; $template->oldPackageCount = $oldPackageCount; $template->commercialPackages = $commercialPackages; $template->gitAvailable = $gitAvailable; $template->hgAvailable = $hgAvailable; $template->svnAvailable = $svnAvailable; $template->mode = $mode; $template->setup = $setup; return $template->parse(); }
/** * Determine the runtime mode to use depending on the availability of functions. * * @return mixed */ private function determineRuntimeMode() { $mode = $GLOBALS['TL_CONFIG']['composerExecutionMode']; if ('inline' === $mode) { return $mode; } $functions = array(); if ($mode === 'process') { $functions = array('proc_open', 'proc_close'); } if ($mode === 'detached') { $functions = array('shell_exec'); if (!defined('PHP_WINDOWS_VERSION_BUILD')) { $functions[] = 'posix_kill'; } } foreach ($functions as $function) { if (!FunctionAvailabilityCheck::isFunctionEnabled($function)) { Messages::addWarning($function . ' is disabled, reverting from ' . $mode . ' to inline execution'); return 'inline'; } } return $mode; }
/** * Build replacement map for installed packages. * * @param RepositoryInterface $repository * * @return array */ protected function calculateLegacyReplaceMap(RepositoryInterface $repository) { $replaceMap = array(); try { $abandon = Downloader::download('https://legacy-packages-via.contao-community-alliance.org/abandoned.json'); } catch (\Exception $exception) { Messages::addError($exception->getMessage()); return array(); } $legacyReplaces = json_decode($abandon, true); /** @var \Composer\Package\PackageInterface $package */ foreach ($repository->getPackages() as $package) { if (isset($legacyReplaces[$package->getName()])) { $replaceMap[$package->getName()] = $legacyReplaces[$package->getName()]; } } return $replaceMap; }