Issues (2739)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Eccube/Application.php (66 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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;
25
26
use Binfo\Silex\MobileDetectServiceProvider;
27
use Eccube\Application\ApplicationTrait;
28
use Eccube\Common\Constant;
29
use Eccube\Doctrine\ORM\Mapping\Driver\YamlDriver;
30
use Eccube\EventListener\TransactionListener;
31
use Symfony\Component\EventDispatcher\EventDispatcher;
32
use Symfony\Component\Finder\Finder;
33
use Symfony\Component\HttpFoundation\Request;
34
use Symfony\Component\HttpFoundation\Response;
35
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
36
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
37
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
38
use Symfony\Component\HttpKernel\KernelEvents;
39
use Symfony\Component\Yaml\Yaml;
40
41
class Application extends ApplicationTrait
0 ignored issues
show
Missing class doc comment
Loading history...
42
{
43
    protected static $instance;
44
45
    protected $initialized = false;
46
    protected $initializedPlugin = false;
47
    protected $testMode = false;
48
49 1233
    public static function getInstance(array $values = array())
0 ignored issues
show
Missing function doc comment
Loading history...
50
    {
51 1233
        if (!is_object(self::$instance)) {
52 1228
            self::$instance = new Application($values);
53
        }
54
55 1233
        return self::$instance;
56
    }
57
58 1229
    public static function clearInstance()
0 ignored issues
show
Missing function doc comment
Loading history...
59
    {
60 1229
        self::$instance = null;
61
    }
62
63
    final public function __clone()
0 ignored issues
show
Missing function doc comment
Loading history...
64
    {
65
        throw new \Exception('Clone is not allowed against '.get_class($this));
66
    }
67
68 1233
    public function __construct(array $values = array())
0 ignored issues
show
Missing function doc comment
Loading history...
69
    {
70 1233
        parent::__construct($values);
71
72 1233
        if (is_null(self::$instance)) {
73 1229
            self::$instance = $this;
74
        }
75
76
        // load config
77 1233
        $this->initConfig();
78
79
        // init monolog
80 1233
        $this->initLogger();
81
    }
82
83
    /**
84
     * Application::runが実行されているか親クラスのプロパティから判定
85
     *
86
     * @return bool
87
     */
88 1233
    public function isBooted()
89
    {
90 1233
        return $this->booted;
91
    }
92
93 1233
    public function initConfig()
0 ignored issues
show
Missing function doc comment
Loading history...
94
    {
95
        // load config
96 1233
        $app = $this;
97
        $this['config'] = $this->share(function() use ($app) {
0 ignored issues
show
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
98 1233
            $configAll = array();
99 1233
            $app->parseConfig('constant', $configAll)
100 1233
                ->parseConfig('path', $configAll)
101 1233
                ->parseConfig('config', $configAll)
102 1233
                ->parseConfig('database', $configAll)
103 1233
                ->parseConfig('mail', $configAll)
104 1233
                ->parseConfig('log', $configAll)
105 1233
                ->parseConfig('nav', $configAll, true)
106 1233
                ->parseConfig('doctrine_cache', $configAll)
107 1233
                ->parseConfig('http_cache', $configAll)
108 1233
                ->parseConfig('session_handler', $configAll);
109
110 1233
            return $configAll;
111 1233
        });
112
    }
113
114 1234
    public function initLogger()
0 ignored issues
show
Missing function doc comment
Loading history...
115
    {
116 1234
        $app = $this;
117 1234
        $this->register(new ServiceProvider\LogServiceProvider($app));
0 ignored issues
show
The call to LogServiceProvider::__construct() has too many arguments starting with $app.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
118
    }
119
120 1230
    public function initialize()
0 ignored issues
show
Missing function doc comment
Loading history...
121
    {
122 1230
        if ($this->initialized) {
123 3
            return;
124
        }
125
126
        // init locale
127 1229
        $this->initLocale();
128
129
        // init session
130 1229
        if (!$this->isSessionStarted()) {
131 1229
            $this->initSession();
132
        }
133
134
        // init twig
135 1229
        $this->initRendering();
136
137
        // init provider
138 1229
        $this->register(new \Silex\Provider\HttpCacheServiceProvider(), array(
139 1229
            'http_cache.cache_dir' => __DIR__.'/../../app/cache/http/',
140
        ));
141 1229
        $this->register(new \Silex\Provider\HttpFragmentServiceProvider());
142 1229
        $this->register(new \Silex\Provider\UrlGeneratorServiceProvider());
143 1229
        $this->register(new \Silex\Provider\FormServiceProvider());
144 1229
        $this->register(new \Silex\Provider\SerializerServiceProvider());
145 1229
        $this->register(new \Silex\Provider\ValidatorServiceProvider());
146 1229
        $this->register(new MobileDetectServiceProvider());
147
148 1229
        $app = $this;
149
        $this->error(function (\Exception $e, $code) use ($app) {
150 20
            if ($app['debug']) {
151 20
                return;
152
            }
153
154
            switch ($code) {
155
                case 403:
156
                    $title = 'アクセスできません。';
157
                    $message = 'お探しのページはアクセスができない状況にあるか、移動もしくは削除された可能性があります。';
158
                    break;
159
                case 404:
160
                    $title = 'ページがみつかりません。';
161
                    $message = 'URLに間違いがないかご確認ください。';
162
                    break;
163
                default:
164
                    $title = 'システムエラーが発生しました。';
165
                    $message = '大変お手数ですが、サイト管理者までご連絡ください。';
166
                    break;
167
            }
168
169
            return $app->render('error.twig', array(
170
                'error_title' => $title,
171
                'error_message' => $message,
172
            ));
173 1229
        });
174
175
        // init mailer
176 1229
        $this->initMailer();
177
178
        // init doctrine orm
179 1229
        $this->initDoctrine();
180
181
        // Set up the DBAL connection now to check for a proper connection to the database.
182 1229
        $this->checkDatabaseConnection();
183
184
        // init security
185 1229
        $this->initSecurity();
186
187
        // init proxy
188 1229
        $this->initProxy();
189
190
        // init ec-cube service provider
191 1229
        $this->register(new ServiceProvider\EccubeServiceProvider());
192
193
        // mount controllers
194 1229
        $this->register(new \Silex\Provider\ServiceControllerServiceProvider());
195 1229
        $this->mount('', new ControllerProvider\FrontControllerProvider());
196 1229
        $this->mount('/'.trim($this['config']['admin_route'], '/').'/', new ControllerProvider\AdminControllerProvider());
197 1229
        Request::enableHttpMethodParameterOverride(); // PUTやDELETEできるようにする
198
199
        // add transaction listener
200 1229
        $this['dispatcher']->addSubscriber(new TransactionListener($this));
201
202
        // init http cache
203 1229
        $this->initCacheRequest();
204
205 1229
        $this->initialized = true;
206
    }
207
208 1229
    public function initLocale()
0 ignored issues
show
Missing function doc comment
Loading history...
209
    {
210
211
        // timezone
212 1229
        if (!empty($this['config']['timezone'])) {
213 1229
            date_default_timezone_set($this['config']['timezone']);
214
        }
215
216 1229
        $this->register(new \Silex\Provider\TranslationServiceProvider(), array(
217 1229
            'locale' => $this['config']['locale'],
218 1229
            'translator.cache_dir' => $this['debug'] ? null : $this['config']['root_dir'].'/app/cache/translator',
219
        ));
220
        $this['translator'] = $this->share($this->extend('translator', function ($translator, \Silex\Application $app) {
221 868
            $translator->addLoader('yaml', new \Symfony\Component\Translation\Loader\YamlFileLoader());
222
223 868
            $file = __DIR__.'/Resource/locale/validator.'.$app['locale'].'.yml';
224 868
            if (file_exists($file)) {
225 868
                $translator->addResource('yaml', $file, $app['locale'], 'validators');
226
            }
227
228 868
            $file = __DIR__.'/Resource/locale/message.'.$app['locale'].'.yml';
229 868
            if (file_exists($file)) {
230 868
                $translator->addResource('yaml', $file, $app['locale']);
231
            }
232
233 868
            return $translator;
234 1229
        }));
235
    }
236
237 1229
    public function initSession()
0 ignored issues
show
Missing function doc comment
Loading history...
238
    {
239 1229
        $this->register(new \Silex\Provider\SessionServiceProvider(), array(
240 1229
            'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
241
            'session.storage.options' => array(
242 1229
                'name' => $this['config']['cookie_name'],
243 1229
                'cookie_path' => $this['config']['root_urlpath'] ?: '/',
244 1229
                'cookie_secure' => $this['config']['force_ssl'],
245 1229
                'cookie_lifetime' => $this['config']['cookie_lifetime'],
246
                'cookie_httponly' => true,
247
                // cookie_domainは指定しない
248
                // http://blog.tokumaru.org/2011/10/cookiedomain.html
249
            ),
250
        ));
251
252 1229
        $options = $this['config']['session_handler'];
253
254 1229
        if ($options['enabled']) {
255
            // @see http://silex.sensiolabs.org/doc/providers/session.html#custom-session-configurations
256
            $this['session.storage.handler'] = null;
257
            ini_set('session.save_handler', $options['save_handler']);
258
            ini_set('session.save_path', $options['save_path']);
259
        }
260
    }
261
262 1229
    public function initRendering()
0 ignored issues
show
Missing function doc comment
Loading history...
263
    {
264 1229
        $this->register(new \Silex\Provider\TwigServiceProvider(), array(
265 1229
            'twig.form.templates' => array('Form/form_layout.twig'),
266
        ));
267
        $this['twig'] = $this->share($this->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
268 610
            $twig->addExtension(new \Eccube\Twig\Extension\EccubeExtension($app));
269 610
            $twig->addExtension(new \Twig_Extension_StringLoader());
270
271 610
            return $twig;
272 1229
        }));
273
274
        $this->before(function (Request $request, \Silex\Application $app) {
275 599
            $app['admin'] = false;
276 599
            $app['front'] = false;
277 599
            $pathinfo = rawurldecode($request->getPathInfo());
278 599
            if (strpos($pathinfo, '/'.trim($app['config']['admin_route'], '/').'/') === 0) {
279 330
                $app['admin'] = true;
280
            } else {
281 271
                $app['front'] = true;
282
            }
283
284
            // フロント or 管理画面ごとにtwigの探索パスを切り替える.
285
            $app['twig'] = $app->share($app->extend('twig', function (\Twig_Environment $twig, \Silex\Application $app) {
286 597
                $paths = array();
287
288
                // 互換性がないのでprofiler とproduction 時のcacheを分離する
289 597
                if (isset($app['profiler'])) {
290
                    $cacheBaseDir = __DIR__.'/../../app/cache/twig/profiler/';
291
                } else {
292 597
                    $cacheBaseDir = __DIR__.'/../../app/cache/twig/production/';
293
                }
294
295 597
                if ($app->isAdminRequest()) {
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Silex\Application as the method isAdminRequest() does only exist in the following sub-classes of Silex\Application: Eccube\Application, Eccube\Application\ApplicationTrait, Eccube\InstallApplication. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
296 330
                    if (file_exists(__DIR__.'/../../app/template/admin')) {
297 330
                        $paths[] = __DIR__.'/../../app/template/admin';
298
                    }
299 330
                    $paths[] = $app['config']['template_admin_realdir'];
300 330
                    $paths[] = __DIR__.'/../../app/Plugin';
301 330
                    $cache = $cacheBaseDir.'admin';
302
0 ignored issues
show
Blank line found at end of control structure
Loading history...
303
                } else {
304 269
                    if (file_exists($app['config']['template_realdir'])) {
305 269
                        $paths[] = $app['config']['template_realdir'];
306
                    }
307 269
                    $paths[] = $app['config']['template_default_realdir'];
308 269
                    $paths[] = __DIR__.'/../../app/Plugin';
309 269
                    $cache = $cacheBaseDir.$app['config']['template_code'];
310 269
                    $app['front'] = true;
311
                }
312 597
                $twig->setCache($cache);
313 597
                $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($paths));
314
315 597
                return $twig;
316 599
            }));
317
318
            // 管理画面のIP制限チェック.
319 599
            if ($app->isAdminRequest()) {
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class Silex\Application as the method isAdminRequest() does only exist in the following sub-classes of Silex\Application: Eccube\Application, Eccube\Application\ApplicationTrait, Eccube\InstallApplication. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
320
                // IP制限チェック
321 330
                $allowHost = $app['config']['admin_allow_host'];
322 330
                if (count($allowHost) > 0) {
323
                    if (array_search($app['request']->getClientIp(), $allowHost) === false) {
324
                        throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
325
                    }
326
                }
327
            }
328 1229
        }, self::EARLY_EVENT);
329
330
        // twigのグローバル変数を定義.
331 1229
        $app = $this;
332
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) use ($app) {
333
            // 未ログイン時にマイページや管理画面以下にアクセスするとSubRequestで実行されるため,
334
            // $event->isMasterRequest()ではなく、グローバル変数が初期化済かどうかの判定を行う
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
335 597
            if (isset($app['twig_global_initialized']) && $app['twig_global_initialized'] === true) {
336 226
                return;
337
            }
338
            // ショップ基本情報
339 597
            $BaseInfo = $app['eccube.repository.base_info']->get();
340 597
            $app['twig']->addGlobal('BaseInfo', $BaseInfo);
341
342 597
            if ($app->isAdminRequest()) {
343
                // 管理画面
344
                // 管理画面メニュー
345 330
                $menus = array('', '', '');
346 330
                $app['twig']->addGlobal('menus', $menus);
347
348 330
                $Member = $app->user();
349 330
                if (is_object($Member)) {
350
                    // ログインしていれば管理者のロールを取得
351 324
                    $AuthorityRoles = $app['eccube.repository.authority_role']->findBy(array('Authority' => $Member->getAuthority()));
352
353 324
                    $roles = array();
354 324
                    foreach ($AuthorityRoles as $AuthorityRole) {
355
                        // 管理画面でメニュー制御するため相対パス全てをセット
356 324
                        $roles[] = $app['request']->getBaseUrl().'/'.$app['config']['admin_route'].$AuthorityRole->getDenyUrl();
357
                    }
358
359 330
                    $app['twig']->addGlobal('AuthorityRoles', $roles);
360
                }
361
0 ignored issues
show
Blank line found at end of control structure
Loading history...
362
            } else {
363
                // フロント画面
364 267
                $request = $event->getRequest();
365 267
                $route = $request->attributes->get('_route');
366 267
                $page = $route;
367
                // ユーザ作成画面
368 267
                if ($route === 'user_data') {
369 2
                    $params = $request->attributes->get('_route_params');
370 2
                    $route = $params['route'];
371
                    // プレビュー画面
372 265
                } elseif ($request->get('preview')) {
373
                    $route = 'preview';
374
                }
375
376
                try {
377 267
                    $DeviceType = $app['eccube.repository.master.device_type']
378 267
                        ->find(\Eccube\Entity\Master\DeviceType::DEVICE_TYPE_PC);
379 267
                    $PageLayout = $app['eccube.repository.page_layout']->getByUrl($DeviceType, $route, $page);
380 149
                } catch (\Doctrine\ORM\NoResultException $e) {
381 149
                    $PageLayout = $app['eccube.repository.page_layout']->newPageLayout($DeviceType);
382
                }
383
384 267
                $app['twig']->addGlobal('PageLayout', $PageLayout);
385 267
                $app['twig']->addGlobal('title', $PageLayout->getName());
386
            }
387
388 597
            $app['twig_global_initialized'] = true;
389 1229
        });
390
    }
391
392 1229
    public function initMailer()
0 ignored issues
show
Missing function doc comment
Loading history...
393
    {
394
395
        // メール送信時の文字エンコード指定(デフォルトはUTF-8)
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
396 1229
        if (isset($this['config']['mail']['charset_iso_2022_jp']) && is_bool($this['config']['mail']['charset_iso_2022_jp'])) {
397 1229
            if ($this['config']['mail']['charset_iso_2022_jp'] === true) {
398
                \Swift::init(function () {
399
                    \Swift_DependencyContainer::getInstance()
400
                        ->register('mime.qpheaderencoder')
401
                        ->asAliasOf('mime.base64headerencoder');
402
                    \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
403
                });
404
            }
405
        }
406
407 1229
        $this->register(new \Silex\Provider\SwiftmailerServiceProvider());
408 1229
        $this['swiftmailer.options'] = $this['config']['mail'];
409
410 1229
        if (isset($this['config']['mail']['use_spool']) && is_bool($this['config']['mail']['use_spool'])) {
411 1229
            $this['swiftmailer.use_spool'] = $this['config']['mail']['use_spool'];
412
        }
413
        // デフォルトはsmtpを使用
414 1229
        $transport = $this['config']['mail']['transport'];
415 1229
        if ($transport == 'sendmail') {
416
            $this['swiftmailer.transport'] = \Swift_SendmailTransport::newInstance();
417 1229
        } elseif ($transport == 'mail') {
418
            $this['swiftmailer.transport'] = \Swift_MailTransport::newInstance();
419
        }
420
    }
421
422 1229
    public function initDoctrine()
0 ignored issues
show
Missing function doc comment
Loading history...
423
    {
424 1229
        $this->register(new \Silex\Provider\DoctrineServiceProvider(), array(
0 ignored issues
show
Add a comma after each item in a multi-line array
Loading history...
425
            'dbs.options' => array(
0 ignored issues
show
Add a comma after each item in a multi-line array
Loading history...
426 1229
                'default' => $this['config']['database']
427
            )));
0 ignored issues
show
This line of the multi-line function call does not seem to be indented correctly. Expected 8 spaces, but found 12.
Loading history...
428 1229
        $this->register(new \Saxulum\DoctrineOrmManagerRegistry\Silex\Provider\DoctrineOrmManagerRegistryProvider());
429
430
        // プラグインのmetadata定義を合わせて行う.
431 1229
        $pluginConfigs = $this->getPluginConfigAll();
432 1229
        $ormMappings = array();
433 1229
        $ormMappings[] = array(
434
            'type' => 'yml',
435
            'namespace' => 'Eccube\Entity',
436
            'path' => array(
437
                __DIR__.'/Resource/doctrine',
438
                __DIR__.'/Resource/doctrine/master',
439
            ),
440
        );
441
442 1229
        foreach ($pluginConfigs as $code) {
443 140
            $config = $code['config'];
444
            // Doctrine Extend
445 140
            if (isset($config['orm.path']) && is_array($config['orm.path'])) {
446
                $paths = array();
447
                foreach ($config['orm.path'] as $path) {
448
                    $paths[] = $this['config']['plugin_realdir'].'/'.$config['code'].$path;
449
                }
450
                $ormMappings[] = array(
451
                    'type' => 'yml',
452
                    'namespace' => 'Plugin\\'.$config['code'].'\\Entity',
453 1229
                    'path' => $paths,
454
                );
455
            }
456
        }
457
458
        $options = array(
0 ignored issues
show
Add a comma after each item in a multi-line array
Loading history...
459 1229
            'mappings' => $ormMappings
460
        );
461
462 1229
        if (!$this['debug']) {
463
            $cacheDrivers = array();
464
            if (array_key_exists('doctrine_cache', $this['config'])) {
465
                $cacheDrivers = $this['config']['doctrine_cache'];
466
            }
467
468
            if (array_key_exists('metadata_cache', $cacheDrivers)) {
469
                $options['metadata_cache'] = $cacheDrivers['metadata_cache'];
470
            }
471
            if (array_key_exists('query_cache', $cacheDrivers)) {
472
                $options['query_cache'] = $cacheDrivers['query_cache'];
473
            }
474
            if (array_key_exists('result_cache', $cacheDrivers)) {
475
                $options['result_cache'] = $cacheDrivers['result_cache'];
476
            }
477
            if (array_key_exists('hydration_cache', $cacheDrivers)) {
478
                $options['hydration_cache'] = $cacheDrivers['hydration_cache'];
479
            }
480
        }
481
482 1229
        $this->register(new \Dflydev\Silex\Provider\DoctrineOrm\DoctrineOrmServiceProvider(), array(
483 1229
            'orm.proxies_dir' => __DIR__.'/../../app/cache/doctrine/proxies',
484 1229
            'orm.em.options' => $options,
485
            'orm.custom.functions.string' => array(
486
                'NORMALIZE' => 'Eccube\Doctrine\ORM\Query\Normalize',
487
            ),
488
            'orm.custom.functions.numeric' => array(
489
                'EXTRACT' => 'Eccube\Doctrine\ORM\Query\Extract',
490
            ),
491
        ));
492
493
        /**
494
         * YamlDriverのPHP7対応. Doctrine2.4で修正されれば不要.
495
         * @see https://github.com/EC-CUBE/ec-cube/issues/1338
496
         */
497 1229
        $config = $this['orm.em']->getConfiguration();
498
        /** @var $driver \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain */
499 1229
        $chain = $config->getMetadataDriverImpl();
500
        // $ormMappingsの1要素ごとにDriverが生成されている.
501 1229
        $drivers = $chain->getDrivers();
502 1229
        foreach ($drivers as $namespace => $oldDriver) {
503
            /** @var $newDriver \Eccube\Doctrine\ORM\Mapping\Driver\YamlDriver */
504 1229
            $newDriver = new YamlDriver($oldDriver->getLocator());
505
            // 修正したDriverに差し替える. メソッド名はaddだけど実際はsetしてる.
506 1229
            $chain->addDriver($newDriver, $namespace);
507
        }
508
    }
509
510 1230
    public function initSecurity()
0 ignored issues
show
Missing function doc comment
Loading history...
511
    {
512 1229
        $this->register(new \Silex\Provider\SecurityServiceProvider());
513 1229
        $this->register(new \Silex\Provider\RememberMeServiceProvider());
514
515 1229
        $this['security.firewalls'] = array(
516
            'admin' => array(
517 1229
                'pattern' => "^/{$this['config']['admin_route']}/",
518
                'form' => array(
519 1229
                    'login_path' => "/{$this['config']['admin_route']}/login",
520 1229
                    'check_path' => "/{$this['config']['admin_route']}/login_check",
521 1229
                    'username_parameter' => 'login_id',
522 1229
                    'password_parameter' => 'password',
523
                    'with_csrf' => true,
524
                    'use_forward' => true,
525 1229
                    'default_target_path' => "/{$this['config']['admin_route']}",
526
                ),
527
                'logout' => array(
528 1229
                    'logout_path' => "/{$this['config']['admin_route']}/logout",
529 1229
                    'target_url' => "/{$this['config']['admin_route']}/",
530
                ),
531 1229
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Member'),
532
                'anonymous' => true,
533 1229
            ),
534
            'customer' => array(
535 1229
                'pattern' => '^/',
536
                'form' => array(
537
                    'login_path' => '/mypage/login',
538
                    'check_path' => '/login_check',
539
                    'username_parameter' => 'login_email',
540
                    'password_parameter' => 'login_pass',
541
                    'with_csrf' => true,
542
                    'use_forward' => true,
543
                ),
544
                'logout' => array(
545
                    'logout_path' => '/logout',
546
                    'target_url' => '/',
547
                ),
548
                'remember_me' => array(
549 1229
                    'key' => sha1($this['config']['auth_magic']),
550 1229
                    'name' => $this['config']['cookie_name'].'_rememberme',
551
                    // lifetimeはデフォルトの1年間にする
552
                    // 'lifetime' => $this['config']['cookie_lifetime'],
0 ignored issues
show
Unused Code Comprehensibility introduced by
77% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
553 1229
                    'path' => $this['config']['root_urlpath'] ?: '/',
554 1229
                    'secure' => $this['config']['force_ssl'],
555
                    'httponly' => true,
556
                    'always_remember_me' => false,
557 1229
                    'remember_me_parameter' => 'login_memory',
558
                ),
559 1229
                'users' => $this['orm.em']->getRepository('Eccube\Entity\Customer'),
560
                'anonymous' => true,
561
            ),
562
        );
563
564 1229
        $channel = null;
565
        // 強制SSL
566 1229
        if ($this['config']['force_ssl'] == \Eccube\Common\Constant::ENABLED) {
567
            $channel = "https";
568
        }
569
570 1229
        $this['security.access_rules'] = array(
571 1229
            array("^/{$this['config']['admin_route']}/login", 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
572 1229
            array("^/{$this['config']['admin_route']}/", 'ROLE_ADMIN', $channel),
573 1229
            array('^/mypage/login', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
574 1229
            array('^/mypage/withdraw_complete', 'IS_AUTHENTICATED_ANONYMOUSLY', $channel),
575 1229
            array('^/mypage/change', 'IS_AUTHENTICATED_FULLY', $channel),
576 1229
            array('^/mypage', 'ROLE_USER', $channel),
577
        );
578
579
        $this['eccube.password_encoder'] = $this->share(function ($app) {
580 1229
            return new \Eccube\Security\Core\Encoder\PasswordEncoder($app['config']);
581 1229
        });
582
        $this['security.encoder_factory'] = $this->share(function ($app) {
583 1229
            return new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array(
584 1229
                'Eccube\Entity\Customer' => $app['eccube.password_encoder'],
585 1229
                'Eccube\Entity\Member' => $app['eccube.password_encoder'],
586
            ));
587 1229
        });
588
        $this['eccube.event_listner.security'] = $this->share(function ($app) {
589 1229
            return new \Eccube\EventListener\SecurityEventListener($app['orm.em']);
590 1229
        });
591
        $this['user'] = function ($app) {
592 1230
            $token = $app['security']->getToken();
593
594 1230
            return ($token !== null) ? $token->getUser() : null;
595
        };
596
597
        // ログイン時のイベントを設定.
598 1229
        $this['dispatcher']->addListener(\Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN, array($this['eccube.event_listner.security'], 'onInteractiveLogin'));
599
600
        // Voterの設定
601 1229
        $app = $this;
602
        $this['authority_voter'] = $this->share(function ($app) {
603 1229
            return new \Eccube\Security\Voter\AuthorityVoter($app);
604 1229
        });
605
606
        $app['security.voters'] = $app->extend('security.voters', function ($voters) use ($app) {
607 1229
            $voters[] = $app['authority_voter'];
608
609 1229
            return $voters;
610 1229
        });
611
612
        $this['security.access_manager'] = $this->share(function ($app) {
613 1229
            return new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager($app['security.voters'], 'unanimous');
614 1229
        });
615
616
    }
617
618
    /**
619
     * ロードバランサー、プロキシサーバの設定を行う
620
     */
621 1229
    public function initProxy()
622
    {
623 1229
        $config = $this['config'];
624 1229
        if (isset($config['trusted_proxies_connection_only']) && !empty($config['trusted_proxies_connection_only'])) {
625
            $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($config) {
626
                // サブリクエストのREMOTE_ADDRも動的に設定を行う必要があるため、KernelEvents::REQUESTを使用する
627
                Request::setTrustedProxies(array_merge(array($event->getRequest()->server->get('REMOTE_ADDR')), $config['trusted_proxies']));
628
            }, self::EARLY_EVENT);
629 1229 View Code Duplication
        } elseif (isset($config['trusted_proxies']) && !empty($config['trusted_proxies'])) {
0 ignored issues
show
This code seems to be duplicated across 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...
630
            Request::setTrustedProxies($config['trusted_proxies']);
631
        }
632
    }
633
634 1227
    public function initializePlugin()
0 ignored issues
show
Missing function doc comment
Loading history...
635
    {
636 1227
        if ($this->initializedPlugin) {
637
            return;
638
        }
639
640
        // setup event dispatcher
641 1227
        $this->initPluginEventDispatcher();
642
643
        // load plugin
644 1227
        $this->loadPlugin();
645
646 1227
        $this->initializedPlugin = true;
647
    }
648
649 1227
    public function initPluginEventDispatcher()
0 ignored issues
show
Missing function doc comment
Loading history...
650
    {
651
        // EventDispatcher
652
        $this['eccube.event.dispatcher'] = $this->share(function () {
653 612
            return new EventDispatcher();
654 1227
        });
655
656 1227
        $app = $this;
657
658
        // hook point
659
        $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($app) {
660 599
            if (!$event->isMasterRequest()) {
661 86
                return;
662
            }
663 599
            $hookpoint = 'eccube.event.app.before';
664 599
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
665 1227
        }, self::EARLY_EVENT);
666
667 View Code Duplication
        $this->on(KernelEvents::REQUEST, function (GetResponseEvent $event) use ($app) {
0 ignored issues
show
This code seems to be duplicated across 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...
668 598
            if (!$event->isMasterRequest()) {
669 86
                return;
670
            }
671 596
            $route = $event->getRequest()->attributes->get('_route');
672 596
            $hookpoint = "eccube.event.controller.$route.before";
673 596
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
674 1227
        });
675
676 View Code Duplication
        $this->on(KernelEvents::RESPONSE, function (FilterResponseEvent $event) use ($app) {
0 ignored issues
show
This code seems to be duplicated across 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...
677 585
            if (!$event->isMasterRequest()) {
678 86
                return;
679
            }
680 585
            $route = $event->getRequest()->attributes->get('_route');
681 585
            $hookpoint = "eccube.event.controller.$route.after";
682 585
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
683 1227
        });
684
685
        $this->on(KernelEvents::RESPONSE, function (FilterResponseEvent $event) use ($app) {
686 585
            if (!$event->isMasterRequest()) {
687 86
                return;
688
            }
689 585
            $hookpoint = 'eccube.event.app.after';
690 585
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
691 1227
        }, self::LATE_EVENT);
692
693
        $this->on(KernelEvents::TERMINATE, function (PostResponseEvent $event) use ($app) {
694 585
            $route = $event->getRequest()->attributes->get('_route');
695 585
            $hookpoint = "eccube.event.controller.$route.finish";
696 585
            $app['eccube.event.dispatcher']->dispatch($hookpoint, $event);
697 1227
        });
698
699
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
700 585
            if (!$event->isMasterRequest()) {
701 86
                return;
702
            }
703 585
            $route = $event->getRequest()->attributes->get('_route');
704 585
            $app['eccube.event.dispatcher']->dispatch('eccube.event.render.'.$route.'.before', $event);
705 1227
        });
706
707
        // Request Event
708 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::REQUEST, function (\Symfony\Component\HttpKernel\Event\GetResponseEvent $event) use ($app) {
0 ignored issues
show
This code seems to be duplicated across 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...
709
710 598
            if (!$event->isMasterRequest()) {
711 86
                return;
712
            }
713
714 598
            $route = $event->getRequest()->attributes->get('_route');
715
716 598
            if (is_null($route)) {
717
                return;
718
            }
719
720 598
            $app['monolog']->debug('KernelEvents::REQUEST '.$route);
721
722
            // 全体
723 598
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.request', $event);
724
725 598
            if (strpos($route, 'admin') === 0) {
726
                // 管理画面
727 330
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.request', $event);
728
            } else {
729
                // フロント画面
730 270
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.request', $event);
731
            }
732
733
            // ルーティング単位
734 598
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.request", $event);
735
736 1227
        }, 30); // Routing(32)が解決しし, 認証判定(8)が実行される前のタイミング.
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
737
738
        // Controller Event
739 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER, function (\Symfony\Component\HttpKernel\Event\FilterControllerEvent $event) use ($app) {
0 ignored issues
show
This code seems to be duplicated across 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...
740
741 597
            if (!$event->isMasterRequest()) {
742 86
                return;
743
            }
744
745 595
            $route = $event->getRequest()->attributes->get('_route');
746
747 595
            if (is_null($route)) {
748
                return;
749
            }
750
751 595
            $app['monolog']->debug('KernelEvents::CONTROLLER '.$route);
752
753
            // 全体
754 595
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.controller', $event);
755
756 595
            if (strpos($route, 'admin') === 0) {
757
                // 管理画面
758 328
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.controller', $event);
759
            } else {
760
                // フロント画面
761 269
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.controller', $event);
762
            }
763
764
            // ルーティング単位
765 595
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.controller", $event);
766 1227
        });
767
768
        // Response Event
769 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
0 ignored issues
show
This code seems to be duplicated across 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...
770 585
            if (!$event->isMasterRequest()) {
771 86
                return;
772
            }
773
774 585
            $route = $event->getRequest()->attributes->get('_route');
775
776 585
            if (is_null($route)) {
777 1
                return;
778
            }
779
780 584
            $app['monolog']->debug('KernelEvents::RESPONSE '.$route);
781
782
            // ルーティング単位
783 584
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.response", $event);
784
785 584
            if (strpos($route, 'admin') === 0) {
786
                // 管理画面
787 323
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.response', $event);
788
            } else {
789
                // フロント画面
790 263
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.response', $event);
791
            }
792
793
            // 全体
794 584
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.response', $event);
795 1227
        });
796
797
        // Exception Event
798 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::EXCEPTION, function (\Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event) use ($app) {
0 ignored issues
show
This code seems to be duplicated across 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...
799
800 22
            if (!$event->isMasterRequest()) {
801
                return;
802
            }
803
804 22
            $route = $event->getRequest()->attributes->get('_route');
805
806 22
            if (is_null($route)) {
807
                return;
808
            }
809
810 22
            $app['monolog']->debug('KernelEvents::EXCEPTION '.$route);
811
812
            // ルーティング単位
813 22
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.exception", $event);
814
815 22
            if (strpos($route, 'admin') === 0) {
816
                // 管理画面
817 9
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.exception', $event);
818
            } else {
819
                // フロント画面
820 13
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.exception', $event);
821
            }
822
823
            // 全体
824 22
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.exception', $event);
825 1227
        });
826
827
        // Terminate Event
828 View Code Duplication
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::TERMINATE, function (\Symfony\Component\HttpKernel\Event\PostResponseEvent $event) use ($app) {
0 ignored issues
show
This code seems to be duplicated across 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...
829
830 585
            $route = $event->getRequest()->attributes->get('_route');
831
832 585
            if (is_null($route)) {
833 1
                return;
834
            }
835
836 584
            $app['monolog']->debug('KernelEvents::TERMINATE '.$route);
837
838
            // ルーティング単位
839 584
            $app['eccube.event.dispatcher']->dispatch("eccube.event.route.{$route}.terminate", $event);
840
841 584
            if (strpos($route, 'admin') === 0) {
842
                // 管理画面
843 323
                $app['eccube.event.dispatcher']->dispatch('eccube.event.admin.terminate', $event);
844
            } else {
845
                // フロント画面
846 263
                $app['eccube.event.dispatcher']->dispatch('eccube.event.front.terminate', $event);
847
            }
848
849
            // 全体
850 584
            $app['eccube.event.dispatcher']->dispatch('eccube.event.app.terminate', $event);
851 1227
        });
852
    }
853
854 1227
    public function loadPlugin()
0 ignored issues
show
Missing function doc comment
Loading history...
855
    {
856
        // プラグインディレクトリを探索.
857 1227
        $basePath = $this['config']['plugin_realdir'];
858 1227
        $pluginConfigs = $this->getPluginConfigAll();
859
860
        // ハンドラ優先順位をdbから持ってきてハッシュテーブルを作成
861 1227
        $priorities = array();
862 1227
        $handlers = $this['orm.em']
863 1227
            ->getRepository('Eccube\Entity\PluginEventHandler')
864 1227
            ->getHandlers();
865
866 1227
        foreach ($handlers as $handler) {
867 1
            if ($handler->getPlugin()->getEnable() && !$handler->getPlugin()->getDelFlg()) {
0 ignored issues
show
Blank line found at start of control structure
Loading history...
868
869
                $priority = $handler->getPriority();
870
            } else {
871
                // Pluginがdisable、削除済みの場合、EventHandlerのPriorityを全て0とみなす
872 1
                $priority = \Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_DISABLED;
873
            }
874 1227
            $priorities[$handler->getPlugin()->getClassName()][$handler->getEvent()][$handler->getHandler()] = $priority;
875
        }
876
877
        // プラグインをロードする.
878
        // config.yml/event.ymlの定義に沿ってインスタンスの生成を行い, イベント設定を行う.
879 1227
        foreach ($pluginConfigs as $code => $pluginConfig) {
880
            // 正しい形式の pluginConfig のみ読み込む
881 142
            $path = $basePath.'/'.$code;
882
            try {
883 142
                $this['eccube.service.plugin']->checkPluginArchiveContent($path, $pluginConfig['config']);
884
            } catch (\Eccube\Exception\PluginException $e) {
885
                $this['monolog']->warning("Configuration file config.yml for plugin {$code} not found or is invalid. Skipping loading.", array(
0 ignored issues
show
Add a comma after each item in a multi-line array
Loading history...
886
                    'path' => $path,
887
                    'original-message' => $e->getMessage()
888
                ));
889
                continue;
890
            }
891 142
            $config = $pluginConfig['config'];
892
893 142
            $plugin = $this['orm.em']
894 142
                ->getRepository('Eccube\Entity\Plugin')
895 142
                ->findOneBy(array('code' => $config['code']));
896
897
            // const
898 142
            if (isset($config['const'])) {
899
                $this['config'] = $this->share($this->extend('config', function ($eccubeConfig) use ($config) {
900 2
                    $eccubeConfig[$config['code']] = array(
901 2
                        'const' => $config['const'],
902
                    );
903
904 2
                    return $eccubeConfig;
905 2
                }));
906
            }
907
908 142
            if ($plugin && $plugin->getEnable() == Constant::DISABLED) {
909
                // プラグインが無効化されていれば読み込まない
910 2
                continue;
911
            }
912
913
            // Type: Event
914 140
            if (isset($config['event'])) {
915 140
                $class = '\\Plugin\\'.$config['code'].'\\'.$config['event'];
916 140
                $eventExists = true;
917
918 140 View Code Duplication
                if (!class_exists($class)) {
0 ignored issues
show
This code seems to be duplicated across 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...
919
                    $this['monolog']->warning("Event class for plugin {$code} not exists.", array(
920
                        'class' => $class,
921
                    ));
922
                    $eventExists = false;
923
                }
924
925 140
                if ($eventExists && isset($config['event'])) {
0 ignored issues
show
Blank line found at start of control structure
Loading history...
926
927 140
                    $subscriber = new $class($this);
928
929 140
                    foreach ($pluginConfig['event'] as $event => $handlers) {
930 140
                        foreach ($handlers as $handler) {
931 140
                            if (!isset($priorities[$config['event']][$event][$handler[0]])) { // ハンドラテーブルに登録されていない(ソースにしか記述されていない)ハンドラは一番後ろにする
932 140
                                $priority = \Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_LATEST;
933
                            } else {
934
                                $priority = $priorities[$config['event']][$event][$handler[0]];
935
                            }
936
                            // 優先度が0のプラグインは登録しない
937 140
                            if (\Eccube\Entity\PluginEventHandler::EVENT_PRIORITY_DISABLED != $priority) {
938 140
                                $this['eccube.event.dispatcher']->addListener($event, array($subscriber, $handler[0]), $priority);
939
                            }
940
                        }
941
                    }
942
                }
943
            }
944
            // Type: ServiceProvider
945 140
            if (isset($config['service'])) {
946
                foreach ($config['service'] as $service) {
947
                    $class = '\\Plugin\\'.$config['code'].'\\ServiceProvider\\'.$service;
948 View Code Duplication
                    if (!class_exists($class)) {
0 ignored issues
show
This code seems to be duplicated across 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...
949
                        $this['monolog']->warning("Service provider class for plugin {$code} not exists.", array(
950
                            'class' => $class,
951
                        ));
952
                        continue;
953
                    }
954 1227
                    $this->register(new $class($this));
955
                }
956
            }
957
        }
958
    }
959
960
    /**
961
     * PHPUnit を実行中かどうかを設定する.
962
     *
963
     * @param boolean $testMode PHPUnit を実行中の場合 true
964
     */
965 1220
    public function setTestMode($testMode)
966
    {
967 1220
        $this->testMode = $testMode;
968
    }
969
970
    /**
971
     * PHPUnit を実行中かどうか.
972
     *
973
     * @return boolean PHPUnit を実行中の場合 true
974
     */
975 599
    public function isTestMode()
976
    {
977 599
        return $this->testMode;
978
    }
979
980
    /**
981
     *
982
     * データベースの接続を確認
983
     * 成功 : trueを返却
984
     * 失敗 : \Doctrine\DBAL\DBALExceptionエラーが発生( 接続に失敗した場合 )、エラー画面を表示しdie()
985
     * 備考 : app['debug']がtrueの際は処理を行わない
986
     *
987
     * @return boolean true
988
     *
989
     */
990 1229
    protected function checkDatabaseConnection()
991
    {
992 1229
        if ($this['debug']) {
993 1229
            return;
994
        }
995
        try {
996
            $this['db']->connect();
997
        } catch (\Doctrine\DBAL\DBALException $e) {
998
            $this['monolog']->error($e->getMessage());
999
            $this['twig.path'] = array(__DIR__.'/Resource/template/exception');
1000
            $html = $this['twig']->render('error.twig', array(
1001
                'error_title' => 'データーベース接続エラー',
1002
                'error_message' => 'データーベースを確認してください',
1003
            ));
1004
            $response = new Response();
1005
            $response->setContent($html);
1006
            $response->setStatusCode('500');
1007
            $response->headers->set('Content-Type', 'text/html');
1008
            $response->send();
1009
            die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method checkDatabaseConnection() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1010
        }
1011
1012
        return true;
1013
    }
1014
1015
    /**
1016
     * Config ファイルをパースし、連想配列を返します.
1017
     *
1018
     * $config_name.yml ファイルをパースし、連想配列を返します.
1019
     * $config_name.php が存在する場合は、 PHP ファイルに記述された連想配列を使用します。
1020
     *
1021
     * @param string $config_name Config 名称
0 ignored issues
show
Expected 2 spaces after parameter type; 1 found
Loading history...
1022
     * @param array $configAll Config の連想配列
0 ignored issues
show
Expected 3 spaces after parameter type; 1 found
Loading history...
Expected 3 spaces after parameter name; 1 found
Loading history...
1023
     * @param boolean $wrap_key Config の連想配列に config_name のキーを生成する場合 true, デフォルト false
0 ignored issues
show
Expected 4 spaces after parameter name; 1 found
Loading history...
1024
     * @param string $ymlPath config yaml を格納したディレクトリ
0 ignored issues
show
Expected 2 spaces after parameter type; 1 found
Loading history...
Expected 5 spaces after parameter name; 1 found
Loading history...
1025
     * @param string $distPath config yaml dist を格納したディレクトリ
0 ignored issues
show
Expected 2 spaces after parameter type; 1 found
Loading history...
Expected 4 spaces after parameter name; 1 found
Loading history...
1026
     * @return Application
1027
     */
1028 1233
    public function parseConfig($config_name, array &$configAll, $wrap_key = false, $ymlPath = null, $distPath = null)
0 ignored issues
show
Declare public methods first, then protected ones and finally private ones
Loading history...
1029
    {
1030 1233
        $ymlPath = $ymlPath ? $ymlPath : __DIR__.'/../../app/config/eccube';
1031 1233
        $distPath = $distPath ? $distPath : __DIR__.'/../../src/Eccube/Resource/config';
1032 1233
        $config = array();
1033 1233
        $config_php = $ymlPath.'/'.$config_name.'.php';
1034 1233
        if (!file_exists($config_php)) {
1035 1233
            $config_yml = $ymlPath.'/'.$config_name.'.yml';
1036 1233
            if (file_exists($config_yml)) {
1037 1233
                $config = Yaml::parse(file_get_contents($config_yml));
1038 1233
                $config = empty($config) ? array() : $config;
1039 1233 View Code Duplication
                if (isset($this['output_config_php']) && $this['output_config_php']) {
0 ignored issues
show
This code seems to be duplicated across 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...
1040 1233
                    file_put_contents($config_php, sprintf('<?php return %s', var_export($config, true)).';');
1041
                }
1042
            }
1043
        } else {
1044
            $config = require $config_php;
1045
        }
1046
1047 1233
        $config_dist = array();
1048 1233
        $config_php_dist = $distPath.'/'.$config_name.'.dist.php';
1049 1233
        if (!file_exists($config_php_dist)) {
1050 1233
            $config_yml_dist = $distPath.'/'.$config_name.'.yml.dist';
1051 1233
            if (file_exists($config_yml_dist)) {
1052 1233
                $config_dist = Yaml::parse(file_get_contents($config_yml_dist));
1053 1233 View Code Duplication
                if (isset($this['output_config_php']) && $this['output_config_php']) {
0 ignored issues
show
This code seems to be duplicated across 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...
1054 1233
                    file_put_contents($config_php_dist, sprintf('<?php return %s', var_export($config_dist, true)).';');
1055
                }
1056
            }
1057
        } else {
1058
            $config_dist = require $config_php_dist;
1059
        }
1060
1061 1233
        if ($wrap_key) {
1062 1233
            $configAll = array_replace_recursive($configAll, array($config_name => $config_dist), array($config_name => $config));
1063
        } else {
1064 1233
            $configAll = array_replace_recursive($configAll, $config_dist, $config);
1065
        }
1066
1067 1233
        return $this;
1068
    }
1069
1070
    /**
1071
     * セッションが開始されているかどうか.
1072
     *
1073
     * @return boolean セッションが開始済みの場合 true
1074
     * @link http://php.net/manual/ja/function.session-status.php#113468
1075
     */
1076 1229
    protected function isSessionStarted()
1077
    {
1078 1229
        if (php_sapi_name() !== 'cli') {
1079 1229
            if (version_compare(phpversion(), '5.4.0', '>=')) {
1080 1229
                return session_status() === PHP_SESSION_ACTIVE ? true : false;
1081
            } else {
1082
                return session_id() === '' ? false : true;
1083
            }
1084
        }
1085
1086
        return false;
1087
    }
1088
1089
    /**
1090
     * Http Cache対応
1091
     */
1092 1229
    protected function initCacheRequest()
1093
    {
1094
        // httpキャッシュが無効の場合はイベント設定を行わない.
1095 1229
        if (!$this['config']['http_cache']['enabled']) {
1096 1229
            return;
1097
        }
1098
1099
        $app = $this;
1100
1101
        // Response Event(http cache対応、event実行は一番遅く設定)
1102
        $this->on(\Symfony\Component\HttpKernel\KernelEvents::RESPONSE, function (\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event) use ($app) {
1103
1104
            if (!$event->isMasterRequest()) {
1105
                return;
1106
            }
1107
1108
            $request = $event->getRequest();
1109
            $response = $event->getResponse();
1110
1111
            $route = $request->attributes->get('_route');
1112
1113
            $etag = md5($response->getContent());
1114
1115
            if (strpos($route, 'admin') === 0) {
1116
                // 管理画面
1117
1118
                // 管理画面ではコンテンツの中身が変更された時点でキャッシュを更新し、キャッシュの適用範囲はprivateに設定
1119
                $response->setCache(array(
1120
                    'etag' => $etag,
1121
                    'private' => true,
1122
                ));
1123
1124
                if ($response->isNotModified($request)) {
1125
                    return $response;
1126
                }
1127
0 ignored issues
show
Blank line found at end of control structure
Loading history...
1128
            } else {
1129
                // フロント画面
1130
                $cacheRoute = $app['config']['http_cache']['route'];
1131
1132
                if (in_array($route, $cacheRoute) === true) {
1133
                    // キャッシュ対象となる画面lが含まれていた場合、キャッシュ化
1134
                    // max-ageを設定しているためExpiresは不要
1135
                    // Last-Modifiedだと比較する項目がないためETagで対応
1136
                    // max-ageを設定していた場合、contentの中身が変更されても変更されない
1137
1138
                    $age = $app['config']['http_cache']['age'];
1139
1140
                    $response->setCache(array(
1141
                        'etag' => $etag,
1142
                        'max_age' => $age,
1143
                        's_maxage' => $age,
1144
                        'public' => true,
1145
                    ));
1146
1147
                    if ($response->isNotModified($request)) {
1148
                        return $response;
1149
                    }
1150
                }
1151
            }
1152
1153
        }, -1024);
1154
    }
1155
1156
    /**
1157
     * すべてのプラグインの設定情報を返す.
1158
     *
1159
     * すべてのプラグインの config.yml 及び event.yml を読み込み、連想配列で返す.
1160
     * キャッシュファイルが存在する場合は、キャッシュを利用する.
1161
     * キャッシュファイルが存在しない場合は、キャッシュを生成する.
1162
     * $app['debug'] = true の場合は、キャッシュを利用しない.
1163
     *
1164
     * @return array
1165
     */
1166 1229
    public function getPluginConfigAll()
0 ignored issues
show
Declare public methods first, then protected ones and finally private ones
Loading history...
1167
    {
1168 1229
        if ($this['debug']) {
1169 1229
            return $this->parsePluginConfigs();
1170
        }
1171 1
        $pluginConfigCache = $this->getPluginConfigCacheFile();
1172 1
        if (file_exists($pluginConfigCache)) {
1173 1
            return require $pluginConfigCache;
1174
        }
1175 1
        if ($this->writePluginConfigCache($pluginConfigCache) === false) {
1176
            return $this->parsePluginConfigs();
1177
        } else {
1178 1
            return require $pluginConfigCache;
1179
        }
1180
    }
1181
1182
    /**
1183
     * プラグイン設定情報のキャッシュを書き込む.
1184
     *
1185
     * @param string $cacheFile
1186
     * @return int|boolean file_put_contents() の結果
1187
     */
1188 6
    public function writePluginConfigCache($cacheFile = null)
1189
    {
1190 6
        if (is_null($cacheFile)) {
1191 6
            $cacheFile = $this->getPluginConfigCacheFile();
1192
        }
1193 6
        $pluginConfigs = $this->parsePluginConfigs();
1194 6
        if (!file_exists($this['config']['plugin_temp_realdir'])) {
1195
            @mkdir($this['config']['plugin_temp_realdir']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1196
        }
1197 6
        $this['monolog']->debug("write plugin config cache", array($pluginConfigs));
1198 6
        return file_put_contents($cacheFile, sprintf('<?php return %s', var_export($pluginConfigs, true)).';');
0 ignored issues
show
Missing blank line before return statement
Loading history...
1199
    }
1200
1201
    /**
1202
     * プラグイン設定情報のキャッシュファイルを削除する.
1203
     *
1204
     * @return boolean
1205
     */
1206 9
    public function removePluginConfigCache()
1207
    {
1208 9
        $cacheFile = $this->getPluginConfigCacheFile();
1209 9
        if (file_exists($cacheFile)) {
1210 8
            $this['monolog']->debug("remove plugin config cache");
1211 8
            return unlink($cacheFile);
0 ignored issues
show
Missing blank line before return statement
Loading history...
1212
        }
1213 5
        return false;
0 ignored issues
show
Missing blank line before return statement
Loading history...
1214
    }
1215
1216
    /**
1217
     * プラグイン設定情報のキャッシュファイルパスを返す.
1218
     *
1219
     * @return string
1220
     */
1221 9
    public function getPluginConfigCacheFile()
1222
    {
1223 9
        return $this['config']['plugin_temp_realdir'].'/config_cache.php';
1224
    }
1225
1226
    /**
1227
     * プラグイン設定情報をパースし, 連想配列で返す.
1228
     *
1229
     * すべてのプラグインを探索し、 config.yml 及び event.yml をパースする.
1230
     * パースした情報を連想配列で返す.
1231
     *
1232
     * @return array
1233
     */
1234 1229
    public function parsePluginConfigs()
1235
    {
1236
1237 1229
        $finder = Finder::create()
1238 1229
            ->in($this['config']['plugin_realdir'])
1239 1229
            ->directories()
1240 1229
            ->depth(0);
1241 1229
        $finder->sortByName();
1242
1243 1229
        $pluginConfigs = array();
1244 1229
        foreach ($finder as $dir) {
1245 146
            $code = $dir->getBaseName();
1246 146
            if (!$code) {
1247
                //PHP5.3のgetBaseNameバグ対応
1248
                if (PHP_VERSION_ID < 50400) {
1249
                    $code = $dir->getFilename();
1250
                }
1251
            }
1252 146
            $file = $dir->getRealPath().'/config.yml';
1253 146
            $config = null;
0 ignored issues
show
$config 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...
1254 146 View Code Duplication
            if (file_exists($file)) {
0 ignored issues
show
This code seems to be duplicated across 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...
1255 146
                $config = Yaml::parse(file_get_contents($file));
1256
            } else {
1257
                $this['monolog']->warning("skip {$code} orm.path loading. config.yml not found.", array('path' => $file));
1258
                continue;
1259
            }
1260
1261 146
            $file = $dir->getRealPath().'/event.yml';
1262 146
            $event = null;
1263 146 View Code Duplication
            if (file_exists($file)) {
0 ignored issues
show
This code seems to be duplicated across 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...
1264 142
                $event = Yaml::parse(file_get_contents($file));
1265
            } else {
1266 4
                $this['monolog']->info("skip {$code} event.yml not found.", array('path' => $file));
1267
            }
1268 146
            if (!is_null($config)) {
1269 146
                $pluginConfigs[$code] = array(
0 ignored issues
show
Add a comma after each item in a multi-line array
Loading history...
1270 146
                    'config' => $config,
1271 146
                    'event' => $event
1272
                );
1273 1229
                $this['monolog']->debug("parse {$code} config", array($code => $pluginConfigs[$code]));
1274
            }
1275
        }
1276
1277 1229
        return $pluginConfigs;
1278
    }
1279
}
1280