usage()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
nc 4
nop 1
dl 0
loc 6
rs 10
c 1
b 0
f 0
1
#!/usr/bin/env php
2
<?php
3
/**
4
 * EGroupware - check namespace usage in converted code
5
 *
6
 * @link http://www.egroupware.org
7
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
8
 * @author Ralf Becker <[email protected]>
9
 * @copyright 2016 by Ralf Becker <[email protected]>
10
 * @version $Id$
11
 */
12
13
if (php_sapi_name() !== 'cli')	// security precaution: forbit calling as web-page
14
{
15
	die('<h1>fix_api.php must NOT be called as web-page --> exiting !!!</h1>');
16
}
17
18
// raw replacements
19
$add_use_api = array(
20
	"#use EGroupware\\\\Api;\n#" => '',	// remove evtl. use EGroupware\Api, as we add it again below
21
	"#<\?php\n+\s*/\*+?(.*)\*/#msU" => "<?php\n/**$1*/\n\nuse EGroupware\\Api;",
22
);
23
$replace = array(
24
	'#egw_framework::csp_connect_src_attrs\(#' => "Api\\Header\\ContentSecurityPolicy::add('connect-src', ",
25
	'#egw_framework::csp_frame_src_attrs\(#' => "Api\\Header\\ContentSecurityPolicy::add('frame-src', ",
26
	'#egw_framework::csp_script_src_attrs\(#' => "Api\\Header\\ContentSecurityPolicy::add('script-src', ",
27
	'#egw_framework::csp_style_src_attrs\(#' => "Api\\Header\\ContentSecurityPolicy::add('style-src', ",
28
	"#egw_session::appsession\(([^,]+),\s*('[^']+')\)#" => 'Api\\Cache::getSession($2, $1)',
29
	"#egw_session::appsession\(([^,]+),\s*('[^']+'),\s*#" => 'Api\\Cache::setSession($2, $1, ',
30
	"#\\\$GLOBALS\['egw'\]->session->appsession\(([^,]+),\s*('[^']+')\)#" => 'Api\\Cache::getSession($2, $1)',
31
	"#\\\$GLOBALS\['egw'\]->session->appsession\(([^,]+),\s*('[^']+'),\s*#" => 'Api\\Cache::setSession($2, $1, ',
32
	"#\\\$GLOBALS\['egw'\]->common->#" => 'common::',
33
	"#\\\$GLOBALS\['egw'\]->hooks->#" => 'Api\\Hooks::',
34
	'#Api\\\\Hooks::hook_implemented#' => 'Api\\Hooks::implemented',
35
	'#Api\\\\Hooks::hook_exists#' => 'Api\\Hooks::exists',
36
	'#Api\\\\Hooks::register_(all_hooks|hooks|single_app_hook)\([^)]*\)#' => 'Api\\Hooks::read(true)',
37
	"#\\\$GLOBALS\['egw'\]->translation->#" => 'Api\\Translation::',
38
	"#\\\$GLOBALS\['egw'\]->country->#" => 'Api\\Country::',
39
	'#egw_framework::csp_script_src_attrs\((.*)\);#' => "Api\\Header\\ContentSecurityPolicy::add('script-src', \$1);",
40
	'#egw_framework::csp_style_src_attrs\((.*)\);#' => "Api\\Header\\ContentSecurityPolicy::add('style-src', \$1);",
41
	'#egw_framework::csp_connect_src_attrs\((.*)\);#' => "Api\\Header\\ContentSecurityPolicy::add('connect-src', \$1);",
42
	'#egw_framework::csp_frame_src_attrs\((.*)\);#' => "Api\\Header\\ContentSecurityPolicy::add('frame-src', \$1);",
43
	'#common::show_date\(([^,]+),\s*([^,]+),\s*false\)#' => 'Api\\DateTime::to($1, $2)',
44
	"#\\\$GLOBALS\['egw'\]->preferences->change#" => '$GLOBALS[\'egw\']->preferences->add',
45
);
46
// enclose class-names and static methods with some syntax check
47
$class_start = '#(?<!function)([\[\s,;().!=])';
48
$class_end = '(::|\\(|\\)|;|\?|:|\\s|,|$)#';
49
foreach(array(
50
	'accounts' => 'Api\\Accounts',
51
	'acl' => 'Api\\Acl',
52
	'EGW_ACL_READ' => 'Api\\Acl::READ',
53
	'EGW_ACL_ADD' => 'Api\\Acl::ADD',
54
	'EGW_ACL_EDIT' => 'Api\\Acl::EDIT',
55
	'EGW_ACL_DELETE' => 'Api\\Acl::DELETE',
56
	'EGW_ACL_PRIVATE' => 'Api\\Acl::PRIVAT',
57
	'EGW_ACL_GROUP_MANAGERS' => 'Api\\Acl::GROUPMGRS',
58
	'EGW_ACL_CUSTOM_1' => 'Api\\Acl::CUSTOM1',
59
	'EGW_ACL_CUSTOM_2' => 'Api\\Acl::CUSTOM2',
60
	'EGW_ACL_CUSTOM_3' => 'Api\\Acl::CUSTOM3',
61
	'applications' => 'Api\\Egw\\Applications',
62
	'asyncservice' => 'Api\\Asyncservice',
63
	'auth' => 'Api\\Auth',
64
	'categories' => 'Api\\Categories',
65
	'config::get_customfields' => 'Api\\Storage\\Customfields::get',
66
	'config' => 'Api\\Config',
67
	'common::setlocale' => 'Api\\Preferences::setlocale',
68
	'common::generate_uid' => 'Api\\CalDAV::generate_uid',
69
	'common::ldap_addslashes' => 'Api\\Ldap::quote',
70
	'common::ldapConnect' => 'Api\\Ldap::factory',
71
	'common::egw_exit' => 'exit',
72
	'common::randomstring' => 'Api\\Auth::randomstring',
73
	'common::display_fullname' => 'Api\\Accounts::format_username',
74
	'common::grab_owner_name' => 'Api\\Accounts::username',
75
	'common::find_image' => 'Api\\Image::find',
76
	'common::image' => 'Api\\Image::find',
77
	'common::svg_usable' => 'Api\\Image::svg_usable',
78
	'common::image_map' => 'Api\\Image::map',
79
	'common::delete_image_map' => 'Api\\Image::invalidate',
80
	'common::transliterate' => 'Api\\Translation::to_ascii',
81
	'common::email_address' => 'Api\\Accounts::email',
82
	'common::next_id' => 'Api\\Accounts\\Ldap::next_id',
83
	'common::last_id' => 'Api\\Accounts\\Ldap::last_id',
84
	'common::egw_header' => "echo \$GLOBALS['egw']->framework->header",
85
	'common::egw_footer' => "echo \$GLOBALS['egw']->framework->footer",
86
	'common::show_date' => 'Api\\DateTime::server2user',
87
	'common::get_tpl_dir' => 'Api\\Framework\\Template::get_dir',
88
	'common::get_referer' => 'Api\\Header\\Referer::get',
89
	'country' => 'Api\\Country',
90
	'egw' => 'Api\\Egw',
91
	'egw_minimal' => 'Api\\Egw\\Base',
92
	'egw_cache' => 'Api\\Cache',
93
	'egw_ckeditor_config' => 'Api\\Html\\CkEditorConfig',
94
	'egw_customfields' => 'Api\\Storage\\Customfields',
95
	'egw_db' => 'Api\\Db',
96
	'egw_digest_auth' => 'Api\\Header\\Authentication',
97
	'egw_exception' => 'Api\\Exception',
98
	'egw_exception_no_permission' => 'Api\\Exception\\NoPermission',
99
	'egw_exception_no_permission_app' => 'Api\\Exception\\NoPermission\\App',
100
	'egw_exception_no_permission_admin' => 'Api\\Exception\\NoPermission\\Admin',
101
	'egw_exception_no_permission_record' => 'Api\\Exception\\NoPermission\\Record',
102
	'egw_exception_not_found' => 'Api\\Exception\\NotFound',
103
	'egw_exception_assertion_failed' => 'Api\\Exception\\AssertionFailed',
104
	'egw_exception_wrong_parameter' => 'Api\\Exception\\WrongParameter',
105
	'egw_exception_wrong_userinput' => 'Api\\Exception\\WrongUserinput',
106
	'egw_exception_db' => 'Api\\Db\\Exception',
107
	'egw_exception_db_invalid_sql' => 'Api\\Db\\Exception\\InvalidSql',
108
	'egw_exception_redirect' => 'Api\\Exception\\Redirect',
109
	'egw_favorites' => 'Api\\Framework\\Favorites',
110
	'egw_framework::validate_file' => 'Api\\Framework::includeJS',
111
	'egw_framework::favorite_list' => 'Api\\Framework\\Favorites::list_favorites',
112
	'egw_framework' => 'Api\\Framework',
113
	'egw_json_request' => 'Api\\Json\\Request',
114
	'egw_json_response' => 'Api\\Json\\Response',
115
	'egw_link' => 'Api\\Link',
116
	'egw_mailer' => 'Api\\Mailer',
117
	'egw_session' => 'Api\\Session',
118
	'egw_tail' => 'Api\\Json\\Tail',
119
	'egw_time' => 'Api\\DateTime',
120
	'egw_vfs' => 'Api\\Vfs',
121
	'groupdav' => 'Api\CalDAV',
122
	'groupdav_principal' => 'Api\\CalDAV\\Principal',
123
	'groupdav_handler' => 'Api\\CalDAV\\Handler',
124
	'egw_ical_iterator' => 'Api\\CalDAV\\IcalIterator',
125
	'historylog' => 'Api\\Storage\\History',
126
	'html::\$user_agent' => 'Api\\Header\\UserAgent::type()',
127
	'html::\$ua_version' => 'Api\\Header\\UserAgent::version()',
128
	'html::\$ua_mobile' => 'Api\\Header\\UserAgent::mobile()',
129
	'html::safe_content_header' => 'Api\\Header\\Content::safe',
130
	'html::content_header' => 'Api\\Header\\Content::type',
131
	'html::content_disposition_header' => 'Api\\Header\\Content::disposition',
132
	'html' => 'Api\\Html',
133
	'iface_stream_wrapper' => 'Api\\Vfs\\StreamWrapperIface',
134
	'mime_magic' => 'Api\\MimeMagic',
135
	'preferences' => 'Api\\Preferences',
136
	'solink' => 'Api\\Link\\Storage',
137
	'sqlfs_stream_wrapper' => 'Api\\Vfs\\Sqlfs\\StreamWrapper',
138
	'sqlfs_utils' => 'Api\\Vfs\\Sqlfs\\Utils',
139
	'Template' => 'Api\\Framework\\Template',
140
	'translation::decodeMailHeader' => 'Api\\Mail\\Html::decodeMailHeader',
141
	'translation::replaceEmailAdresses' => 'Api\\Mail\\Html::replaceEmailAdresses',
142
	'translation::replaceTagsCompletley' => 'Api\\Mail\\Html::replaceTagsCompletley',
143
	'translation::transform_mailto2text' => 'Api\\Mail\\Html::transform_mailto2text',
144
	'translation::transform_url2text' => 'Api\\Mail\\Html::transform_url2text',
145
	'translation::convertHTMLToText' => 'Api\\Mail\\Html::convertHTMLToText',
146
	'translation::splithtmlByPRE' => 'Api\\Mail\\Html::splithtmlByPRE',
147
	'translation' => 'Api\\Translation',
148
	// etemplate2
149
	'etemplate_new' => 'Api\\Etemplate',
150
	'etemplate_widget' => 'Api\\Etemplate\\Widget',
151
	'etemplate_widget_entry' => 'Api\\Etemplate\\Widget\\Entry',
152
	'etemplate_widget_tree' => 'Api\\Etemplate\\Widget\\Tree',
153
	'etemplate_widget_select' => 'Api\\Etemplate\\Widget\\Select',
154
	'etemplate_widget_link' => 'Api\\Etemplate\\Widget\\Link',
155
	'etemplate_widget_nextmatch' => 'Api\\Etemplate\\Widget\\Nextmatch',
156
	'etemplate_widget_taglist' => 'Api\\Etemplate\\Widget\\Taglist',
157
	'etemplate_widget_file' => 'Api\\Etemplate\\Widget\\File',
158
	'etemplate_widget_vfs' => 'Api\\Etemplate\\Widget\\Vfs',
159
	'etemplate_request' => 'Api\\Etemplate\\Request',
160
	'nextmatch_widget::category_action' => 'Api\\Etemplate\\Widget\\Nextmatch::category_action',
161
	'nextmatch_widget::DEFAULT_MAX_MENU_LENGTH' => 'Api\\Etemplate\\Widget\\Nextmatch::DEFAULT_MAX_MENU_LENGTH',
162
	'customfields_widget::update_customfield_links' => 'Api\Storage\Customfields::update_links',
163
	'egw_keymanager' => 'Api\\Etemplate\\KeyManager',
164
	'etemplate::array_stripslashes' => 'array_stripslashes',
165
	// so_sql and friends
166
	'so_sql' => 'Api\\Storage\\Base',
167
	'so_sql_cf' => 'Api\\Storage',
168
	'so_sql2' => 'Api\\Storage\\Base2',
169
	'bo_tracking' => 'Api\\Storage\\Tracking',
170
	'bo_merge' => 'Api\\Storage\\Merge',
171
	// addressbook backend
172
	'addressbook_bo' => 'Api\\Contacts',
173
	'addressbook_so' => 'Api\\Contacts\\Storage',
174
	'addressbook_merge' => 'Api\\Contacts\\Merge',
175
) as $from => $to)
176
{
177
	$replace[$class_start.$from.$class_end] = '$1'.$to.'$2';
178
}
179
// raw expressions running after regular replacements, because they would be replaced themself if running before
180
$replace += array(
181
	"#\\\$GLOBALS\['egw'\]->js->#" => 'egw_framework::',
182
);
183
//print_r($replace);
184
185
/**
186
 * Check namespace usage in converted code
187
 *
188
 * @param string $file filename
189
 * @param boolean $dry_run =false true: only echo fixed file, not fix it
190
 * @return boolean false on error
191
 */
192
function fix_api($file, $dry_run=false)
193
{
194
	global $prog, $replace, $add_use_api;
195
	if (basename($file) == $prog) return true;	// dont fix ourself ;-)
196
197
	if (($content = $content_in = file_get_contents($file)) === false) return false;
198
199
	if (!preg_match("|<\?php\n+\s*/\*\*?.*\*/|msU", $content))
200
	{
201
		error_log("No file-level phpDoc block found in $file to add 'use EGroupware\\Api;'\n");
202
		return;
203
	}
204
	$content2 = preg_replace(array_keys($replace), array_values($replace), $content);
205
206
	if ($content2 == $content_in) return true;	// nothing changed
207
208
	$content = preg_replace(array_keys($add_use_api), array_values($add_use_api), $content2);
209
210
	// shorten some classes, if used, with further use declarations
211
	foreach(array('Api\\Etemplate', 'Api\\Vfs', 'Api\\Acl', 'Api\\Egw', 'Api\\Framework', 'Api\\Link') as $namespace)
212
	{
213
		if (strpos($content, $namespace) !== false && strpos($content, 'use EGroupware\\'.$namespace) === false)
214
		{
215
			$content = strtr($content, array(
216
				$namespace => str_replace('Api\\', '', $namespace),
217
				"use EGroupware\\Api;" => "use EGroupware\\Api;\nuse EGroupware\\$namespace;"
218
			));
219
		}
220
	}
221
222
	if ($dry_run)
223
	{
224
		echo $content;
225
	}
226
	else
227
	{
228
		file_put_contents($file.'.new', $content);
229
		$ret = 0;
230
		system('/usr/bin/php -l '.$file.'.new', $ret);
231
		system('/usr/bin/diff -u '.$file.' '.$file.'.new');
232
		if (!$ret)
233
		{
234
			unlink($file);
235
			rename($file.'.new', $file);
236
		}
237
		return !$ret;
238
	}
239
240
	return true;
241
}
242
243
/**
244
 * Loop recursive through directory and call fix_api for each php file
245
 *
246
 * @param string $dir
247
 * @param boolean $dry_run =false true: only echo fixed file, not fix it
248
 * @return boolean false on error
249
 */
250
function fix_api_recursive($dir, $dry_run=false)
251
{
252
	if (!is_dir($dir)) return false;
253
254
	foreach(scandir($dir) as $file)
255
	{
256
		if ($file == '.' || $file == '..') continue;
257
258
		if (is_dir($dir.'/'.$file))
259
		{
260
			fix_api_recursive($dir.'/'.$file, $dry_run);
261
		}
262
		elseif(substr($file,-4) == '.php')
263
		{
264
			echo "\r".str_repeat(' ',100)."\r".$dir.'/'.$file.': ';
265
			fix_api($dir.'/'.$file, $dry_run);
266
		}
267
	}
268
	echo "\r".str_repeat(' ',100)."\r";
269
	return true;
270
}
271
272
/**
273
 * Give usage
274
 *
275
 * @param string $error =null
276
 */
277
function usage($error=null)
278
{
279
	global $prog;
280
	echo "Usage: $prog [-h|--help] [-d|--dry-run] file(s) or dir(s)\n\n";
281
	if ($error) echo $error."\n\n";
282
	exit($error ? 1 : 0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
283
}
284
285
$args = $_SERVER['argv'];
286
$prog = basename(array_shift($args));
287
288
if (!$args) usage();
289
290
$dry_run = false;
291
while(($arg = array_shift($args)) && $arg[0] == '-')
292
{
293
	switch($arg)
294
	{
295
		case '-h':
296
		case '--help':
297
			usage();
298
			break;
299
300
		case '-d':
301
		case '--dry-run':
302
			$dry_run = true;
303
			break;
304
305
		default:
306
			if ($args)	// not last argument
307
			{
308
				usage("Unknown argument '$arg'!");
309
			}
310
			break 2;
311
	}
312
}
313
314
do {
315
	if (!file_exists($arg)) usage("Error: $arg not found!");
316
317
	if (!is_dir($arg))
318
	{
319
		fix_api($arg, $dry_run);
320
	}
321
	else
322
	{
323
		fix_api_recursive($arg, $dry_run);
324
	}
325
}
326
while(($arg = array_shift($args)));
327