src/Eccube/Controller/Install/InstallController.php line 118

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Eccube\Controller\Install;
  13. use Doctrine\Common\Annotations\AnnotationReader;
  14. use Doctrine\Common\Annotations\CachedReader;
  15. use Doctrine\Common\Cache\ArrayCache;
  16. use Doctrine\DBAL\Connection;
  17. use Doctrine\DBAL\DriverManager;
  18. use Doctrine\DBAL\Migrations\Configuration\Configuration;
  19. use Doctrine\DBAL\Migrations\Migration;
  20. use Doctrine\DBAL\Migrations\MigrationException;
  21. use Doctrine\DBAL\Types\Type;
  22. use Doctrine\ORM\EntityManager;
  23. use Doctrine\ORM\Tools\SchemaTool;
  24. use Doctrine\ORM\Tools\Setup;
  25. use Eccube\Common\Constant;
  26. use Eccube\Controller\AbstractController;
  27. use Eccube\Doctrine\DBAL\Types\UTCDateTimeType;
  28. use Eccube\Doctrine\DBAL\Types\UTCDateTimeTzType;
  29. use Eccube\Doctrine\ORM\Mapping\Driver\AnnotationDriver;
  30. use Eccube\Form\Type\Install\Step1Type;
  31. use Eccube\Form\Type\Install\Step3Type;
  32. use Eccube\Form\Type\Install\Step4Type;
  33. use Eccube\Form\Type\Install\Step5Type;
  34. use Eccube\Security\Core\Encoder\PasswordEncoder;
  35. use Eccube\Util\CacheUtil;
  36. use Eccube\Util\StringUtil;
  37. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  38. use Symfony\Component\Filesystem\Filesystem;
  39. use Symfony\Component\Finder\Finder;
  40. use Symfony\Component\HttpFoundation\Request;
  41. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  42. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  43. use Symfony\Component\Routing\Annotation\Route;
  44. class InstallController extends AbstractController
  45. {
  46.     /**
  47.      * default value of auth magic
  48.      */
  49.     const DEFAULT_AUTH_MAGIC '<change.me>';
  50.     protected $requiredModules = [
  51.         'pdo',
  52.         'phar',
  53.         'mbstring',
  54.         'zlib',
  55.         'ctype',
  56.         'session',
  57.         'JSON',
  58.         'xml',
  59.         'libxml',
  60.         'OpenSSL',
  61.         'zip',
  62.         'cURL',
  63.         'fileinfo',
  64.         'intl',
  65.     ];
  66.     protected $recommendedModules = [
  67.         'hash',
  68.         'mcrypt',
  69.     ];
  70.     protected $eccubeDirs = [
  71.         'app/Plugin',
  72.         'app/PluginData',
  73.         'app/proxy',
  74.         'app/template',
  75.         'html',
  76.         'var',
  77.         'vendor',
  78.     ];
  79.     protected $eccubeFiles = [
  80.         'composer.json',
  81.         'composer.lock',
  82.     ];
  83.     /**
  84.      * @var PasswordEncoder
  85.      */
  86.     protected $encoder;
  87.     /**
  88.      * @var CacheUtil
  89.      */
  90.     protected $cacheUtil;
  91.     public function __construct(PasswordEncoder $encoderCacheUtil $cacheUtil)
  92.     {
  93.         $this->encoder $encoder;
  94.         $this->cacheUtil $cacheUtil;
  95.     }
  96.     /**
  97.      * 最初からやり直す場合、SESSION情報をクリア.
  98.      *
  99.      * @Route("/", name="homepage")
  100.      * @Route("/install", name="install")
  101.      *
  102.      * @Template("index.twig")
  103.      *
  104.      * @return \Symfony\Component\HttpFoundation\RedirectResponse
  105.      */
  106.     public function index()
  107.     {
  108.         if (!$this->isInstallEnv()) {
  109.             throw new NotFoundHttpException();
  110.         }
  111.         $this->removeSessionData($this->session);
  112.         return $this->redirectToRoute('install_step1');
  113.     }
  114.     /**
  115.      * ようこそ.
  116.      *
  117.      * @Route("/install/step1", name="install_step1")
  118.      * @Template("step1.twig")
  119.      *
  120.      * @param Request $request
  121.      *
  122.      * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
  123.      */
  124.     public function step1(Request $request)
  125.     {
  126.         if (!$this->isInstallEnv()) {
  127.             throw new NotFoundHttpException();
  128.         }
  129.         $form $this->formFactory
  130.             ->createBuilder(Step1Type::class)
  131.             ->getForm();
  132.         $form->setData($this->getSessionData($this->session));
  133.         $form->handleRequest($request);
  134.         if ($form->isSubmitted() && $form->isValid()) {
  135.             $this->setSessionData($this->session$form->getData());
  136.             return $this->redirectToRoute('install_step2');
  137.         }
  138.         $this->checkModules();
  139.         $authmagic $this->getParameter('eccube_auth_magic');
  140.         if ($authmagic === self::DEFAULT_AUTH_MAGIC) {
  141.             $authmagic StringUtil::random(32);
  142.         }
  143.         $this->setSessionData($this->session, ['authmagic' => $authmagic]);
  144.         return [
  145.             'form' => $form->createView(),
  146.         ];
  147.     }
  148.     /**
  149.      * ディレクトリとファイルの書き込み権限をチェック.
  150.      *
  151.      * @Route("/install/step2", name="install_step2")
  152.      * @Template("step2.twig")
  153.      *
  154.      * @return array
  155.      */
  156.     public function step2()
  157.     {
  158.         if (!$this->isInstallEnv()) {
  159.             throw new NotFoundHttpException();
  160.         }
  161.         $noWritePermissions = [];
  162.         $projectDir $this->getParameter('kernel.project_dir');
  163.         $eccubeDirs array_map(function ($dir) use ($projectDir) {
  164.             return $projectDir.'/'.$dir;
  165.         }, $this->eccubeDirs);
  166.         $eccubeFiles array_map(function ($file) use ($projectDir) {
  167.             return $projectDir.'/'.$file;
  168.         }, $this->eccubeFiles);
  169.         // ルートディレクトリの書き込み権限をチェック
  170.         if (!is_writable($projectDir)) {
  171.             $noWritePermissions[] = $projectDir;
  172.         }
  173.         // 対象ディレクトリの書き込み権限をチェック
  174.         foreach ($eccubeDirs as $dir) {
  175.             if (!is_writable($dir)) {
  176.                 $noWritePermissions[] = $dir;
  177.             }
  178.         }
  179.         // 対象ディレクトリ配下のディレクトリ・ファイルの書き込み権限をチェック
  180.         $finder Finder::create()->in($eccubeDirs);
  181.         foreach ($finder as $file) {
  182.             if (!is_writable($file->getRealPath())) {
  183.                 $noWritePermissions[] = $file;
  184.             }
  185.         }
  186.         // composer.json, composer.lockの書き込み権限をチェック
  187.         foreach ($eccubeFiles as $file) {
  188.             if (!is_writable($file)) {
  189.                 $noWritePermissions[] = $file;
  190.             }
  191.         }
  192.         $faviconPath '/assets/img/common/favicon.ico';
  193.         if (!file_exists($this->getParameter('eccube_html_dir').'/user_data'.$faviconPath)) {
  194.             $file = new Filesystem();
  195.             $file->copy(
  196.                 $this->getParameter('eccube_html_front_dir').$faviconPath,
  197.                 $this->getParameter('eccube_html_dir').'/user_data'.$faviconPath
  198.             );
  199.         }
  200.         $logoPath '/assets/pdf/logo.png';
  201.         if (!file_exists($this->getParameter('eccube_html_dir').'/user_data'.$logoPath)) {
  202.             $file = new Filesystem();
  203.             $file->copy(
  204.                 $this->getParameter('eccube_html_admin_dir').$logoPath,
  205.                 $this->getParameter('eccube_html_dir').'/user_data'.$logoPath
  206.             );
  207.         }
  208.         return [
  209.             'noWritePermissions' => $noWritePermissions,
  210.         ];
  211.     }
  212.     /**
  213.      * サイトの設定.
  214.      *
  215.      * @Route("/install/step3", name="install_step3")
  216.      * @Template("step3.twig")
  217.      *
  218.      * @param Request $request
  219.      *
  220.      * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
  221.      *
  222.      * @throws \Doctrine\DBAL\DBALException
  223.      * @throws \Exception
  224.      */
  225.     public function step3(Request $request)
  226.     {
  227.         if (!$this->isInstallEnv()) {
  228.             throw new NotFoundHttpException();
  229.         }
  230.         $sessionData $this->getSessionData($this->session);
  231.         // 再インストールの場合は環境変数から復旧
  232.         if ($this->isInstalled()) {
  233.             // ショップ名/メールアドレス
  234.             $conn $this->entityManager->getConnection();
  235.             $stmt $conn->query('SELECT shop_name, email01 FROM dtb_base_info WHERE id = 1;');
  236.             $row $stmt->fetch();
  237.             $sessionData['shop_name'] = $row['shop_name'];
  238.             $sessionData['email'] = $row['email01'];
  239.             $databaseUrl $this->getParameter('eccube_database_url');
  240.             $sessionData array_merge($sessionData$this->extractDatabaseUrl($databaseUrl));
  241.             // 管理画面ルーティング
  242.             $sessionData['admin_dir'] = $this->getParameter('eccube_admin_route');
  243.             // 管理画面許可IP
  244.             $sessionData['admin_allow_hosts'] = implode($this->getParameter('eccube_admin_allow_hosts'));
  245.             // 強制SSL
  246.             $sessionData['admin_force_ssl'] = $this->getParameter('eccube_force_ssl');
  247.             // メール
  248.             $mailerUrl $this->getParameter('eccube_mailer_url');
  249.             $sessionData array_merge($sessionData$this->extractMailerUrl($mailerUrl));
  250.         } else {
  251.             // 初期値設定
  252.             if (!isset($sessionData['admin_allow_hosts'])) {
  253.                 $sessionData['admin_allow_hosts'] = '';
  254.             }
  255.             if (!isset($sessionData['smtp_host'])) {
  256.                 $sessionData array_merge($sessionData$this->extractMailerUrl('smtp://localhost:25'));
  257.             }
  258.         }
  259.         $form $this->formFactory
  260.             ->createBuilder(Step3Type::class)
  261.             ->getForm();
  262.         $form->setData($sessionData);
  263.         $form->handleRequest($request);
  264.         if ($form->isSubmitted() && $form->isValid()) {
  265.             $this->setSessionData($this->session$form->getData());
  266.             return $this->redirectToRoute('install_step4');
  267.         }
  268.         return [
  269.             'form' => $form->createView(),
  270.             'request' => $request,
  271.         ];
  272.     }
  273.     /**
  274.      * データベースの設定.
  275.      *
  276.      * @Route("/install/step4", name="install_step4")
  277.      * @Template("step4.twig")
  278.      *
  279.      * @param Request $request
  280.      *
  281.      * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
  282.      *
  283.      * @throws \Exception
  284.      */
  285.     public function step4(Request $request)
  286.     {
  287.         if (!$this->isInstallEnv()) {
  288.             throw new NotFoundHttpException();
  289.         }
  290.         $sessionData $this->getSessionData($this->session);
  291.         if (empty($sessionData['database'])) {
  292.             // 再インストールの場合は環境変数から復旧.
  293.             if ($this->isInstalled()) {
  294.                 $databaseUrl $this->getParameter('eccube_database_url');
  295.                 $sessionData array_merge($sessionData$this->extractDatabaseUrl($databaseUrl));
  296.             }
  297.         }
  298.         $form $this->formFactory
  299.             ->createBuilder(Step4Type::class)
  300.             ->getForm();
  301.         $form->setData($sessionData);
  302.         $form->handleRequest($request);
  303.         if ($form->isSubmitted() && $form->isValid()) {
  304.             $data $form->getData();
  305.             if ($data['database'] === 'pdo_sqlite') {
  306.                 $data['database_name'] = '/var/eccube.db';
  307.             }
  308.             $this->setSessionData($this->session$data);
  309.             return $this->redirectToRoute('install_step5');
  310.         }
  311.         return [
  312.             'form' => $form->createView(),
  313.         ];
  314.     }
  315.     /**
  316.      * データベースの初期化.
  317.      *
  318.      * @Route("/install/step5", name="install_step5")
  319.      * @Template("step5.twig")
  320.      *
  321.      * @param Request $request
  322.      *
  323.      * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
  324.      *
  325.      * @throws \Exception
  326.      */
  327.     public function step5(Request $request)
  328.     {
  329.         if (!$this->isInstallEnv()) {
  330.             throw new NotFoundHttpException();
  331.         }
  332.         $form $this->formFactory
  333.             ->createBuilder(Step5Type::class)
  334.             ->getForm();
  335.         $sessionData $this->getSessionData($this->session);
  336.         $form->setData($sessionData);
  337.         $form->handleRequest($request);
  338.         if ($form->isSubmitted() && $form->isValid()) {
  339.             $noUpdate $form['no_update']->getData();
  340.             $url $this->createDatabaseUrl($sessionData);
  341.             try {
  342.                 $conn $this->createConnection(['url' => $url]);
  343.                 $em $this->createEntityManager($conn);
  344.                 $migration $this->createMigration($conn);
  345.                 if ($noUpdate) {
  346.                     $this->update($conn, [
  347.                         'auth_magic' => $sessionData['authmagic'],
  348.                         'login_id' => $sessionData['login_id'],
  349.                         'login_pass' => $sessionData['login_pass'],
  350.                         'shop_name' => $sessionData['shop_name'],
  351.                         'email' => $sessionData['email'],
  352.                     ]);
  353.                 } else {
  354.                     $this->dropTables($em);
  355.                     $this->createTables($em);
  356.                     $this->importCsv($em);
  357.                     $this->migrate($migration);
  358.                     $this->insert($conn, [
  359.                         'auth_magic' => $sessionData['authmagic'],
  360.                         'login_id' => $sessionData['login_id'],
  361.                         'login_pass' => $sessionData['login_pass'],
  362.                         'shop_name' => $sessionData['shop_name'],
  363.                         'email' => $sessionData['email'],
  364.                     ]);
  365.                 }
  366.             } catch (\Exception $e) {
  367.                 log_error($e->getMessage());
  368.                 $this->addError($e->getMessage());
  369.                 return [
  370.                     'form' => $form->createView(),
  371.                 ];
  372.             }
  373.             if (isset($sessionData['agree']) && $sessionData['agree']) {
  374.                 $host $request->getSchemeAndHttpHost();
  375.                 $basePath $request->getBasePath();
  376.                 $params = [
  377.                     'http_url' => $host.$basePath,
  378.                     'shop_name' => $sessionData['shop_name'],
  379.                 ];
  380.                 $this->sendAppData($params$em);
  381.             }
  382.             $version $this->getDatabaseVersion($em);
  383.             $this->setSessionData($this->session, ['database_version' => $version]);
  384.             return $this->redirectToRoute('install_complete');
  385.         }
  386.         return [
  387.             'form' => $form->createView(),
  388.         ];
  389.     }
  390.     /**
  391.      * インストール完了
  392.      *
  393.      * @Route("/install/complete", name="install_complete")
  394.      * @Template("complete.twig")
  395.      */
  396.     public function complete(Request $request)
  397.     {
  398.         if (!$this->isInstallEnv()) {
  399.             throw new NotFoundHttpException();
  400.         }
  401.         $sessionData $this->getSessionData($this->session);
  402.         $databaseUrl $this->createDatabaseUrl($sessionData);
  403.         $mailerUrl $this->createMailerUrl($sessionData);
  404.         $forceSSL = isset($sessionData['admin_force_ssl']) ? (bool) $sessionData['admin_force_ssl'] : false;
  405.         if ($forceSSL === false) {
  406.             $forceSSL 'false';
  407.         } elseif ($forceSSL === true) {
  408.             $forceSSL 'true';
  409.         }
  410.         $env file_get_contents(__DIR__.'/../../../../.env.dist');
  411.         $replacement = [
  412.             'APP_ENV' => 'prod',
  413.             'APP_DEBUG' => '0',
  414.             'DATABASE_URL' => $databaseUrl,
  415.             'MAILER_URL' => $mailerUrl,
  416.             'ECCUBE_AUTH_MAGIC' => $sessionData['authmagic'],
  417.             'DATABASE_SERVER_VERSION' => isset($sessionData['database_version']) ? $sessionData['database_version'] : '3',
  418.             'ECCUBE_ADMIN_ALLOW_HOSTS' => $this->convertAdminAllowHosts($sessionData['admin_allow_hosts']),
  419.             'ECCUBE_FORCE_SSL' => $forceSSL,
  420.             'ECCUBE_ADMIN_ROUTE' => isset($sessionData['admin_dir']) ? $sessionData['admin_dir'] : 'admin',
  421.             'ECCUBE_COOKIE_PATH' => $request->getBasePath() ? $request->getBasePath() : '/',
  422.             'ECCUBE_TEMPLATE_CODE' => 'default',
  423.             'ECCUBE_LOCALE' => 'ja',
  424.         ];
  425.         $env StringUtil::replaceOrAddEnv($env$replacement);
  426.         if ($this->getParameter('kernel.environment') === 'install') {
  427.             file_put_contents(__DIR__.'/../../../../.env'$env);
  428.         }
  429.         $host $request->getSchemeAndHttpHost();
  430.         $basePath $request->getBasePath();
  431.         $adminUrl $host.$basePath.'/'.$replacement['ECCUBE_ADMIN_ROUTE'];
  432.         $this->removeSessionData($this->session);
  433.         $this->cacheUtil->clearCache('prod');
  434.         return [
  435.             'admin_url' => $adminUrl,
  436.         ];
  437.     }
  438.     protected function getSessionData(SessionInterface $session)
  439.     {
  440.         return $session->get('eccube.session.install', []);
  441.     }
  442.     protected function removeSessionData(SessionInterface $session)
  443.     {
  444.         $session->clear();
  445.     }
  446.     protected function setSessionData(SessionInterface $session$data = [])
  447.     {
  448.         $data array_replace_recursive($this->getSessionData($session), $data);
  449.         $session->set('eccube.session.install'$data);
  450.     }
  451.     protected function checkModules()
  452.     {
  453.         foreach ($this->requiredModules as $module) {
  454.             if (!extension_loaded($module)) {
  455.                 $this->addDanger(trans('install.required_extension_disabled', ['%module%' => $module]), 'install');
  456.             }
  457.         }
  458.         if (!extension_loaded('pdo_mysql') && !extension_loaded('pdo_pgsql')) {
  459.             $this->addDanger(trans('install.required_database_extension_disabled'), 'install');
  460.         }
  461.         foreach ($this->recommendedModules as $module) {
  462.             if (!extension_loaded($module)) {
  463.                 if ($module == 'mcrypt' && PHP_VERSION_ID >= 70100) {
  464.                     //The mcrypt extension has been deprecated in PHP 7.1.x
  465.                     //http://php.net/manual/en/migration71.deprecated.php
  466.                     continue;
  467.                 }
  468.                 $this->addInfo(trans('install.recommend_extension_disabled', ['%module%' => $module]), 'install');
  469.             }
  470.         }
  471.         if ('\\' === DIRECTORY_SEPARATOR) { // for Windows
  472.             if (!extension_loaded('wincache')) {
  473.                 $this->addInfo(trans('install.recommend_extension_disabled', ['%module%' => 'wincache']), 'install');
  474.             }
  475.         } else {
  476.             if (!extension_loaded('apc')) {
  477.                 $this->addInfo(trans('install.recommend_extension_disabled', ['%module%' => 'apc']), 'install');
  478.             }
  479.         }
  480.         if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false) {
  481.             if (!function_exists('apache_get_modules')) {
  482.                 $this->addWarning(trans('install.mod_rewrite_unknown'), 'install');
  483.             } elseif (!in_array('mod_rewrite'apache_get_modules())) {
  484.                 $this->addDanger(trans('install.mod_rewrite_disabled'), 'install');
  485.             }
  486.         } elseif (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false) {
  487.             // iis
  488.         } elseif (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
  489.             // nginx
  490.         }
  491.     }
  492.     protected function createConnection(array $params)
  493.     {
  494.         if (strpos($params['url'], 'mysql') !== false) {
  495.             $params['charset'] = 'utf8';
  496.             $params['defaultTableOptions'] = [
  497.                 'collate' => 'utf8_general_ci',
  498.             ];
  499.         }
  500.         Type::overrideType('datetime'UTCDateTimeType::class);
  501.         Type::overrideType('datetimetz'UTCDateTimeTzType::class);
  502.         $conn DriverManager::getConnection($params);
  503.         $conn->ping();
  504.         $platform $conn->getDatabasePlatform();
  505.         $platform->markDoctrineTypeCommented('datetime');
  506.         $platform->markDoctrineTypeCommented('datetimetz');
  507.         return $conn;
  508.     }
  509.     protected function createEntityManager(Connection $conn)
  510.     {
  511.         $paths = [
  512.             $this->getParameter('kernel.project_dir').'/src/Eccube/Entity',
  513.             $this->getParameter('kernel.project_dir').'/app/Customize/Entity',
  514.         ];
  515.         $config Setup::createConfiguration(true);
  516.         $driver = new AnnotationDriver(new CachedReader(new AnnotationReader(), new ArrayCache()), $paths);
  517.         $driver->setTraitProxiesDirectory($this->getParameter('kernel.project_dir').'/app/proxy/entity');
  518.         $config->setMetadataDriverImpl($driver);
  519.         $em EntityManager::create($conn$config);
  520.         return $em;
  521.     }
  522.     /**
  523.      * @param array $params
  524.      *
  525.      * @return string
  526.      */
  527.     public function createDatabaseUrl(array $params)
  528.     {
  529.         if (!isset($params['database'])) {
  530.             return null;
  531.         }
  532.         $url '';
  533.         switch ($params['database']) {
  534.             case 'pdo_sqlite':
  535.                 $url 'sqlite://'.$params['database_name'];
  536.                 break;
  537.             case 'pdo_mysql':
  538.             case 'pdo_pgsql':
  539.                 $url str_replace('pdo_'''$params['database']);
  540.                 $url .= '://';
  541.                 if (isset($params['database_user'])) {
  542.                     $url .= $params['database_user'];
  543.                     if (isset($params['database_password'])) {
  544.                         $url .= ':'.\rawurlencode($params['database_password']);
  545.                     }
  546.                     $url .= '@';
  547.                 }
  548.                 if (isset($params['database_host'])) {
  549.                     $url .= $params['database_host'];
  550.                     if (isset($params['database_port'])) {
  551.                         $url .= ':'.$params['database_port'];
  552.                     }
  553.                     $url .= '/';
  554.                 }
  555.                 $url .= $params['database_name'];
  556.                 break;
  557.         }
  558.         return $url;
  559.     }
  560.     /**
  561.      * @param string $url
  562.      *
  563.      * @return array
  564.      */
  565.     public function extractDatabaseUrl($url)
  566.     {
  567.         if (preg_match('|^sqlite://(.*)$|'$url$matches)) {
  568.             return [
  569.                 'database' => 'pdo_sqlite',
  570.                 'database_name' => $matches[1],
  571.             ];
  572.         }
  573.         $parsed parse_url($url);
  574.         if ($parsed === false) {
  575.             throw new \Exception('Malformed parameter "url".');
  576.         }
  577.         return [
  578.             'database' => 'pdo_'.$parsed['scheme'],
  579.             'database_name' => ltrim($parsed['path'], '/'),
  580.             'database_host' => $parsed['host'],
  581.             'database_port' => isset($parsed['port']) ? $parsed['port'] : null,
  582.             'database_user' => isset($parsed['user']) ? $parsed['user'] : null,
  583.             'database_password' => isset($parsed['pass']) ? $parsed['pass'] : null,
  584.         ];
  585.     }
  586.     /**
  587.      * @param array $params
  588.      *
  589.      * @return string
  590.      *
  591.      * @see https://github.com/symfony/swiftmailer-bundle/blob/9728097df87e76e2db71fc41fd7d211c06daea3e/DependencyInjection/SwiftmailerTransportFactory.php#L80-L142
  592.      */
  593.     public function createMailerUrl(array $params)
  594.     {
  595.         $url '';
  596.         if (isset($params['transport'])) {
  597.             $url $params['transport'].'://';
  598.         } else {
  599.             $url 'smtp://';
  600.         }
  601.         if (isset($params['smtp_username'])) {
  602.             $url .= $params['smtp_username'];
  603.             if (isset($params['smtp_password'])) {
  604.                 $url .= ':'.$params['smtp_password'];
  605.             }
  606.             $url .= '@';
  607.         }
  608.         $queryStrings = [];
  609.         if (isset($params['encryption'])) {
  610.             $queryStrings['encryption'] = $params['encryption'];
  611.             if ($params['encryption'] === 'ssl' && !isset($params['smtp_port'])) {
  612.                 $params['smtp_port'] = 465;
  613.             }
  614.         }
  615.         if (isset($params['auth_mode'])) {
  616.             $queryStrings['auth_mode'] = $params['auth_mode'];
  617.         } else {
  618.             if (isset($params['smtp_username'])) {
  619.                 $queryStrings['auth_mode'] = 'plain';
  620.             }
  621.         }
  622.         ksort($queryStringsSORT_STRING);
  623.         if (isset($params['smtp_host'])) {
  624.             $url .= $params['smtp_host'];
  625.             if (isset($params['smtp_port'])) {
  626.                 $url .= ':'.$params['smtp_port'];
  627.             }
  628.         }
  629.         if (isset($params['smtp_username']) || array_values($queryStrings)) {
  630.             $url .= '?';
  631.             $i count($queryStrings);
  632.             foreach ($queryStrings as $key => $value) {
  633.                 $url .= $key.'='.$value;
  634.                 if ($i 1) {
  635.                     $url .= '&';
  636.                 }
  637.                 $i--;
  638.             }
  639.         }
  640.         return $url;
  641.     }
  642.     /**
  643.      * @param string $url
  644.      *
  645.      * @return array
  646.      */
  647.     public function extractMailerUrl($url)
  648.     {
  649.         $options = [
  650.             'transport' => null,
  651.             'smtp_username' => null,
  652.             'smtp_password' => null,
  653.             'smtp_host' => null,
  654.             'smtp_port' => null,
  655.             'encryption' => null,
  656.             'auth_mode' => null,
  657.         ];
  658.         if ($url) {
  659.             $parts parse_url($url);
  660.             if (isset($parts['scheme'])) {
  661.                 $options['transport'] = $parts['scheme'];
  662.             }
  663.             if (isset($parts['user'])) {
  664.                 $options['smtp_username'] = $parts['user'];
  665.             }
  666.             if (isset($parts['pass'])) {
  667.                 $options['smtp_password'] = $parts['pass'];
  668.             }
  669.             if (isset($parts['host'])) {
  670.                 $options['smtp_host'] = $parts['host'];
  671.             }
  672.             if (isset($parts['port'])) {
  673.                 $options['smtp_port'] = $parts['port'];
  674.             }
  675.             if (isset($parts['query'])) {
  676.                 parse_str($parts['query'], $query);
  677.                 foreach (array_keys($options) as $key) {
  678.                     if (isset($query[$key]) && $query[$key] != '') {
  679.                         $options[$key] = $query[$key];
  680.                     }
  681.                 }
  682.             }
  683.         }
  684.         if (!isset($options['transport'])) {
  685.             $options['transport'] = 'smtp';
  686.         } elseif ('gmail' === $options['transport']) {
  687.             $options['encryption'] = 'ssl';
  688.             $options['auth_mode'] = 'login';
  689.             $options['smtp_host'] = 'smtp.gmail.com';
  690.             $options['transport'] = 'smtp';
  691.         }
  692.         if (!isset($options['smtp_port'])) {
  693.             $options['smtp_port'] = 'ssl' === $options['encryption'] ? 465 25;
  694.         }
  695.         if (isset($options['smtp_username']) && !isset($options['auth_mode'])) {
  696.             $options['auth_mode'] = 'plain';
  697.         }
  698.         ksort($optionsSORT_STRING);
  699.         return $options;
  700.     }
  701.     protected function createMigration(Connection $conn)
  702.     {
  703.         $config = new Configuration($conn);
  704.         $config->setMigrationsNamespace('DoctrineMigrations');
  705.         $migrationDir $this->getParameter('kernel.project_dir').'/src/Eccube/Resource/doctrine/migration';
  706.         $config->setMigrationsDirectory($migrationDir);
  707.         $config->registerMigrationsFromDirectory($migrationDir);
  708.         $migration = new Migration($config);
  709.         $migration->setNoMigrationException(true);
  710.         return $migration;
  711.     }
  712.     protected function dropTables(EntityManager $em)
  713.     {
  714.         $metadatas $em->getMetadataFactory()->getAllMetadata();
  715.         $schemaTool = new SchemaTool($em);
  716.         $schemaTool->dropSchema($metadatas);
  717.         $em->getConnection()->executeQuery('DROP TABLE IF EXISTS doctrine_migration_versions');
  718.     }
  719.     protected function createTables(EntityManager $em)
  720.     {
  721.         $metadatas $em->getMetadataFactory()->getAllMetadata();
  722.         $schemaTool = new SchemaTool($em);
  723.         $schemaTool->createSchema($metadatas);
  724.     }
  725.     protected function importCsv(EntityManager $em)
  726.     {
  727.         // for full locale code cases
  728.         $locale env('ECCUBE_LOCALE''ja_JP');
  729.         $locale str_replace('_''-'$locale);
  730.         $locales = \Locale::parseLocale($locale);
  731.         $localeDir is_null($locales) ? 'ja' $locales['language'];
  732.         $loader = new \Eccube\Doctrine\Common\CsvDataFixtures\Loader();
  733.         $loader->loadFromDirectory($this->getParameter('kernel.project_dir').'/src/Eccube/Resource/doctrine/import_csv/'.$localeDir);
  734.         $executer = new \Eccube\Doctrine\Common\CsvDataFixtures\Executor\DbalExecutor($em);
  735.         $fixtures $loader->getFixtures();
  736.         $executer->execute($fixtures);
  737.     }
  738.     protected function insert(Connection $conn, array $data)
  739.     {
  740.         $conn->beginTransaction();
  741.         try {
  742.             $salt StringUtil::random(32);
  743.             $this->encoder->setAuthMagic($data['auth_magic']);
  744.             $password $this->encoder->encodePassword($data['login_pass'], $salt);
  745.             $id = ('postgresql' === $conn->getDatabasePlatform()->getName())
  746.                 ? $conn->fetchColumn("select nextval('dtb_base_info_id_seq')")
  747.                 : null;
  748.             $conn->insert('dtb_base_info', [
  749.                 'id' => $id,
  750.                 'shop_name' => $data['shop_name'],
  751.                 'email01' => $data['email'],
  752.                 'email02' => $data['email'],
  753.                 'email03' => $data['email'],
  754.                 'email04' => $data['email'],
  755.                 'update_date' => new \DateTime(),
  756.                 'discriminator_type' => 'baseinfo',
  757.             ], [
  758.                 'update_date' => \Doctrine\DBAL\Types\Type::DATETIME,
  759.             ]);
  760.             $member_id = ('postgresql' === $conn->getDatabasePlatform()->getName())
  761.                 ? $conn->fetchColumn("select nextval('dtb_member_id_seq')")
  762.                 : null;
  763.             $conn->insert('dtb_member', [
  764.                 'id' => $member_id,
  765.                 'login_id' => $data['login_id'],
  766.                 'password' => $password,
  767.                 'salt' => $salt,
  768.                 'work_id' => 1,
  769.                 'authority_id' => 0,
  770.                 'creator_id' => 1,
  771.                 'sort_no' => 1,
  772.                 'update_date' => new \DateTime(),
  773.                 'create_date' => new \DateTime(),
  774.                 'name' => trans('install.member_name'),
  775.                 'department' => $data['shop_name'],
  776.                 'discriminator_type' => 'member',
  777.             ], [
  778.                 'update_date' => Type::DATETIME,
  779.                 'create_date' => Type::DATETIME,
  780.             ]);
  781.             $conn->commit();
  782.         } catch (\Exception $e) {
  783.             $conn->rollback();
  784.             throw $e;
  785.         }
  786.     }
  787.     protected function update(Connection $conn, array $data)
  788.     {
  789.         $conn->beginTransaction();
  790.         try {
  791.             $salt StringUtil::random(32);
  792.             $stmt $conn->prepare('SELECT id FROM dtb_member WHERE login_id = :login_id;');
  793.             $stmt->execute([':login_id' => $data['login_id']]);
  794.             $row $stmt->fetch();
  795.             $this->encoder->setAuthMagic($data['auth_magic']);
  796.             $password $this->encoder->encodePassword($data['login_pass'], $salt);
  797.             if ($row) {
  798.                 // 同一の管理者IDであればパスワードのみ更新
  799.                 $sth $conn->prepare('UPDATE dtb_member set password = :password, salt = :salt, update_date = current_timestamp WHERE login_id = :login_id;');
  800.                 $sth->execute([
  801.                     ':password' => $password,
  802.                     ':salt' => $salt,
  803.                     ':login_id' => $data['login_id'],
  804.                 ]);
  805.             } else {
  806.                 // 新しい管理者IDが入力されたらinsert
  807.                 $sth $conn->prepare("INSERT INTO dtb_member (login_id, password, salt, work_id, authority_id, creator_id, sort_no, update_date, create_date,name,department,discriminator_type) VALUES (:login_id, :password , :salt , '1', '0', '1', '1', current_timestamp, current_timestamp,'管理者','EC-CUBE SHOP', 'member');");
  808.                 $sth->execute([
  809.                     ':login_id' => $data['login_id'],
  810.                     ':password' => $password,
  811.                     ':salt' => $salt,
  812.                 ]);
  813.             }
  814.             $stmt $conn->prepare('UPDATE dtb_base_info set
  815.                 shop_name = :shop_name,
  816.                 email01 = :admin_mail,
  817.                 email02 = :admin_mail,
  818.                 email03 = :admin_mail,
  819.                 email04 = :admin_mail,
  820.                 update_date = current_timestamp
  821.             WHERE id = 1;');
  822.             $stmt->execute([
  823.                 ':shop_name' => $data['shop_name'],
  824.                 ':admin_mail' => $data['email'],
  825.             ]);
  826.             $conn->commit();
  827.         } catch (\Exception $e) {
  828.             $conn->rollback();
  829.             throw $e;
  830.         }
  831.     }
  832.     public function migrate(Migration $migration)
  833.     {
  834.         try {
  835.             // nullを渡すと最新バージョンまでマイグレートする
  836.             $migration->migrate(nullfalse);
  837.         } catch (MigrationException $e) {
  838.         }
  839.     }
  840.     /**
  841.      * @param array $params
  842.      * @param EntityManager $em
  843.      *
  844.      * @return array
  845.      */
  846.     public function createAppData($paramsEntityManager $em)
  847.     {
  848.         $platform $em->getConnection()->getDatabasePlatform()->getName();
  849.         $version $this->getDatabaseVersion($em);
  850.         $data = [
  851.             'site_url' => $params['http_url'],
  852.             'shop_name' => $params['shop_name'],
  853.             'cube_ver' => Constant::VERSION,
  854.             'php_ver' => phpversion(),
  855.             'db_ver' => $platform.' '.$version,
  856.             'os_type' => php_uname(),
  857.         ];
  858.         return $data;
  859.     }
  860.     /**
  861.      * @param array $params
  862.      * @param EntityManager $em
  863.      */
  864.     protected function sendAppData($paramsEntityManager $em)
  865.     {
  866.         try {
  867.             $query http_build_query($this->createAppData($params$em));
  868.             $header = [
  869.                 'Content-Type: application/x-www-form-urlencoded',
  870.                 'Content-Length: '.strlen($query),
  871.             ];
  872.             $context stream_context_create(
  873.                 [
  874.                     'http' => [
  875.                         'method' => 'POST',
  876.                         'header' => $header,
  877.                         'content' => $query,
  878.                     ],
  879.                 ]
  880.             );
  881.             file_get_contents('https://www.ec-cube.net/mall/use_site.php'false$context);
  882.         } catch (\Exception $e) {
  883.             // 送信に失敗してもインストールは継続できるようにする
  884.             log_error($e->getMessage());
  885.         }
  886.         return $this;
  887.     }
  888.     /**
  889.      * @param EntityManager $em
  890.      *
  891.      * @return string
  892.      */
  893.     public function getDatabaseVersion(EntityManager $em)
  894.     {
  895.         $rsm = new \Doctrine\ORM\Query\ResultSetMapping();
  896.         $rsm->addScalarResult('server_version''server_version');
  897.         $platform $em->getConnection()->getDatabasePlatform()->getName();
  898.         switch ($platform) {
  899.             case 'sqlite':
  900.                 $sql 'SELECT sqlite_version() AS server_version';
  901.                 break;
  902.             case 'mysql':
  903.                 $sql 'SELECT version() AS server_version';
  904.                 break;
  905.             case 'postgresql':
  906.             default:
  907.                 $sql 'SHOW server_version';
  908.         }
  909.         $version $em->createNativeQuery($sql$rsm)
  910.             ->getSingleScalarResult();
  911.         // postgresqlのバージョンが10.x以降の場合に、getSingleScalarResult()で取得される不要な文字列を除く処理
  912.         if ($platform === 'postgresql') {
  913.             preg_match('/\A([\d+\.]+)/'$version$matches);
  914.             $version $matches[1];
  915.         }
  916.         return $version;
  917.     }
  918.     /**
  919.      * @param string
  920.      *
  921.      * @return string
  922.      */
  923.     public function convertAdminAllowHosts($adminAllowHosts)
  924.     {
  925.         if (empty($adminAllowHosts)) {
  926.             return '[]';
  927.         }
  928.         $adminAllowHosts = \json_encode(
  929.             \explode("\n"StringUtil::convertLineFeed($adminAllowHosts))
  930.         );
  931.         return "'$adminAllowHosts'";
  932.     }
  933.     /**
  934.      * @return bool
  935.      */
  936.     protected function isInstalled()
  937.     {
  938.         return self::DEFAULT_AUTH_MAGIC !== $this->getParameter('eccube_auth_magic');
  939.     }
  940.     /**
  941.      * @return bool
  942.      */
  943.     protected function isInstallEnv()
  944.     {
  945.         $env $this->getParameter('kernel.environment');
  946.         if ($env === 'install' || $env === 'test') {
  947.             return true;
  948.         }
  949.         return false;
  950.     }
  951. }