setup_cmd_header::exec()   F
last analyzed

Complexity

Conditions 24
Paths 210

Size

Total Lines 83
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 24
eloc 43
c 0
b 0
f 0
nc 210
nop 1
dl 0
loc 83
rs 3.2083

How to fix   Long Method    Complexity   

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
 * EGgroupware setup - create or update the header.inc.php
4
 *
5
 * @link http://www.egroupware.org
6
 * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
7
 * @package setup
8
 * @copyright (c) 2007-19 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
9
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
10
 */
11
12
use EGroupware\Api;
13
14
/**
15
 * setup command: create or update the header.inc.php
16
 *
17
 * @ToDo: incorporate setup_header here
18
 */
19
class setup_cmd_header extends setup_cmd
20
{
21
	/**
22
	 * Instance of setup's header object
23
	 *
24
	 * @var setup_header
25
	 */
26
	private $setup_header;
27
	/**
28
	 * Full path of the header.inc.php
29
	 *
30
	 * @var string
31
	 */
32
	private $header_path;
33
34
	/**
35
	 * Constructor
36
	 *
37
	 * @param string|array $sub_command ='create' 'create','edit','delete'(-domain) or array with all arguments
38
	 * @param array $arguments =null comand line arguments
39
	 */
40
	function __construct($sub_command='create',$arguments=null)
41
	{
42
		if (!is_array($sub_command))
43
		{
44
			$sub_command = array(
45
				'sub_command' => $sub_command,
46
				'arguments'   => $arguments,
47
			);
48
		}
49
		//echo __CLASS__.'::__construct()'; _debug_array($domain);
50
		admin_cmd::__construct($sub_command);
51
52
		// header is 3 levels lower then this command in setup/inc
53
		$this->header_path = dirname(dirname(__DIR__)).'/header.inc.php';
54
55
		// if header is a symlink --> work on it's target
56
		if (is_link($this->header_path))
57
		{
58
			$this->header_path = readlink($this->header_path);
59
			if ($this->header_path[0] != '/' && $this->header_path[1] != ':')
60
			{
61
				$this->header_path = dirname(dirname(__DIR__)).'/'.$this->header_path;
62
			}
63
		}
64
		$this->setup_header = new setup_header();
65
	}
66
67
	/**
68
	 * Create or update header.inc.php
69
	 *
70
	 * @param boolean $check_only =false only run the checks (and throw the exceptions), but not the command itself
71
	 * @return string serialized $GLOBALS defined in the header.inc.php
72
	 * @throws Exception(lang('Wrong credentials to access the header.inc.php file!'),2);
73
	 * @throws Exception('header.inc.php not found!');
74
	 */
75
	protected function exec($check_only=false)
76
	{
77
		if ($check_only && $this->remote_id)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->remote_id of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
78
		{
79
			return true;	// can only check locally
80
		}
81
		if (!file_exists($this->header_path) || filesize($this->header_path) < 200)	// redirect header in rpms is ~150 byte
82
		{
83
			if ($this->sub_command != 'create')
0 ignored issues
show
Bug Best Practice introduced by
The property sub_command does not exist on setup_cmd_header. Since you implemented __get, consider adding a @property annotation.
Loading history...
84
			{
85
				throw new Api\Exception\WrongUserinput(lang('EGroupware configuration file (header.inc.php) does NOT exist.')."\n".lang('Use --create-header to create the configuration file (--usage gives more options).'),1);
86
			}
87
			$this->defaults(false);
0 ignored issues
show
Bug introduced by
The method defaults() does not exist on setup_cmd_header. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

87
			$this->/** @scrutinizer ignore-call */ 
88
          defaults(false);
Loading history...
88
		}
89
		else
90
		{
91
			if ($this->sub_command == 'create')
92
			{
93
				throw new Api\Exception\WrongUserinput(
94
					lang('EGroupware configuration file header.inc.php already exists, you need to use --edit-header or delete it first!'),20);
95
			}
96
			if ($this->arguments)
0 ignored issues
show
Bug Best Practice introduced by
The property arguments does not exist on setup_cmd_header. Since you implemented __get, consider adding a @property annotation.
Loading history...
97
			{
98
				list($this->header_admin_password,$this->header_admin_user) = explode(',',$this->arguments[1]);
0 ignored issues
show
Bug Best Practice introduced by
The property header_admin_password does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
Bug Best Practice introduced by
The property header_admin_user does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
99
			}
100
			$this->check_setup_auth($this->header_admin_user,$this->header_admin_password);	// no domain, we require header access!
101
102
			$GLOBALS['egw_info']['server']['server_root'] = EGW_SERVER_ROOT;
103
			$GLOBALS['egw_info']['server']['include_root'] = EGW_INCLUDE_ROOT;
104
		}
105
106
		if ($this->arguments)	// we have command line arguments
107
		{
108
			$this->_parse_cli_arguments();
109
		}
110
		elseif ($this->sub_command == 'delete')
111
		{
112
			self::_delete_domain($this->domain);
0 ignored issues
show
Bug Best Practice introduced by
The property domain does not exist on setup_cmd_header. Since you implemented __get, consider adding a @property annotation.
Loading history...
113
		}
114
		else
115
		{
116
			$this->_parse_properties();
117
		}
118
		if (($errors = $this->validation_errors($GLOBALS['egw_info']['server']['server_root'],
0 ignored issues
show
Bug introduced by
The method validation_errors() does not exist on setup_cmd_header. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
		if (($errors = $this->/** @scrutinizer ignore-call */ validation_errors($GLOBALS['egw_info']['server']['server_root'],
Loading history...
119
			$GLOBALS['egw_info']['server']['include_root'])))
120
		{
121
			if ($this->arguments)
122
			{
123
				unset($GLOBALS['egw_info']['flags']);
124
				echo '$GLOBALS[egw_info] = '; print_r($GLOBALS['egw_info']);
125
				echo '$GLOBALS[egw_domain] = '; print_r($GLOBALS['egw_domain']);
126
			}
127
			throw new Api\Exception\WrongUserinput(lang('Configuration errors:')."\n- ".implode("\n- ",$errors)."\n".lang("You need to fix the above errors, before the configuration file header.inc.php can be written!"),23);
128
		}
129
		if ($check_only)
130
		{
131
			return true;
132
		}
133
		// check if php has persistent mysql connections disabled --> disable it in header, to not fill the log with warnings
134
		if ($GLOBALS['egw_info']['server']['db_persistent'])
135
		{
136
			$GLOBALS['egw_info']['server']['db_persistent'] = $this->check_db_persistent($GLOBALS['egw_domain']);
0 ignored issues
show
Bug introduced by
The method check_db_persistent() does not exist on setup_cmd_header. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

136
			/** @scrutinizer ignore-call */ 
137
   $GLOBALS['egw_info']['server']['db_persistent'] = $this->check_db_persistent($GLOBALS['egw_domain']);
Loading history...
137
		}
138
		$header = $this->generate($GLOBALS['egw_info'],$GLOBALS['egw_domain']);
0 ignored issues
show
Bug introduced by
The method generate() does not exist on setup_cmd_header. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

138
		/** @scrutinizer ignore-call */ 
139
  $header = $this->generate($GLOBALS['egw_info'],$GLOBALS['egw_domain']);
Loading history...
139
140
		if ($this->arguments)
141
		{
142
			echo $header;	// for cli, we echo the header
143
		}
144
		if (file_exists($this->header_path) && is_writable($this->header_path) || is_writable(dirname($this->header_path)) ||
145
			function_exists('posix_getuid') && !posix_getuid())	// root has all rights
146
		{
147
			if (file_exists($this->header_path) && !is_writable($this->header_path))
148
			{
149
				unlink($this->header_path);
150
			}
151
			if (($f = fopen($this->header_path,'wb')) && fwrite($f,$header))
152
			{
153
				fclose($f);
154
				return lang('header.inc.php successful written.');
155
			}
156
		}
157
		throw new Api\Exception\NoPermission(lang("Failed writing configuration file header.inc.php, check the permissions !!!"),24);
158
	}
159
160
	/**
161
	 * Magic method to allow to call all methods from setup_header, as if they were our own
162
	 *
163
	 * @param string $method
164
	 * @param array $args =null
165
	 * @return mixed
166
	 */
167
	function __call($method,array $args=null)
168
	{
169
		if (method_exists($this->setup_header,$method))
170
		{
171
			return call_user_func_array(array($this->setup_header,$method),$args);
172
		}
173
	}
174
175
	/**
176
	 * Available options and allowed arguments
177
	 *
178
	 * @var array
179
	 */
180
	static $options = array(
181
		'--create-header' => array(
182
			'header_admin_password' => 'egw_info/server/',
183
			'header_admin_user' => 'egw_info/server/',
184
		),
185
		'--edit-header'   => array(
186
			'header_admin_password' => 'egw_info/server/',
187
			'header_admin_user' => 'egw_info/server/',
188
			'new_admin_password' => 'egw_info/server/header_admin_password',
189
			'new_admin_user' => 'egw_info/server/header_admin_user',
190
		),
191
		'--server-root'  => 'egw_info/server/server_root',
192
		'--include-root' => 'egw_info/server/include_root',
193
		'--session-type' => array(
194
			'sessions_type' => array(
195
				'type' => 'egw_info/server/',
196
				'allowed' => array('php'=>'php4','php4'=>'php4','php-restore'=>'php4-restore','php4-restore'=>'php4-restore','db'=>'db'),
197
			),
198
		),
199
		'--session-handler' => array(
200
			'session_handler' => array(
201
				'type' => 'egw_info/server/',
202
				'allowed' => array('files'=>'files','memcache'=>'memcache','db'=>'db'),
203
			),
204
		),
205
		'--limit-access' => 'egw_info/server/setup_acl',	// name used in setup
206
		'--setup-acl'    => 'egw_info/server/setup_acl',	// alias to match the real name
207
		'--mcrypt' => array(
208
			'mcrypt_enabled' => array(
209
				'type' => 'egw_info/server/',
210
				'allowed' => array('on' => true,'off' => false),
211
			),
212
			'mcrypt_iv' => 'egw_info/server/',
213
			'mcrypt' => 'egw_info/versions/mcrypt',
214
		),
215
		'--domain-selectbox' => array(
216
			'show_domain_selectbox' => array(
217
				'type' => 'egw_info/server/',
218
				'allowed' => array('on' => true,'off' => false),
219
			),
220
		),
221
		'--db-persistent' => array(
222
			'db_persistent' => array(
223
				'type' => 'egw_info/server/',
224
				'allowed' => array('on' => true,'off' => false),
225
			),
226
		),
227
		'--domain' => array(
228
			'domain' => '@',
229
			'db_name' => 'egw_domain/@/',
230
			'db_user' => 'egw_domain/@/',
231
			'db_pass' => 'egw_domain/@/',
232
			'db_type' => 'egw_domain/@/',
233
			'db_host' => 'egw_domain/@/',
234
			'db_port' => 'egw_domain/@/',
235
			'config_user'   => 'egw_domain/@/',
236
			'config_passwd' => 'egw_domain/@/',
237
		),
238
		'--delete-domain' => true,
239
	);
240
241
	/**
242
	 * Parses properties from this object
243
	 */
244
	private function _parse_properties()
245
	{
246
		foreach(self::$options as $arg => $option)
247
		{
248
			foreach(is_array($option) ? $option : array($option => $option) as $name => $data)
249
			{
250
				if (strpos($name,'/') !== false)
251
				{
252
					$name = array_pop($parts = explode('/',$name));
0 ignored issues
show
Bug introduced by
$parts = explode('/', $name) cannot be passed to array_pop() as the parameter $array expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

252
					$name = array_pop(/** @scrutinizer ignore-type */ $parts = explode('/',$name));
Loading history...
253
				}
254
				if (isset($this->$name))
255
				{
256
					$this->_parse_value($arg,$name,$data,$this->$name);
257
				}
258
			}
259
		}
260
	}
261
262
	/**
263
	 * Parses command line arguments in $this->arguments
264
	 */
265
	private function _parse_cli_arguments()
266
	{
267
		$arguments = $this->arguments;
0 ignored issues
show
Bug Best Practice introduced by
The property arguments does not exist on setup_cmd_header. Since you implemented __get, consider adding a @property annotation.
Loading history...
268
		while(($arg = array_shift($arguments)))
269
		{
270
			$values = count($arguments) && substr($arguments[0],0,2) !== '--' ? array_shift($arguments) : 'on';
271
272
			if ($arg == '--delete-domain')
273
			{
274
				$this->_delete_domain($values);
275
				continue;
276
			}
277
278
			if (!isset(self::$options[$arg]))
279
			{
280
				throw new Api\Exception\WrongUserinput(lang("Unknown option '%1' !!!",$arg),90);
0 ignored issues
show
Unused Code introduced by
The call to lang() has too many arguments starting with $arg. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

280
				throw new Api\Exception\WrongUserinput(/** @scrutinizer ignore-call */ lang("Unknown option '%1' !!!",$arg),90);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
281
			}
282
283
			$option = self::$options[$arg];
284
			$vals = !is_array($option) ? array($values) : explode(',',$values);
285
			if (!is_array($option)) $option = array($option => $option);
286
			$n = 0;
287
			foreach($option as $name => $data)
288
			{
289
				if ($n >= count($vals)) break;
290
291
				$this->_parse_value($arg,$name,$data,$vals[$n++]);
292
			}
293
		}
294
	}
295
296
	/**
297
	 * Delete a given domain/instance from the header
298
	 *
299
	 * @param string $domain
300
	 */
301
	private static function _delete_domain($domain)
302
	{
303
		if (!isset($GLOBALS['egw_domain'][$domain]))
304
		{
305
			throw new Api\Exception\WrongUserinput(lang("Domain '%1' does NOT exist !!!",$domain),92);
0 ignored issues
show
Unused Code introduced by
The call to lang() has too many arguments starting with $domain. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

305
			throw new Api\Exception\WrongUserinput(/** @scrutinizer ignore-call */ lang("Domain '%1' does NOT exist !!!",$domain),92);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
306
		}
307
		unset($GLOBALS['egw_domain'][$domain]);
308
	}
309
310
	/**
311
	 * Parses a single value
312
	 *
313
	 * @param string $arg current cli argument processed
314
	 * @param string $name name of the property
315
	 * @param array/string $data string with type or array containing values for type, allowed
0 ignored issues
show
Documentation Bug introduced by
The doc comment array/string at position 0 could not be parsed: Unknown type name 'array/string' at position 0 in array/string.
Loading history...
316
	 * @param mixed $value value to set
317
	 */
318
	private function _parse_value($arg,$name,$data,$value)
319
	{
320
		static $domain=null;
321
322
		if (!is_array($data)) $data = array('type' => $data);
323
		$type = $data['type'];
324
325
		if (isset($data['allowed']))
326
		{
327
			if (!isset($data['allowed'][$value]))
328
			{
329
				throw new Api\Exception\WrongUserinput(lang("'%1' is not allowed as %2. arguments of option %3 !!!",$value,1,$arg),91);
0 ignored issues
show
Unused Code introduced by
The call to lang() has too many arguments starting with $value. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

329
				throw new Api\Exception\WrongUserinput(/** @scrutinizer ignore-call */ lang("'%1' is not allowed as %2. arguments of option %3 !!!",$value,1,$arg),91);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
330
			}
331
			$value = $data['allowed'][$value];
332
		}
333
		if ($type == '@')
334
		{
335
			$domain = $arg == '--domain' && !$value ? 'default' : $value;
336
			if ($arg == '--domain' && (!isset($GLOBALS['egw_domain'][$domain]) || $this->sub_command == 'create'))
0 ignored issues
show
Bug Best Practice introduced by
The property sub_command does not exist on setup_cmd_header. Since you implemented __get, consider adding a @property annotation.
Loading history...
337
			{
338
				$GLOBALS['egw_domain'][$domain] = $this->domain_defaults($GLOBALS['egw_info']['server']['header_admin_user'],$GLOBALS['egw_info']['server']['header_admin_password']);
0 ignored issues
show
Bug introduced by
The method domain_defaults() does not exist on setup_cmd_header. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

338
				/** @scrutinizer ignore-call */ 
339
    $GLOBALS['egw_domain'][$domain] = $this->domain_defaults($GLOBALS['egw_info']['server']['header_admin_user'],$GLOBALS['egw_info']['server']['header_admin_password']);
Loading history...
339
			}
340
		}
341
		elseif ($value !== '')
342
		{
343
			self::_set_value($GLOBALS,str_replace('@',$domain,$type),$name,$value);
344
			if ($type == 'egw_info/server/server_root')
345
			{
346
				self::_set_value($GLOBALS,'egw_info/server/include_root',$name,$value);
347
			}
348
		}
349
	}
350
351
	/**
352
	 * Set a value in the given array $arr with (multidimensional) key $index[/$name]
353
	 *
354
	 * @param array &$arr
355
	 * @param string $index multidimensional index written with / as separator, eg. egw_info/server/
356
	 * @param string $name additional index to use if $index end with a slash
357
	 * @param mixed $value value to set
358
	 */
359
	static private function _set_value(&$arr,$index,$name,$value)
360
	{
361
		if (substr($index,-1) == '/') $index .= $name;
362
363
		$var =& $arr;
364
		foreach(explode('/',$index) as $name)
0 ignored issues
show
introduced by
$name is overwriting one of the parameters of this function.
Loading history...
365
		{
366
			$var =& $var[$name];
367
		}
368
		if (true) $var = $value;
369
	}
370
}
371