setDescription('Ensure development settings'); $this->addArgument('conf', InputArgument::OPTIONAL, 'The file to check', null); $this->addOption('strict', 's', InputOption::VALUE_NONE, 'Wheter to fail on alerts or not'); return $this; } public function requireSetup() { return true; } protected function doExecute(InputInterface $input, OutputInterface $output) { $this->configuration = $this->container['phraseanet.configuration']; $this->checkParse($output); $output->writeln(sprintf("Will Ensure Development Settings on %s", $this->configuration->getEnvironnement())); $this->runTests($output); $retval = $this->errors; if ($input->getOption('strict')) { $retval += $this->alerts; } if ($retval > 0) { $output->writeln("\nSome errors found in your conf"); } else { $output->writeln("\nYour dev settings are setted correctly ! Enjoy"); } $output->writeln('End'); return $retval; } private function runTests(OutputInterface $output) { foreach ($this->testSuite as $test) { $display = ""; switch ($test) { case 'checkPhraseanetScope' : $display = "Phraseanet Configuration"; break; case 'checkDatabaseScope' : $display = "Database"; break; case 'checkTeamplateEngineService' : $display = "Template Engine"; break; case 'checkOrmService' : $display = "ORM"; break; case 'checkCacheService' : $display = "Cache"; break; case 'checkOpcodeCacheService' : $display = "Opcode"; break; case 'checkBorderService' : $display = "Border"; break; default: throw new \Exception('Unknown test'); break; } $output->writeln(sprintf("\n||| %s", mb_strtoupper($display))); call_user_func(array($this, $test), $output); } } private function checkParse(OutputInterface $output) { if (!$this->configuration->getConfigurations()) { throw new \Exception("Unable to load configurations\n"); } if (!$this->configuration->getConnexions()) { throw new \Exception("Unable to load connexions\n"); } if (!$this->configuration->getServices()) { throw new \Exception("Unable to load services\n"); } return; } private function checkCacheService(OutputInterface $output) { $cache = $this->configuration->getCache(); if ($this->probeCacheService($output, $cache)) { if ($this->recommendedCacheService($output, $cache, true)) { $work_message = 'Works !'; } else { $work_message = 'Cache server recommended'; $this->alerts++; } } else { $work_message = 'Failed - could not connect !'; $this->errors++; } $verification = sprintf("\t--> Verify %s : %s", 'MainCache', $work_message); $this->printConf($output, "\t" . 'service', $cache, false, $verification); $this->verifyCacheOptions($output, $cache); } private function checkOpcodeCacheService(OutputInterface $output) { $cache = $this->configuration->getOpcodeCache(); if ($this->probeCacheService($output, $cache)) { if ($this->recommendedCacheService($output, $cache, false)) { $work_message = 'Works !'; } else { $work_message = 'No cache required'; $this->errors++; } } else { $work_message = 'Failed - could not connect !'; $this->errors++; } $verification = sprintf("\t--> Verify %s : %s", 'OpcodeCache', $work_message); $this->printConf($output, "\t" . 'service', $cache, false, $verification); $this->verifyCacheOptions($output, $cache); } private function checkBorderService(OutputInterface $output) { $serviceName = $this->configuration->getBorder(); $configuration = $this->configuration->getService($serviceName); $listChecks = false; try { $service = Builder::create($this->container, $configuration); $work_message = 'Works !'; $listChecks = true; } catch (\Exception $e) { $work_message = 'Failed - could not load Border Manager service !'; $this->errors++; } $output->writeln(sprintf("\t--> Verify Border Manager%s : %s", $serviceName, $work_message)); if ($listChecks) { $borderManager = $service->getDriver(); foreach ($service->getUnregisteredCheckers() as $check) { $output->writeln(sprintf("\t\t--> check %s could not be loaded for the following reason %s", $check['checker'], $check['message'])); } } } private function checkPhraseanetScope(OutputInterface $output) { $required = array('servername', 'maintenance', 'debug', 'display_errors', 'database'); $phraseanet = $this->configuration->getPhraseanet(); foreach ($phraseanet->all() as $conf => $value) { switch ($conf) { default: $this->alerts++; $this->printConf($output, $conf, $value, false, 'Not recognized'); break; case 'servername': $url = $value; $required = array_diff($required, array($conf)); $parseUrl = parse_url($url); if (empty($url)) { $message = "should not be empty"; $this->errors++; } elseif ($url == 'http://sub.domain.tld/') { $this->alerts++; $message = "may be wrong"; } elseif (!filter_var($url, FILTER_VALIDATE_URL)) { $message = "not valid"; $this->errors++; } else { $message = "OK"; } $this->printConf($output, $conf, $value, false, $message); break; case 'maintenance': $required = array_diff($required, array($conf)); $message = 'OK'; if ($value !== false) { $message = 'Should be true'; $this->errors++; } $this->printConf($output, $conf, $value, false, $message); break; case 'debug': case 'display_errors': $required = array_diff($required, array($conf)); $message = 'OK'; if ($value !== true) { $message = 'Should be true'; $this->errors++; } $this->printConf($output, $conf, $value, false, $message); break; case 'database': $required = array_diff($required, array($conf)); try { $service = $this->configuration->getConnexion($value); if ($this->verifyDatabaseConnexion($service)) { $message = 'OK'; } else { $message = 'Connection not available'; $this->errors++; } } catch (\Exception $e) { $message = 'Unknown connection'; $this->errors++; } $this->printConf($output, $conf, $value, false, $message); break; } } if (count($required) > 0) { $output->writeln(sprintf('Miss required keys %s', implode(', ', $required))); $this->errors++; } return; } private function checkDatabaseScope(OutputInterface $output) { $connexionName = $this->configuration->getPhraseanet()->get('database'); $connexion = $this->configuration->getConnexion($connexionName); try { if ($this->verifyDatabaseConnexion($connexion)) { $work_message = 'Works !'; } else { $work_message = 'Failed - could not connect !'; $this->errors++; } } catch (\Exception $e) { $work_message = 'Failed - could not connect !'; $this->errors++; } $output->writeln(sprintf("\t--> Verify connection %s : %s", $connexionName, $work_message)); $required = array('driver'); if (!$connexion->has('driver')) { $output->writeln("\nConnection has no driver"); $this->errors++; } elseif ($connexion->get('driver') == 'pdo_mysql') { $required = array('driver', 'dbname', 'charset', 'password', 'user', 'port', 'host'); } elseif ($connexion->get('driver') == 'pdo_sqlite') { $required = array('driver', 'path', 'charset'); } else { $output->writeln("\nYour driver is not managed"); $this->errors++; } foreach ($connexion->all() as $conf => $value) { switch ($conf) { default: $this->alerts++; $this->printConf($output, $conf, $value, false, 'Not recognized'); break; case 'charset': $required = array_diff($required, array($conf)); $message = 'OK'; if ($value !== 'UTF8') { $message = 'Not recognized'; $this->alerts++; } $this->printConf($output, $conf, $value, false, $message); break; case 'path': $required = array_diff($required, array($conf)); $message = is_writable(dirname($value)) ? 'OK' : 'Not writeable'; $this->printConf($output, $conf, $value, false, $message); break; case 'dbname': case 'user': case 'host': $required = array_diff($required, array($conf)); $message = 'OK'; if (!is_scalar($value)) { $message = 'Should be scalar'; $this->errors++; } $this->printConf($output, $conf, $value, false, $message); break; case 'port': $required = array_diff($required, array($conf)); $message = 'OK'; if (!ctype_digit($value)) { $message = 'Should be ctype_digit'; $this->errors++; } $this->printConf($output, $conf, $value, false, $message); break; case 'password': $required = array_diff($required, array($conf)); $message = 'OK'; if (!is_scalar($value)) { $message = 'Should be scalar'; $this->errors++; } $value = '***********'; $this->printConf($output, $conf, $value, false, $message); break; case 'driver': $required = array_diff($required, array($conf)); $message = 'OK'; if ($value !== 'pdo_mysql') { $message = 'MySQL recommended'; $this->errors++; } $this->printConf($output, $conf, $value, false, $message); break; } } if (count($required) > 0) { $output->writeln(sprintf('Miss required keys %s', implode(', ', $required))); $this->errors++; } return; } protected function verifyDatabaseConnexion(\Symfony\Component\DependencyInjection\ParameterBag\ParameterBag $connexion) { try { $config = new \Doctrine\DBAL\Configuration(); $conn = \Doctrine\DBAL\DriverManager::getConnection($connexion->all(), $config); return true; } catch (\Exception $e) { } return false; } private function checkTeamplateEngineService(OutputInterface $output) { $templateEngineName = $this->configuration->getTemplating(); $configuration = $this->configuration->getService($templateEngineName); try { Builder::create($this->container, $configuration); $work_message = 'Works !'; } catch (\Exception $e) { $work_message = 'Failed - could not load template engine !'; $this->errors++; } $output->writeln(sprintf("\t--> Verify Template engine %s : %s", $templateEngineName, $work_message)); if (!$configuration->has('type')) { $output->writeln("\nConfiguration has no type"); $this->errors++; } elseif ($configuration->get('type') == 'TemplateEngine\\Twig') { $required = array('debug', 'charset', 'strict_variables', 'autoescape', 'optimizer'); } else { $output->writeln("\nYour type is not managed"); $this->errors++; } foreach ($configuration->all() as $conf => $value) { switch ($conf) { case 'type': $message = 'OK'; if ($value !== 'TemplateEngine\\Twig') { $message = 'Not recognized'; $this->alerts++; } $this->printConf($output, $conf, $value, false, $message); break; case 'options': $message = 'OK'; if (!is_array($value)) { $message = 'Should be array'; $this->errors++; } $this->printConf($output, $conf, 'array()', false, $message); break; default: $this->alerts++; $this->printConf($output, $conf, 'unknown', false, 'Not recognized'); break; } } foreach ($configuration->get('options') as $conf => $value) { switch ($conf) { case 'debug'; case 'strict_variables'; $required = array_diff($required, array($conf)); $message = 'OK'; if ($value !== true) { $message = 'Should be false'; $this->errors++; } $this->printConf($output, "\t" . $conf, $value, false, $message); break; case 'autoescape'; case 'optimizer'; $required = array_diff($required, array($conf)); $message = 'OK'; if ($value !== true) { $message = 'Should be true'; $this->errors++; } $this->printConf($output, "\t" . $conf, $value, false, $message); break; case 'charset'; $required = array_diff($required, array($conf)); $message = 'OK'; if ($value !== 'utf-8') { $message = 'Not recognized'; $this->alerts++; } $this->printConf($output, "\t" . $conf, $value, false, $message); break; default: $this->alerts++; $this->printConf($output, "\t" . $conf, $value, false, 'Not recognized'); break; } } if (count($required) > 0) { $output->writeln(sprintf('Miss required keys %s', implode(', ', $required))); $this->errors++; } return; } private function checkOrmService(OutputInterface $output) { $ormName = $this->configuration->getOrm(); $configuration = $this->configuration->getService($ormName); try { $service = Builder::create($this->container, $configuration); $work_message = 'Works !'; } catch (\Exception $e) { $work_message = 'Failed - could not connect !'; $this->errors++; } $output->writeln(sprintf("\t--> Verify ORM engine %s : %s", $ormName, $work_message)); if (!$configuration->has('type')) { $output->writeln("\nConfiguration has no type"); $this->errors++; } elseif ($configuration->get('type') == 'Orm\\Doctrine') { $required = array('debug', 'dbal', 'cache'); } else { $output->writeln("\nYour type is not managed"); $this->errors++; } foreach ($configuration->all() as $conf => $value) { switch ($conf) { case 'type': $message = $value == 'Orm\\Doctrine' ? 'OK' : 'Not recognized'; $this->printConf($output, $conf, $value, false, $message); break; case 'options': $message = 'OK'; if (!is_array($value)) { $message = 'Should be array'; $this->errors++; } $this->printConf($output, $conf, 'array()', false, $message); break; default: $this->alerts++; $this->printConf($output, $conf, 'unknown', false, 'Not recognized'); break; } } foreach ($configuration->get('options') as $conf => $value) { switch ($conf) { case 'log': $message = 'OK'; $this->printConf($output, $conf, $value, false, $message); break; case 'cache': $required = array_diff($required, array($conf)); $message = 'OK'; if (!is_array($value)) { $message = 'Should be Array'; $this->errors++; } $this->printConf($output, $conf, 'array()', false, $message); $required_caches = array('query', 'result', 'metadata'); foreach ($value as $name => $cache_type) { $required_caches = array_diff($required_caches, array($name)); foreach ($cache_type as $key_cache => $value_cache) { switch ($key_cache) { case 'service': if ($this->probeCacheService($output, $value_cache)) { $server = $name === 'result'; if ($this->recommendedCacheService($output, $value_cache, $server)) { $work_message = 'Works !'; } else { $this->errors++; $work_message = 'No cache required'; } } else { $work_message = 'Failed - could not connect !'; $this->errors++; } $verification = sprintf("\t--> Verify %s : %s", $name, $work_message); $this->printConf($output, "\t" . $key_cache, $value_cache, false, $verification); $this->verifyCacheOptions($output, $value_cache); break; default: $this->alerts++; $this->printConf($output, "\t" . $key_cache, $value_cache, false, 'Not recognized'); break; } if (!isset($cache_type['service'])) { $output->writeln('Miss service for %s', $cache_type); $this->errors++; } } } if (count($required_caches) > 0) { $output->writeln(sprintf('Miss required caches %s', implode(', ', $required_caches))); $this->errors++; } break; case 'debug': $required = array_diff($required, array($conf)); $message = 'OK'; if ($value !== true) { $message = 'Should be true'; $this->errors++; } $this->printConf($output, $conf, $value, false, $message); break; case 'dbal': $required = array_diff($required, array($conf)); try { $connexion = $this->configuration->getConnexion($value); $this->verifyDatabaseConnexion($connexion); $message = 'OK'; } catch (\Exception $e) { $message = 'Failed'; $this->errors++; } $this->printConf($output, $conf, $value, false, $message); break; default: $this->alerts++; $this->printConf($output, $conf, $value, false, 'Not recognized'); break; } } if (count($required) > 0) { $output->writeln(sprintf('Miss required keys %s', implode(', ', $required))); $this->errors++; } return; } protected function verifyCacheOptions(OutputInterface $output, $ServiceName) { try { $conf = $this->configuration->getService($ServiceName); $Service = Builder::create($this->container, $conf); } catch (\Exception $e) { return false; } $required_options = array(); switch ($Service->getType()) { default: break; case 'memcache': case 'memcached': case 'redis': $required_options = array('host', 'port'); break; } if ($required_options) { foreach ($conf->get('options') as $conf => $value) { switch ($conf) { case 'host'; $required_options = array_diff($required_options, array($conf)); $message = 'OK'; if (!is_scalar($value)) { $message = 'Should be scalar'; $this->errors++; } $this->printConf($output, "\t\t" . $conf, $value, false, $message); break; case 'port'; $required_options = array_diff($required_options, array($conf)); $message = 'OK'; if (!ctype_digit($value)) { $message = 'Not recognized'; $this->alerts++; } $this->printConf($output, "\t\t" . $conf, $value, false, $message); break; default: $this->alerts++; $this->printConf($output, "\t\t" . $conf, $value, false, 'Not recognized'); break; } } } if (count($required_options) > 0) { $output->writeln(sprintf('Miss required keys %s', implode(', ', $required_options))); $this->errors++; } } protected function probeCacheService(OutputInterface $output, $ServiceName) { try { $originalConfiguration = $this->configuration->getService($ServiceName); $Service = Builder::create($this->container, $originalConfiguration); } catch (\Exception $e) { return false; } try { $driver = $Service->getDriver(); } catch (\Exception $e) { return false; } if ($driver->isServer()) { switch ($Service->getType()) { default: return false; break; case 'memcache': if (!@memcache_connect($Service->getHost(), $Service->getPort())) { return false; } break; case 'memcached': $ret = false; try { $memcached = new \Memcached(); $memcached->addServer($Service->getHost(), $Service->getPort()); $stats = $memcached->getStats(); if (!isset($stats[$key]) || !$stats[$key]) { throw new \Exception('Unable to connect to memcached server'); } $ret = true; } catch (\Exception $e) { } unset($memcached); return $ret; break; case 'redis': $ret = false; try { $redis = new \Redis(); if (@$redis->connect($Service->getHost(), $Service->getPort())) { $ret = true; } } catch (\Exception $e) { } unset($redis); return $ret; break; } } return true; } protected function recommendedCacheService(OutputInterface $output, $ServiceName, $server) { try { $originalConfiguration = $this->configuration->getService($ServiceName); $Service = Builder::create($this->container, $originalConfiguration); } catch (\Exception $e) { return false; } return $Service->getType() === 'array'; } private function printConf($output, $scope, $value, $scopage = false, $message = '') { if (is_array($value)) { foreach ($value as $key => $val) { if ($scopage) $key = $scope . ":" . $key; $this->printConf($output, $key, $val, $scopage, ''); } } elseif (is_bool($value)) { if ($value === false) { $value = 'false'; } elseif ($value === true) { $value = 'true'; } $output->writeln(sprintf("\t%s: %s %s", $scope, $value, $message)); } elseif (!empty($value)) { $output->writeln(sprintf("\t%s: %s %s", $scope, $value, $message)); } } }