Completed
Push — master ( 4ad6bd...3873e4 )
by Ingo
11:53
created

Installer::createHtaccess()   C

Complexity

Conditions 9
Paths 40

Size

Total Lines 91
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 32
nc 40
nop 0
dl 0
loc 91
rs 5.1434
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\Dev\Install;
4
5
use Exception;
6
use SilverStripe\Control\HTTPRequest;
7
use SilverStripe\Control\Session;
8
use SilverStripe\Core\CoreKernel;
9
use SilverStripe\Control\HTTPApplication;
10
use SilverStripe\Core\Kernel;
11
use SilverStripe\Core\Startup\ParameterConfirmationToken;
12
use SilverStripe\ORM\DatabaseAdmin;
13
use SilverStripe\Security\DefaultAdminService;
14
use SilverStripe\Security\Security;
15
16
/**
17
 * SilverStripe CMS SilverStripe\Dev\Install\Installer
18
 * This installer doesn't use any of the fancy SilverStripe stuff in case it's unsupported.
19
 */
20
class Installer extends InstallRequirements
21
{
22
    public function __construct()
23
    {
24
        // Cache the baseDir value
25
        $this->getBaseDir();
0 ignored issues
show
Unused Code introduced by
The call to the method SilverStripe\Dev\Install\Installer::getBaseDir() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
26
    }
27
28
    protected function installHeader()
29
    {
30
        ?>
31
        <html>
32
        <head>
33
            <meta charset="utf-8"/>
34
            <title>Installing SilverStripe...</title>
35
            <link rel="stylesheet" type="text/css"
36
                  href="framework/src/Dev/Install/client/styles/install.css"/>
37
            <script src="//code.jquery.com/jquery-1.7.2.min.js"></script>
38
        </head>
39
        <body>
40
        <div class="install-header">
41
            <div class="inner">
42
                <div class="brand">
43
                    <span class="logo"></span>
44
45
                    <h1>SilverStripe</h1>
46
                </div>
47
            </div>
48
        </div>
49
50
        <div id="Navigation">&nbsp;</div>
51
        <div class="clear"><!-- --></div>
52
53
        <div class="main">
54
            <div class="inner">
55
                <h2>Installing SilverStripe...</h2>
56
57
                <p>I am now running through the installation steps (this should take about 30 seconds)</p>
58
59
                <p>If you receive a fatal error, refresh this page to continue the installation</p>
60
                <ul>
61
        <?php
62
    }
63
64
    public function install($config)
0 ignored issues
show
Coding Style introduced by
install uses the super-global variable $_SESSION which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
install uses the super-global variable $_POST which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
install uses the super-global variable $_SERVER which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
65
    {
66
        // Render header
67
        $this->installHeader();
0 ignored issues
show
Unused Code introduced by
The call to the method SilverStripe\Dev\Install...taller::installHeader() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
68
69
        $webserver = $this->findWebserver();
70
        $isIIS = $this->isIIS();
71
        $isApache = $this->isApache();
72
73
        flush();
74
75
        if (isset($config['stats'])) {
76
            if (file_exists(FRAMEWORK_PATH . '/silverstripe_version')) {
77
                $silverstripe_version = file_get_contents(FRAMEWORK_PATH . '/silverstripe_version');
78
            } else {
79
                $silverstripe_version = "unknown";
80
            }
81
82
            $phpVersion = urlencode(phpversion());
83
            $encWebserver = urlencode($webserver);
84
            $dbType = $config['db']['type'];
85
86
            // Try to determine the database version from the helper
87
            $databaseVersion = $config['db']['type'];
88
            $helper = $this->getDatabaseConfigurationHelper($dbType);
89
            if ($helper && method_exists($helper, 'getDatabaseVersion')) {
90
                $versionConfig = $config['db'][$dbType];
91
                $versionConfig['type'] = $dbType;
92
                $databaseVersion = urlencode($dbType . ': ' . $helper->getDatabaseVersion($versionConfig));
93
            }
94
95
            $url = "http://ss2stat.silverstripe.com/Installation/add?SilverStripe=$silverstripe_version&PHP=$phpVersion&Database=$databaseVersion&WebServer=$encWebserver";
96
97
            if (isset($_SESSION['StatsID']) && $_SESSION['StatsID']) {
98
                $url .= '&ID=' . $_SESSION['StatsID'];
99
            }
100
101
            @$_SESSION['StatsID'] = file_get_contents($url);
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...
102
        }
103
104
        if (file_exists('mysite/_config.php')) {
105
            // Truncate the contents of _config instead of deleting it - we can't re-create it because Windows handles permissions slightly
106
            // differently to UNIX based filesystems - it takes the permissions from the parent directory instead of retaining them
107
            $fh = fopen('mysite/_config.php', 'wb');
108
            fclose($fh);
109
        }
110
111
        // Escape user input for safe insertion into PHP file
112
        $theme = isset($_POST['template']) ? addcslashes($_POST['template'], "\'") : 'simple';
113
        $locale = isset($_POST['locale']) ? addcslashes($_POST['locale'], "\'") : 'en_US';
114
        $type = addcslashes($config['db']['type'], "\'");
115
        $dbConfig = $config['db'][$type];
116
        foreach ($dbConfig as &$configValue) {
117
            $configValue = addcslashes($configValue, "\\\'");
118
        }
119
        if (!isset($dbConfig['path'])) {
120
            $dbConfig['path'] = '';
121
        }
122
        if (!$dbConfig) {
123
            echo "<p style=\"color: red\">Bad config submitted</p><pre>";
124
            print_r($config);
125
            echo "</pre>";
126
            die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method install() 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...
127
        }
128
129
        // Write the config file
130
        global $usingEnv;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
131
        if ($usingEnv) {
132
            $this->statusMessage("Setting up 'mysite/_config.php' for use with environment variables...");
133
            $this->writeToFile("mysite/_config.php", "<?php\n ");
134
        } else {
135
            $this->statusMessage("Setting up 'mysite/_config.php'...");
136
            // Create databaseConfig
137
            $lines = array(
138
                $lines[] = "    'type' => '$type'"
0 ignored issues
show
Coding Style Comprehensibility introduced by
$lines was never initialized. Although not strictly required by PHP, it is generally a good practice to add $lines = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
139
            );
140
            foreach ($dbConfig as $key => $value) {
141
                $lines[] = "    '{$key}' => '$value'";
142
            }
143
            $databaseConfigContent = implode(",\n", $lines);
144
            $this->writeToFile("mysite/_config.php", <<<PHP
145
<?php
146
147
use SilverStripe\\ORM\\DB;
148
149
DB::setConfig([
150
{$databaseConfigContent}
151
]);
152
153
PHP
154
            );
155
        }
156
157
        $this->statusMessage("Setting up 'mysite/_config/config.yml'");
158
        $this->writeToFile("mysite/_config/config.yml", <<<YML
159
---
160
Name: mysite
161
---
162
# YAML configuration for SilverStripe
163
# See http://doc.silverstripe.org/framework/en/topics/configuration
164
# Caution: Indentation through two spaces, not tabs
165
SilverStripe\\View\\SSViewer:
166
  themes:
167
    - '$theme'
168
    - '\$default'
169
SilverStripe\\i18n\\i18n:
170
  default_locale: '$locale'
171
YML
172
        );
173
174
        if (!$this->checkModuleExists('cms')) {
175
            $this->writeToFile("mysite/code/RootURLController.php", <<<PHP
176
<?php
177
178
use SilverStripe\\Control\\Controller;
179
180
class RootURLController extends Controller {
181
182
    public function index() {
183
        echo "<html>Your site is now set up. Start adding controllers to mysite to get started.</html>";
184
    }
185
186
}
187
PHP
188
            );
189
        }
190
191
        // Write the appropriate web server configuration file for rewriting support
192
        if ($this->hasRewritingCapability()) {
193
            if ($isApache) {
194
                $this->statusMessage("Setting up '.htaccess' file...");
195
                $this->createHtaccess();
196
            } elseif ($isIIS) {
197
                $this->statusMessage("Setting up 'web.config' file...");
198
                $this->createWebConfig();
199
            }
200
        }
201
202
        // Mock request
203
        $session = new Session(isset($_SESSION) ? $_SESSION : array());
204
        $request = new HTTPRequest('GET', '/');
205
        $request->setSession($session);
206
207
        // Install kernel (fix to dev)
208
        $kernel = new CoreKernel(BASE_PATH);
209
        $kernel->setEnvironment(Kernel::DEV);
210
        $app = new HTTPApplication($kernel);
211
212
        // Build db within HTTPApplication
213
        $app->execute($request, function (HTTPRequest $request) use ($config) {
214
            // Start session and execute
215
            $request->getSession()->init();
216
217
            // Output status
218
            $this->statusMessage("Building database schema...");
219
220
            // Setup DB
221
            $dbAdmin = new DatabaseAdmin();
222
            $dbAdmin->setRequest($request);
223
            $dbAdmin->pushCurrent();
224
            $dbAdmin->doInit();
225
            $dbAdmin->doBuild(true);
226
227
            // Create default administrator user and group in database
228
            // (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...
229
            $adminMember = DefaultAdminService::singleton()->findOrCreateDefaultAdmin();
230
            $adminMember->Email = $config['admin']['username'];
231
            $adminMember->Password = $config['admin']['password'];
232
            $adminMember->PasswordEncryption = Security::config()->get('encryption_algorithm');
233
234
            try {
235
                $this->statusMessage('Creating default CMS admin account...');
236
                $adminMember->write();
237
            } catch (Exception $e) {
238
                $this->statusMessage(
239
                    sprintf('Warning: Default CMS admin account could not be created (error: %s)', $e->getMessage())
240
                );
241
            }
242
243
            $request->getSession()->set('username', $config['admin']['username']);
244
            $request->getSession()->set('password', $config['admin']['password']);
245
            $request->getSession()->save();
246
        }, true);
247
248
        // Check result of install
249
        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...
250
            if (isset($_SERVER['HTTP_HOST']) && $this->hasRewritingCapability()) {
251
                $this->statusMessage("Checking that friendly URLs work...");
252
                $this->checkRewrite();
253
            } else {
254
                $token = new ParameterConfirmationToken('flush', $request);
255
                $params = http_build_query($token->params());
256
257
                $destinationURL = 'index.php/' .
258
                    ($this->checkModuleExists('cms') ? "home/successfullyinstalled?$params" : "?$params");
259
260
                echo <<<HTML
261
                <li>SilverStripe successfully installed; I am now redirecting you to your SilverStripe site...</li>
262
                <script>
263
                    setTimeout(function() {
264
                        window.location = "$destinationURL";
265
                    }, 2000);
266
                </script>
267
                <noscript>
268
                <li><a href="$destinationURL">Click here to access your site.</a></li>
269
                </noscript>
270
HTML;
271
            }
272
        }
273
274
        return $this->errors;
275
    }
276
277
    public function writeToFile($filename, $content)
278
    {
279
        $base = $this->getBaseDir();
280
        $this->statusMessage("Setting up $base$filename");
281
282
        if ((@$fh = fopen($base . $filename, 'wb')) && fwrite($fh, $content) && fclose($fh)) {
283
            return true;
284
        }
285
        $this->error("Couldn't write to file $base$filename");
286
        return false;
287
    }
288
289
    public function createHtaccess()
0 ignored issues
show
Coding Style introduced by
createHtaccess uses the super-global variable $_SERVER which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
290
    {
291
        $start = "### SILVERSTRIPE START ###\n";
292
        $end = "\n### SILVERSTRIPE END ###";
293
294
        $base = dirname($_SERVER['SCRIPT_NAME']);
295
        if (defined('DIRECTORY_SEPARATOR')) {
296
            $base = str_replace(DIRECTORY_SEPARATOR, '/', $base);
297
        } else {
298
            $base = str_replace("\\", '/', $base);
299
        }
300
301
        if ($base != '.') {
302
            $baseClause = "RewriteBase '$base'\n";
303
        } else {
304
            $baseClause = "";
305
        }
306
        if (strpos(strtolower(php_sapi_name()), "cgi") !== false) {
307
            $cgiClause = "RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n";
308
        } else {
309
            $cgiClause = "";
310
        }
311
        $rewrite = <<<TEXT
312
# Deny access to templates (but allow from localhost)
313
<Files *.ss>
314
    Order deny,allow
315
    Deny from all
316
    Allow from 127.0.0.1
317
</Files>
318
319
# Deny access to IIS configuration
320
<Files web.config>
321
    Order deny,allow
322
    Deny from all
323
</Files>
324
325
# Deny access to YAML configuration files which might include sensitive information
326
<Files *.yml>
327
    Order allow,deny
328
    Deny from all
329
</Files>
330
331
# Route errors to static pages automatically generated by SilverStripe
332
ErrorDocument 404 /assets/error-404.html
333
ErrorDocument 500 /assets/error-500.html
334
335
<IfModule mod_rewrite.c>
336
337
    # Turn off index.php handling requests to the homepage fixes issue in apache >=2.4
338
    <IfModule mod_dir.c>
339
        DirectoryIndex disabled
340
    </IfModule>
341
342
    SetEnv HTTP_MOD_REWRITE On
343
    RewriteEngine On
344
    $baseClause
345
    $cgiClause
346
347
    # Deny access to potentially sensitive files and folders
348
    RewriteRule ^vendor(/|$) - [F,L,NC]
349
    RewriteRule silverstripe-cache(/|$) - [F,L,NC]
350
    RewriteRule composer\.(json|lock) - [F,L,NC]
351
352
    # Process through SilverStripe if no file with the requested name exists.
353
    # Pass through the original path as a query parameter, and retain the existing parameters.
354
    RewriteCond %{REQUEST_URI} ^(.*)$
355
    RewriteCond %{REQUEST_FILENAME} !-f
356
    RewriteRule .* framework/main.php?url=%1 [QSA]
357
</IfModule>
358
TEXT;
359
360
        if (file_exists('.htaccess')) {
361
            $htaccess = file_get_contents('.htaccess');
362
363
            if (strpos($htaccess, '### SILVERSTRIPE START ###') === false
364
                && strpos($htaccess, '### SILVERSTRIPE END ###') === false
365
            ) {
366
                $htaccess .= "\n### SILVERSTRIPE START ###\n### SILVERSTRIPE END ###\n";
367
            }
368
369
            if (strpos($htaccess, '### SILVERSTRIPE START ###') !== false
370
                && strpos($htaccess, '### SILVERSTRIPE END ###') !== false
371
            ) {
372
                $start = substr($htaccess, 0, strpos($htaccess, '### SILVERSTRIPE START ###'))
373
                    . "### SILVERSTRIPE START ###\n";
374
                $end = "\n" . substr($htaccess, strpos($htaccess, '### SILVERSTRIPE END ###'));
375
            }
376
        }
377
378
        $this->writeToFile('.htaccess', $start . $rewrite . $end);
379
    }
380
381
    /**
382
     * Writes basic configuration to the web.config for IIS
383
     * so that rewriting capability can be use.
384
     */
385
    public function createWebConfig()
386
    {
387
        $content = <<<TEXT
388
<?xml version="1.0" encoding="utf-8"?>
389
<configuration>
390
    <system.webServer>
391
        <security>
392
            <requestFiltering>
393
                <hiddenSegments applyToWebDAV="false">
394
                    <add segment="silverstripe-cache" />
395
                    <add segment="vendor" />
396
                    <add segment="composer.json" />
397
                    <add segment="composer.lock" />
398
                </hiddenSegments>
399
                <fileExtensions allowUnlisted="true" >
400
                    <add fileExtension=".ss" allowed="false"/>
401
                    <add fileExtension=".yml" allowed="false"/>
402
                </fileExtensions>
403
            </requestFiltering>
404
        </security>
405
        <rewrite>
406
            <rules>
407
                <rule name="SilverStripe Clean URLs" stopProcessing="true">
408
                    <match url="^(.*)$" />
409
                    <conditions>
410
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
411
                    </conditions>
412
                    <action type="Rewrite" url="framework/main.php?url={R:1}" appendQueryString="true" />
413
                </rule>
414
            </rules>
415
        </rewrite>
416
    </system.webServer>
417
</configuration>
418
TEXT;
419
420
        $this->writeToFile('web.config', $content);
421
    }
422
423
    public function checkRewrite()
0 ignored issues
show
Coding Style introduced by
checkRewrite uses the super-global variable $_SERVER which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
424
    {
425
        $token = new ParameterConfirmationToken('flush', new HTTPRequest('GET', '/'));
426
        $params = http_build_query($token->params());
427
428
        $destinationURL = str_replace('install.php', '', $_SERVER['SCRIPT_NAME']) .
429
            ($this->checkModuleExists('cms') ? "home/successfullyinstalled?$params" : "?$params");
430
431
        echo <<<HTML
432
<li id="ModRewriteResult">Testing...</li>
433
<script>
434
    if (typeof $ == 'undefined') {
435
        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.";
436
        setTimeout(function() {
437
            window.location = "$destinationURL";
438
        }, 10000);
439
    } else {
440
        $.ajax({
441
            method: 'get',
442
            url: 'InstallerTest/testrewrite',
443
            complete: function(response) {
444
                var r = response.responseText.replace(/[^A-Z]?/g,"");
445
                if (r === "OK") {
446
                    $('#ModRewriteResult').html("Friendly URLs set up successfully; I am now redirecting you to your SilverStripe site...")
447
                    setTimeout(function() {
448
                        window.location = "$destinationURL";
449
                    }, 2000);
450
                } else {
451
                    $('#ModRewriteResult').html("Friendly URLs are not working. This is most likely because a rewrite module isn't configured "
452
                        + "correctly on your site. You may need to get your web host or server administrator to do this for you: "
453
                        + "<ul>"
454
                        + "<li><strong>mod_rewrite</strong> or other rewrite module is enabled on your web server</li>"
455
                        + "<li><strong>AllowOverride All</strong> is set for the directory where SilverStripe is installed</li>"
456
                        + "</ul>");
457
                }
458
            }
459
        });
460
    }
461
</script>
462
<noscript>
463
    <li><a href="$destinationURL">Click here</a> to check friendly URLs are working. If you get a 404 then something is wrong.</li>
464
</noscript>
465
HTML;
466
    }
467
468
    public function var_export_array_nokeys($array)
469
    {
470
        $retval = "array(\n";
471
        foreach ($array as $item) {
472
            $retval .= "\t'";
473
            $retval .= trim($item);
474
            $retval .= "',\n";
475
        }
476
        $retval .= ")";
477
        return $retval;
478
    }
479
480
    /**
481
     * Show an installation status message.
482
     * The output differs depending on whether this is CLI or web based
483
     *
484
     * @param string $msg
485
     */
486
    public function statusMessage($msg)
487
    {
488
        echo "<li>$msg</li>\n";
489
        flush();
490
    }
491
}
492