/**
  * {@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;
 }