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); |
|
|
|
|
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
|
|
|
|
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.