EnvironmentChecker::log()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\EnvironmentCheck;
4
5
use Psr\Log\LoggerInterface;
6
use Psr\Log\LogLevel;
7
use SilverStripe\Control\Director;
8
use SilverStripe\Control\Email\Email;
9
use SilverStripe\Control\HTTPResponse;
10
use SilverStripe\Control\HTTPResponse_Exception;
11
use SilverStripe\Control\RequestHandler;
12
use SilverStripe\Core\Environment;
13
use SilverStripe\Core\Injector\Injector;
14
use SilverStripe\Dev\Deprecation;
15
use SilverStripe\Security\Member;
16
use SilverStripe\Security\Permission;
17
use SilverStripe\Security\Security;
18
19
/**
20
 * Provides an interface for checking the given EnvironmentCheckSuite.
21
 *
22
 * @package environmentcheck
23
 */
24
class EnvironmentChecker extends RequestHandler
25
{
26
    /**
27
     * @var array
28
     */
29
    private static $url_handlers = [
0 ignored issues
show
introduced by
The private property $url_handlers is not used, and could be removed.
Loading history...
30
        '' => 'index',
31
    ];
32
33
    /**
34
     * @var string
35
     */
36
    protected $checkSuiteName;
37
38
    /**
39
     * @var string
40
     */
41
    protected $title;
42
43
    /**
44
     * @var int
45
     */
46
    protected $errorCode = 500;
47
48
    /**
49
     * @var null|string
50
     */
51
    private static $to_email_address = null;
0 ignored issues
show
introduced by
The private property $to_email_address is not used, and could be removed.
Loading history...
52
53
    /**
54
     * @var null|string
55
     */
56
    private static $from_email_address = null;
0 ignored issues
show
introduced by
The private property $from_email_address is not used, and could be removed.
Loading history...
57
58
    /**
59
     * @var bool
60
     */
61
    private static $email_results = false;
0 ignored issues
show
introduced by
The private property $email_results is not used, and could be removed.
Loading history...
62
63
    /**
64
     * @var bool Log results via {@link \Psr\Log\LoggerInterface}
65
     */
66
    private static $log_results_warning = false;
0 ignored issues
show
introduced by
The private property $log_results_warning is not used, and could be removed.
Loading history...
67
68
    /**
69
     * @var string Maps to {@link \Psr\Log\LogLevel} levels. Defaults to LogLevel::WARNING
70
     */
71
    private static $log_results_warning_level = LogLevel::WARNING;
0 ignored issues
show
introduced by
The private property $log_results_warning_level is not used, and could be removed.
Loading history...
72
73
    /**
74
     * @var bool Log results via a {@link \Psr\Log\LoggerInterface}
75
     */
76
    private static $log_results_error = false;
0 ignored issues
show
introduced by
The private property $log_results_error is not used, and could be removed.
Loading history...
77
78
    /**
79
     * @var int Maps to {@link \Psr\Log\LogLevel} levels. Defaults to LogLevel::ALERT
80
     */
81
    private static $log_results_error_level = LogLevel::ALERT;
0 ignored issues
show
introduced by
The private property $log_results_error_level is not used, and could be removed.
Loading history...
82
83
    /**
84
     * @param string $checkSuiteName
85
     * @param string $title
86
     */
87
    public function __construct($checkSuiteName, $title)
88
    {
89
        parent::__construct();
90
91
        $this->checkSuiteName = $checkSuiteName;
92
        $this->title = $title;
93
    }
94
95
    /**
96
     * @param string $permission
97
     *
98
     * @throws HTTPResponse_Exception
99
     */
100
    public function init($permission = 'ADMIN')
101
    {
102
        // if the environment supports it, provide a basic auth challenge and see if it matches configured credentials
103
        if (Environment::getEnv('ENVCHECK_BASICAUTH_USERNAME')
104
            && Environment::getEnv('ENVCHECK_BASICAUTH_PASSWORD')
105
        ) {
106
            // Check that details are both provided, and match
107
            if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])
108
                || $_SERVER['PHP_AUTH_USER'] != Environment::getEnv('ENVCHECK_BASICAUTH_USERNAME')
109
                || $_SERVER['PHP_AUTH_PW'] != Environment::getEnv('ENVCHECK_BASICAUTH_PASSWORD')
110
            ) {
111
                // Fail check with basic auth challenge
112
                $response = new HTTPResponse(null, 401);
113
                $response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\"");
114
                throw new HTTPResponse_Exception($response);
115
            }
116
        } elseif (!$this->canAccess(null, $permission)) {
117
            // Fail check with silverstripe login challenge
118
            $result = Security::permissionFailure(
119
                $this,
0 ignored issues
show
Bug introduced by
$this of type SilverStripe\EnvironmentCheck\EnvironmentChecker is incompatible with the type SilverStripe\Control\Controller expected by parameter $controller of SilverStripe\Security\Se...ty::permissionFailure(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

119
                /** @scrutinizer ignore-type */ $this,
Loading history...
120
                "You must have the {$permission} permission to access this check"
121
            );
122
            throw new HTTPResponse_Exception($result);
123
        }
124
    }
125
126
    /**
127
     * Determine if the current member can access the environment checker
128
     *
129
     * @param null|int|Member $member
130
     * @param string          $permission
131
     * @return bool
132
     */
133
    public function canAccess($member = null, $permission = 'ADMIN')
134
    {
135
        if (!$member) {
136
            $member = Security::getCurrentUser();
137
        }
138
139
        // We allow access to this controller regardless of live-status or ADMIN permission only
140
        // if on CLI.  Access to this controller is always allowed in "dev-mode", or of the user is ADMIN.
141
        if (Director::isDev()
142
            || Director::is_cli()
143
            || empty($permission)
144
            || Permission::checkMember($member, $permission)
145
        ) {
146
            return true;
147
        }
148
149
        // Extended access checks.
150
        // "Veto" style, return NULL to abstain vote.
151
        $canExtended = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $canExtended is dead and can be removed.
Loading history...
152
        $results = $this->extend('canAccess', $member);
153
        if ($results && is_array($results)) {
154
            if (!min($results)) {
155
                return false;
156
            }
157
            return true;
158
        }
159
160
        return false;
161
    }
162
163
    /**
164
     * @return HTTPResponse
165
     */
166
    public function index()
167
    {
168
        $response = new HTTPResponse;
169
        $result = EnvironmentCheckSuite::inst($this->checkSuiteName)->run();
170
171
        if (!$result->ShouldPass()) {
172
            $response->setStatusCode($this->errorCode);
173
        }
174
175
        $resultText = $result->customise([
176
            'URL'       => Director::absoluteBaseURL(),
177
            'Title'     => $this->title,
178
            'Name'      => $this->checkSuiteName,
179
            'ErrorCode' => $this->errorCode,
180
        ])->renderWith(__CLASS__);
181
182
        if ($this->config()->get('email_results') && !$result->ShouldPass()) {
183
            $email = new Email(
184
                $this->config()->get('from_email_address'),
185
                $this->config()->get('to_email_address'),
186
                $this->title,
187
                $resultText
188
            );
189
            $email->send();
190
        }
191
192
        // Optionally log errors and warnings individually
193
        foreach ($result->Details() as $detail) {
194
            if ($this->config()->get('log_results_warning') && $detail->StatusCode == EnvironmentCheck::WARNING) {
195
                $this->log(
196
                    sprintf('EnvironmentChecker warning at "%s" check. Message: %s', $detail->Check, $detail->Message),
197
                    $this->config()->get('log_results_warning_level')
198
                );
199
            } elseif ($this->config()->get('log_results_error') && $detail->StatusCode == EnvironmentCheck::ERROR) {
200
                $this->log(
201
                    sprintf('EnvironmentChecker error at "%s" check. Message: %s', $detail->Check, $detail->Message),
202
                    $this->config()->get('log_results_error_level')
203
                );
204
            }
205
        }
206
207
        // output the result as JSON if requested
208
        if ($this->getRequest()->getExtension() == 'json'
209
            || strpos($this->getRequest()->getHeader('Accept'), 'application/json') !== false
210
        ) {
211
            $response->setBody($result->toJSON());
212
            $response->addHeader('Content-Type', 'application/json');
213
            return $response;
214
        }
215
216
        $response->setBody($resultText);
217
218
        return $response;
219
    }
220
221
    /**
222
     * Sends a log entry to the configured PSR-3 LoggerInterface
223
     *
224
     * @param string $message
225
     * @param int    $level
226
     */
227
    public function log($message, $level)
228
    {
229
        Injector::inst()->get(LoggerInterface::class)->log($level, $message);
230
    }
231
232
    /**
233
     * Set the HTTP status code that should be returned when there's an error.
234
     *
235
     * @param int $errorCode
236
     */
237
    public function setErrorCode($errorCode)
238
    {
239
        $this->errorCode = $errorCode;
240
    }
241
242
    /**
243
     * @deprecated
244
     * @param string $from
245
     */
246
    public static function set_from_email_address($from)
247
    {
248
        Deprecation::notice('2.0', 'Use config API instead');
249
        static::config()->set('from_email_address', $from);
250
    }
251
252
    /**
253
     * @deprecated
254
     * @return null|string
255
     */
256
    public static function get_from_email_address()
257
    {
258
        Deprecation::notice('2.0', 'Use config API instead');
259
        return static::config()->get('from_email_address');
260
    }
261
262
    /**
263
     * @deprecated
264
     * @param string $to
265
     */
266
    public static function set_to_email_address($to)
267
    {
268
        Deprecation::notice('2.0', 'Use config API instead');
269
        static::config()->set('to_email_address', $to);
270
    }
271
272
    /**
273
     * @deprecated
274
     * @return null|string
275
     */
276
    public static function get_to_email_address()
277
    {
278
        Deprecation::notice('2.0', 'Use config API instead');
279
        return static::config()->get('to_email_address');
280
    }
281
282
    /**
283
     * @deprecated
284
     * @param bool $results
285
     */
286
    public static function set_email_results($results)
287
    {
288
        Deprecation::notice('2.0', 'Use config API instead');
289
        static::config()->set('email_results', $results);
290
    }
291
292
    /**
293
     * @deprecated
294
     * @return bool
295
     */
296
    public static function get_email_results()
297
    {
298
        Deprecation::notice('2.0', 'Use config API instead');
299
        return static::config()->get('email_results');
300
    }
301
}
302