Passed
Push — master ( 0208b2...1155ca )
by Robbie
09:03
created

Installer::error()   A

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 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Dev\Install;
4
5
use BadMethodCallException;
6
use Exception;
7
use SilverStripe\Control\Cookie;
8
use SilverStripe\Control\HTTPApplication;
9
use SilverStripe\Control\HTTPRequest;
10
use SilverStripe\Control\HTTPRequestBuilder;
11
use SilverStripe\Core\Convert;
12
use SilverStripe\Core\CoreKernel;
13
use SilverStripe\Core\EnvironmentLoader;
14
use SilverStripe\Core\Kernel;
15
use SilverStripe\Core\Path;
16
use SilverStripe\Core\Startup\ParameterConfirmationToken;
17
use SilverStripe\ORM\DatabaseAdmin;
18
use SilverStripe\Security\DefaultAdminService;
19
use SilverStripe\Security\Security;
20
21
/**
22
 * This installer doesn't use any of the fancy SilverStripe stuff in case it's unsupported.
23
 */
24
class Installer
25
{
26
    use InstallEnvironmentAware;
27
28
    /**
29
     * Errors during install
30
     *
31
     * @var array
32
     */
33
    protected $errors = [];
34
35
    /**
36
     * value='' attribute placeholder for password fields
37
     */
38
    const PASSWORD_PLACEHOLDER = '********';
39
40
    public function __construct($basePath = null)
41
    {
42
        $this->initBaseDir($basePath);
43
    }
44
45
    /**
46
     * Installer error
47
     *
48
     * @param string $message
49
     */
50
    protected function error($message = null)
51
    {
52
        $this->errors[] = $message;
53
    }
54
55
    protected function installHeader()
56
    {
57
        $clientPath = PUBLIC_DIR
58
            ? 'resources/vendor/silverstripe/framework/src/Dev/Install/client'
59
            : 'resources/silverstripe/framework/src/Dev/Install/client';
60
        ?>
61
        <html>
62
        <head>
63
            <meta charset="utf-8"/>
64
            <title>Installing SilverStripe...</title>
65
            <link rel="stylesheet" type="text/css" href="<?=$clientPath; ?>/styles/install.css"/>
66
            <script src="//code.jquery.com/jquery-1.7.2.min.js"></script>
67
        </head>
68
        <body>
69
        <div class="install-header">
70
            <div class="inner">
71
                <div class="brand">
72
                    <h1>SilverStripe</h1>
73
                </div>
74
            </div>
75
        </div>
76
77
        <div id="Navigation">&nbsp;</div>
78
        <div class="clear"><!-- --></div>
79
80
        <div class="main">
81
            <div class="inner">
82
                <h2>Installing SilverStripe...</h2>
83
84
                <p>I am now running through the installation steps (this should take about 30 seconds)</p>
85
86
                <p>If you receive a fatal error, refresh this page to continue the installation</p>
87
                <ul>
88
        <?php
89
    }
90
91
    public function install($config)
92
    {
93
        // Render header
94
        $this->installHeader();
95
        $isIIS = $this->isIIS();
96
        $isApache = $this->isApache();
97
        $projectDir = $this->getProjectDir();
98
        $projectSrcDir = $this->getProjectSrcDir();
99
100
        flush();
101
102
        // Send install stats
103
        if (!empty($config['stats'])) {
104
            $this->sendInstallStats($config);
105
        }
106
107
        // Cleanup _config.php
108
        $basePath = $this->getBaseDir();
109
        $appConfigPath = $basePath . "{$projectDir}/_config.php";
110
        if (file_exists($appConfigPath)) {
111
            // Truncate the contents of _config instead of deleting it - we can't re-create it because Windows handles
112
            // permissions slightly differently to UNIX based filesystems - it takes the permissions from the parent
113
            // directory instead of retaining them
114
            $fh = fopen($appConfigPath, 'wb');
115
            fclose($fh);
0 ignored issues
show
Bug introduced by
It seems like $fh can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

115
            fclose(/** @scrutinizer ignore-type */ $fh);
Loading history...
116
        }
117
118
        // Write all files
119
        $this->writeIndexPHP();
120
        $this->writeConfigPHP($config);
121
        $this->writeConfigYaml($config);
122
        $this->writeConfigEnv($config);
123
124
        // Write other stuff
125
        if (!$this->checkModuleExists('cms')) {
126
            $rootURLControllerPath = $basePath . "{$projectSrcDir}/RootURLController.php";
127
            $this->writeToFile($rootURLControllerPath, <<<PHP
128
<?php
129
130
use SilverStripe\\Control\\Controller;
131
132
class RootURLController extends Controller
133
{
134
    public function index()
135
    {
136
        echo "<html>Your site is now set up. Start adding controllers to app/src to get started.</html>";
137
    }
138
}
139
PHP
140
            );
141
        }
142
143
        // Write the appropriate web server configuration file for rewriting support
144
        if ($this->hasRewritingCapability()) {
145
            if ($isApache) {
146
                $this->createHtaccess();
147
            } elseif ($isIIS) {
148
                $this->createWebConfig();
149
            }
150
        }
151
152
        // Build request
153
        $request = HTTPRequestBuilder::createFromEnvironment();
154
155
        // Install kernel (fix to dev)
156
        $kernel = new CoreKernel(Path::normalise($basePath));
157
        $kernel->setEnvironment(Kernel::DEV);
158
        $app = new HTTPApplication($kernel);
159
160
        // Build db within HTTPApplication
161
        $app->execute($request, function (HTTPRequest $request) use ($config) {
162
            // Suppress cookie errors on install
163
            Cookie::config()->set('report_errors', false);
164
165
            // Start session and execute
166
            $request->getSession()->init($request);
167
168
            // Output status
169
            $this->statusMessage("Building database schema...");
170
171
            // Setup DB
172
            $dbAdmin = new DatabaseAdmin();
173
            $dbAdmin->setRequest($request);
174
            $dbAdmin->pushCurrent();
175
            $dbAdmin->doInit();
176
            $dbAdmin->doBuild(true);
177
178
            // Create default administrator user and group in database
179
            // (not using Security::setDefaultAdmin())
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% 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...
180
            $username = $config['admin']['username'];
181
            $password = $config['admin']['password'];
182
            $adminMember = DefaultAdminService::singleton()
183
                ->findOrCreateAdmin(
184
                    $username,
185
                    _t('SilverStripe\\Security\\DefaultAdminService.DefaultAdminFirstname', 'Default Admin')
186
                );
187
            $adminMember->Email = $username;
188
            $adminMember->Password = $password;
189
            $adminMember->PasswordEncryption = Security::config()->get('encryption_algorithm');
190
191
            try {
192
                $this->statusMessage('Creating default CMS admin account...');
193
                $adminMember->write();
194
            } catch (Exception $e) {
195
                $this->statusMessage(
196
                    sprintf('Warning: Default CMS admin account could not be created (error: %s)', $e->getMessage())
197
                );
198
            }
199
200
            $request->getSession()->set('username', $username);
201
            $request->getSession()->set('password', $password);
202
            $request->getSession()->save($request);
203
        }, true);
204
205
        // Check result of install
206
        if (!$this->errors) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->errors of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
207
            if (isset($_SERVER['HTTP_HOST']) && $this->hasRewritingCapability()) {
208
                $this->statusMessage("Checking that friendly URLs work...");
209
                $this->checkRewrite();
210
            } else {
211
                $token = new ParameterConfirmationToken('flush', $request);
212
                $params = http_build_query($token->params());
213
214
                $destinationURL = 'index.php/' .
215
                    ($this->checkModuleExists('cms') ? "home/successfullyinstalled?$params" : "?$params");
216
217
                echo <<<HTML
218
                <li>SilverStripe successfully installed; I am now redirecting you to your SilverStripe site...</li>
219
                <script>
220
                    setTimeout(function() {
221
                        window.location = "$destinationURL";
222
                    }, 2000);
223
                </script>
224
                <noscript>
225
                <li><a href="$destinationURL">Click here to access your site.</a></li>
226
                </noscript>
227
HTML;
228
            }
229
        } else {
230
            // Output all errors
231
            $this->statusMessage('Encountered ' . count($this->errors) . ' errors during install:');
232
            echo "<ul>";
233
            foreach ($this->errors as $error) {
234
                $this->statusMessage($error);
235
            }
236
            echo "</ul>";
237
            $this->statusMessage('Please <a href="install.php">Click here</a> to return to the installer.');
238
        }
239
240
        return $this->errors;
241
    }
242
243
    protected function writeIndexPHP()
244
    {
245
        $content = <<<'PHP'
246
<?php
247
248
use SilverStripe\Control\HTTPApplication;
249
use SilverStripe\Control\HTTPRequestBuilder;
250
use SilverStripe\Core\CoreKernel;
251
use SilverStripe\Core\Startup\ErrorControlChainMiddleware;
252
253
// Find autoload.php
254
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
255
    require __DIR__ . '/vendor/autoload.php';
256
} elseif (file_exists(__DIR__ . '/../vendor/autoload.php')) {
257
    require __DIR__ . '/../vendor/autoload.php';
258
} else {
259
    echo "autoload.php not found";
260
    die;
261
}
262
263
// Build request and detect flush
264
$request = HTTPRequestBuilder::createFromEnvironment();
265
266
// Default application
267
$kernel = new CoreKernel(BASE_PATH);
268
$app = new HTTPApplication($kernel);
269
$app->addMiddleware(new ErrorControlChainMiddleware($app));
270
$response = $app->handle($request);
271
$response->output();
272
PHP;
273
        $path = $this->getPublicDir() . 'index.php';
274
        $this->writeToFile($path, $content, true);
275
    }
276
277
    /**
278
     * Write all .env files
279
     *
280
     * @param $config
281
     */
282
    protected function writeConfigEnv($config)
283
    {
284
        if (!$config['usingEnv']) {
285
            return;
286
        }
287
288
        $path = $this->getBaseDir() . '.env';
289
        $vars = [];
290
291
        // Retain existing vars
292
        $env = new EnvironmentLoader();
293
        if (file_exists($path)) {
294
            $vars = $env->loadFile($path) ?: [];
295
        }
296
297
        // Set base URL
298
        if (!isset($vars['SS_BASE_URL']) && isset($_SERVER['HTTP_HOST'])) {
299
            $vars['SS_BASE_URL'] = 'http://' . $_SERVER['HTTP_HOST'] . BASE_URL;
300
        }
301
302
        // Set DB env
303
        if (empty($config['db']['database'])) {
304
            $vars['SS_DATABASE_CHOOSE_NAME'] = true;
305
        } else {
306
            $vars['SS_DATABASE_NAME'] = $config['db']['database'];
307
        }
308
        $vars['SS_DATABASE_CLASS'] = $config['db']['type'];
309
        if (isset($config['db']['server'])) {
310
            $vars['SS_DATABASE_SERVER'] = $config['db']['server'];
311
        }
312
        if (isset($config['db']['username'])) {
313
            $vars['SS_DATABASE_USERNAME'] = $config['db']['username'];
314
        }
315
        if (isset($config['db']['password'])) {
316
            $vars['SS_DATABASE_PASSWORD'] = $config['db']['password'];
317
        }
318
        if (isset($config['db']['path'])) {
319
            $vars['SS_DATABASE_PATH'] = $config['db']['path'];
320
            // sqlite compat
321
            $vars['SS_SQLITE_DATABASE_PATH'] = $config['db']['path'];
322
        }
323
        if (isset($config['db']['key'])) {
324
            $vars['SS_DATABASE_KEY'] = $config['db']['key'];
325
            // sqlite compat
326
            $vars['SS_SQLITE_DATABASE_KEY'] = $config['db']['key'];
327
        }
328
329
        // Write all env vars
330
        $lines = [
331
            '# Generated by SilverStripe Installer'
332
        ];
333
        ksort($vars);
334
        foreach ($vars as $key => $value) {
335
            $lines[] = $key . '="' . addcslashes($value, '"') . '"';
336
        }
337
338
        $this->writeToFile('.env', implode("\n", $lines));
339
340
        // Re-load env vars for installer access
341
        $env->loadFile($path);
342
    }
343
344
    /**
345
     * Write all *.php files
346
     *
347
     * @param array $config
348
     */
349
    protected function writeConfigPHP($config)
350
    {
351
        $configPath = $this->getProjectDir() . DIRECTORY_SEPARATOR . "_config.php";
352
        if ($config['usingEnv']) {
353
            $this->writeToFile($configPath, "<?php\n ");
354
            return;
355
        }
356
357
        // Create databaseConfig
358
        $lines = [];
359
        foreach ($config['db'] as $key => $value) {
360
            $lines[] = sprintf(
361
                "    '%s' => '%s'",
362
                addslashes($key),
363
                addslashes($value)
364
            );
365
        }
366
        $databaseConfigContent = implode(",\n", $lines);
367
        $this->writeToFile($configPath, <<<PHP
368
<?php
369
370
use SilverStripe\\ORM\\DB;
371
372
DB::setConfig([
373
{$databaseConfigContent}
374
]);
375
376
PHP
377
        );
378
    }
379
380
    /**
381
     * Write yml files
382
     *
383
     * @param array $config
384
     */
385
    protected function writeConfigYaml($config)
386
    {
387
        // Escape user input for safe insertion into PHP file
388
        $locale = $this->ymlString($config['locale']);
389
        $projectDir = $this->getProjectDir();
390
391
        // Set either specified, or no theme
392
        if ($config['theme'] && $config['theme'] !== 'tutorial') {
393
            $theme = $this->ymlString($config['theme']);
394
            $themeYML = <<<YML
395
    - '\$public'
396
    - '$theme'
397
    - '\$default'
398
YML;
399
        } else {
400
            $themeYML = <<<YML
401
    - '\$public'
402
    - '\$default'
403
YML;
404
        }
405
406
        // Write theme.yml
407
        $this->writeToFile("{$projectDir}/_config/theme.yml", <<<YML
408
---
409
Name: mytheme
410
---
411
SilverStripe\\View\\SSViewer:
412
  themes:
413
$themeYML
414
SilverStripe\\i18n\\i18n:
415
  default_locale: '$locale'
416
YML
417
        );
418
    }
419
420
    /**
421
     * Escape yml string
422
     *
423
     * @param string $string
424
     * @return mixed
425
     */
426
    protected function ymlString($string)
427
    {
428
        // just escape single quotes using ''
429
        return str_replace("'", "''", $string);
430
    }
431
432
    /**
433
     * Write file to given location
434
     *
435
     * @param string $filename
436
     * @param string $content
437
     * @param bool $absolute If $filename is absolute path set to true
438
     * @return bool
439
     */
440
    public function writeToFile($filename, $content, $absolute = false)
441
    {
442
        // Get absolute / relative paths by either combining or removing base from path
443
        list($absolutePath, $relativePath) = $absolute
444
            ? [
445
                $filename,
446
                substr($filename, strlen($this->getBaseDir()))]
447
            : [
448
                $this->getBaseDir() . $filename,
449
                $filename
450
            ];
451
        $this->statusMessage("Setting up $relativePath");
452
453
        if ((@$fh = fopen($absolutePath, 'wb')) && fwrite($fh, $content) && fclose($fh)) {
0 ignored issues
show
Bug introduced by
It seems like $fh can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

453
        if ((@$fh = fopen($absolutePath, 'wb')) && fwrite($fh, $content) && fclose(/** @scrutinizer ignore-type */ $fh)) {
Loading history...
Bug introduced by
It seems like $fh can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

453
        if ((@$fh = fopen($absolutePath, 'wb')) && fwrite(/** @scrutinizer ignore-type */ $fh, $content) && fclose($fh)) {
Loading history...
454
            // Set permissions to writable
455
            @chmod($absolutePath, 0775);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

455
            /** @scrutinizer ignore-unhandled */ @chmod($absolutePath, 0775);

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...
456
            return true;
457
        }
458
        $this->error("Couldn't write to file $relativePath");
459
        return false;
460
    }
461
462
    /**
463
     * Ensure root .htaccess is setup
464
     */
465
    public function createHtaccess()
466
    {
467
        $start = "### SILVERSTRIPE START ###\n";
468
        $end = "\n### SILVERSTRIPE END ###";
469
470
        $base = dirname($_SERVER['SCRIPT_NAME']);
471
        $base = Convert::slashes($base, '/');
472
473
        if ($base != '.') {
474
            $baseClause = "RewriteBase '$base'\n";
475
        } else {
476
            $baseClause = "";
477
        }
478
        if (strpos(strtolower(php_sapi_name()), "cgi") !== false) {
479
            $cgiClause = "RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n";
480
        } else {
481
            $cgiClause = "";
482
        }
483
        $rewrite = <<<TEXT
484
# Deny access to templates (but allow from localhost)
485
<Files *.ss>
486
    Order deny,allow
487
    Deny from all
488
    Allow from 127.0.0.1
489
</Files>
490
491
# Deny access to IIS configuration
492
<Files web.config>
493
    Order deny,allow
494
    Deny from all
495
</Files>
496
497
# Deny access to YAML configuration files which might include sensitive information
498
<Files ~ "\.ya?ml$">
499
    Order allow,deny
500
    Deny from all
501
</Files>
502
503
# Route errors to static pages automatically generated by SilverStripe
504
ErrorDocument 404 /assets/error-404.html
505
ErrorDocument 500 /assets/error-500.html
506
507
<IfModule mod_rewrite.c>
508
509
    # Turn off index.php handling requests to the homepage fixes issue in apache >=2.4
510
    <IfModule mod_dir.c>
511
        DirectoryIndex disabled
512
        DirectorySlash On
513
    </IfModule>
514
515
    SetEnv HTTP_MOD_REWRITE On
516
    RewriteEngine On
517
    $baseClause
518
    $cgiClause
519
520
    # Deny access to potentially sensitive files and folders
521
    RewriteRule ^vendor(/|$) - [F,L,NC]
522
    RewriteRule ^\.env - [F,L,NC]
523
    RewriteRule silverstripe-cache(/|$) - [F,L,NC]
524
    RewriteRule composer\.(json|lock) - [F,L,NC]
525
    RewriteRule (error|silverstripe|debug)\.log - [F,L,NC]
526
527
    # Process through SilverStripe if no file with the requested name exists.
528
    # Pass through the original path as a query parameter, and retain the existing parameters.
529
    # Try finding framework in the vendor folder first
530
    RewriteCond %{REQUEST_URI} ^(.*)$
531
    RewriteCond %{REQUEST_FILENAME} !-f
532
    RewriteRule .* index.php
533
</IfModule>
534
TEXT;
535
536
        $htaccessPath = $this->getPublicDir() . '.htaccess';
537
        if (file_exists($htaccessPath)) {
538
            $htaccess = file_get_contents($htaccessPath);
539
540
            if (strpos($htaccess, '### SILVERSTRIPE START ###') === false
541
                && strpos($htaccess, '### SILVERSTRIPE END ###') === false
542
            ) {
543
                $htaccess .= "\n### SILVERSTRIPE START ###\n### SILVERSTRIPE END ###\n";
544
            }
545
546
            if (strpos($htaccess, '### SILVERSTRIPE START ###') !== false
547
                && strpos($htaccess, '### SILVERSTRIPE END ###') !== false
548
            ) {
549
                $start = substr($htaccess, 0, strpos($htaccess, '### SILVERSTRIPE START ###'))
550
                    . "### SILVERSTRIPE START ###\n";
551
                $end = "\n" . substr($htaccess, strpos($htaccess, '### SILVERSTRIPE END ###'));
552
            }
553
        }
554
555
        $this->writeToFile($htaccessPath, $start . $rewrite . $end, true);
556
    }
557
558
    /**
559
     * Writes basic configuration to the web.config for IIS
560
     * so that rewriting capability can be use.
561
     */
562
    public function createWebConfig()
563
    {
564
        $content = <<<TEXT
565
<?xml version="1.0" encoding="utf-8"?>
566
<configuration>
567
    <system.webServer>
568
        <security>
569
            <requestFiltering>
570
                <hiddenSegments applyToWebDAV="false">
571
                    <add segment="silverstripe-cache" />
572
                    <add segment="composer.json" />
573
                    <add segment="composer.lock" />
574
                </hiddenSegments>
575
                <fileExtensions allowUnlisted="true" >
576
                    <add fileExtension=".ss" allowed="false"/>
577
                    <add fileExtension=".yml" allowed="false"/>
578
                </fileExtensions>
579
            </requestFiltering>
580
        </security>
581
        <rewrite>
582
            <rules>
583
                <rule name="SilverStripe Clean URLs" stopProcessing="true">
584
                    <match url="^(.*)$" />
585
                    <conditions>
586
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
587
                    </conditions>
588
                    <action type="Rewrite" url="index.php" appendQueryString="true" />
589
                </rule>
590
            </rules>
591
        </rewrite>
592
    </system.webServer>
593
</configuration>
594
TEXT;
595
596
        $path = $this->getPublicDir() . 'web.config';
597
        $this->writeToFile($path, $content, true);
598
    }
599
600
    public function checkRewrite()
601
    {
602
        $token = new ParameterConfirmationToken('flush', new HTTPRequest('GET', '/'));
603
        $params = http_build_query($token->params());
604
605
        $destinationURL = BASE_URL . '/' . (
606
            $this->checkModuleExists('cms')
607
                ? "home/successfullyinstalled?$params"
608
                : "?$params"
609
        );
610
611
        // phpcs:disable
612
        echo <<<HTML
613
<li id="ModRewriteResult">Testing...</li>
614
<script>
615
    if (typeof $ == 'undefined') {
616
        document.getElemenyById('ModeRewriteResult').innerHTML = "I can't run jQuery ajax to set rewriting; I will redirect you to the homepage to see if everything is working.";
617
        setTimeout(function() {
618
            window.location = "$destinationURL";
619
        }, 10000);
620
    } else {
621
        $.ajax({
622
            method: 'get',
623
            url: 'InstallerTest/testrewrite',
624
            complete: function(response) {
625
                var r = response.responseText.replace(/[^A-Z]?/g,"");
626
                if (r === "OK") {
627
                    $('#ModRewriteResult').html("Friendly URLs set up successfully; I am now redirecting you to your SilverStripe site...")
628
                    setTimeout(function() {
629
                        window.location = "$destinationURL";
630
                    }, 2000);
631
                } else {
632
                    $('#ModRewriteResult').html("Friendly URLs are not working. This is most likely because a rewrite module isn't configured "
633
                        + "correctly on your site. You may need to get your web host or server administrator to do this for you: "
634
                        + "<ul>"
635
                        + "<li><strong>mod_rewrite</strong> or other rewrite module is enabled on your web server</li>"
636
                        + "<li><strong>AllowOverride All</strong> is set for the directory where SilverStripe is installed</li>"
637
                        + "</ul>");
638
                }
639
            }
640
        });
641
    }
642
</script>
643
<noscript>
644
    <li><a href="$destinationURL">Click here</a> to check friendly URLs are working. If you get a 404 then something is wrong.</li>
645
</noscript>
646
HTML;
647
        // phpcs:enable
648
    }
649
650
    /**
651
     * Show an installation status message.
652
     * The output differs depending on whether this is CLI or web based
653
     *
654
     * @param string $msg
655
     */
656
    public function statusMessage($msg)
657
    {
658
        echo "<li>$msg</li>\n";
659
        flush();
660
    }
661
662
    /**
663
     * @param $config
664
     */
665
    protected function sendInstallStats($config)
666
    {
667
        // Try to determine the database version from the helper
668
        $dbType = $config['db']['type'];
669
        $helper = $this->getDatabaseConfigurationHelper($dbType);
670
        if ($helper) {
0 ignored issues
show
introduced by
$helper is of type SilverStripe\Dev\Install...baseConfigurationHelper, thus it always evaluated to true.
Loading history...
671
            $databaseVersion = $dbType . ': ' . $helper->getDatabaseVersion($config['db']);
672
        } else {
673
            $databaseVersion = $dbType;
674
        }
675
676
        $args = http_build_query(array_filter([
677
            'SilverStripe' => $config['version'],
678
            'PHP' => phpversion(),
679
            'Database' => $databaseVersion,
680
            'WebServer' => $this->findWebserver(),
681
            'ID' => empty($_SESSION['StatsID']) ? null : $_SESSION['StatsID']
682
        ]));
683
        $url = "http://ss2stat.silverstripe.com/Installation/add?{$args}";
684
        @$_SESSION['StatsID'] = file_get_contents($url);
685
    }
686
}
687