Failed Conditions
Pull Request — experimental/3.1 (#2550)
by chihiro
34:58
created

InstallController::step4()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 46
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 7.0671

Importance

Changes 0
Metric Value
cc 7
eloc 30
nc 12
nop 3
dl 0
loc 46
rs 6.7272
c 0
b 0
f 0
ccs 24
cts 27
cp 0.8889
crap 7.0671
1
<?php
2
/*
3
 * This file is part of EC-CUBE
4
 *
5
 * Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved.
6
 *
7
 * http://www.lockon.co.jp/
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License
11
 * as published by the Free Software Foundation; either version 2
12
 * of the License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
 */
23
24
namespace Eccube\Controller\Install;
25
26
use Doctrine\DBAL\Connection;
27
use Doctrine\DBAL\DriverManager;
28
use Doctrine\DBAL\Migrations\Configuration\Configuration;
29
use Doctrine\DBAL\Migrations\Migration;
30
use Doctrine\DBAL\Migrations\MigrationException;
31
use Doctrine\DBAL\Types\Type;
32
use Doctrine\ORM\EntityManager;
33
use Doctrine\ORM\Tools\SchemaTool;
34
use Doctrine\ORM\Tools\Setup;
35
use Eccube\Common\Constant;
36
use Eccube\Form\Type\Install\Step1Type;
37
use Eccube\Form\Type\Install\Step3Type;
38
use Eccube\Form\Type\Install\Step4Type;
39
use Eccube\Form\Type\Install\Step5Type;
40
use Eccube\InstallApplication;
41
use Eccube\Security\Core\Encoder\PasswordEncoder;
42
use Eccube\Util\Str;
43
use Symfony\Component\Dotenv\Dotenv;
44
use Symfony\Component\Filesystem\Filesystem;
45
use Symfony\Component\Finder\Finder;
46
use Symfony\Component\HttpFoundation\Request;
47
use Symfony\Component\HttpFoundation\Response;
48
use Symfony\Component\HttpFoundation\Session\Session;
49
50
class InstallController
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
51
{
52
    protected $requiredModules = [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
53
        'pdo',
54
        'phar',
55
        'mbstring',
56
        'zlib',
57
        'ctype',
58
        'session',
59
        'JSON',
60
        'xml',
61
        'libxml',
62
        'OpenSSL',
63
        'zip',
64
        'cURL',
65
        'fileinfo',
66
        'intl'
67
    ];
68
69
    protected $recommendedModules = [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
70
        'hash',
71
        'mcrypt'
72
    ];
73
74
    protected $writableDirs = [
75
        '/html',
76
        '/app',
77
        '/app/template',
78
        '/app/cache',
79
        '/app/config',
80
        '/app/config/eccube',
81
        '/app/log',
82
        '/app/Plugin',
83
        '/app/proxy',
84
        '/app/proxy/entity',
85
    ];
86
87
    protected $rootDir;
88
    protected $configDir;
89
    protected $configDistDir;
90
    protected $cacheDir;
91
92 7
    public function __construct()
0 ignored issues
show
introduced by
Missing function doc comment
Loading history...
93
    {
94 7
        $this->rootDir = realpath(__DIR__.'/../../../..');
95 7
        $this->configDir = realpath($this->rootDir.'/app/config/eccube');
96 7
        $this->configDistDir = realpath($this->rootDir.'/src/Eccube/Resource/config');
97 7
        $this->cacheDir = realpath($this->rootDir.'/app/cache');
98
    }
99
100
    /**
101
     * 最初からやり直す場合、SESSION情報をクリア.
102
     *
103
     * @param InstallApplication $app
104
     * @param Request $request
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
105
     * @param Session $session
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
106
     * @return Response
107
     */
108 1
    public function index(InstallApplication $app, Request $request, Session $session)
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...
109
    {
110 1
        $this->removeSessionData($session);
111
112 1
        return $app->redirect($app->path('install_step1'));
113
    }
114
115
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$session" missing
Loading history...
116
     * ようこそ.
117
     *
118
     * @param InstallApplication $app
119
     * @param Request $request
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
120
     * @return Response
121
     */
122 1
    public function step1(InstallApplication $app, Request $request, Session $session)
123
    {
124 1
        $form = $app['form.factory']
125 1
            ->createBuilder(Step1Type::class)
126 1
            ->getForm();
127
128 1
        $form->setData($this->getSessionData($session));
129 1
        $form->handleRequest($request);
130
131 1
        if ($form->isSubmitted() && $form->isValid()) {
132
            $this->setSessionData($session, $form->getData());
133
134
            return $app->redirect($app->path('install_step2'));
135
        }
136
137 1
        $this->checkModules($app);
138
139 1
        return $app['twig']->render('step1.twig', [
140 1
            'form' => $form->createView(),
141 1
            'publicPath' => '..'.RELATIVE_PUBLIC_DIR_PATH.'/',
142
        ]);
143
    }
144
145
    /**
146
     * ディレクトリの書き込み権限をチェック.
147
     *
148
     * @param InstallApplication $app
149
     * @param Request $request
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
150
     * @param Session $session
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
151
     * @return Response
152
     */
153 1
    public function step2(InstallApplication $app, Request $request, Session $session)
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...
Unused Code introduced by
The parameter $session 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...
154
    {
155 1
        $protectedDirs = [];
156 1
        foreach ($this->writableDirs as $dir) {
157 1
            if (!is_writable($this->rootDir.$dir)) {
158 1
                $protectedDirs[] = $dir;
159
            }
160
        }
161
162
        // 権限がある場合, キャッシュディレクトリをクリア
163 1
        if (empty($protectedDirs)) {
164 1
            $finder = Finder::create()
165 1
                ->in($this->cacheDir)
166 1
                ->notName('.gitkeep')
167 1
                ->files();
168 1
            $fs = new Filesystem();
169 1
            $fs->remove($finder);
170
        }
171
172 1
        return $app['twig']->render('step2.twig', [
173 1
            'protectedDirs' => $protectedDirs,
174 1
            'publicPath' => '..'.RELATIVE_PUBLIC_DIR_PATH.'/',
175
        ]);
176
    }
177
178
    /**
179
     * サイトの設定.
180
     *
181
     * @param InstallApplication $app
182
     * @param Request $request
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
183
     * @param Session $session
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
184
     * @return Response
185
     */
186 1
    public function step3(InstallApplication $app, Request $request, Session $session)
187
    {
188 1
        $sessionData = $this->getSessionData($session);
189
190 1
        if (empty($sessionData['shop_name'])) {
191
            // 再インストールの場合は設定ファイルから復旧
192 1
            if (file_exists($this->configDir.'/config.php')) {
193 1
                // ショップ名/メールアドレス
194
                $config = require $this->configDir.'/database.php';
195 1
                $conn = $this->createConnection($config['database'][$config['database']['default']]);
196 1
                $stmt = $conn->query("SELECT shop_name, email01 FROM dtb_base_info WHERE id = 1;");
197 1
                $row = $stmt->fetch();
198 1
                $sessionData['shop_name'] = $row['shop_name'];
199 1
                $sessionData['email'] = $row['email01'];
200 1
201
                // 管理画面ルーティング
202
                $config = require $this->configDir.'/path.php';
203 1
                $sessionData['admin_dir'] = $config['admin_route'];
204 1
205
                // 管理画面許可IP
206
                $config = require $this->configDir.'/config.php';
207 1 View Code Duplication
                if (!empty($config['admin_allow_hosts'])) {
208 1
                    $sessionData['admin_allow_hosts']
209
                        = Str::convertLineFeed(implode("\n", $config['admin_allow_hosts']));
210
                }
211
                // 強制SSL
212
                $sessionData['admin_force_ssl'] = $config['force_ssl'];
213 1
214
                // ロードバランサ, プロキシサーバ
215
                if (!empty($config['trusted_proxies_connection_only'])) {
216 1
                    $sessionData['trusted_proxies_connection_only'] = (bool)$config['trusted_proxies_connection_only'];
0 ignored issues
show
Coding Style introduced by
As per coding-style, a cast statement should be followed by a single space.
Loading history...
217
                }
218 View Code Duplication
                if (!empty($config['trusted_proxies'])) {
219 1
                    $sessionData['trusted_proxies'] = Str::convertLineFeed(implode("\n",
220
                        $sessionData['trusted_proxies']));
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 20 spaces, but found 24.
Loading history...
221
                }
222
                // メール
223
                $file = $this->configDir.'/mail.php';
224 1
                $config = require $file;
225 1
                $sessionData['mail_backend'] = $config['mail']['transport'];
226 1
                $sessionData['smtp_host'] = $config['mail']['host'];
227 1
                $sessionData['smtp_port'] = $config['mail']['port'];
228 1
                $sessionData['smtp_username'] = $config['mail']['username'];
229 1
                $sessionData['smtp_password'] = $config['mail']['password'];
230 1
            } else {
231
                // 初期値にmailを設定.
232
                $sessionData['mail_backend'] = 'mail';
233
            }
234
        }
235
236
        $form = $app['form.factory']
237 1
            ->createBuilder(Step3Type::class)
238 1
            ->getForm();
239 1
240
        $form->setData($sessionData);
241 1
        $form->handleRequest($request);
242 1
243
        if ($form->isSubmitted() && $form->isValid()) {
244 1
            $this->setSessionData($session, $form->getData());
245
246
            return $app->redirect($app->path('install_step4'));
247
        }
248
249
        return $app['twig']->render('step3.twig', [
250 1
            'form' => $form->createView(),
251 1
            'publicPath' => '..'.RELATIVE_PUBLIC_DIR_PATH.'/',
252 1
        ]);
253
    }
254
255
    /**
256
     * データベースの設定.
257
     *
258
     * @param InstallApplication $app
259
     * @param Request $request
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
260
     * @param Session $session
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
261
     * @return Response
262
     */
263
    public function step4(InstallApplication $app, Request $request, Session $session)
264 1
    {
265
        $sessionData = $this->getSessionData($session);
266 1
267
        if (empty($sessionData['database'])) {
268 1
            // 再インストールの場合は設定ファイルから復旧.
269
            $file = $this->configDir.'/database.php';
270 1
            if (file_exists($file)) {
271 1
                // データベース設定
272 1
                $config = require $file;
273
                $database = $config['database'][$config['database']['default']];
274 1
                $sessionData['database'] = $database['driver'];
275 1
                if ($database['driver'] === 'pdo_sqlite') {
276 1
                    $sessionData['database_name'] = $this->configDir.'/eccube.db';
277 1
                } else {
278
                    $sessionData['database_host'] = $database['host'];
279
                    $sessionData['database_port'] = $database['port'];
280 1
                    $sessionData['database_name'] = $database['dbname'];
281 1
                    $sessionData['database_user'] = $database['user'];
282 1
                    $sessionData['database_password'] = $database['password'];
283 1
                }
284 1
            }
285
        }
286
287
        $form = $app['form.factory']
288
            ->createBuilder(Step4Type::class)
289 1
            ->getForm();
290 1
291 1
        $form->setData($sessionData);
292
        $form->handleRequest($request);
293 1
294 1
        if ($form->isSubmitted() && $form->isValid()) {
295
            $data = $form->getData();
296 1
            if ($data['database'] === 'pdo_sqlite') {
297
                $data['database_name'] = $this->configDir.'/eccube.db';
298
            }
299
            $this->setSessionData($session, $data);
300
301
            return $app->redirect($app->path('install_step5'));
302 1
        }
303 1
304 1
        return $app['twig']->render('step4.twig', [
305
            'form' => $form->createView(),
306
            'publicPath' => '..'.RELATIVE_PUBLIC_DIR_PATH.'/',
307
        ]);
308
    }
309
310
    /**
311
     * データベースの初期化.
312
     *
313
     * @param InstallApplication $app
314
     * @param Request $request
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
315
     * @param Session $session
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
316 1
     * @return Response
317
     */
318 1
    public function step5(InstallApplication $app, Request $request, Session $session)
319 1
    {
320 1
        $form = $app['form.factory']
321
            ->createBuilder(Step5Type::class)
322 1
            ->getForm();
323 1
324 1
        $sessionData = $this->getSessionData($session);
325
        $form->setData($sessionData);
326 1
        $form->handleRequest($request);
327
328
        if ($form->isSubmitted() && $form->isValid()) {
329
            $noUpdate = $form['no_update']->getData();
330
331
            $this->copyConfigFiles();
332
            $data = array_merge(['root_urlpath' => $request->getBasePath()], $sessionData);
333
            $this->replaceConfigFiles($data, !$noUpdate);
334
335
            $params = require $this->configDir.'/database.php';
336
            $conn = $this->createConnection($params['database'][$params['database']['default']]);
337
            $em = $this->createEntityManager($conn);
338
            $migration = $this->createMigration($conn);
339
340
            $config = require $this->configDir.'/config.php';
341
            if ($noUpdate) {
342
                $this->update($conn, [
343
                    'auth_magic' => $config['auth_magic'],
344
                    'login_id' => $sessionData['login_id'],
345
                    'login_pass' => $sessionData['login_pass'],
346
                    'shop_name' => $sessionData['shop_name'],
347
                    'email' => $sessionData['email'],
348
                ]);
349
            } else {
350
                $this->dropTables($em);
351
                $this->createTables($em);
352
                $this->importCsv($em);
353
                $this->migrate($migration);
354
                $this->insert($conn, [
355
                    'auth_magic' => $config['auth_magic'],
356
                    'login_id' => $sessionData['login_id'],
357
                    'login_pass' => $sessionData['login_pass'],
358
                    'shop_name' => $sessionData['shop_name'],
359
                    'email' => $sessionData['email'],
360
                ]);
361
            }
362
363
            if (isset($sessionData['agree']) && $sessionData['agree']) {
364
                $host = $request->getSchemeAndHttpHost();
365
                $basePath = $request->getBasePath();
366
                $params = array(
367
                    'http_url' => $host.$basePath,
368
                    'shop_name' => $sessionData['shop_name'],
369
                );
370
                $this->sendAppData($params);
371
            }
372
373
            $this->removeSessionData($session);
374
375
            return $app->redirect($app->path('install_complete'));
376
        }
377
378 1
        return $app['twig']->render('step5.twig', [
379 1
            'form' => $form->createView(),
380 1
            'publicPath' => '..'.RELATIVE_PUBLIC_DIR_PATH.'/',
381
        ]);
382
    }
383
384
    //    インストール完了
385 1
    public function complete(InstallApplication $app, Request $request)
0 ignored issues
show
introduced by
You must use "/**" style comments for a function comment
Loading history...
386
    {
387 1
        $config = require $this->configDir.'/config.php';
388 1
        if (isset($config['trusted_proxies_connection_only']) && !empty($config['trusted_proxies_connection_only'])) {
389 1
            Request::setTrustedProxies(array_merge(array($request->server->get('REMOTE_ADDR')),
390
                $config['trusted_proxies']));
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 12 spaces, but found 16.
Loading history...
391 View Code Duplication
        } elseif (isset($config['trusted_proxies']) && !empty($config['trusted_proxies'])) {
392 1
            Request::setTrustedProxies($config['trusted_proxies']);
393
        }
394
395
        $pathConfig = require $this->configDir.'/path.php';
396 1
        $host = $request->getSchemeAndHttpHost();
397 1
        $basePath = $request->getBasePath();
398 1
        $adminUrl = $host.$basePath.'/'.$pathConfig['admin_route'];
399 1
400
        return $app['twig']->render('complete.twig', [
401 1
            'admin_url' => $adminUrl,
402 1
            'publicPath' => '..'.RELATIVE_PUBLIC_DIR_PATH.'/',
403 1
        ]);
404
    }
405
406
    private function getSessionData(Session $session)
407 4
    {
408
        return $session->get('eccube.session.install', []);
409 4
    }
410
411
    private function removeSessionData(Session $session)
412 1
    {
413
        $session->remove('eccube.session.install');
414 1
    }
415
416
    private function setSessionData(Session $session, $data = [])
417
    {
418
        $data = array_replace_recursive($this->getSessionData($session), $data);
419
        $session->set('eccube.session.install', $data);
420
    }
421
422
    private function checkModules($app)
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...
423 1
    {
424
        foreach ($this->requiredModules as $module) {
425 1
            if (!extension_loaded($module)) {
426 1
                $app->addDanger('[必須] '.$module.' 拡張モジュールが有効になっていません。', 'install');
427 1
            }
428
        }
429
        if (!extension_loaded('pdo_mysql') && !extension_loaded('pdo_pgsql')) {
430 1
            $app->addDanger('[必須] '.'pdo_pgsql又はpdo_mysql 拡張モジュールを有効にしてください。', 'install');
431
        }
432
        foreach ($this->recommendedModules as $module) {
433 1
            if (!extension_loaded($module)) {
434 1
                if ($module == 'mcrypt' && PHP_VERSION_ID >= 70100) {
435
                    //The mcrypt extension has been deprecated in PHP 7.1.x
436
                    //http://php.net/manual/en/migration71.deprecated.php
437
                    continue;
438
                }
439
                $app->addInfo('[推奨] '.$module.' 拡張モジュールが有効になっていません。', 'install');
440 1
            }
441
        }
442
        if ('\\' === DIRECTORY_SEPARATOR) { // for Windows
443 1
            if (!extension_loaded('wincache')) {
444
                $app->addInfo('[推奨] WinCache 拡張モジュールが有効になっていません。', 'install');
445
            }
446
        } else {
447
            if (!extension_loaded('apc')) {
448 1
                $app->addInfo('[推奨] APC 拡張モジュールが有効になっていません。', 'install');
449 1
            }
450
        }
451
        if (isset($_SERVER['SERVER_SOFTWARE']) && strpos('Apache', $_SERVER['SERVER_SOFTWARE']) !== false) {
452 1
            if (!function_exists('apache_get_modules')) {
453
                $app->addWarning('mod_rewrite が有効になっているか不明です。', 'install');
454
            } elseif (!in_array('mod_rewrite', apache_get_modules())) {
455
                $app->addDanger('[必須] '.'mod_rewriteを有効にしてください。', 'install');
456
            }
457
        } elseif (isset($_SERVER['SERVER_SOFTWARE']) && strpos('Microsoft-IIS',
0 ignored issues
show
Unused Code introduced by
This elseif statement is empty, and could be removed.

This check looks for the bodies of elseif statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These elseif bodies can be removed. If you have an empty elseif but statements in the else branch, consider inverting the condition.

Loading history...
458 1
                $_SERVER['SERVER_SOFTWARE']) !== false
459 1
        ) {
460
            // iis
461
        } elseif (isset($_SERVER['SERVER_SOFTWARE']) && strpos('nginx', $_SERVER['SERVER_SOFTWARE']) !== false) {
0 ignored issues
show
Unused Code introduced by
This elseif statement is empty, and could be removed.

This check looks for the bodies of elseif statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These elseif bodies can be removed. If you have an empty elseif but statements in the else branch, consider inverting the condition.

Loading history...
462 1
            // nginx
463
        }
464
    }
465
466
    private function createConnection(array $params)
467 1
    {
468
        $conn = DriverManager::getConnection($params);
469 1
        $conn->ping();
470 1
471
        return $conn;
472 1
    }
473
474
    private function createEntityManager(Connection $conn)
475
    {
476
        $paths = [
477
            $this->rootDir.'/src/Eccube/Entity',
478
            $this->rootDir.'/app/Acme/Entity',
479
        ];
480
        $config = Setup::createAnnotationMetadataConfiguration($paths, true, null, null, false);
481
        $em = EntityManager::create($conn, $config);
482
483
        return $em;
484
    }
485
486 View Code Duplication
    private function createMigration(Connection $conn)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
487
    {
488
        $config = new Configuration($conn);
489
        $config->setMigrationsNamespace('DoctrineMigrations');
490
        $migrationDir = $this->rootDir.'/src/Eccube/Resource/doctrine/migration';
491
        $config->setMigrationsDirectory($migrationDir);
492
        $config->registerMigrationsFromDirectory($migrationDir);
493
494
        $migration = new Migration($config);
495
        $migration->setNoMigrationException(true);
496
497
        return $migration;
498
    }
499
500
    private function dropTables(EntityManager $em)
501
    {
502
        $metadatas = $em->getMetadataFactory()->getAllMetadata();
503
        $schemaTool = new SchemaTool($em);
504
        $schemaTool->dropSchema($metadatas);
505
        $em->getConnection()->executeQuery('DROP TABLE IF EXISTS doctrine_migration_versions');
506
    }
507
508
    private function createTables(EntityManager $em)
509
    {
510
        $metadatas = $em->getMetadataFactory()->getAllMetadata();
511
        $schemaTool = new SchemaTool($em);
512
        $schemaTool->createSchema($metadatas);
513
    }
514
515
    private function importCsv(EntityManager $em)
516
    {
517
        $loader = new \Eccube\Doctrine\Common\CsvDataFixtures\Loader();
518
        $loader->loadFromDirectory($this->rootDir.'/src/Eccube/Resource/doctrine/import_csv');
519
        $executer = new \Eccube\Doctrine\Common\CsvDataFixtures\Executor\DbalExecutor($em);
520
        $fixtures = $loader->getFixtures();
521
        $executer->execute($fixtures);
522
    }
523
524
    private function insert(Connection $conn, array $data)
525
    {
526
        $conn->beginTransaction();
527
        try {
528
            $config = array(
529
                'auth_type' => '',
530
                'auth_magic' => $data['auth_magic'],
531
                'password_hash_algos' => 'sha256',
532
            );
533
            $encoder = new PasswordEncoder($config);
534
            $salt = Str::random(32);
535
            $password = $encoder->encodePassword($data['login_pass'], $salt);
536
537
            $id = ('postgresql' === $conn->getDatabasePlatform()->getName())
538
                ? $conn->fetchColumn("select nextval('dtb_base_info_id_seq')")
539
                : null;
540
541
            $conn->insert('dtb_base_info', [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
542
                'id' => $id,
543
                'shop_name' => $data['shop_name'],
544
                'email01' => $data['email'],
545
                'email02' => $data['email'],
546
                'email03' => $data['email'],
547
                'email04' => $data['email'],
548
                'update_date' => new \DateTime(),
549
                'discriminator_type' => 'baseinfo'
550
            ], [
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 16 spaces, but found 12.
Loading history...
introduced by
Add a comma after each item in a multi-line array
Loading history...
551
                'update_date' => \Doctrine\DBAL\Types\Type::DATETIME
552
            ]);
553
554
            $member_id = ('postgresql' === $conn->getDatabasePlatform()->getName())
555
                ? $conn->fetchColumn("select nextval('dtb_member_member_id_seq')")
556
                : null;
557
558
            $conn->insert('dtb_member', [
0 ignored issues
show
introduced by
Add a comma after each item in a multi-line array
Loading history...
559
                'member_id' => $member_id,
560
                'login_id' => $data['login_id'],
561
                'password' => $password,
562
                'salt' => $salt,
563
                'work' => 1,
564
                'authority' => 0,
565
                'creator_id' => 1,
566
                'rank' => 1,
567
                'update_date' => new \DateTime(),
568
                'create_date' => new \DateTime(),
569
                'name' => '管理者',
570
                'department' => 'EC-CUBE SHOP',
571
                'discriminator_type' => 'member'
572
            ], [
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 16 spaces, but found 12.
Loading history...
573
                'update_date' => Type::DATETIME,
574
                'create_date' => Type::DATETIME,
575
            ]);
576
            $conn->commit();
577
        } catch (\Exception $e) {
578
            $conn->rollback();
579
            throw $e;
580
        }
581
    }
582
583
    private function update(Connection $conn, array $data)
584
    {
585
        $conn->beginTransaction();
586
        try {
587
            $config = array(
588
                'auth_type' => '',
589
                'auth_magic' => $data['auth_magic'],
590
                'password_hash_algos' => 'sha256',
591
            );
592
            $encoder = new PasswordEncoder($config);
593
            $salt = Str::random(32);
594
            $stmt = $conn->prepare("SELECT member_id FROM dtb_member WHERE login_id = :login_id;");
595
            $stmt->execute([':login_id' => $data['login_id']]);
596
            $row = $stmt->fetch();
597
            $password = $encoder->encodePassword($data['login_pass'], $salt);
598
            if ($row) {
599
                // 同一の管理者IDであればパスワードのみ更新
600
                $sth = $conn->prepare("UPDATE dtb_member set password = :password, salt = :salt, update_date = current_timestamp WHERE login_id = :login_id;");
601
                $sth->execute([
602
                    ':password' => $password,
603
                    ':salt' => $salt,
604
                    ':login_id' => $data['login_id'],
605
                ]);
606
            } else {
607
                // 新しい管理者IDが入力されたらinsert
608
                $sth = $conn->prepare("INSERT INTO dtb_member (login_id, password, salt, work, del_flg, authority, creator_id, rank, update_date, create_date,name,department,discriminator_type) VALUES (:login_id, :password , :salt , '1', '0', '0', '1', '1', current_timestamp, current_timestamp,'管理者','EC-CUBE SHOP', 'member');");
609
                $sth->execute([
610
                    ':login_id' => $data['login_id'],
611
                    ':password' => $password,
612
                    ':salt' => $salt,
613
                ]);
614
            }
615
            $stmt = $conn->prepare('UPDATE dtb_base_info set
616
                shop_name = :shop_name,
617
                email01 = :admin_mail,
618
                email02 = :admin_mail,
619
                email03 = :admin_mail,
620
                email04 = :admin_mail,
621
                update_date = current_timestamp
622
            WHERE id = 1;');
623
            $stmt->execute(array(
624
                ':shop_name' => $data['shop_name'],
625
                ':admin_mail' => $data['email'],
626
            ));
627
            $stmt->commit();
0 ignored issues
show
Bug introduced by
The method commit() does not seem to exist on object<Doctrine\DBAL\Driver\Statement>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
628
        } catch (\Exception $e) {
629
            $stmt->rollback();
0 ignored issues
show
Bug introduced by
The variable $stmt does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The method rollback() does not seem to exist on object<Doctrine\DBAL\Driver\Statement>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
630
            throw $e;
631
        }
632
    }
633
634
    private function migrate(Migration $migration)
635
    {
636
        try {
637
            // nullを渡すと最新バージョンまでマイグレートする
638
            $migration->migrate(null, false);
639
        } catch (MigrationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
Coding Style introduced by
Blank line found at start of control structure
Loading history...
640
641
        }
642
    }
643
644
    private function copyConfigFiles()
645
    {
646
        $from = $this->configDistDir;
647
        $to = $this->configDir;
648
        $fs = new \Symfony\Component\Filesystem\Filesystem();
649
        $fs->mirror($from, $to, null, ['override' => true]);
650
    }
651
652
    private function replaceConfigFiles($data, $updateAuthMagic = true)
653
    {
654
        $values['ECCUBE_INSTALL'] = 1;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$values was never initialized. Although not strictly required by PHP, it is generally a good practice to add $values = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
655
        $values['ECCUBE_ROOT_URLPATH'] = $data['root_urlpath'];
656
657
        if ($updateAuthMagic) {
658
            $values['ECCUBE_AUTH_MAGIC'] = Str::random(32);
659
        } else {
660
            if (empty($values['ECCUBE_AUTH_MAGIC'])) {
661
                $values['ECCUBE_AUTH_MAGIC'] = Str::random(32);
662
            }
663
        }
664
        if (isset($data['force_ssl'])) {
665
            $values['ECCUBE_FORCE_SSL'] = $data['force_ssl'];
666
        }
667
        if (isset($data['admin_dir'])) {
668
            $values['ECCUBE_ADMIN_ROUTE'] = $data['admin_dir'];
669
        }
670
        if (isset($data['database'])) {
671
            $values['ECCUBE_DB_DEFAULT'] = str_replace('pdo_', '', $data['database']);
672
        }
673
        if (isset($data['database_host'])) {
674
            $values['ECCUBE_DB_HOST'] = $data['database_host'];
675
        }
676
        if (isset($data['database_port'])) {
677
            $values['ECCUBE_DB_PORT'] = $data['database_port'];
678
        }
679
        if (isset($data['database_name'])) {
680
            $values['ECCUBE_DB_DATABASE'] = $data['database_name'];
681
        }
682
        if (isset($data['database_user'])) {
683
            $values['ECCUBE_DB_USERNAME'] = $data['database_user'];
684
        }
685
        if (isset($data['database_password'])) {
686
            $values['ECCUBE_DB_PASSWORD'] = $data['database_password'];
687
        }
688
        if (isset($data['mail_backend'])) {
689
            $values['ECCUBE_MAIL_TRANSPORT'] = $data['mail_backend'];
690
        }
691
        if (isset($data['smtp_host'])) {
692
            $values['ECCUBE_MAIL_HOST'] = $data['smtp_host'];
693
        }
694
        if (isset($data['smtp_port'])) {
695
            $values['ECCUBE_MAIL_PORT'] = $data['smtp_port'];
696
        }
697
        if (isset($data['smtp_username'])) {
698
            $values['ECCUBE_MAIL_USERNAME'] = $data['smtp_username'];
699
        }
700
        if (isset($data['smtp_password'])) {
701
            $values['ECCUBE_MAIL_PASSWORD'] = $data['smtp_password'];
702
        }
703
        if (isset($data['admin_allow_hosts'])) {
704
            $values['ECCUBE_ADMIN_ALLOW_HOSTS'] = $data['admin_allow_hosts'];
705
        }
706
        if (isset($data['admin_allow_hosts'])) {
707
            $hosts = Str::convertLineFeed($data['admin_allow_hosts']);
708
            if ($hosts) {
709
                $values['ECCUBE_ADMIN_ALLOW_HOSTS'] = explode("\n", $hosts);
710
            }
711
        }
712
        if (isset($data['trusted_proxies'])) {
713
            $proxies = Str::convertLineFeed($data['trusted_proxies']);
714
            if ($proxies) {
715
                $proxies = explode("\n", $proxies);
716
                // ループバックアドレスを含める
717
                $values['ECCUBE_TRUSTED_PROXIES'] = array_merge($proxies, ['127.0.0.1/8', '::1']);
718
            }
719
        }
720
        if (isset($data['ECCUBE_trusted_proxies_connection_only']) && $data['trusted_proxies_connection_only']) {
721
            // ループバックアドレスを含める
722
            $values['ECCUBE_TRUSTED_PROXIES'] = array_merge($proxies, ['127.0.0.1/8', '::1']);
0 ignored issues
show
Bug introduced by
The variable $proxies does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
723
        }
724
725
        foreach ($values as &$value) {
726 View Code Duplication
            if (is_bool($value)
727
                || is_null($value)
728
                || is_array($value)
729
                || is_numeric($value)
730
            ) {
731
                $value = var_export($value, true);
732
            } else {
733
                $value = "'".$value."'";
734
            }
735
        }
736
737
        $dir = $this->configDir;
738
        $files = [
739
            $dir.'/config.php',
740
            $dir.'/database.php',
741
            $dir.'/mail.php',
742
            $dir.'/path.php',
743
        ];
744
745
        $patternFormat = "/(env\('%s'.*?\),)/s";
746
        $replacementFormat = "env('%s', %s),";
747
748
        foreach ($files as $file) {
749
            $content = file_get_contents($file);
750
            foreach ($values as $k => $v) {
751
                $pattern = sprintf($patternFormat, $k);
752
                $replace = sprintf($replacementFormat, $k, $v);
753
                $content = preg_replace($pattern, $replace, $content);
754
                if (is_null($content)) {
755
                    throw new \Exception();
756
                }
757
            }
758
            file_put_contents($file, $content);
759
        }
760
    }
761
762
    private function sendAppData($params)
763
    {
764
        $config = require $this->configDir.'/database.php';
765
        $conn = $this->createConnection($config['database']);
766
        $stmt = $conn->query('select version() as v');
767
        $version = '';
768
769
        foreach ($stmt as $row) {
770
            $version = $row['v'];
771
        }
772
773
        if ($config['database']['driver'] === 'pdo_mysql') {
774
            $db_ver = 'MySQL:'.$version;
775
        } else {
776
            $db_ver = $version;
777
        }
778
779
        $data = http_build_query(
780
            array(
781
                'site_url' => $params['http_url'],
782
                'shop_name' => $params['shop_name'],
783
                'cube_ver' => Constant::VERSION,
784
                'php_ver' => phpversion(),
785
                'db_ver' => $db_ver,
786
                'os_type' => php_uname(),
787
            )
788
        );
789
        $header = array(
790
            'Content-Type: application/x-www-form-urlencoded',
791
            'Content-Length: '.strlen($data),
792
        );
793
        $context = stream_context_create(
794
            array(
795
                'http' => array(
796
                    'method' => 'POST',
797
                    'header' => $header,
798
                    'content' => $data,
799
                ),
800
            )
801
        );
802
        file_get_contents('http://www.ec-cube.net/mall/use_site.php', false, $context);
803
804
        return $this;
805
    }
806
807
    /**
808
     * マイグレーション画面を表示する.
809
     *
810
     * @param InstallApplication $app
811
     * @param Request $request
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
812
     *
813
     * @return \Symfony\Component\HttpFoundation\Response
814
     */
815
    public function migration(InstallApplication $app, Request $request)
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...
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
816
    {
817
        return $app['twig']->render('migration.twig', array(
818
            'publicPath' => '..'.RELATIVE_PUBLIC_DIR_PATH.'/',
819
        ));
820
    }
821
822
    /**
823
     * インストール済プラグインの一覧を表示する.
824
     * プラグインがインストールされていない場合は, マイグレーション実行画面へリダイレクトする.
825
     *
826
     * @param InstallApplication $app
827
     * @param Request $request
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
828
     *
829
     * @return \Symfony\Component\HttpFoundation\Response
830
     */
831
    public function migration_plugin(InstallApplication $app, Request $request)
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...
Coding Style introduced by
Method name "InstallController::migration_plugin" is not in camel caps format
Loading history...
832
    {
833
        $eccube = \Eccube\Application::getInstance();
834
        $eccube->initialize();
835
        $eccube->boot();
836
        $pluginRepository = $eccube['orm.em']->getRepository('Eccube\Entity\Plugin');
837
        $Plugins = $pluginRepository->findBy(array('del_flg' => Constant::DISABLED));
838
        if (empty($Plugins)) {
839
            // インストール済プラグインがない場合はマイグレーション実行画面へリダイレクト.
840
            return $app->redirect($app->path('migration_end'));
841
        } else {
842
            return $app['twig']->render('migration_plugin.twig', array(
843
                'Plugins' => $Plugins,
844
                'version' => Constant::VERSION,
845
                'publicPath' => '..'.RELATIVE_PUBLIC_DIR_PATH.'/',
846
            ));
847
        }
848
    }
849
850
    /**
851
     * マイグレーションを実行し, 完了画面を表示させる
852
     *
853
     * @param InstallApplication $app
854
     * @param Request $request
0 ignored issues
show
introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
855
     *
856
     * @return \Symfony\Component\HttpFoundation\Response
857
     */
858
    public function migration_end(InstallApplication $app, Request $request)
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...
Coding Style introduced by
Method name "InstallController::migration_end" is not in camel caps format
Loading history...
859
    {
860
        $this->doMigrate();
0 ignored issues
show
Bug introduced by
The method doMigrate() does not exist on Eccube\Controller\Install\InstallController. Did you maybe mean migrate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
861
        $config_app = new \Eccube\Application(); // install用のappだとconfigが取れないので
862
        $config_app->initialize();
863
        $config_app->boot();
864
        \Eccube\Util\Cache::clear($config_app, true);
865
866
        return $app['twig']->render('migration_end.twig', array(
867
            'publicPath' => '..'.RELATIVE_PUBLIC_DIR_PATH.'/',
868
        ));
869
    }
870
}