Completed
Push — php7.2-travis ( 83e6ee...46fda5 )
by
unknown
265:12 queued 251:40
created

store   B

Complexity

Total Complexity 54

Size/Duplication

Total Lines 410
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 43.58%

Importance

Changes 0
Metric Value
dl 0
loc 410
ccs 78
cts 179
cp 0.4358
rs 7.0642
c 0
b 0
f 0
wmc 54
lcom 1
cbo 2

35 Methods

Rating   Name   Duplication   Size   Complexity  
call() 0 1 ?
count() 0 1 ?
info() 0 1 ?
get() 0 1 ?
touch() 0 1 ?
ls() 0 1 ?
parents() 0 1 ?
find() 0 1 ?
save() 0 1 ?
purge() 0 1 ?
delete() 0 1 ?
exists() 0 1 ?
link() 0 1 ?
move() 0 1 ?
list_paths() 0 1 ?
AR_implements() 0 1 ?
load_properties() 0 1 ?
load_property() 0 1 ?
add_property() 0 1 ?
del_property() 0 1 ?
get_nextid() 0 1 ?
A close() 0 8 3
A __destruct() 0 3 1
A __construct() 0 4 1
A make_path() 0 3 1
B save_properties() 0 19 7
A get_filestore() 0 13 4
A get_filestore_svn() 0 7 2
D serialize() 0 35 9
B get_config() 0 15 5
B is_supported() 0 24 6
A compilerFactory() 0 9 2
A newobject() 0 22 3
A fixObjectClass() 0 3 1
D unserialize() 0 32 9

How to fix   Complexity   

Complex Class

Complex classes like store often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use store, and based on these observations, apply Extract Interface, too.

1
<?php
2
/******************************************************************************
3
  Generic Store 1.0						Ariadne
4
5
  Copyright (C) 1998-2005  Muze
6
7
  This program is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU General Public License
9
  as published by the Free Software Foundation; either version 2
10
  of the License, or (at your option) any later version.
11
12
  This program is distributed in the hope that it will be useful,
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
  GNU General Public License for more details.
16
17
  You should have received a copy of the GNU General Public License
18
  along with this program; if not, write to the Free Software
19
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21
  --------------------------------------------------------------------------
22
23
  This Is a Generic implementation of the store, all generic functions are defined here
24
25
  the implemented functions are
26
27
	function get_config($field)
28
	function is_supported($feature)
29
	function newobject($path, $parent, $type, $data, $id=0, $lastchanged=0, $vtype="", $size=0, $priority=0)
30
	function close()
31
	function make_path($curr_dir, $path)
32
	function save_properties($properties, $id)
33
	function get_filestore($name)
34
35
*******************************************************************************/
36
37
38
abstract class store {
39
40
	public $error;
41
	public $root;
42
	public $rootoptions;
43
	public $mod_lock;
44
	public $total;
45
	protected $code;
46
	protected $files;
47
	protected $_filestores;
48
	protected $config;
49
50
51
52
	public function __construct($path, $config) {
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
53
		echo "You have not configured the store properly. Please check your configuration files.";
54
		exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method __construct() 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...
55
	}
56
57
	/*  abstract functions
58
		 need implementation in your implementation of this store
59
	*/
60
61
	public abstract function call($template, $args, $objects);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
62
63
	public abstract function count($objects);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
64
65
	public abstract function info($objects);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
66
67
	public abstract function get($path);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
68
	/**********************************************************************************
69
	 This function takes as argument a path to an object in the store and will retrieve
70
	 all the necessary data and return this in the objectlist type needed for
71
	 store->call(). If the requested path does not exist, it will retrieve the object
72
	 with the longest matching path.
73
74
	 $path should always start and end with a '/'.
75
	 **********************************************************************************/
76
77
	public abstract function touch($id, $timestamp = -1);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
78
	/**********************************************************************************
79
	 This function takes as argument a path to an object (or id of an object)
80
     in the store and will set the timestamp to $timestamp.
81
82
	 $path should always start and end with a '/'.
83
	 **********************************************************************************/
84
85
	public abstract function ls($path);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
86
	/**********************************************************************************
87
	 This function takes as argument a path to an object in the store and will retrieve
88
	 all the objects and their data which have this object as their parent. It will
89
	 then return this in the objectlist type needed for store->call(). If the requested
90
	 path does not exist, it will retrieve the object with the longest matching path.
91
92
	 $path should always start and end with a '/'.
93
	 **********************************************************************************/
94
95
	public abstract function parents($path, $top="/");
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
96
	/**********************************************************************************
97
	 This function takes as argument a path to an object in the store. It will return
98
	 all objects with a path which is a substring of the given path. The resulsts are
99
	 ordered by path (length), shortest paths first.
100
	 In effect all parents of an object in the tree are called, in order, starting at
101
	 the root.
102
103
	 $path should always start and end with a '/'.
104
	 **********************************************************************************/
105
106
	public abstract function find($path, $criteria, $limit=100, $offset=0);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
107
	/**********************************************************************************
108
	 This function takes as arguments a path to an object in the store and some search
109
	 criteria. It will search for all matching objects under the given path. If the
110
	 given path is not in this store but in a substore it will not automatically search
111
	 that substore.
112
113
	 $criteria is of the form
114
115
	 $criteria ::= ({ $property_name => ({ $valuename => ({ $compare_function, $value }) }) })
116
117
	 e.g.: $criteria["status"]["value"][">"]="published";
118
119
	 $path should always start and end with a '/'.
120
121
	 **********************************************************************************/
122
123
124
	public abstract function save($path, $type, $data, $properties="", $vtype="", $priority=false);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
125
	/***************************************************************
126
		This function takes as argument a path, type, objectdata and
127
		possibly a properties list and vtype (virtual type).
128
		If there exists no object with the given path, a new object is
129
		saved with the given type, data, properties and vtype, and a
130
		new path is saved pointing to it.
131
		If there does exist an object with the given path, it's object
132
		data is overwritten with the given data and if vtype is set the
133
		current vtype is overwritten with the new one.
134
135
		$path must be an absolute path (containing no '..' and starting
136
			with '/')
137
		$type must be a valid type
138
		$data can be any string (usually a serialized object.)
139
		$properties is a multidimensional hash of the following form:
140
			$properties[{property_name}][][{value_name}]={value}
141
			{property_name} must be a valid property name
142
			{value_name} must be a valid value name for this property
143
			{value} can be a number, boolean or string.
144
		example:
145
			$properties["name"][0]["value"]="A name";
146
			$properties["name"][1]["value"]="A second name!";
147
		if $properties["name"]=1 then all properties for property name
148
			will be removed.
149
150
		$vtype must be a valid type.
151
152
		if $properties or $vtype are not set or empty ("",0 or false)
153
		they will be ignored. $vtype defaults to $type.
154
		Only those properties listed in $properties will be updated.
155
		Any other property set will remain as it was.
156
	***************************************************************/
157
158
159
	protected abstract function purge($path);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
160
	/**********************************************************************
161
		This function will delete the object pointed to by $path and all
162
	other paths pointing to that object. It will then remove any property
163
	for this object from all property tables.
164
		The function returns the number of paths found and removed or 1 if
165
	there was no path found (meaning that the object doesn't exist and
166
	therefor purge succeeded while doing nothing.)
167
168
	 $path should always start and end with a '/'.
169
	**********************************************************************/
170
171
	public abstract function delete($path);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
172
	/**********************************************************************
173
		This function deletes the path given. If this is the last path pointing
174
	to an object, the object will be purged instead.
175
176
	$path should always start and end with a '/'.
177
	**********************************************************************/
178
179
	abstract function exists($path);
180
	/**********************************************************************
181
		This function checks the given path to see if it exists. If it does
182
	it returns the id of the object to which it points. Otherwise it returns
183
	0.
184
185
	$path should always start and end with a '/'.
186
	**********************************************************************/
187
188
189
	public abstract function link($source, $destination);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
190
	/**********************************************************************
191
		Link adds an extra path to an already existing object. It has two
192
	arguments: $source and $destination. $source is an existing path of
193
	an object, $destination is the new path. $destination must not already
194
	exist.
195
196
	$destination should always start and end with a '/'.
197
	**********************************************************************/
198
199
	public abstract function move($source, $destination);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
200
	/**********************************************************************
201
	$destination should always start and end with a '/'.
202
	**********************************************************************/
203
204
205
	public abstract function list_paths($path);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
206
	/**********************************************************************
207
		This function returns an array of all paths pointing to the same object
208
	as $path does.
209
	**********************************************************************/
210
211
	public abstract function AR_implements($type, $implements);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
212
	/**********************************************************************
213
		This function returns 1 if the $type implements the type or
214
	interface in $implements. Otherwise it returns 0.
215
	**********************************************************************/
216
217
	public abstract function load_properties($object, $values="");
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
218
219
	public abstract function load_property($object, $property, $values="");
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
220
221
	public abstract function add_property($object, $property, $values);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
222
223
	public abstract function del_property($object, $property="", $values="");
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
224
225
	protected abstract function get_nextid($path, $mask="{5:id}");
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
226
	/**********************************************************************
227
		'private' function of mysql store. This will return the next
228
		'autoid' for $path.
229
	**********************************************************************/
230
231
232
233
	/*
234
		Implemented functions
235
	*/
236
237
	public function get_config($field) {
238
		switch ($field) {
239
			case 'code':
240
			case 'files':
241
			case 'root':
242
			case 'rootoptions':
243
				$result = $this->$field;
244
				break;
245
			default:
246
				$result =  null;
247
				debug("store::get_config: undefined field $field requested","store");
248
				break;
249
		}
250
		return $result;
251
	}
252
253 15
	public function is_supported($feature) {
254
	/**********************************************************************************
255
		This function takes as argument a feature description and returns
256
		true if this feature is supported and false otherwise
257
	**********************************************************************************/
258 15
		$result = false;
259
		switch($feature) {
260
			// features depending on config values
261 15
			case 'fulltext_boolean':
262 15
			case 'fulltext':
263 12
				if ($this->config[$feature]) {
264
					$result = true;
265
				} else {
266 12
					$result = false;
267
				}
268 12
			break;
269
			// features depending store implementation, if stores don't implements this, they have to override this function
270 15
			case 'grants':
271 15
			case 'regexp':
272 15
				$result = true;
273 15
			break;
274
		}
275 15
		return $result;
276
	}
277
278
	/**********************************************************************************
279
		This functions creates a new ariadne object
280
	**********************************************************************************/
281 35
	public function newobject($path, $parent, $type, $data, $id=0, $lastchanged=0, $vtype="", $size=0, $priority=0) {
282 35
		global $ARnls;
283 35
		$class = $type;
284 35
		if ($subcpos = strpos($type, '.')) {
285 6
			$class = substr($type, 0, $subcpos);
286 6
			$vtype = $class;
287 6
		}
288 35
		if (!class_exists($class, false)) {
289 1
			include_once($this->code."objects/".$class.".phtml");
290 1
		}
291 35
		$object=new $class;
292 35
		$object->type=$type;
293 35
		$object->parent=$parent;
294 35
		$object->id=(int)$id;
295 35
		$object->lastchanged=(int)$lastchanged;
296 35
		$object->vtype=$vtype;
297 35
		$object->size=(int)$size;
298 35
		$object->priority=(int)$priority;
299 35
		$object->ARnls = $ARnls;
300 35
		$object->init($this, $path, $data);
301 35
		return $object;
302
	}
303
304 26
	public function close() {
305
		// This is the destructor function, nothing much to see :)
306 26
		if (is_array($this->_filestores)) {
307
			foreach ($this->_filestores as $filestore) {
308
				$filestore->close();
309
			}
310
		}
311 26
	}
312
313 26
	public function __destruct() {
314 26
		$this->close();
315 26
	}
316
317 28
	public function make_path($curr_dir, $path) {
318 28
		return \arc\path::collapse($path, $curr_dir);
319
	}
320
321 17
	public function save_properties($properties, $id) {
322
	/********************************************************************
323
		'private' function of mysql.phtml. It updates all property tables
324
		defined in $properties and sets the values to the values in
325
		$properties.
326
	********************************************************************/
327
328 17
		if ($properties && (is_array($properties)) && (is_numeric($id))) {
329 12
			foreach ( $properties as $property => $property_set ) {
330 12
				$this->del_property((int)$id, $property);
331 12
				if (is_array($property_set)) {
332 12
					$property_set = array_unique($property_set,SORT_REGULAR);
333 12
					foreach ( $property_set as $values ) {
334 12
						$this->add_property((int)$id, $property, $values);
335 12
					}
336 12
				}
337 12
			}
338 12
		}
339 17
	}
340
341
342 25
	public function get_filestore($name) {
343 25
		global $AR;
344 25
		if (!$this->_filestores[$name]) {
345 25
			if ($AR->SVN->enabled && ($name == "templates")) {
346
				require_once($this->code."modules/mod_filestore_svn.phtml");
347
				$this->_filestores[$name]=new filestore_svn($name, $this->files, $this);
348
			} else {
349 25
				require_once($this->code."modules/mod_filestore.phtml");
350 25
				$this->_filestores[$name]=new filestore($name, $this->files, $this);
351
			}
352 25
		}
353 25
		return $this->_filestores[$name];
354
	}
355
356 7
	public function get_filestore_svn($name) {
357 7
		require_once($this->code."modules/mod_filestore_svn.phtml");
358 7
		if (!$this->_filestores["svn_" . $name]) {
359 7
			$this->_filestores["svn_" . $name] = new filestore_svn($name, $this->files, $this);
360 7
		}
361 7
		return $this->_filestores["svn_" . $name];
362
	}
363
364
	protected function compilerFactory(){
365
		switch($this->config["dbms"]){
366
			case 'axstore':
367
				return false;
368
			default:
369
				$compiler = $this->config["dbms"].'_compiler';
370
				return new $compiler($this,$this->tbl_prefix);
0 ignored issues
show
Bug introduced by
The property tbl_prefix does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
371
		}
372
	}
373
374 17
	protected function serialize($value, $path) {
375 17
		if ($value->failedDecrypt && $value->originalData) {
376
			$value = $value->originalData;
377
			return $value;
378
		}
379
380
		// Notice: When upgrading to a new crypto format, prepend the object data with a key of the crypto. This way you can be backwards compatible but new objects will be saved in the new crypto.
381 17
		if ($this->config['crypto'] instanceof \Closure) {
382
			$crypto = $this->config['crypto']();
383
			// use the last crypto configured;
384
			$cryptoConfig = end($crypto);
385
			if (is_array($cryptoConfig['paths'])) {
386
				foreach ($cryptoConfig['paths'] as $cryptoPath) {
387
					if (strpos($path, $cryptoPath) === 0) {
388
						$value->ARcrypted = true;
389
						switch ($cryptoConfig['method']) {
390
							case 'ar_crypt':
391
								$key = base64_decode($cryptoConfig['key']);
392
								$crypto = new ar_crypt($key,$cryptoConfig['crypto'],1);
393
								$cryptedValue = $crypto->crypt(serialize($value));
394
								if($cryptedValue !== false ) {
395
									return $cryptoConfig['token'] . ":" . $cryptedValue;
396
								}
397
							break;
398
							default:
399
							break;
400
						}
401
402
					}
403
				}
404
			}
405
		}
406 17
		unset($value->ARcrypted);
407 17
		return serialize($value);
408
	}
409
410 35
	private function fixObjectClass($value) {
411 35
		return str_replace('O:6:"object"', 'O:8:"stdClass"', $value);
412
	}
413
414 35
	protected function unserialize($value, $path) {
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
415 35
		if ($value[0] === "O" && $value[1] === ":") {
416 35
			return unserialize(self::fixObjectClass($value));
417
		} else if ($this->config['crypto'] instanceof \Closure) {
418
			$crypto = $this->config['crypto']();
419
			list($token,$datavalue) = explode(':', $value, 2);
420
			foreach ($crypto as $cryptoConfig) {
421
				$cryptoToken = $cryptoConfig['token'];
422
				if ($token === $cryptoToken ) {
423
					$value = $datavalue;
424
					switch ($cryptoConfig['method']) {
425
						case 'ar_crypt':
426
							$key = base64_decode($cryptoConfig['key']);
427
							$crypto = new ar_crypt($key,$cryptoConfig['crypto'],1);
428
							$decryptedValue =  $crypto->decrypt($value);
429
						break;
430
						default:
431
						break;
432
					}
433
				}
434
			}
435
436
			if ($decryptedValue[0] === "O" && $decryptedValue[1] === ":") {
437
				return unserialize(self::fixObjectClass($decryptedValue));
0 ignored issues
show
Bug introduced by
The variable $decryptedValue does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
438
			} else {
439
				$dummy = self::fixObjectClass(unserialize('O:6:"object":7:{s:5:"value";s:0:"";s:3:"nls";O:6:"object":2:{s:7:"default";s:2:"nl";s:4:"list";a:1:{s:2:"nl";s:10:"Nederlands";}}s:2:"nl";O:6:"object":1:{s:4:"name";s:14:"Crypted object";}s:6:"config";O:6:"object":2:{s:10:"owner_name";s:6:"Nobody";s:5:"owner";s:6:"nobody";}s:5:"mtime";i:0;s:5:"ctime";i:0;s:5:"muser";s:6:"nobody";}'));
440
				$dummy->failedDecrypt = true;
441
				$dummy->originalData = $value;
442
				return $dummy;
443
			}
444
		}
445
	}
446
447
} 
448