Completed
Pull Request — 4.0 (#4744)
by Hideki
05:26
created

InstallController::migrate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 6
1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.ec-cube.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Controller\Install;
15
16
use Doctrine\Common\Annotations\AnnotationReader;
17
use Doctrine\Common\Annotations\CachedReader;
18
use Doctrine\Common\Cache\ArrayCache;
19
use Doctrine\DBAL\Connection;
20
use Doctrine\DBAL\DriverManager;
21
use Doctrine\DBAL\Migrations\Configuration\Configuration;
22
use Doctrine\DBAL\Migrations\Migration;
23
use Doctrine\DBAL\Migrations\MigrationException;
24
use Doctrine\DBAL\Types\Type;
25
use Doctrine\ORM\EntityManager;
26
use Doctrine\ORM\Tools\SchemaTool;
27
use Doctrine\ORM\Tools\Setup;
28
use Eccube\Common\Constant;
29
use Eccube\Controller\AbstractController;
30
use Eccube\Doctrine\DBAL\Types\UTCDateTimeType;
31
use Eccube\Doctrine\DBAL\Types\UTCDateTimeTzType;
32
use Eccube\Doctrine\ORM\Mapping\Driver\AnnotationDriver;
33
use Eccube\Form\Type\Install\Step1Type;
34
use Eccube\Form\Type\Install\Step3Type;
35
use Eccube\Form\Type\Install\Step4Type;
36
use Eccube\Form\Type\Install\Step5Type;
37
use Eccube\Repository\PluginRepository;
38
use Eccube\Security\Core\Encoder\PasswordEncoder;
39
use Eccube\Service\PluginService;
40
use Eccube\Util\CacheUtil;
41
use Eccube\Util\StringUtil;
42
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
43
use Symfony\Component\Filesystem\Filesystem;
44
use Symfony\Component\Finder\Finder;
45
use Symfony\Component\HttpFoundation\Request;
46
use Symfony\Component\HttpFoundation\Session\SessionInterface;
47
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
48
use Symfony\Component\Routing\Annotation\Route;
49
50
class InstallController extends AbstractController
51
{
52
    /**
53
     * default value of auth magic
54
     */
55
    const DEFAULT_AUTH_MAGIC = '<change.me>';
56
57
    protected $requiredModules = [
58
        'pdo',
59
        'phar',
60
        'mbstring',
61
        'zlib',
62
        'ctype',
63
        'session',
64
        'JSON',
65
        'xml',
66
        'libxml',
67
        'OpenSSL',
68
        'zip',
69
        'cURL',
70
        'fileinfo',
71
        'intl',
72
    ];
73
74
    protected $recommendedModules = [
75
        'hash',
76
        'mcrypt',
77
    ];
78
79
    protected $eccubeDirs = [
80
        'app/Plugin',
81
        'app/PluginData',
82
        'app/proxy',
83
        'app/template',
84
        'html',
85
        'var',
86
        'vendor',
87
    ];
88
89
    protected $eccubeFiles = [
90
        'composer.json',
91
        'composer.lock',
92
    ];
93
94
    /**
95
     * @var PasswordEncoder
96
     */
97
    protected $encoder;
98
99
    /**
100
     * @var CacheUtil
101
     */
102
    protected $cacheUtil;
103
104
    public function __construct(PasswordEncoder $encoder, CacheUtil $cacheUtil)
105
    {
106
        $this->encoder = $encoder;
107
        $this->cacheUtil = $cacheUtil;
108
    }
109
110
    /**
111
     * 最初からやり直す場合、SESSION情報をクリア.
112
     *
113
     * @Route("/", name="homepage")
114
     * @Route("/install", name="install")
115
     *
116
     * @Template("index.twig")
117
     *
118
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
119
     */
120
    public function index()
121
    {
122
        if (!$this->isInstallEnv()) {
123
            throw new NotFoundHttpException();
124
        }
125
126
        $this->removeSessionData($this->session);
127
128
        return $this->redirectToRoute('install_step1');
129
    }
130
131
    /**
132
     * ようこそ.
133
     *
134
     * @Route("/install/step1", name="install_step1")
135
     * @Template("step1.twig")
136
     *
137
     * @param Request $request
138
     *
139
     * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
140
     */
141
    public function step1(Request $request)
142
    {
143
        if (!$this->isInstallEnv()) {
144
            throw new NotFoundHttpException();
145
        }
146
147
        $form = $this->formFactory
148
            ->createBuilder(Step1Type::class)
149
            ->getForm();
150
151
        $form->setData($this->getSessionData($this->session));
152
        $form->handleRequest($request);
153
154 View Code Duplication
        if ($form->isSubmitted() && $form->isValid()) {
155
            $this->setSessionData($this->session, $form->getData());
156
157
            return $this->redirectToRoute('install_step2');
158
        }
159
160
        $this->checkModules();
161
162
        $authmagic = $this->getParameter('eccube_auth_magic');
163
        if ($authmagic === self::DEFAULT_AUTH_MAGIC) {
164
            $authmagic = StringUtil::random(32);
165
        }
166
        $this->setSessionData($this->session, ['authmagic' => $authmagic]);
167
168
        return [
169
            'form' => $form->createView(),
170
        ];
171
    }
172
173
    /**
174
     * ディレクトリとファイルの書き込み権限をチェック.
175
     *
176
     * @Route("/install/step2", name="install_step2")
177
     * @Template("step2.twig")
178
     *
179
     * @return array
180
     */
181
    public function step2()
182
    {
183
        if (!$this->isInstallEnv()) {
184
            throw new NotFoundHttpException();
185
        }
186
187
        $noWritePermissions = [];
188
189
        $projectDir = $this->getParameter('kernel.project_dir');
190
191
        $eccubeDirs = array_map(function ($dir) use ($projectDir) {
192
            return $projectDir.'/'.$dir;
193
        }, $this->eccubeDirs);
194
195
        $eccubeFiles = array_map(function ($file) use ($projectDir) {
196
            return $projectDir.'/'.$file;
197
        }, $this->eccubeFiles);
198
199
        // ルートディレクトリの書き込み権限をチェック
200
        if (!is_writable($projectDir)) {
201
            $noWritePermissions[] = $projectDir;
202
        }
203
204
        // 対象ディレクトリの書き込み権限をチェック
205
        foreach ($eccubeDirs as $dir) {
206
            if (!is_writable($dir)) {
207
                $noWritePermissions[] = $dir;
208
            }
209
        }
210
211
        // 対象ディレクトリ配下のディレクトリ・ファイルの書き込み権限をチェック
212
        $finder = Finder::create()->in($eccubeDirs);
213
        foreach ($finder as $file) {
214
            if (!is_writable($file->getRealPath())) {
215
                $noWritePermissions[] = $file;
216
            }
217
        }
218
219
        // composer.json, composer.lockの書き込み権限をチェック
220
        foreach ($eccubeFiles as $file) {
221
            if (!is_writable($file)) {
222
                $noWritePermissions[] = $file;
223
            }
224
        }
225
226
        $faviconPath = '/assets/img/common/favicon.ico';
227
        if (!file_exists($this->getParameter('eccube_html_dir').'/user_data'.$faviconPath)) {
228
            $file = new Filesystem();
229
            $file->copy(
230
                $this->getParameter('eccube_html_front_dir').$faviconPath,
231
                $this->getParameter('eccube_html_dir').'/user_data'.$faviconPath
232
            );
233
        }
234
235
        $logoPath = '/assets/pdf/logo.png';
236
        if (!file_exists($this->getParameter('eccube_html_dir').'/user_data'.$logoPath)) {
237
            $file = new Filesystem();
238
            $file->copy(
239
                $this->getParameter('eccube_html_admin_dir').$logoPath,
240
                $this->getParameter('eccube_html_dir').'/user_data'.$logoPath
241
            );
242
        }
243
244
        return [
245
            'noWritePermissions' => $noWritePermissions,
246
        ];
247
    }
248
249
    /**
250
     * サイトの設定.
251
     *
252
     * @Route("/install/step3", name="install_step3")
253
     * @Template("step3.twig")
254
     *
255
     * @param Request $request
256
     *
257
     * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
258
     *
259
     * @throws \Doctrine\DBAL\DBALException
260
     * @throws \Exception
261
     */
262
    public function step3(Request $request)
263
    {
264
        if (!$this->isInstallEnv()) {
265
            throw new NotFoundHttpException();
266
        }
267
268
        $sessionData = $this->getSessionData($this->session);
269
270
        // 再インストールの場合は環境変数から復旧
271
        if ($this->isInstalled()) {
272
            // ショップ名/メールアドレス
273
            $conn = $this->entityManager->getConnection();
274
            $stmt = $conn->query('SELECT shop_name, email01 FROM dtb_base_info WHERE id = 1;');
275
            $row = $stmt->fetch();
276
            $sessionData['shop_name'] = $row['shop_name'];
277
            $sessionData['email'] = $row['email01'];
278
279
            $databaseUrl = $this->getParameter('eccube_database_url');
280
            $sessionData = array_merge($sessionData, $this->extractDatabaseUrl($databaseUrl));
281
282
            // 管理画面ルーティング
283
            $sessionData['admin_dir'] = $this->getParameter('eccube_admin_route');
284
285
            // 管理画面許可IP
286
            $sessionData['admin_allow_hosts'] = implode($this->getParameter('eccube_admin_allow_hosts'));
287
288
            // 強制SSL
289
            $sessionData['admin_force_ssl'] = $this->getParameter('eccube_force_ssl');
290
291
            // メール
292
            $mailerUrl = $this->getParameter('eccube_mailer_url');
293
            $sessionData = array_merge($sessionData, $this->extractMailerUrl($mailerUrl));
294
        } else {
295
            // 初期値設定
296
            if (!isset($sessionData['admin_allow_hosts'])) {
297
                $sessionData['admin_allow_hosts'] = '';
298
            }
299
            if (!isset($sessionData['smtp_host'])) {
300
                $sessionData = array_merge($sessionData, $this->extractMailerUrl('smtp://localhost:25'));
301
            }
302
        }
303
304
        $form = $this->formFactory
305
            ->createBuilder(Step3Type::class)
306
            ->getForm();
307
308
        $form->setData($sessionData);
309
        $form->handleRequest($request);
310
311 View Code Duplication
        if ($form->isSubmitted() && $form->isValid()) {
312
            $this->setSessionData($this->session, $form->getData());
313
314
            return $this->redirectToRoute('install_step4');
315
        }
316
317
        return [
318
            'form' => $form->createView(),
319
            'request' => $request,
320
        ];
321
    }
322
323
    /**
324
     * データベースの設定.
325
     *
326
     * @Route("/install/step4", name="install_step4")
327
     * @Template("step4.twig")
328
     *
329
     * @param Request $request
330
     *
331
     * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
332
     *
333
     * @throws \Exception
334
     */
335
    public function step4(Request $request)
336
    {
337
        if (!$this->isInstallEnv()) {
338
            throw new NotFoundHttpException();
339
        }
340
341
        $sessionData = $this->getSessionData($this->session);
342
343
        if (empty($sessionData['database'])) {
344
            // 再インストールの場合は環境変数から復旧.
345
            if ($this->isInstalled()) {
346
                $databaseUrl = $this->getParameter('eccube_database_url');
347
                $sessionData = array_merge($sessionData, $this->extractDatabaseUrl($databaseUrl));
348
            }
349
        }
350
351
        $form = $this->formFactory
352
            ->createBuilder(Step4Type::class)
353
            ->getForm();
354
355
        $form->setData($sessionData);
356
        $form->handleRequest($request);
357
358
        if ($form->isSubmitted() && $form->isValid()) {
359
            $data = $form->getData();
360
            if ($data['database'] === 'pdo_sqlite') {
361
                $data['database_name'] = '/var/eccube.db';
362
            }
363
364
            $this->setSessionData($this->session, $data);
365
366
            return $this->redirectToRoute('install_step5');
367
        }
368
369
        return [
370
            'form' => $form->createView(),
371
        ];
372
    }
373
374
    /**
375
     * データベースの初期化.
376
     *
377
     * @Route("/install/step5", name="install_step5")
378
     * @Template("step5.twig")
379
     *
380
     * @param Request $request
381
     *
382
     * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
383
     *
384
     * @throws \Exception
385
     */
386
    public function step5(Request $request)
387
    {
388
        if (!$this->isInstallEnv()) {
389
            throw new NotFoundHttpException();
390
        }
391
392
        $form = $this->formFactory
393
            ->createBuilder(Step5Type::class)
394
            ->getForm();
395
396
        $sessionData = $this->getSessionData($this->session);
397
        $form->setData($sessionData);
398
        $form->handleRequest($request);
399
400
        if ($form->isSubmitted() && $form->isValid()) {
401
            $noUpdate = $form['no_update']->getData();
402
403
            $url = $this->createDatabaseUrl($sessionData);
404
405
            try {
406
                $conn = $this->createConnection(['url' => $url]);
407
                $em = $this->createEntityManager($conn);
408
                $migration = $this->createMigration($conn);
409
410
                if ($noUpdate) {
411
                    $this->update($conn, [
412
                        'auth_magic' => $sessionData['authmagic'],
413
                        'login_id' => $sessionData['login_id'],
414
                        'login_pass' => $sessionData['login_pass'],
415
                        'shop_name' => $sessionData['shop_name'],
416
                        'email' => $sessionData['email'],
417
                    ]);
418
                } else {
419
                    $this->dropTables($em);
420
                    $this->createTables($em);
421
                    $this->importCsv($em);
422
                    $this->migrate($migration);
423
                    $this->insert($conn, [
424
                        'auth_magic' => $sessionData['authmagic'],
425
                        'login_id' => $sessionData['login_id'],
426
                        'login_pass' => $sessionData['login_pass'],
427
                        'shop_name' => $sessionData['shop_name'],
428
                        'email' => $sessionData['email'],
429
                    ]);
430
                }
431
            } catch (\Exception $e) {
432
                log_error($e->getMessage());
433
                $this->addError($e->getMessage());
434
435
                return [
436
                    'form' => $form->createView(),
437
                ];
438
            }
439
440
            if (isset($sessionData['agree']) && $sessionData['agree']) {
441
                $host = $request->getSchemeAndHttpHost();
442
                $basePath = $request->getBasePath();
443
                $params = [
444
                    'http_url' => $host.$basePath,
445
                    'shop_name' => $sessionData['shop_name'],
446
                ];
447
                $this->sendAppData($params, $em);
448
            }
449
            $version = $this->getDatabaseVersion($em);
450
            $this->setSessionData($this->session, ['database_version' => $version]);
451
452
            return $this->redirectToRoute('install_complete');
453
        }
454
455
        return [
456
            'form' => $form->createView(),
457
        ];
458
    }
459
460
    /**
461
     * インストール完了
462
     *
463
     * @Route("/install/complete", name="install_complete")
464
     */
465
    public function complete(Request $request)
466
    {
467
        if (!$this->isInstallEnv()) {
468
            throw new NotFoundHttpException();
469
        }
470
471
        $sessionData = $this->getSessionData($this->session);
472
        $databaseUrl = $this->createDatabaseUrl($sessionData);
473
        $mailerUrl = $this->createMailerUrl($sessionData);
474
        $forceSSL = isset($sessionData['admin_force_ssl']) ? (bool) $sessionData['admin_force_ssl'] : false;
475 View Code Duplication
        if ($forceSSL === false) {
476
            $forceSSL = 'false';
477
        } elseif ($forceSSL === true) {
478
            $forceSSL = 'true';
479
        }
480
        $env = file_get_contents(__DIR__.'/../../../../.env.dist');
481
        $replacement = [
482
            'APP_ENV' => 'prod',
483
            'APP_DEBUG' => '0',
484
            'DATABASE_URL' => $databaseUrl,
485
            'MAILER_URL' => $mailerUrl,
486
            'ECCUBE_AUTH_MAGIC' => $sessionData['authmagic'],
487
            'DATABASE_SERVER_VERSION' => isset($sessionData['database_version']) ? $sessionData['database_version'] : '3',
488
            'ECCUBE_ADMIN_ALLOW_HOSTS' => $this->convertAdminAllowHosts($sessionData['admin_allow_hosts']),
489
            'ECCUBE_FORCE_SSL' => $forceSSL,
490
            'ECCUBE_ADMIN_ROUTE' => isset($sessionData['admin_dir']) ? $sessionData['admin_dir'] : 'admin',
491
            'ECCUBE_COOKIE_PATH' => $request->getBasePath() ? $request->getBasePath() : '/',
492
            'ECCUBE_TEMPLATE_CODE' => 'default',
493
            'ECCUBE_LOCALE' => 'ja',
494
        ];
495
496
        $env = StringUtil::replaceOrAddEnv($env, $replacement);
497
498
        if ($this->getParameter('kernel.environment') === 'install') {
499
            file_put_contents(__DIR__.'/../../../../.env', $env);
500
        }
501
502
        $this->removeSessionData($this->session);
503
504
        $this->cacheUtil->clearCache('prod');
505
506
        return $this->redirectToRoute('install_plugin');
507
    }
508
509
    /**
510
     * プラグインの有効化
511
     *
512
     * @Route("/install/plugin", name="install_plugin")
513
     */
514
    public function plugin(Request $request, PluginRepository $pluginRepository, PluginService $pluginService)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
515
    {
516
        $plugins = $pluginRepository->findBy(['enabled' => '0']);
517
518
        foreach ($plugins as $plugin) {
519
            if (!$plugin->isInitialized()) {
520
                $pluginService->installWithCode($plugin->getCode());
521
            }
522
523
            $pluginService->enable($plugin);
524
            $this->cacheUtil->clearCache('prod');
525
        }
526
527
        return $this->redirectToRoute('admin_login');
528
    }
529
530
    protected function getSessionData(SessionInterface $session)
531
    {
532
        return $session->get('eccube.session.install', []);
533
    }
534
535
    protected function removeSessionData(SessionInterface $session)
536
    {
537
        $session->clear();
538
    }
539
540
    protected function setSessionData(SessionInterface $session, $data = [])
541
    {
542
        $data = array_replace_recursive($this->getSessionData($session), $data);
543
        $session->set('eccube.session.install', $data);
544
    }
545
546
    protected function checkModules()
547
    {
548
        foreach ($this->requiredModules as $module) {
549
            if (!extension_loaded($module)) {
550
                $this->addDanger(trans('install.required_extension_disabled', ['%module%' => $module]), 'install');
551
            }
552
        }
553
        if (!extension_loaded('pdo_mysql') && !extension_loaded('pdo_pgsql')) {
554
            $this->addDanger(trans('install.required_database_extension_disabled'), 'install');
555
        }
556
        foreach ($this->recommendedModules as $module) {
557
            if (!extension_loaded($module)) {
558
                if ($module == 'mcrypt' && PHP_VERSION_ID >= 70100) {
559
                    //The mcrypt extension has been deprecated in PHP 7.1.x
560
                    //http://php.net/manual/en/migration71.deprecated.php
561
                    continue;
562
                }
563
                $this->addInfo(trans('install.recommend_extension_disabled', ['%module%' => $module]), 'install');
564
            }
565
        }
566
        if ('\\' === DIRECTORY_SEPARATOR) { // for Windows
567
            if (!extension_loaded('wincache')) {
568
                $this->addInfo(trans('install.recommend_extension_disabled', ['%module%' => 'wincache']), 'install');
569
            }
570
        } else {
571
            if (!extension_loaded('apc')) {
572
                $this->addInfo(trans('install.recommend_extension_disabled', ['%module%' => 'apc']), 'install');
573
            }
574
        }
575
        if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false) {
576
            if (!function_exists('apache_get_modules')) {
577
                $this->addWarning(trans('install.mod_rewrite_unknown'), 'install');
578
            } elseif (!in_array('mod_rewrite', apache_get_modules())) {
579
                $this->addDanger(trans('install.mod_rewrite_disabled'), 'install');
580
            }
581
        } elseif (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false) {
582
            // iis
583
        } elseif (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
584
            // nginx
585
        }
586
    }
587
588
    protected function createConnection(array $params)
589
    {
590
        if (strpos($params['url'], 'mysql') !== false) {
591
            $params['charset'] = 'utf8';
592
            $params['defaultTableOptions'] = [
593
                'collate' => 'utf8_general_ci',
594
            ];
595
        }
596
597
        Type::overrideType('datetime', UTCDateTimeType::class);
598
        Type::overrideType('datetimetz', UTCDateTimeTzType::class);
599
600
        $conn = DriverManager::getConnection($params);
601
        $conn->ping();
602
603
        $platform = $conn->getDatabasePlatform();
604
        $platform->markDoctrineTypeCommented('datetime');
605
        $platform->markDoctrineTypeCommented('datetimetz');
606
607
        return $conn;
608
    }
609
610
    protected function createEntityManager(Connection $conn)
611
    {
612
        $paths = [
613
            $this->getParameter('kernel.project_dir').'/src/Eccube/Entity',
614
            $this->getParameter('kernel.project_dir').'/app/Customize/Entity',
615
        ];
616
        $config = Setup::createConfiguration(true);
617
        $driver = new AnnotationDriver(new CachedReader(new AnnotationReader(), new ArrayCache()), $paths);
618
        $driver->setTraitProxiesDirectory($this->getParameter('kernel.project_dir').'/app/proxy/entity');
619
        $config->setMetadataDriverImpl($driver);
620
621
        $em = EntityManager::create($conn, $config);
622
623
        return $em;
624
    }
625
626
    /**
627
     * @param array $params
628
     *
629
     * @return string
630
     */
631
    public function createDatabaseUrl(array $params)
632
    {
633
        if (!isset($params['database'])) {
634
            return null;
635
        }
636
637
        $url = '';
638
        switch ($params['database']) {
639
            case 'pdo_sqlite':
640
                $url = 'sqlite://'.$params['database_name'];
641
                break;
642
643
            case 'pdo_mysql':
644
            case 'pdo_pgsql':
645
                $url = str_replace('pdo_', '', $params['database']);
646
                $url .= '://';
647
                if (isset($params['database_user'])) {
648
                    $url .= $params['database_user'];
649
                    if (isset($params['database_password'])) {
650
                        $url .= ':'.\rawurlencode($params['database_password']);
651
                    }
652
                    $url .= '@';
653
                }
654 View Code Duplication
                if (isset($params['database_host'])) {
655
                    $url .= $params['database_host'];
656
                    if (isset($params['database_port'])) {
657
                        $url .= ':'.$params['database_port'];
658
                    }
659
                    $url .= '/';
660
                }
661
                $url .= $params['database_name'];
662
                break;
663
        }
664
665
        return $url;
666
    }
667
668
    /**
669
     * @param string $url
670
     *
671
     * @return array
672
     */
673
    public function extractDatabaseUrl($url)
674
    {
675
        if (preg_match('|^sqlite://(.*)$|', $url, $matches)) {
676
            return [
677
                'database' => 'pdo_sqlite',
678
                'database_name' => $matches[1],
679
            ];
680
        }
681
682
        $parsed = parse_url($url);
683
684
        if ($parsed === false) {
685
            throw new \Exception('Malformed parameter "url".');
686
        }
687
688
        return [
689
            'database' => 'pdo_'.$parsed['scheme'],
690
            'database_name' => ltrim($parsed['path'], '/'),
691
            'database_host' => $parsed['host'],
692
            'database_port' => isset($parsed['port']) ? $parsed['port'] : null,
693
            'database_user' => isset($parsed['user']) ? $parsed['user'] : null,
694
            'database_password' => isset($parsed['pass']) ? $parsed['pass'] : null,
695
        ];
696
    }
697
698
    /**
699
     * @param array $params
700
     *
701
     * @return string
702
     *
703
     * @see https://github.com/symfony/swiftmailer-bundle/blob/9728097df87e76e2db71fc41fd7d211c06daea3e/DependencyInjection/SwiftmailerTransportFactory.php#L80-L142
704
     */
705
    public function createMailerUrl(array $params)
706
    {
707
        $url = '';
0 ignored issues
show
Unused Code introduced by
$url is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
708
        if (isset($params['transport'])) {
709
            $url = $params['transport'].'://';
710
        } else {
711
            $url = 'smtp://';
712
        }
713 View Code Duplication
        if (isset($params['smtp_username'])) {
714
            $url .= $params['smtp_username'];
715
            if (isset($params['smtp_password'])) {
716
                $url .= ':'.$params['smtp_password'];
717
            }
718
            $url .= '@';
719
        }
720
721
        $queryStrings = [];
722
        if (isset($params['encryption'])) {
723
            $queryStrings['encryption'] = $params['encryption'];
724
            if ($params['encryption'] === 'ssl' && !isset($params['smtp_port'])) {
725
                $params['smtp_port'] = 465;
726
            }
727
        }
728
        if (isset($params['auth_mode'])) {
729
            $queryStrings['auth_mode'] = $params['auth_mode'];
730
        } else {
731
            if (isset($params['smtp_username'])) {
732
                $queryStrings['auth_mode'] = 'plain';
733
            }
734
        }
735
        ksort($queryStrings, SORT_STRING);
736
737 View Code Duplication
        if (isset($params['smtp_host'])) {
738
            $url .= $params['smtp_host'];
739
            if (isset($params['smtp_port'])) {
740
                $url .= ':'.$params['smtp_port'];
741
            }
742
        }
743
744
        if (isset($params['smtp_username']) || array_values($queryStrings)) {
745
            $url .= '?';
746
            $i = count($queryStrings);
747
            foreach ($queryStrings as $key => $value) {
748
                $url .= $key.'='.$value;
749
                if ($i > 1) {
750
                    $url .= '&';
751
                }
752
                $i--;
753
            }
754
        }
755
756
        return $url;
757
    }
758
759
    /**
760
     * @param string $url
761
     *
762
     * @return array
763
     */
764
    public function extractMailerUrl($url)
765
    {
766
        $options = [
767
            'transport' => null,
768
            'smtp_username' => null,
769
            'smtp_password' => null,
770
            'smtp_host' => null,
771
            'smtp_port' => null,
772
            'encryption' => null,
773
            'auth_mode' => null,
774
        ];
775
776
        if ($url) {
777
            $parts = parse_url($url);
778
            if (isset($parts['scheme'])) {
779
                $options['transport'] = $parts['scheme'];
780
            }
781
            if (isset($parts['user'])) {
782
                $options['smtp_username'] = $parts['user'];
783
            }
784
            if (isset($parts['pass'])) {
785
                $options['smtp_password'] = $parts['pass'];
786
            }
787
            if (isset($parts['host'])) {
788
                $options['smtp_host'] = $parts['host'];
789
            }
790
            if (isset($parts['port'])) {
791
                $options['smtp_port'] = $parts['port'];
792
            }
793
            if (isset($parts['query'])) {
794
                parse_str($parts['query'], $query);
795
                foreach (array_keys($options) as $key) {
796
                    if (isset($query[$key]) && $query[$key] != '') {
797
                        $options[$key] = $query[$key];
798
                    }
799
                }
800
            }
801
        }
802
        if (!isset($options['transport'])) {
803
            $options['transport'] = 'smtp';
804
        } elseif ('gmail' === $options['transport']) {
805
            $options['encryption'] = 'ssl';
806
            $options['auth_mode'] = 'login';
807
            $options['smtp_host'] = 'smtp.gmail.com';
808
            $options['transport'] = 'smtp';
809
        }
810
        if (!isset($options['smtp_port'])) {
811
            $options['smtp_port'] = 'ssl' === $options['encryption'] ? 465 : 25;
812
        }
813
        if (isset($options['smtp_username']) && !isset($options['auth_mode'])) {
814
            $options['auth_mode'] = 'plain';
815
        }
816
        ksort($options, SORT_STRING);
817
818
        return $options;
819
    }
820
821
    protected function createMigration(Connection $conn)
822
    {
823
        $config = new Configuration($conn);
824
        $config->setMigrationsNamespace('DoctrineMigrations');
825
        $migrationDir = $this->getParameter('kernel.project_dir').'/src/Eccube/Resource/doctrine/migration';
826
        $config->setMigrationsDirectory($migrationDir);
827
        $config->registerMigrationsFromDirectory($migrationDir);
828
829
        $migration = new Migration($config);
830
        $migration->setNoMigrationException(true);
831
832
        return $migration;
833
    }
834
835
    protected function dropTables(EntityManager $em)
836
    {
837
        $metadatas = $em->getMetadataFactory()->getAllMetadata();
838
        $schemaTool = new SchemaTool($em);
839
        $schemaTool->dropSchema($metadatas);
840
        $em->getConnection()->executeQuery('DROP TABLE IF EXISTS doctrine_migration_versions');
841
    }
842
843
    protected function createTables(EntityManager $em)
844
    {
845
        $metadatas = $em->getMetadataFactory()->getAllMetadata();
846
        $schemaTool = new SchemaTool($em);
847
        $schemaTool->createSchema($metadatas);
848
    }
849
850
    protected function importCsv(EntityManager $em)
851
    {
852
        // for full locale code cases
853
        $locale = env('ECCUBE_LOCALE', 'ja_JP');
854
        $locale = str_replace('_', '-', $locale);
855
        $locales = \Locale::parseLocale($locale);
856
        $localeDir = is_null($locales) ? 'ja' : $locales['language'];
857
858
        $loader = new \Eccube\Doctrine\Common\CsvDataFixtures\Loader();
859
        $loader->loadFromDirectory($this->getParameter('kernel.project_dir').'/src/Eccube/Resource/doctrine/import_csv/'.$localeDir);
860
        $executer = new \Eccube\Doctrine\Common\CsvDataFixtures\Executor\DbalExecutor($em);
861
        $fixtures = $loader->getFixtures();
862
        $executer->execute($fixtures);
863
    }
864
865
    protected function insert(Connection $conn, array $data)
866
    {
867
        $conn->beginTransaction();
868
        try {
869
            $salt = StringUtil::random(32);
870
            $this->encoder->setAuthMagic($data['auth_magic']);
871
            $password = $this->encoder->encodePassword($data['login_pass'], $salt);
872
873
            $id = ('postgresql' === $conn->getDatabasePlatform()->getName())
874
                ? $conn->fetchColumn("select nextval('dtb_base_info_id_seq')")
875
                : null;
876
877
            $conn->insert('dtb_base_info', [
878
                'id' => $id,
879
                'shop_name' => $data['shop_name'],
880
                'email01' => $data['email'],
881
                'email02' => $data['email'],
882
                'email03' => $data['email'],
883
                'email04' => $data['email'],
884
                'authentication_key' => 'FIXME', // FIXME: package-apiの修正で認証コードの登録を不要にする。動作確認時は発行済の認証コードで置き換えること
885
                'update_date' => new \DateTime(),
886
                'discriminator_type' => 'baseinfo',
887
            ], [
888
                'update_date' => \Doctrine\DBAL\Types\Type::DATETIME,
889
            ]);
890
891
            $member_id = ('postgresql' === $conn->getDatabasePlatform()->getName())
892
                ? $conn->fetchColumn("select nextval('dtb_member_id_seq')")
893
                : null;
894
895
            $conn->insert('dtb_member', [
896
                'id' => $member_id,
897
                'login_id' => $data['login_id'],
898
                'password' => $password,
899
                'salt' => $salt,
900
                'work_id' => 1,
901
                'authority_id' => 0,
902
                'creator_id' => 1,
903
                'sort_no' => 1,
904
                'update_date' => new \DateTime(),
905
                'create_date' => new \DateTime(),
906
                'name' => trans('install.member_name'),
907
                'department' => $data['shop_name'],
908
                'discriminator_type' => 'member',
909
            ], [
910
                'update_date' => Type::DATETIME,
911
                'create_date' => Type::DATETIME,
912
            ]);
913
            $conn->commit();
914
        } catch (\Exception $e) {
915
            $conn->rollback();
916
            throw $e;
917
        }
918
    }
919
920
    protected function update(Connection $conn, array $data)
921
    {
922
        $conn->beginTransaction();
923
        try {
924
            $salt = StringUtil::random(32);
925
            $stmt = $conn->prepare('SELECT id FROM dtb_member WHERE login_id = :login_id;');
926
            $stmt->execute([':login_id' => $data['login_id']]);
927
            $row = $stmt->fetch();
928
            $this->encoder->setAuthMagic($data['auth_magic']);
929
            $password = $this->encoder->encodePassword($data['login_pass'], $salt);
930
            if ($row) {
931
                // 同一の管理者IDであればパスワードのみ更新
932
                $sth = $conn->prepare('UPDATE dtb_member set password = :password, salt = :salt, update_date = current_timestamp WHERE login_id = :login_id;');
933
                $sth->execute([
934
                    ':password' => $password,
935
                    ':salt' => $salt,
936
                    ':login_id' => $data['login_id'],
937
                ]);
938
            } else {
939
                // 新しい管理者IDが入力されたらinsert
940
                $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');");
941
                $sth->execute([
942
                    ':login_id' => $data['login_id'],
943
                    ':password' => $password,
944
                    ':salt' => $salt,
945
                ]);
946
            }
947
            $stmt = $conn->prepare('UPDATE dtb_base_info set
948
                shop_name = :shop_name,
949
                email01 = :admin_mail,
950
                email02 = :admin_mail,
951
                email03 = :admin_mail,
952
                email04 = :admin_mail,
953
                update_date = current_timestamp
954
            WHERE id = 1;');
955
            $stmt->execute([
956
                ':shop_name' => $data['shop_name'],
957
                ':admin_mail' => $data['email'],
958
            ]);
959
            $conn->commit();
960
        } catch (\Exception $e) {
961
            $conn->rollback();
962
            throw $e;
963
        }
964
    }
965
966
    public function migrate(Migration $migration)
967
    {
968
        try {
969
            // nullを渡すと最新バージョンまでマイグレートする
970
            $migration->migrate(null, false);
971
        } catch (MigrationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
972
        }
973
    }
974
975
    /**
976
     * @param array $params
977
     * @param EntityManager $em
978
     *
979
     * @return array
980
     */
981
    public function createAppData($params, EntityManager $em)
982
    {
983
        $platform = $em->getConnection()->getDatabasePlatform()->getName();
984
        $version = $this->getDatabaseVersion($em);
985
        $data = [
986
            'site_url' => $params['http_url'],
987
            'shop_name' => $params['shop_name'],
988
            'cube_ver' => Constant::VERSION,
989
            'php_ver' => phpversion(),
990
            'db_ver' => $platform.' '.$version,
991
            'os_type' => php_uname(),
992
        ];
993
994
        return $data;
995
    }
996
997
    /**
998
     * @param array $params
999
     * @param EntityManager $em
1000
     */
1001
    protected function sendAppData($params, EntityManager $em)
1002
    {
1003
        try {
1004
            $query = http_build_query($this->createAppData($params, $em));
1005
            $header = [
1006
                'Content-Type: application/x-www-form-urlencoded',
1007
                'Content-Length: '.strlen($query),
1008
            ];
1009
            $context = stream_context_create(
1010
                [
1011
                    'http' => [
1012
                        'method' => 'POST',
1013
                        'header' => $header,
1014
                        'content' => $query,
1015
                    ],
1016
                ]
1017
            );
1018
            file_get_contents('https://www.ec-cube.net/mall/use_site.php', false, $context);
1019
        } catch (\Exception $e) {
1020
            // 送信に失敗してもインストールは継続できるようにする
1021
            log_error($e->getMessage());
1022
        }
1023
1024
        return $this;
1025
    }
1026
1027
    /**
1028
     * @param EntityManager $em
1029
     *
1030
     * @return string
1031
     */
1032
    public function getDatabaseVersion(EntityManager $em)
1033
    {
1034
        $rsm = new \Doctrine\ORM\Query\ResultSetMapping();
1035
        $rsm->addScalarResult('server_version', 'server_version');
1036
1037
        $platform = $em->getConnection()->getDatabasePlatform()->getName();
1038 View Code Duplication
        switch ($platform) {
1039
            case 'sqlite':
1040
                $sql = 'SELECT sqlite_version() AS server_version';
1041
                break;
1042
1043
            case 'mysql':
1044
                $sql = 'SELECT version() AS server_version';
1045
                break;
1046
1047
            case 'postgresql':
1048
            default:
1049
                $sql = 'SHOW server_version';
1050
        }
1051
1052
        $version = $em->createNativeQuery($sql, $rsm)
1053
            ->getSingleScalarResult();
1054
1055
        // postgresqlのバージョンが10.x以降の場合に、getSingleScalarResult()で取得される不要な文字列を除く処理
1056
        if ($platform === 'postgresql') {
1057
            preg_match('/\A([\d+\.]+)/', $version, $matches);
1058
            $version = $matches[1];
1059
        }
1060
1061
        return $version;
1062
    }
1063
1064
    /**
1065
     * @param string
1066
     *
1067
     * @return string
1068
     */
1069
    public function convertAdminAllowHosts($adminAllowHosts)
1070
    {
1071
        if (empty($adminAllowHosts)) {
1072
            return '[]';
1073
        }
1074
1075
        $adminAllowHosts = \json_encode(
1076
            \explode("\n", StringUtil::convertLineFeed($adminAllowHosts))
1077
        );
1078
1079
        return "'$adminAllowHosts'";
1080
    }
1081
1082
    /**
1083
     * @return bool
1084
     */
1085
    protected function isInstalled()
1086
    {
1087
        return self::DEFAULT_AUTH_MAGIC !== $this->getParameter('eccube_auth_magic');
1088
    }
1089
1090
    /**
1091
     * @return bool
1092
     */
1093
    protected function isInstallEnv()
1094
    {
1095
        $env = $this->getParameter('kernel.environment');
1096
1097
        if ($env === 'install' || $env === 'test') {
1098
            return true;
1099
        }
1100
1101
        return false;
1102
    }
1103
}
1104