Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
66.67% covered (warning)
66.67%
62 / 93
81.25% covered (warning)
81.25%
13 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
common_configuration_FileSystemComponent
66.67% covered (warning)
66.67%
62 / 93
81.25% covered (warning)
81.25%
13 / 16
103.26
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getLocation
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setLocation
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setRecursive
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRecursive
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setMustCheckIfEmpty
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMustCheckIfEmpty
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 exists
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getExpectedRights
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setExpectedRights
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 check
51.22% covered (warning)
51.22%
21 / 41
0.00% covered (danger)
0.00%
0 / 1
21.61
 hasLocationAccess
56.52% covered (warning)
56.52%
13 / 23
0.00% covered (danger)
0.00%
0 / 1
23.84
 isReadable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isWritable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isExecutable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isEmptyDirectory
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg
19 *                         (under the project TAO & TAO2);
20 *               2008-2010 (update and modification) Deutsche Institut für Internationale Pädagogische Forschung
21 *                         (under the project TAO-TRANSFER);
22 *               2009-2012 (update and modification) Public Research Centre Henri Tudor
23 *                         (under the project TAO-SUSTAIN & TAO-DEV);
24 *
25 */
26
27/**
28 * Short description of class common_configuration_FileSystemComponent
29 *
30 * @access public
31 * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu>
32 * @package generis
33
34 */
35class common_configuration_FileSystemComponent extends common_configuration_Component
36{
37    // --- ASSOCIATIONS ---
38
39
40    // --- ATTRIBUTES ---
41
42    /**
43     * Whether should be checked recursively (if passed location of directory).
44     *
45     * @access private
46     * @var boolean
47     */
48    private $recursive = false;
49
50    /**
51     * Short description of attribute location
52     *
53     * @access private
54     * @var string
55     */
56    private $location = '';
57
58    /**
59     * Short description of attribute expectedRights
60     *
61     * @access private
62     * @var string
63     */
64    private $expectedRights = '';
65
66    /**
67     * Whether must check if is empty (if passed location of directory).
68     *
69     * @access private
70     * @var boolean
71     */
72    private $mustCheckIfEmpty = false;
73
74    // --- OPERATIONS ---
75
76    /**
77     * Short description of method __construct
78     *
79     * @access public
80     * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu>
81     * @param  string location
82     * @param  string expectedRights
83     * @param  boolean optional
84     * @throws common_configuration_MalformedRightsException
85     * @return mixed
86     */
87    public function __construct(
88        $location,
89        $expectedRights,
90        $optional = false,
91        $recursive = false,
92        $mustCheckIfEmpty = false
93    ) {
94        parent::__construct('tao.configuration.filesystem', $optional);
95
96        $this->setExpectedRights($expectedRights);
97        $this->setLocation($location);
98        $this->setRecursive($recursive);
99        $this->setMustCheckIfEmpty($mustCheckIfEmpty);
100    }
101
102    /**
103     * Short description of method getLocation
104     *
105     * @access public
106     * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu>
107     * @return string
108     */
109    public function getLocation()
110    {
111        $returnValue = $this->location;
112
113        return (string) $returnValue;
114    }
115
116    /**
117     * Short description of method setLocation
118     *
119     * @access public
120     * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu>
121     * @param  string location
122     * @return void
123     */
124    public function setLocation($location)
125    {
126        $this->location = $location;
127    }
128
129    /**
130     * Set $this->recursive value
131     *
132     * @access public
133     * @author Aleh Hutnikau, <hutnikau@1pt.com>
134     * @param boolean $recursive
135     * @return void
136     */
137    public function setRecursive($recursive)
138    {
139        $this->recursive = $recursive;
140    }
141
142    /**
143     * Get $this->recursive value
144     *
145     * @access public
146     * @author Aleh Hutnikau, <hutnikau@1pt.com>
147     * @return boolean
148     */
149    public function getRecursive()
150    {
151        return $this->recursive;
152    }
153
154    /**
155     * Set $this->mustCheckIfEmpty value
156     *
157     * @access public
158     * @author Jonathan VUiLLEMIN, <jonathan@taotesting.com>
159     * @param boolean $mustCheckIfEmpty
160     * @return void
161     */
162    public function setMustCheckIfEmpty($mustCheckIfEmpty)
163    {
164        $this->mustCheckIfEmpty = $mustCheckIfEmpty;
165    }
166
167    /**
168     * Get $this->mustCheckIfEmpty value
169     *
170     * @access public
171     * @author Jonathan VUiLLEMIN, <jonathan@taotesting.com>
172     * @return boolean
173     */
174    public function getMustCheckIfEmpty()
175    {
176        return $this->mustCheckIfEmpty;
177    }
178
179    /**
180     * Short description of method exists
181     *
182     * @access public
183     * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu>
184     * @return boolean
185     */
186    public function exists()
187    {
188        $returnValue = @file_exists($this->getLocation());
189
190        return (bool) $returnValue;
191    }
192
193    /**
194     * Short description of method getExpectedRights
195     *
196     * @access public
197     * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu>
198     * @return string
199     */
200    public function getExpectedRights()
201    {
202        $returnValue = $this->expectedRights;
203
204        return (string) $returnValue;
205    }
206
207    /**
208     * Short description of method setExpectedRights
209     *
210     * @access public
211     * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu>
212     * @param  string expectedRights
213     * @return void
214     */
215    public function setExpectedRights($expectedRights)
216    {
217
218        if (!empty($expectedRights) && preg_match('/^r*w*x*$/', $expectedRights) !== 0) {
219            $this->expectedRights = $expectedRights;
220        } else {
221            throw new common_configuration_MalformedRightsException("Malformed rights. Expected format is r|rw|rwx.");
222        }
223    }
224
225    /**
226     * Short description of method check
227     *
228     * @access public
229     * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu>
230     * @return common_configuration_Report
231     */
232    public function check()
233    {
234        $returnValue = null;
235
236        $expectedRights = $this->getExpectedRights();
237        $location = $this->getLocation();
238        $name = $this->getName();
239
240        if (!$this->exists()) {
241            return new common_configuration_Report(
242                common_configuration_Report::UNKNOWN,
243                "File system component '${name}' could not be found in '${location}'.",
244                $this
245            );
246        } else {
247            if (strpos($expectedRights, 'r') !== false && !$this->isReadable($location)) {
248                return new common_configuration_Report(
249                    common_configuration_Report::INVALID,
250                    "File system component '${name}' in '${location} is not readable.",
251                    $this
252                );
253            }
254
255            if (strpos($expectedRights, 'w') !== false && !$this->isWritable($location)) {
256                return new common_configuration_Report(
257                    common_configuration_Report::INVALID,
258                    "File system component '${name}' in '${location} is not writable.",
259                    $this
260                );
261            }
262
263            if (strpos($expectedRights, 'x') !== false && !$this->isExecutable($location)) {
264                return new common_configuration_Report(
265                    common_configuration_Report::INVALID,
266                    "File system component '${name}' in '${location} is not executable.",
267                    $this
268                );
269            }
270
271            if ($this->getMustCheckIfEmpty()) {
272                if (!$this->isEmptyDirectory($location)) {
273                    return new common_configuration_Report(
274                        common_configuration_Report::INVALID,
275                        "File system component '${name}' in '${location} is not empty.",
276                        $this
277                    );
278                }
279            }
280
281            return new common_configuration_Report(
282                common_configuration_Report::VALID,
283                "File system component '${name}' in '${location} is compliant with expected rights "
284                    . "(${expectedRights}).'",
285                $this
286            );
287        }
288
289
290        return $returnValue;
291    }
292
293    private function hasLocationAccess($location = null, $rule = 'Readable')
294    {
295        $returnValue = true;
296
297        if ($location === null) {
298            $location = $this->getLocation();
299        }
300
301        if (
302            !file_exists($location)
303            || !is_readable($location)
304            || !isset($rule)
305            || !is_string($rule)
306            || !in_array($rule, ['Readable', 'Writable', 'Executable'])
307        ) {
308            $returnValue = false;
309        } elseif (is_file($location) || !$this->getRecursive()) {
310            $funcName = 'is_' . strtolower($rule);
311            $returnValue = $funcName($location);
312        } else {
313            $iterator = new \RecursiveIteratorIterator(
314                new \RecursiveDirectoryIterator($location, \RecursiveDirectoryIterator::SKIP_DOTS)
315            );
316
317            try {
318                $method = 'is' . $rule;
319                foreach ($iterator as $file) {
320                    if (!$file->$method()) {
321                        $returnValue = false;
322                        break;
323                    }
324                }
325            } catch (\UnexpectedValueException  $e) {
326                $returnValue = false;
327            }
328        }
329
330        return $returnValue;
331    }
332
333    /**
334     * If file is readable.
335     *
336     * @access public
337     * @author Aleh Hutnikau, <hutnikau@1pt.com>
338     * @param string $location File location
339     * @return boolean
340     */
341    public function isReadable($location = null)
342    {
343        return $this->hasLocationAccess($location, 'Readable');
344    }
345
346    /**
347     * If file is writable.
348     *
349     * @access public
350     * @author Aleh Hutnikau, <hutnikau@1pt.com>
351     * @param string $location File location
352     * @return boolean
353     */
354    public function isWritable($location = null)
355    {
356        return $this->hasLocationAccess($location, 'Writable');
357    }
358
359    /**
360     * If file is executable.
361     *
362     * @access public
363     * @author Aleh Hutnikau, <hutnikau@1pt.com>
364     * @param string $location File location
365     * @return boolean
366     */
367    public function isExecutable($location = null)
368    {
369        return $this->hasLocationAccess($location, 'Executable');
370    }
371
372    /**
373     * If directory is empty.
374     *
375     * @access public
376     * @author Jonathan VUILLEMIN <jonathan@taotesting.com>
377     * @param string $location location
378     * @return boolean
379     */
380    public function isEmptyDirectory($location = null)
381    {
382        $returnValue = false;
383
384        if ($location === null) {
385            $location = $this->getLocation();
386        }
387
388        if (is_readable($location) && is_dir($location)) {
389            $iterator = new RecursiveDirectoryIterator($location, RecursiveDirectoryIterator::SKIP_DOTS);
390            $returnValue = iterator_count($iterator) === 0;
391        }
392
393        return $returnValue;
394    }
395}