Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
18 / 18
CRAP
100.00% covered (success)
100.00%
1 / 1
HtaccessCapabilityTester
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
18 / 18
21
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 runTest
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 setHttpRequester
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTestFilesLineUpper
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 htaccessEnabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 moduleLoaded
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 rewriteWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addTypeWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 headerSetWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 requestHeaderWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 contentDigestWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 serverSignatureWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 directoryIndexWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 passingInfoFromRewriteToScriptThroughRequestHeaderWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 passingInfoFromRewriteToScriptThroughEnvWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 crashTest
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 innocentRequestWorks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 customTest
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace HtaccessCapabilityTester;
4
5use \HtaccessCapabilityTester\Testers\AbstractTester;
6use \HtaccessCapabilityTester\Testers\AddTypeTester;
7use \HtaccessCapabilityTester\Testers\ContentDigestTester;
8use \HtaccessCapabilityTester\Testers\CrashTester;
9use \HtaccessCapabilityTester\Testers\CustomTester;
10use \HtaccessCapabilityTester\Testers\DirectoryIndexTester;
11use \HtaccessCapabilityTester\Testers\HeaderSetTester;
12use \HtaccessCapabilityTester\Testers\HtaccessEnabledTester;
13use \HtaccessCapabilityTester\Testers\InnocentRequestTester;
14use \HtaccessCapabilityTester\Testers\ModuleLoadedTester;
15use \HtaccessCapabilityTester\Testers\PassInfoFromRewriteToScriptThroughRequestHeaderTester;
16use \HtaccessCapabilityTester\Testers\PassInfoFromRewriteToScriptThroughEnvTester;
17use \HtaccessCapabilityTester\Testers\RewriteTester;
18use \HtaccessCapabilityTester\Testers\RequestHeaderTester;
19use \HtaccessCapabilityTester\Testers\ServerSignatureTester;
20
21/**
22 * Main entrance.
23 *
24 * @package    HtaccessCapabilityTester
25 * @author     Bjørn Rosell <it@rosell.dk>
26 * @since      Class available since 0.7
27 */
28class HtaccessCapabilityTester
29{
30
31    /** @var string  The dir where the test files should be put */
32    protected $baseDir;
33
34    /** @var string  The base url that the tests can be run from (corresponds to $baseDir) */
35    protected $baseUrl;
36
37    /** @var string  Additional info regarding last test (often empty) */
38    public $infoFromLastTest;
39
40    /** @var string  Status code from last test (can be empty) */
41    public $statusCodeOfLastRequest;
42
43
44    /** @var HttpRequesterInterface  The object used to make the HTTP request */
45    private $requester;
46
47    /** @var TestFilesLineUpperInterface  The object used to line up the test files */
48    private $testFilesLineUpper;
49
50    /**
51     * Constructor.
52     *
53     * @param  string  $baseDir  Directory on the server where the test files can be put
54     * @param  string  $baseUrl  The base URL of the test files
55     *
56     * @return void
57     */
58    public function __construct($baseDir, $baseUrl)
59    {
60        $this->baseDir = $baseDir;
61        $this->baseUrl = $baseUrl;
62    }
63
64    /**
65     * Run a test, store the info and return the status.
66     *
67     * @param  AbstractTester  $tester
68     *
69     * @return bool|null   true=success, false=failure, null=inconclusive
70     */
71    private function runTest($tester)
72    {
73        //$tester->setHtaccessCapabilityTester($this);
74        if (isset($this->requester)) {
75            $tester->setHttpRequester($this->requester);
76        }
77        if (isset($this->testFilesLineUpper)) {
78            $tester->setTestFilesLineUpper($this->testFilesLineUpper);
79        }
80        //$tester->setHtaccessCapabilityTester($this);
81
82        $cacheKeys = [$this->baseDir, $tester->getCacheKey()];
83        if (TestResultCache::isCached($cacheKeys)) {
84            $testResult = TestResultCache::getCached($cacheKeys);
85        } else {
86            $testResult = $tester->run($this->baseDir, $this->baseUrl);
87            TestResultCache::cache($cacheKeys, $testResult);
88        }
89
90        $this->infoFromLastTest = $testResult->info;
91        $this->statusCodeOfLastRequest = $testResult->statusCodeOfLastRequest;
92        return $testResult->status;
93    }
94
95    /**
96     * Run a test, store the info and return the status.
97     *
98     * @param  HttpRequesterInterface  $requester
99     *
100     * @return void
101     */
102    public function setHttpRequester($requester)
103    {
104        $this->requester = $requester;
105    }
106
107    /**
108     * Set object responsible for lining up the test files.
109     *
110     * @param  TestFilesLineUpperInterface  $testFilesLineUpper
111     * @return void
112     */
113    public function setTestFilesLineUpper($testFilesLineUpper)
114    {
115        $this->testFilesLineUpper = $testFilesLineUpper;
116    }
117
118    /**
119     * Test if .htaccess files are enabled
120     *
121     * Apache can be configured to completely ignore .htaccess files. This test examines
122     * if .htaccess files are proccesed.
123     *
124     * @return bool|null   true=success, false=failure, null=inconclusive
125     */
126    public function htaccessEnabled()
127    {
128        return $this->runTest(new HtaccessEnabledTester());
129    }
130
131    /**
132     * Test if a module is loaded.
133     *
134     * This test detects if directives inside a "IfModule" is run for a given module
135     *
136     * @param string       $moduleName  A valid Apache module name (ie "rewrite")
137     * @return bool|null   true=success, false=failure, null=inconclusive
138     */
139    public function moduleLoaded($moduleName)
140    {
141        return $this->runTest(new ModuleLoadedTester($moduleName));
142    }
143
144    /**
145     * Test if rewriting works.
146     *
147     * The .htaccess in this test uses the following directives:
148     * - IfModule
149     * - RewriteEngine
150     * - Rewrite
151     *
152     * @return bool|null   true=success, false=failure, null=inconclusive
153     */
154    public function rewriteWorks()
155    {
156        return $this->runTest(new RewriteTester());
157    }
158
159    /**
160     * Test if AddType works.
161     *
162     * The .htaccess in this test uses the following directives:
163     * - IfModule (core)
164     * - AddType  (mod_mime, FileInfo)
165     *
166     * @return bool|null   true=success, false=failure, null=inconclusive
167     */
168    public function addTypeWorks()
169    {
170        return $this->runTest(new AddTypeTester());
171    }
172
173    /**
174     * Test if setting a Response Header with the Header directive works.
175     *
176     * @return bool|null   true=success, false=failure, null=inconclusive
177     */
178    public function headerSetWorks()
179    {
180        return $this->runTest(new HeaderSetTester());
181    }
182
183    /**
184     * Test if setting a Request Header with the RequestHeader directive works.
185     *
186     * @return bool|null   true=success, false=failure, null=inconclusive
187     */
188    public function requestHeaderWorks()
189    {
190        return $this->runTest(new RequestHeaderTester());
191    }
192
193    /**
194     * Test if ContentDigest directive works.
195     *
196     * @return bool|null   true=success, false=failure, null=inconclusive
197     */
198    public function contentDigestWorks()
199    {
200        return $this->runTest(new ContentDigestTester());
201    }
202
203    /**
204     * Test if ServerSignature directive works.
205     *
206     * @return bool|null   true=success, false=failure, null=inconclusive
207     */
208    public function serverSignatureWorks()
209    {
210        return $this->runTest(new ServerSignatureTester());
211    }
212
213
214    /**
215     * Test if DirectoryIndex works.
216     *
217     * @return bool|null   true=success, false=failure, null=inconclusive
218     */
219    public function directoryIndexWorks()
220    {
221        return $this->runTest(new DirectoryIndexTester());
222    }
223
224    /**
225     * Test a complex construct for passing information from a rewrite to a script through a request header.
226     *
227     * @return bool|null   true=success, false=failure, null=inconclusive
228     */
229    public function passingInfoFromRewriteToScriptThroughRequestHeaderWorks()
230    {
231        return $this->runTest(new PassInfoFromRewriteToScriptThroughRequestHeaderTester());
232    }
233
234
235    /**
236     * Test if an environment variable can be set in a rewrite rule  and received in PHP.
237     *
238     * @return bool|null   true=success, false=failure, null=inconclusive
239     */
240    public function passingInfoFromRewriteToScriptThroughEnvWorks()
241    {
242        return $this->runTest(new PassInfoFromRewriteToScriptThroughEnvTester());
243    }
244
245    /**
246     * Call one of the methods of this class (not all allowed).
247     *
248     * @param string  $functionCall  ie "rewriteWorks()"
249     *
250     * @return bool|null   true=success, false=failure, null=inconclusive
251     */
252     /*
253    public function callMethod($functionCall)
254    {
255        switch ($functionCall) {
256            case 'htaccessEnabled()':
257                return $this->htaccessEnabled();
258            case 'rewriteWorks()':
259                return $this->rewriteWorks();
260            case 'addTypeWorks()':
261                return $this->addTypeWorks();
262            case 'headerSetWorks()':
263                return $this->headerSetWorks();
264            case 'requestHeaderWorks()':
265                return $this->requestHeaderWorks();
266            case 'contentDigestWorks()':
267                return $this->contentDigestWorks();
268            case 'directoryIndexWorks()':
269                return $this->directoryIndexWorks();
270            case 'passingInfoFromRewriteToScriptThroughRequestHeaderWorks()':
271                return $this->passingInfoFromRewriteToScriptThroughRequestHeaderWorks();
272            case 'passingInfoFromRewriteToScriptThroughEnvWorks()':
273                return $this->passingInfoFromRewriteToScriptThroughEnvWorks();
274            default:
275                throw new \Exception('The method is not callable');
276        }
277
278        // TODO:             moduleLoaded($moduleName)
279    }*/
280
281    /**
282     * Crash-test some .htaccess rules.
283     *
284     * Tests if the server can withstand the given rules without going fatal.
285     *
286     * - success: if the rules does not result in status 500.
287     * - failure: if the rules results in status 500 while a request to a file in a directory
288     *        without any .htaccess succeeds (<> 500)
289     * - inconclusive: if the rules results in status 500 while a request to a file in a directory
290     *        without any .htaccess also fails (500)
291     *
292     * @param string       $rules   Rules to crash-test
293     * @param string       $subDir  (optional) Subdir for the .htaccess to reside.
294     *                              if left out, a unique string will be generated
295     *
296     * @return bool|null   true=success, false=failure, null=inconclusive
297     */
298    public function crashTest($rules, $subDir = null)
299    {
300        return $this->runTest(new CrashTester($rules, $subDir));
301    }
302
303    /**
304     * Test an innocent request to a text file.
305     *
306     * If this fails, everything else will also fail.
307     *
308     * Possible reasons for failure:
309     * - A .htaccess in a parent folder has forbidden tags / syntax errors
310     *
311     * Possible reasons for inconclusive (= test could not be run)
312     * - 403 Forbidden
313     * - 404 Not Found
314     * - Request fails (ie due to timeout)
315     *
316     * @return bool|null   true=success, false=failure, null=inconclusive
317     */
318    public function innocentRequestWorks()
319    {
320        return $this->runTest(new InnocentRequestTester());
321    }
322
323    /**
324     * Run a custom test.
325     *
326     * @param array       $definition
327     *
328     * @return bool|null   true=success, false=failure, null=inconclusive
329     */
330    public function customTest($definition)
331    {
332        return $this->runTest(new CustomTester($definition));
333    }
334}