Failed Conditions
Pull Request — 4.0 (#4085)
by chihiro
06:18
created

InstallController::update()   A

Complexity

Conditions 3
Paths 18

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
533
    {
534
        foreach ($this->requiredModules as $module) {
535
            if (!extension_loaded($module)) {
536
                $this->addDanger(trans('install.required_extension_disabled', ['%module%' => $module]), 'install');
537
            }
538
        }
539
        if (!extension_loaded('pdo_mysql') && !extension_loaded('pdo_pgsql')) {
540
            $this->addDanger(trans('install.required_database_extension_disabled'), 'install');
541
        }
542
        foreach ($this->recommendedModules as $module) {
543
            if (!extension_loaded($module)) {
544
                if ($module == 'mcrypt' && PHP_VERSION_ID >= 70100) {
545
                    //The mcrypt extension has been deprecated in PHP 7.1.x
546
                    //http://php.net/manual/en/migration71.deprecated.php
547
                    continue;
548
                }
549
                $this->addInfo(trans('install.recommend_extension_disabled', ['%module%' => $module]), 'install');
550
            }
551
        }
552
        if ('\\' === DIRECTORY_SEPARATOR) { // for Windows
553
            if (!extension_loaded('wincache')) {
554
                $this->addInfo(trans('install.recommend_extension_disabled', ['%module%' => 'wincache']), 'install');
555
            }
556
        } else {
557
            if (!extension_loaded('apc')) {
558
                $this->addInfo(trans('install.recommend_extension_disabled', ['%module%' => 'apc']), 'install');
559
            }
560
        }
561
        if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false) {
562
            if (!function_exists('apache_get_modules')) {
563
                $this->addWarning(trans('install.mod_rewrite_unknown'), 'install');
564
            } elseif (!in_array('mod_rewrite', apache_get_modules())) {
565
                $this->addDanger(trans('install.mod_rewrite_disabled'), 'install');
566
            }
567
        } elseif (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false) {
568
            // iis
569
        } elseif (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
570
            // nginx
571
        }
572
    }
573
574
    protected function createConnection(array $params)
575
    {
576
        if (strpos($params['url'], 'mysql') !== false) {
577
            $params['charset'] = 'utf8';
578
            $params['defaultTableOptions'] = [
579
                'collate' => 'utf8_general_ci',
580
            ];
581
        }
582
583
        Type::overrideType('datetime', UTCDateTimeType::class);
584
        Type::overrideType('datetimetz', UTCDateTimeTzType::class);
585
586
        $conn = DriverManager::getConnection($params);
587
        $conn->ping();
588
589
        $platform = $conn->getDatabasePlatform();
590
        $platform->markDoctrineTypeCommented('datetime');
591
        $platform->markDoctrineTypeCommented('datetimetz');
592
593
        return $conn;
594
    }
595
596
    protected function createEntityManager(Connection $conn)
597
    {
598
        $paths = [
599
            $this->getParameter('kernel.project_dir').'/src/Eccube/Entity',
600
            $this->getParameter('kernel.project_dir').'/app/Customize/Entity',
601
        ];
602
        $config = Setup::createConfiguration(true);
603
        $driver = new AnnotationDriver(new CachedReader(new AnnotationReader(), new ArrayCache()), $paths);
604
        $driver->setTraitProxiesDirectory($this->getParameter('kernel.project_dir').'/app/proxy/entity');
605
        $config->setMetadataDriverImpl($driver);
606
607
        $em = EntityManager::create($conn, $config);
608
609
        return $em;
610
    }
611
612
    /**
613
     * @param array $params
614
     *
615
     * @return string
616
     */
617
    public function createDatabaseUrl(array $params)
618
    {
619
        if (!isset($params['database'])) {
620
            return null;
621
        }
622
623
        $url = '';
624
        switch ($params['database']) {
625
            case 'pdo_sqlite':
626
                $url = 'sqlite://'.$params['database_name'];
627
                break;
628
629
            case 'pdo_mysql':
630
            case 'pdo_pgsql':
631
                $url = str_replace('pdo_', '', $params['database']);
632
                $url .= '://';
633
                if (isset($params['database_user'])) {
634
                    $url .= $params['database_user'];
635
                    if (isset($params['database_password'])) {
636
                        $url .= ':'.\rawurlencode($params['database_password']);
637
                    }
638
                    $url .= '@';
639
                }
640 View Code Duplication
                if (isset($params['database_host'])) {
641
                    $url .= $params['database_host'];
642
                    if (isset($params['database_port'])) {
643
                        $url .= ':'.$params['database_port'];
644
                    }
645
                    $url .= '/';
646
                }
647
                $url .= $params['database_name'];
648
                break;
649
        }
650
651
        return $url;
652
    }
653
654
    /**
655
     * @param string $url
656
     *
657
     * @return array
658
     */
659
    public function extractDatabaseUrl($url)
660
    {
661
        if (preg_match('|^sqlite://(.*)$|', $url, $matches)) {
662
            return [
663
                'database' => 'pdo_sqlite',
664
                'database_name' => $matches[1],
665
            ];
666
        }
667
668
        $parsed = parse_url($url);
669
670
        if ($parsed === false) {
671
            throw new \Exception('Malformed parameter "url".');
672
        }
673
674
        return [
675
            'database' => 'pdo_'.$parsed['scheme'],
676
            'database_name' => ltrim($parsed['path'], '/'),
677
            'database_host' => $parsed['host'],
678
            'database_port' => isset($parsed['port']) ? $parsed['port'] : null,
679
            'database_user' => isset($parsed['user']) ? $parsed['user'] : null,
680
            'database_password' => isset($parsed['pass']) ? $parsed['pass'] : null,
681
        ];
682
    }
683
684
    /**
685
     * @param array $params
686
     *
687
     * @return string
688
     *
689
     * @see https://github.com/symfony/swiftmailer-bundle/blob/9728097df87e76e2db71fc41fd7d211c06daea3e/DependencyInjection/SwiftmailerTransportFactory.php#L80-L142
690
     */
691
    public function createMailerUrl(array $params)
692
    {
693
        $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...
694
        if (isset($params['transport'])) {
695
            $url = $params['transport'].'://';
696
        } else {
697
            $url = 'smtp://';
698
        }
699 View Code Duplication
        if (isset($params['smtp_username'])) {
700
            $url .= $params['smtp_username'];
701
            if (isset($params['smtp_password'])) {
702
                $url .= ':'.$params['smtp_password'];
703
            }
704
            $url .= '@';
705
        }
706
707
        $queryStrings = [];
708
        if (isset($params['encryption'])) {
709
            $queryStrings['encryption'] = $params['encryption'];
710
            if ($params['encryption'] === 'ssl' && !isset($params['smtp_port'])) {
711
                $params['smtp_port'] = 465;
712
            }
713
        }
714
        if (isset($params['auth_mode'])) {
715
            $queryStrings['auth_mode'] = $params['auth_mode'];
716
        } else {
717
            if (isset($params['smtp_username'])) {
718
                $queryStrings['auth_mode'] = 'plain';
719
            }
720
        }
721
        ksort($queryStrings, SORT_STRING);
722
723 View Code Duplication
        if (isset($params['smtp_host'])) {
724
            $url .= $params['smtp_host'];
725
            if (isset($params['smtp_port'])) {
726
                $url .= ':'.$params['smtp_port'];
727
            }
728
        }
729
730
        if (isset($params['smtp_username']) || array_values($queryStrings)) {
731
            $url .= '?';
732
            $i = count($queryStrings);
733
            foreach ($queryStrings as $key => $value) {
734
                $url .= $key.'='.$value;
735
                if ($i > 1) {
736
                    $url .= '&';
737
                }
738
                $i--;
739
            }
740
        }
741
742
        return $url;
743
    }
744
745
    /**
746
     * @param string $url
747
     *
748
     * @return array
749
     */
750
    public function extractMailerUrl($url)
751
    {
752
        $options = [
753
            'transport' => null,
754
            'smtp_username' => null,
755
            'smtp_password' => null,
756
            'smtp_host' => null,
757
            'smtp_port' => null,
758
            'encryption' => null,
759
            'auth_mode' => null,
760
        ];
761
762
        if ($url) {
763
            $parts = parse_url($url);
764
            if (isset($parts['scheme'])) {
765
                $options['transport'] = $parts['scheme'];
766
            }
767
            if (isset($parts['user'])) {
768
                $options['smtp_username'] = $parts['user'];
769
            }
770
            if (isset($parts['pass'])) {
771
                $options['smtp_password'] = $parts['pass'];
772
            }
773
            if (isset($parts['host'])) {
774
                $options['smtp_host'] = $parts['host'];
775
            }
776
            if (isset($parts['port'])) {
777
                $options['smtp_port'] = $parts['port'];
778
            }
779
            if (isset($parts['query'])) {
780
                parse_str($parts['query'], $query);
781
                foreach (array_keys($options) as $key) {
782
                    if (isset($query[$key]) && $query[$key] != '') {
783
                        $options[$key] = $query[$key];
784
                    }
785
                }
786
            }
787
        }
788
        if (!isset($options['transport'])) {
789
            $options['transport'] = 'smtp';
790
        } elseif ('gmail' === $options['transport']) {
791
            $options['encryption'] = 'ssl';
792
            $options['auth_mode'] = 'login';
793
            $options['smtp_host'] = 'smtp.gmail.com';
794
            $options['transport'] = 'smtp';
795
        }
796
        if (!isset($options['smtp_port'])) {
797
            $options['smtp_port'] = 'ssl' === $options['encryption'] ? 465 : 25;
798
        }
799
        if (isset($options['smtp_username']) && !isset($options['auth_mode'])) {
800
            $options['auth_mode'] = 'plain';
801
        }
802
        ksort($options, SORT_STRING);
803
804
        return $options;
805
    }
806
807
    protected function createMigration(Connection $conn)
808
    {
809
        $config = new Configuration($conn);
810
        $config->setMigrationsNamespace('DoctrineMigrations');
811
        $migrationDir = $this->getParameter('kernel.project_dir').'/src/Eccube/Resource/doctrine/migration';
812
        $config->setMigrationsDirectory($migrationDir);
813
        $config->registerMigrationsFromDirectory($migrationDir);
814
815
        $migration = new Migration($config);
816
        $migration->setNoMigrationException(true);
817
818
        return $migration;
819
    }
820
821
    protected function dropTables(EntityManager $em)
822
    {
823
        $metadatas = $em->getMetadataFactory()->getAllMetadata();
824
        $schemaTool = new SchemaTool($em);
825
        $schemaTool->dropSchema($metadatas);
826
        $em->getConnection()->executeQuery('DROP TABLE IF EXISTS doctrine_migration_versions');
827
    }
828
829
    protected function createTables(EntityManager $em)
830
    {
831
        $metadatas = $em->getMetadataFactory()->getAllMetadata();
832
        $schemaTool = new SchemaTool($em);
833
        $schemaTool->createSchema($metadatas);
834
    }
835
836
    protected function importCsv(EntityManager $em)
837
    {
838
        // for full locale code cases
839
        $locale = env('ECCUBE_LOCALE', 'ja_JP');
840
        $locale = str_replace('_', '-', $locale);
841
        $locales = \Locale::parseLocale($locale);
842
        $localeDir = is_null($locales) ? 'ja' : $locales['language'];
843
844
        $loader = new \Eccube\Doctrine\Common\CsvDataFixtures\Loader();
845
        $loader->loadFromDirectory($this->getParameter('kernel.project_dir').'/src/Eccube/Resource/doctrine/import_csv/'.$localeDir);
846
        $executer = new \Eccube\Doctrine\Common\CsvDataFixtures\Executor\DbalExecutor($em);
847
        $fixtures = $loader->getFixtures();
848
        $executer->execute($fixtures);
849
    }
850
851
    protected function insert(Connection $conn, array $data)
852
    {
853
        $conn->beginTransaction();
854
        try {
855
            $salt = StringUtil::random(32);
856
            $this->encoder->setAuthMagic($data['auth_magic']);
857
            $password = $this->encoder->encodePassword($data['login_pass'], $salt);
858
859
            $id = ('postgresql' === $conn->getDatabasePlatform()->getName())
860
                ? $conn->fetchColumn("select nextval('dtb_base_info_id_seq')")
861
                : null;
862
863
            $conn->insert('dtb_base_info', [
864
                'id' => $id,
865
                'shop_name' => $data['shop_name'],
866
                'email01' => $data['email'],
867
                'email02' => $data['email'],
868
                'email03' => $data['email'],
869
                'email04' => $data['email'],
870
                'update_date' => new \DateTime(),
871
                'discriminator_type' => 'baseinfo',
872
            ], [
873
                'update_date' => \Doctrine\DBAL\Types\Type::DATETIME,
874
            ]);
875
876
            $member_id = ('postgresql' === $conn->getDatabasePlatform()->getName())
877
                ? $conn->fetchColumn("select nextval('dtb_member_id_seq')")
878
                : null;
879
880
            $conn->insert('dtb_member', [
881
                'id' => $member_id,
882
                'login_id' => $data['login_id'],
883
                'password' => $password,
884
                'salt' => $salt,
885
                'work_id' => 1,
886
                'authority_id' => 0,
887
                'creator_id' => 1,
888
                'sort_no' => 1,
889
                'update_date' => new \DateTime(),
890
                'create_date' => new \DateTime(),
891
                'name' => trans('install.member_name'),
892
                'department' => $data['shop_name'],
893
                'discriminator_type' => 'member',
894
            ], [
895
                'update_date' => Type::DATETIME,
896
                'create_date' => Type::DATETIME,
897
            ]);
898
            $conn->commit();
899
        } catch (\Exception $e) {
900
            $conn->rollback();
901
            throw $e;
902
        }
903
    }
904
905
    protected function update(Connection $conn, array $data)
906
    {
907
        $conn->beginTransaction();
908
        try {
909
            $salt = StringUtil::random(32);
910
            $stmt = $conn->prepare('SELECT id FROM dtb_member WHERE login_id = :login_id;');
911
            $stmt->execute([':login_id' => $data['login_id']]);
912
            $row = $stmt->fetch();
913
            $this->encoder->setAuthMagic($data['auth_magic']);
914
            $password = $this->encoder->encodePassword($data['login_pass'], $salt);
915
            if ($row) {
916
                // 同一の管理者IDであればパスワードのみ更新
917
                $sth = $conn->prepare('UPDATE dtb_member set password = :password, salt = :salt, update_date = current_timestamp WHERE login_id = :login_id;');
918
                $sth->execute([
919
                    ':password' => $password,
920
                    ':salt' => $salt,
921
                    ':login_id' => $data['login_id'],
922
                ]);
923
            } else {
924
                // 新しい管理者IDが入力されたらinsert
925
                $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');");
926
                $sth->execute([
927
                    ':login_id' => $data['login_id'],
928
                    ':password' => $password,
929
                    ':salt' => $salt,
930
                ]);
931
            }
932
            $stmt = $conn->prepare('UPDATE dtb_base_info set
933
                shop_name = :shop_name,
934
                email01 = :admin_mail,
935
                email02 = :admin_mail,
936
                email03 = :admin_mail,
937
                email04 = :admin_mail,
938
                update_date = current_timestamp
939
            WHERE id = 1;');
940
            $stmt->execute([
941
                ':shop_name' => $data['shop_name'],
942
                ':admin_mail' => $data['email'],
943
            ]);
944
            $conn->commit();
945
        } catch (\Exception $e) {
946
            $conn->rollback();
947
            throw $e;
948
        }
949
    }
950
951
    public function migrate(Migration $migration)
952
    {
953
        try {
954
            // nullを渡すと最新バージョンまでマイグレートする
955
            $migration->migrate(null, false);
956
        } catch (MigrationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
957
        }
958
    }
959
960
    /**
961
     * @param array $params
962
     * @param EntityManager $em
963
     *
964
     * @return array
965
     */
966
    public function createAppData($params, EntityManager $em)
967
    {
968
        $platform = $em->getConnection()->getDatabasePlatform()->getName();
969
        $version = $this->getDatabaseVersion($em);
970
        $data = [
971
            'site_url' => $params['http_url'],
972
            'shop_name' => $params['shop_name'],
973
            'cube_ver' => Constant::VERSION,
974
            'php_ver' => phpversion(),
975
            'db_ver' => $platform.' '.$version,
976
            'os_type' => php_uname(),
977
        ];
978
979
        return $data;
980
    }
981
982
    /**
983
     * @param array $params
984
     * @param EntityManager $em
985
     */
986
    protected function sendAppData($params, EntityManager $em)
987
    {
988
        try {
989
            $query = http_build_query($this->createAppData($params, $em));
990
            $header = [
991
                'Content-Type: application/x-www-form-urlencoded',
992
                'Content-Length: '.strlen($query),
993
            ];
994
            $context = stream_context_create(
995
                [
996
                    'http' => [
997
                        'method' => 'POST',
998
                        'header' => $header,
999
                        'content' => $query,
1000
                    ],
1001
                ]
1002
            );
1003
            file_get_contents('https://www.ec-cube.net/mall/use_site.php', false, $context);
1004
        } catch (\Exception $e) {
1005
            // 送信に失敗してもインストールは継続できるようにする
1006
            log_error($e->getMessage());
1007
        }
1008
1009
        return $this;
1010
    }
1011
1012
    /**
1013
     * @param EntityManager $em
1014
     *
1015
     * @return string
1016
     */
1017
    public function getDatabaseVersion(EntityManager $em)
1018
    {
1019
        $rsm = new \Doctrine\ORM\Query\ResultSetMapping();
1020
        $rsm->addScalarResult('server_version', 'server_version');
1021
1022
        $platform = $em->getConnection()->getDatabasePlatform()->getName();
1023
        switch ($platform) {
1024
            case 'sqlite':
1025
                $sql = 'SELECT sqlite_version() AS server_version';
1026
                break;
1027
1028
            case 'mysql':
1029
                $sql = 'SELECT version() AS server_version';
1030
                break;
1031
1032
            case 'pgsql':
1033
            default:
1034
                $sql = 'SHOW server_version';
1035
        }
1036
1037
        $version = $em->createNativeQuery($sql, $rsm)
1038
            ->getSingleScalarResult();
1039
1040
        return $version;
1041
    }
1042
1043
    /**
1044
     * @param string
1045
     *
1046
     * @return string
1047
     */
1048
    public function convertAdminAllowHosts($adminAllowHosts)
1049
    {
1050
        if (empty($adminAllowHosts)) {
1051
            return '[]';
1052
        }
1053
1054
        $adminAllowHosts = \json_encode(
1055
            \explode("\n", StringUtil::convertLineFeed($adminAllowHosts))
1056
        );
1057
1058
        return "'$adminAllowHosts'";
1059
    }
1060
1061
    /**
1062
     * @return bool
1063
     */
1064
    protected function isInstalled()
1065
    {
1066
        return self::DEFAULT_AUTH_MAGIC !== $this->getParameter('eccube_auth_magic');
1067
    }
1068
1069
    /**
1070
     * @return bool
1071
     */
1072
    protected function isInstallEnv()
1073
    {
1074
        $env = $this->getParameter('kernel.environment');
1075
1076
        if ($env === 'install' || $env === 'test') {
1077
            return true;
1078
        }
1079
1080
        return false;
1081
    }
1082
}
1083