1
- <?php
1
+ <?php
2
2
if (!defined ('sugarEntry ' ) || !sugarEntry) die ('Not A Valid Entry Point ' );
3
3
/*********************************************************************************
4
4
* SugarCRM Community Edition is a customer relationship management program developed by
@@ -53,11 +53,11 @@ class ModuleScanner{
53
53
'install_languages ' =>'language ' ,
54
54
'install_logichooks ' =>'logic_hooks ' ,
55
55
'post_execute ' =>'post_execute ' ,
56
-
56
+
57
57
);
58
-
58
+
59
59
private $ blackListExempt = array ();
60
-
60
+
61
61
private $ validExt = array ('png ' , 'gif ' , 'jpg ' , 'css ' , 'js ' , 'php ' , 'txt ' , 'html ' , 'htm ' , 'tpl ' , 'pdf ' , 'md5 ' , 'xml ' );
62
62
private $ blackList = array (
63
63
'popen ' ,
@@ -120,9 +120,9 @@ class ModuleScanner{
120
120
'exec ' ,
121
121
'system ' ,
122
122
'shell_exec ' ,
123
- 'passthru ' ,
123
+ 'passthru ' ,
124
124
'chgrp ' ,
125
- 'chmod ' ,
125
+ 'chmod ' ,
126
126
'chwown ' ,
127
127
'file_put_contents ' ,
128
128
'file ' ,
@@ -133,7 +133,7 @@ class ModuleScanner{
133
133
'filemtime ' ,
134
134
'fileowner ' ,
135
135
'fileperms ' ,
136
- 'fopen ' ,
136
+ 'fopen ' ,
137
137
'is_executable ' ,
138
138
'is_writable ' ,
139
139
'is_writeable ' ,
@@ -152,7 +152,7 @@ class ModuleScanner{
152
152
'call_user_func ' ,
153
153
'call_user_func_array ' ,
154
154
'create_function ' ,
155
-
155
+
156
156
157
157
//mutliple files per function call
158
158
'copy ' ,
@@ -182,14 +182,14 @@ public function printToWiki(){
182
182
echo "'''Default Extensions'''<br> " ;
183
183
foreach ($ this ->validExt as $ b ){
184
184
echo '# ' . $ b . '<br> ' ;
185
-
185
+
186
186
}
187
187
echo "'''Default Black Listed Functions'''<br> " ;
188
188
foreach ($ this ->blackList as $ b ){
189
189
echo '# ' . $ b . '<br> ' ;
190
-
190
+
191
191
}
192
-
192
+
193
193
}
194
194
195
195
public function __construct (){
@@ -202,42 +202,42 @@ public function __construct(){
202
202
if (!empty ($ GLOBALS ['sugar_config ' ]['moduleInstaller ' ]['validExt ' ])){
203
203
$ this ->validExt = array_merge ($ this ->validExt , $ GLOBALS ['sugar_config ' ]['moduleInstaller ' ]['validExt ' ]);
204
204
}
205
-
205
+
206
206
}
207
207
208
208
private $ issues = array ();
209
209
private $ pathToModule = '' ;
210
-
210
+
211
211
/**
212
212
*returns a list of issues
213
213
*/
214
214
public function getIssues (){
215
215
return $ this ->issues ;
216
216
}
217
-
217
+
218
218
/**
219
219
*returns true or false if any issues were found
220
220
*/
221
221
public function hasIssues (){
222
222
return !empty ($ this ->issues );
223
223
}
224
-
224
+
225
225
/**
226
226
*Ensures that a file has a valid extension
227
227
*/
228
228
private function isValidExtension ($ file ){
229
229
$ file = strtolower ($ file );
230
-
230
+
231
231
$ extPos = strrpos ($ file , '. ' );
232
232
//make sure they don't override the files.md5
233
233
if ($ extPos === false || $ file == 'files.md5 ' )return false ;
234
234
$ ext = substr ($ file , $ extPos + 1 );
235
235
return in_array ($ ext , $ this ->validExt );
236
-
236
+
237
237
}
238
-
238
+
239
239
/**
240
- *Scans a directory and calls on scan file for each file
240
+ *Scans a directory and calls on scan file for each file
241
241
**/
242
242
public function scanDir ($ path ){
243
243
static $ startPath = '' ;
@@ -249,21 +249,40 @@ public function scanDir($path){
249
249
if (is_dir ($ next )){
250
250
if (substr ($ e , 0 , 1 ) == '. ' )continue ;
251
251
$ this ->scanDir ($ next );
252
- }else {
252
+ }else {
253
253
$ issues = $ this ->scanFile ($ next );
254
-
255
-
254
+
255
+
256
256
}
257
257
}
258
258
return true ;
259
259
}
260
-
261
-
260
+
261
+ /**
262
+ * Check if the file contents looks like PHP
263
+ * @param string $contents File contents
264
+ * @return boolean
265
+ */
266
+ protected function isPHPFile ($ contents )
267
+ {
268
+ if (stripos ($ contents , '<?php ' ) !== false ) return true ;
269
+ for ($ tag =0 ;($ tag = stripos ($ contents , '<? ' , $ tag )) !== false ;$ tag ++) {
270
+ if (strncasecmp (substr ($ contents , $ tag , 13 ), '<?xml version ' , 13 )) {
271
+ // <?xml version is OK, skip it
272
+ $ tag ++;
273
+ continue ;
274
+ }
275
+ // found <?, it's PHP
276
+ return true ;
277
+ }
278
+ return false ;
279
+ }
280
+
262
281
/**
263
- * Given a file it will open it's contents and check if it is a PHP file (not safe to just rely on extensions) if it finds <?php tags it will use the tokenizer to scan the file
264
- * $var() and ` are always prevented then whatever is in the blacklist.
282
+ * Given a file it will open it's contents and check if it is a PHP file (not safe to just rely on extensions) if it finds <?php tags it will use the tokenizer to scan the file
283
+ * $var() and ` are always prevented then whatever is in the blacklist.
265
284
* It will also ensure that all files are of valid extension types
266
- *
285
+ *
267
286
*/
268
287
public function scanFile ($ file ){
269
288
$ issues = array ();
@@ -273,8 +292,8 @@ public function scanFile($file){
273
292
return $ issues ;
274
293
}
275
294
$ contents = file_get_contents ($ file );
276
- if (stripos ($ contents, ' <?php ' ) === false ) return $ issues ;
277
- $ tokens = token_get_all ($ contents );
295
+ if (! $ this -> isPHPFile ($ contents)) return $ issues ;
296
+ $ tokens = @ token_get_all ($ contents );
278
297
$ checkFunction = false ;
279
298
$ possibleIssue = '' ;
280
299
$ lastToken = false ;
@@ -285,7 +304,7 @@ public function scanFile($file){
285
304
$ issues ['backtick ' ] = translate ('ML_INVALID_FUNCTION ' ) . " '`' " ;
286
305
case '( ' :
287
306
if ($ checkFunction )$ issues [] = $ possibleIssue ;
288
- break ;
307
+ break ;
289
308
}
290
309
$ checkFunction = false ;
291
310
$ possibleIssue = '' ;
@@ -301,16 +320,16 @@ public function scanFile($file){
301
320
$ token [1 ] = strtolower ($ token [1 ]);
302
321
if (!in_array ($ token [1 ], $ this ->blackList ))break ;
303
322
if (in_array ($ token [1 ], $ this ->blackListExempt ))break ;
304
- if ($ lastToken !== false &&
305
- ($ lastToken [0 ] == T_NEW || $ lastToken [0 ] == T_OBJECT_OPERATOR || $ lastToken [0 ] == T_DOUBLE_COLON ))
323
+ if ($ lastToken !== false &&
324
+ ($ lastToken [0 ] == T_NEW || $ lastToken [0 ] == T_OBJECT_OPERATOR || $ lastToken [0 ] == T_DOUBLE_COLON ))
306
325
{
307
326
break ;
308
327
}
309
328
case T_VARIABLE :
310
329
$ checkFunction = true ;
311
330
$ possibleIssue = translate ('ML_INVALID_FUNCTION ' ) . ' ' . $ token [1 ] . '() ' ;
312
331
break ;
313
-
332
+
314
333
default :
315
334
$ checkFunction = false ;
316
335
$ possibleIssue = '' ;
@@ -321,18 +340,18 @@ public function scanFile($file){
321
340
$ lastToken = $ token ;
322
341
}
323
342
}
324
-
343
+
325
344
}
326
345
if (!empty ($ issues )){
327
346
$ this ->issues ['file ' ][$ file ] = $ issues ;
328
347
}
329
-
330
- return $ issues ;
348
+
349
+ return $ issues ;
331
350
}
332
-
333
-
351
+
352
+
334
353
/*
335
- * checks files.md5 file to see if the file is from sugar
354
+ * checks files.md5 file to see if the file is from sugar
336
355
* ONLY WORKS ON FILES
337
356
*/
338
357
public function sugarFileExists ($ path ){
@@ -343,11 +362,11 @@ public function sugarFileExists($path){
343
362
$ md5 = $ md5_string ;
344
363
}
345
364
if (isset ($ md5 ['./ ' . $ path ]))return true ;
346
-
347
-
365
+
366
+
348
367
}
349
-
350
-
368
+
369
+
351
370
/**
352
371
*This function will scan the Manifest for disabled actions specified in $GLOBALS['sugar_config']['moduleInstaller']['disableActions']
353
372
*if $GLOBALS['sugar_config']['moduleInstaller']['disableRestrictedCopy'] is set to false or not set it will call on scanCopy to ensure that it is not overriding files
@@ -364,18 +383,18 @@ public function scanManifest($manifestPath){
364
383
return $ fileIssues ;
365
384
}
366
385
include ($ manifestPath );
367
-
368
-
369
- //scan for disabled actions
386
+
387
+
388
+ //scan for disabled actions
370
389
if (isset ($ GLOBALS ['sugar_config ' ]['moduleInstaller ' ]['disableActions ' ])){
371
390
foreach ($ GLOBALS ['sugar_config ' ]['moduleInstaller ' ]['disableActions ' ] as $ action ){
372
391
if (isset ($ installdefs [$ this ->manifestMap [$ action ]])){
373
392
$ issues [] = translate ('ML_INVALID_ACTION_IN_MANIFEST ' ) . $ this ->manifestMap [$ action ];
374
393
}
375
394
}
376
395
}
377
-
378
- //now lets scan for files that will override our files
396
+
397
+ //now lets scan for files that will override our files
379
398
if (empty ($ GLOBALS ['sugar_config ' ]['moduleInstaller ' ]['disableRestrictedCopy ' ]) && isset ($ installdefs ['copy ' ])){
380
399
foreach ($ installdefs ['copy ' ] as $ copy ){
381
400
$ from = str_replace ('<basepath> ' , $ this ->pathToModule , $ copy ['from ' ]);
@@ -391,25 +410,25 @@ public function scanManifest($manifestPath){
391
410
}
392
411
while (substr_count ($ to , '// ' )){
393
412
$ to = str_replace ('// ' , '/ ' , $ to );
394
- }
413
+ }
395
414
$ this ->scanCopy ($ from , $ to );
396
415
}
397
416
}
398
417
if (!empty ($ issues )){
399
418
$ this ->issues ['manifest ' ][$ manifestPath ] = $ issues ;
400
419
}
401
-
402
-
403
-
420
+
421
+
422
+
404
423
}
405
-
406
-
424
+
425
+
407
426
408
427
/**
409
- * Takes in where the file will is specified to be copied from and to
410
- * and ensures that there is no official sugar file there. If the file exists it will check
428
+ * Takes in where the file will is specified to be copied from and to
429
+ * and ensures that there is no official sugar file there. If the file exists it will check
411
430
* against the MD5 file list to see if Sugar Created the file
412
- *
431
+ *
413
432
*/
414
433
function scanCopy ($ from , $ to ){
415
434
//if the file doesn't exist for the $to then it is not overriding anything
@@ -421,28 +440,28 @@ function scanCopy($from, $to){
421
440
}
422
441
$ to .= '/ ' . basename ($ from );
423
442
}
424
- //if the $to is a file and it is found in sugarFileExists then don't allow overriding it
443
+ //if the $to is a file and it is found in sugarFileExists then don't allow overriding it
425
444
if (is_file ($ to ) && $ this ->sugarFileExists ($ to )){
426
445
$ this ->issues ['copy ' ][$ from ] = translate ('ML_OVERRIDE_CORE_FILES ' ) . '( ' . $ to . ') ' ;
427
446
}
428
-
447
+
429
448
if (is_dir ($ from )){
430
449
$ d = dir ($ from );
431
450
while ($ e = $ d ->read ()){
432
451
if ($ e == '. ' || $ e == '.. ' )continue ;
433
- $ this ->scanCopy ($ from .'/ ' . $ e , $ to .'/ ' . $ e );
452
+ $ this ->scanCopy ($ from .'/ ' . $ e , $ to .'/ ' . $ e );
434
453
}
435
454
}
436
-
437
-
438
-
439
-
440
-
455
+
456
+
457
+
458
+
459
+
441
460
}
442
-
443
-
461
+
462
+
444
463
/**
445
- *Main external function that takes in a path to a package and then scans
464
+ *Main external function that takes in a path to a package and then scans
446
465
*that package's manifest for disabled actions and then it scans the PHP files
447
466
*for restricted function calls
448
467
*
@@ -454,22 +473,22 @@ public function scanPackage($path){
454
473
$ this ->scanDir ($ path );
455
474
}
456
475
}
457
-
476
+
458
477
/**
459
- *This function will take all issues of the current instance and print them to the screen
478
+ *This function will take all issues of the current instance and print them to the screen
460
479
**/
461
480
public function displayIssues ($ package ='Package ' ){
462
- echo '<h2> ' .str_replace ('{PACKAGE} ' , $ package ,translate ('ML_PACKAGE_SCANNING ' )). '</h2><BR><h2 class="error"> ' . translate ('ML_INSTALLATION_FAILED ' ) . '</h2><br><p> ' .str_replace ('{PACKAGE} ' , $ package ,translate ('ML_PACKAGE_NOT_CONFIRM ' )). '</p><ul><li> ' . translate ('ML_OBTAIN_NEW_PACKAGE ' ) . '<li> ' . translate ('ML_RELAX_LOCAL ' ).
481
+ echo '<h2> ' .str_replace ('{PACKAGE} ' , $ package ,translate ('ML_PACKAGE_SCANNING ' )). '</h2><BR><h2 class="error"> ' . translate ('ML_INSTALLATION_FAILED ' ) . '</h2><br><p> ' .str_replace ('{PACKAGE} ' , $ package ,translate ('ML_PACKAGE_NOT_CONFIRM ' )). '</p><ul><li> ' . translate ('ML_OBTAIN_NEW_PACKAGE ' ) . '<li> ' . translate ('ML_RELAX_LOCAL ' ).
463
482
'</ul></p><br> ' . translate ('ML_SUGAR_LOADING_POLICY ' ) . ' <a href=" http://kb.sugarcrm.com/custom/module-loader-restrictions-for-sugar-open-cloud/"> ' . translate ('ML_SUGAR_KB ' ) . '</a>. ' .
464
483
'<br> ' . translate ('ML_AVAIL_RESTRICTION ' ). ' <a href=" http://developers.sugarcrm.com/wordpress/2009/08/14/module-loader-restrictions/"> ' . translate ('ML_SUGAR_DZ ' ) . '</a>.<br><br> ' ;
465
484
466
-
485
+
467
486
foreach ($ this ->issues as $ type =>$ issues ){
468
487
echo '<div class="error"><h2> ' . ucfirst ($ type ) .' ' . translate ('ML_ISSUES ' ) . '</h2> </div> ' ;
469
- echo '<div id="details ' . $ type . '" > ' ;
488
+ echo '<div id="details ' . $ type . '" > ' ;
470
489
foreach ($ issues as $ file =>$ issue ){
471
490
$ file = str_replace ($ this ->pathToModule . '/ ' , '' , $ file );
472
- echo '<div style="position:relative;left:10px"><b> ' . $ file . '</b></div><div style="position:relative;left:20px"> ' ;
491
+ echo '<div style="position:relative;left:10px"><b> ' . $ file . '</b></div><div style="position:relative;left:20px"> ' ;
473
492
if (is_array ($ issue )){
474
493
foreach ($ issue as $ i ){
475
494
echo "$ i<br> " ;
@@ -480,13 +499,13 @@ public function displayIssues($package='Package'){
480
499
echo "</div> " ;
481
500
}
482
501
echo '</div> ' ;
483
-
502
+
484
503
}
485
504
echo "<br><input class='button' onclick='document.location.href= \"index.php?module=Administration&action=UpgradeWizard&view=module \"' type='button' value= \"" . translate ('LBL_UW_BTN_BACK_TO_MOD_LOADER ' ) . "\" /> " ;
486
-
505
+
487
506
}
488
-
489
-
507
+
508
+
490
509
}
491
510
492
511
0 commit comments