Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.43% covered (success)
98.43%
125 / 127
81.82% covered (warning)
81.82%
9 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
ModuleLoadedTester
98.43% covered (success)
98.43%
125 / 127
81.82% covered (warning)
81.82%
9 / 11
20
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSubDir
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 registerTestFiles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getServerSignatureBasedTest
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
1
 getRewriteBasedTest
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
1
 getHeaderSetBasedTest
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
1
 getContentDigestBasedTest
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
1
 getDirectoryIndexBasedTest
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
1
 getAddTypeBasedTest
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
1
 run2
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
7.01
 run
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
4.01
1<?php
2
3namespace HtaccessCapabilityTester\Testers;
4
5use \HtaccessCapabilityTester\TestResult;
6
7/**
8 * Class for testing if a module is loaded.
9 *
10 * @package    HtaccessCapabilityTester
11 * @author     Bjørn Rosell <it@rosell.dk>
12 * @since      Class available since 0.7
13 */
14class ModuleLoadedTester extends AbstractTester
15{
16
17    /* @var string A valid Apache module name (ie "rewrite") */
18    protected $moduleName;
19
20    /**
21     * Constructor.
22     *
23     * @return void
24     */
25    public function __construct($moduleName)
26    {
27        $this->moduleName = $moduleName;
28    }
29
30    /**
31     * Child classes must implement this method, which tells which subdir the
32     * test files are to be put.
33     *
34     * @return  string  A subdir for the test files
35     */
36    public function getSubDir()
37    {
38        return 'module-loaded/' . $this->moduleName;
39    }
40
41    /**
42     * Register the test files using the "registerTestFile" method
43     *
44     * @return  void
45     */
46    public function registerTestFiles()
47    {
48        // No test files for this test
49    }
50
51    private function getServerSignatureBasedTest()
52    {
53        // Test files, method : Using ServerSignature
54        // --------------------------------------------------
55        // Requires (in order not to be inconclusive):
56        // - Override: All
57        // - Status: Core
58        // - Directives: ServerSignature, IfModule
59        // - PHP?: Yes
60
61        $php = <<<'EOD'
62<?php
63if (isset($_SERVER['SERVER_SIGNATURE']) && ($_SERVER['SERVER_SIGNATURE'] != '')) {
64    echo 1;
65} else {
66    echo 0;
67}
68EOD;
69
70        $htaccess = <<<'EOD'
71# The beauty of this trick is that ServerSignature is available in core.
72# (it requires no modules and cannot easily be made forbidden)
73# However, it requires PHP to check for the effect
74
75ServerSignature Off
76<IfModule mod_xxx.c>
77ServerSignature On
78</IfModule>
79EOD;
80
81        $htaccess = str_replace('mod_xxx', 'mod_' . $this->moduleName, $htaccess);
82
83        return [
84            'subdir' => $this->getSubDir() . '/server-signature',
85            'files' => [
86                ['.htaccess', $htaccess],
87                ['test.php', $php],
88            ],
89            'request' => 'test.php',
90            'interpretation' => [
91                ['success', 'body', 'equals', '1'],
92                ['failure', 'body', 'equals', '0'],
93                // This time we do not fail for 500 because it is very unlikely that any of the
94                // directives used are forbidden
95            ]
96        ];
97    }
98
99    /**
100     *  @return  array
101     */
102    private function getRewriteBasedTest()
103    {
104        // Test files, method: Using Rewrite
105        // --------------------------------------------------
106        // Requires (in order not to be inconclusive)
107        // - Module: mod_rewrite
108        // - Override: FileInfo
109        // - Directives: RewriteEngine, RewriteRule and IfModule
110        // - PHP?: No
111
112        $htaccess = <<<'EOD'
113RewriteEngine On
114<IfModule mod_xxx.c>
115    RewriteRule ^request-me\.txt$ 1.txt [L]
116</IfModule>
117<IfModule !mod_xxx.c>
118    RewriteRule ^request-me\.txt$ 0.txt [L]
119</IfModule>
120EOD;
121
122        $htaccess = str_replace('mod_xxx', 'mod_' . $this->moduleName, $htaccess);
123
124        return [
125            'subdir' => $this->getSubDir() . '/rewrite',
126            'files' => [
127                ['.htaccess', $htaccess],
128                ['0.txt', '0'],
129                ['1.txt', '1'],
130                ['request-me.txt', 'Redirect failed even though rewriting has been proven to work. Strange!'],
131            ],
132            'request' => 'request-me.txt',
133            'interpretation' => [
134                ['success', 'body', 'equals', '1'],
135                ['failure', 'body', 'equals', '0'],
136                //['inconclusive', 'status-code', 'not-equals', '200'],
137            ]
138        ];
139    }
140
141    /**
142     *  @return  array
143     */
144    private function getHeaderSetBasedTest()
145    {
146
147        // Test files, method: Using Response Header
148        // --------------------------------------------------
149        // Requires (in order not to be inconclusive)
150        // - Module: mod_headers
151        // - Override: FileInfo
152        // - Directives: Header and IfModule
153        // - PHP?: No
154
155        $htaccess = <<<'EOD'
156<IfModule mod_xxx.c>
157    Header set X-Response-Header-Test: 1
158</IfModule>
159<IfModule !mod_xxx.c>
160    Header set X-Response-Header-Test: 0
161</IfModule>
162EOD;
163
164        $htaccess = str_replace('mod_xxx', 'mod_' . $this->moduleName, $htaccess);
165
166        return [
167            'subdir' => $this->getSubDir() . '/header-set',
168            'files' => [
169                ['.htaccess', $htaccess],
170                ['request-me.txt', 'thanks'],
171            ],
172            'request' => 'request-me.txt',
173            'interpretation' => [
174                ['success', 'headers', 'contains-key-value', 'X-Response-Header-Test', '1'],
175                ['failure', 'headers', 'contains-key-value', 'X-Response-Header-Test', '0'],
176            ]
177        ];
178    }
179
180    /**
181     *  @return  array
182     */
183    private function getContentDigestBasedTest()
184    {
185        // Test files, method: Using ContentDigest
186        // --------------------------------------------------
187        //
188        // Requires (in order not to be inconclusive)
189        // - Module: None - its in core
190        // - Override: Options
191        // - Directives: ContentDigest
192        // - PHP?: No
193
194        $htaccess = <<<'EOD'
195<IfModule mod_xxx.c>
196    ContentDigest On
197</IfModule>
198<IfModule !mod_xxx.c>
199    ContentDigest Off
200</IfModule>
201EOD;
202
203        $htaccess = str_replace('mod_xxx', 'mod_' . $this->moduleName, $htaccess);
204
205        return [
206            'subdir' => $this->getSubDir() . '/content-digest',
207            'files' => [
208                ['.htaccess', $htaccess],
209                ['request-me.txt', 'thanks'],
210            ],
211            'request' => 'request-me.txt',
212            'interpretation' => [
213                ['success', 'headers', 'contains-key', 'Content-MD5'],
214                ['failure', 'headers', 'not-contains-key', 'Content-MD5'],
215            ]
216        ];
217    }
218
219    /**
220     *  @return  array
221     */
222    private function getDirectoryIndexBasedTest()
223    {
224        // Test files, method: Using DirectoryIndex
225        // --------------------------------------------------
226        //
227        // Requires (in order not to be inconclusive)
228        // - Module: mod_dir (Status: Base)
229        // - Override: Indexes
230        // - Directives: DirectoryIndex
231        // - PHP?: No
232
233        $htaccess = <<<'EOD'
234<IfModule mod_xxx.c>
235    DirectoryIndex 1.html
236</IfModule>
237<IfModule !mod_xxx.c>
238    DirectoryIndex 0.html
239</IfModule>
240EOD;
241
242        $htaccess = str_replace('mod_xxx', 'mod_' . $this->moduleName, $htaccess);
243
244        return [
245            'subdir' => $this->getSubDir() . '/directory-index',
246            'files' => [
247                ['.htaccess', $htaccess],
248                ['0.html', '0'],
249                ['1.html', '1'],
250            ],
251            'request' => '',        // empty - in order to request the index
252            'interpretation' => [
253                ['success', 'body', 'equals', '1'],
254                ['failure', 'body', 'equals', '0'],
255            ]
256        ];
257    }
258
259
260    /**
261     *  @return  array
262     */
263    private function getAddTypeBasedTest()
264    {
265        // Test files, method: Using AddType
266        // --------------------------------------------------
267        //
268        // Requires (in order not to be inconclusive)
269        // - Module: mod_mime
270        // - Override: FileInfo
271        // - Directives: AddType and IfModule
272        // - PHP?: No
273
274        $htaccess = <<<'EOD'
275<IfModule mod_xxx.c>
276    AddType image/gif .test
277</IfModule>
278<IfModule !mod_xxx.c>
279    AddType image/jpeg .test
280</IfModule>
281EOD;
282
283        $htaccess = str_replace('mod_xxx', 'mod_' . $this->moduleName, $htaccess);
284
285        return [
286            'subdir' => $this->getSubDir() . '/add-type',
287            'files' => [
288                ['.htaccess', $htaccess],
289                ['request-me.test', 'hi'],
290            ],
291            'request' => 'request-me.test',
292            'interpretation' => [
293                ['success', 'headers', 'contains-key-value', 'Content-Type', 'image/gif'],
294                ['failure', 'headers', 'contains-key-value', 'Content-Type', 'image/jpeg'],
295            ]
296        ];
297    }
298
299    /**
300     * @return  bool|null
301     */
302    private function run2()
303    {
304        $hct = $this->getHtaccessCapabilityTester();
305
306        $testResult = $hct->customTest($this->getServerSignatureBasedTest());
307        if (!is_null($testResult)) {
308            // PHP
309            return $testResult;
310        }
311
312        if ($hct->contentDigestWorks()) {
313            // Override: Options
314            return $hct->customTest($this->getContentDigestBasedTest());
315        }
316
317        if ($hct->addTypeWorks()) {
318            // Override: FileInfo, Status: Base (mod_mime)
319            return $hct->customTest($this->getAddTypeBasedTest());
320        }
321
322        if ($hct->directoryIndexWorks()) {
323            // Override: Indexes, Status: Base (mod_dir)
324            return $hct->customTest($this->getDirectoryIndexBasedTest());
325        }
326
327        if ($hct->rewriteWorks()) {
328            // Override: FileInfo, Module: mod_rewrite
329            return $hct->customTest($this->getRewriteBasedTest());
330        }
331
332        if ($hct->headerSetWorks()) {
333            //Override: FileInfo, Module: mod_headers
334            return $hct->customTest($this->getHeaderSetBasedTest());
335        }
336        return null;
337    }
338
339    /**
340     *  Run the test.
341     *
342     * @param  string  $baseDir  Directory on the server where the test files can be put
343     * @param  string  $baseUrl  The base URL of the test files
344     *
345     * @return TestResult   Returns a test result
346     */
347    public function run($baseDir, $baseUrl)
348    {
349        $this->prepareForRun($baseDir, $baseUrl);
350
351        $hct = $this->getHtaccessCapabilityTester();
352
353        $htaccessEnabledTest = $hct->htaccessEnabled();
354        if ($htaccessEnabledTest === false) {
355            return new TestResult(false, '.htaccess files are ignored');
356        } elseif (is_null($htaccessEnabledTest)) {
357            // We happen to know that if that test cannot establish anything,
358            // then none of the usual weapons works - we can surrender right away
359            return new TestResult(null, 'no methods available - we surrender early');
360        }
361
362        $status = $this->run2();
363        if (is_null($status)) {
364            return new TestResult(null, 'no methods worked');
365        } else {
366            return new TestResult($status, '');
367        }
368    }
369}