Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

ModuleInstall/PackageManager/PackageManager.php (17 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*********************************************************************************
3
 * SugarCRM Community Edition is a customer relationship management program developed by
4
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
5
6
 * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
7
 * Copyright (C) 2011 - 2014 Salesagility Ltd.
8
 *
9
 * This program is free software; you can redistribute it and/or modify it under
10
 * the terms of the GNU Affero General Public License version 3 as published by the
11
 * Free Software Foundation with the addition of the following permission added
12
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
13
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
14
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
15
 *
16
 * This program is distributed in the hope that it will be useful, but WITHOUT
17
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License along with
22
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
23
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24
 * 02110-1301 USA.
25
 *
26
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
27
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
28
 *
29
 * The interactive user interfaces in modified source and object code versions
30
 * of this program must display Appropriate Legal Notices, as required under
31
 * Section 5 of the GNU Affero General Public License version 3.
32
 *
33
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
34
 * these Appropriate Legal Notices must retain the display of the "Powered by
35
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
36
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
37
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
38
 ********************************************************************************/
39
40
41
define("CREDENTIAL_CATEGORY", "ml");
42
define("CREDENTIAL_USERNAME", "username");
43
define("CREDENTIAL_PASSWORD", "password");
44
45
require_once('include/nusoap/nusoap.php');
46
require_once('include/utils/zip_utils.php');
47
require_once('ModuleInstall/PackageManager/PackageManagerDisplay.php');
48
require_once('ModuleInstall/ModuleInstaller.php');
49
require_once('include/entryPoint.php');
50
require_once('ModuleInstall/PackageManager/PackageManagerComm.php');
51
52
class PackageManager{
53
    var $soap_client;
54
55
    /**
56
     * Constructor: In this method we will initialize the nusoap client to point to the hearbeat server
57
     */
58
    function __construct(){
59
        $this->db = DBManagerFactory::getInstance();
60
        $this->upload_dir = empty($GLOBALS['sugar_config']['upload_dir']) ? 'upload' : rtrim($GLOBALS['sugar_config']['upload_dir'], '/\\');
61
    }
62
63
    /**
64
     * @deprecated deprecated since version 7.6, PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code, use __construct instead
65
     */
66
    function PackageManager(){
67
        $deprecatedMessage = 'PHP4 Style Constructors are deprecated and will be remove in 7.8, please update your code';
68
        if(isset($GLOBALS['log'])) {
69
            $GLOBALS['log']->deprecated($deprecatedMessage);
70
        }
71
        else {
72
            trigger_error($deprecatedMessage, E_USER_DEPRECATED);
73
        }
74
        self::__construct();
75
    }
76
77
78
    function initializeComm(){
79
80
    }
81
82
    /**
83
     * Obtain a promotion from SugarDepot
84
     * @return string   the string from the promotion
85
     */
86
    function getPromotion(){
87
        $name_value_list = PackageManagerComm::getPromotion();
88
        if(!empty($name_value_list)){
89
            $name_value_list = PackageManager::fromNameValueList($name_value_list);
90
            return $name_value_list['description'];
91
        }else {
92
           return '';
93
        }
94
    }
95
96
    /**
97
     * Obtain a list of category/packages/releases for use within the module loader
98
     */
99
    function getModuleLoaderCategoryPackages($category_id = ''){
100
    	$filter = array();
101
    	$filter = array('type' => "'module', 'theme', 'langpack'");
102
    	$filter = PackageManager::toNameValueList($filter);
103
    	return PackageManager::getCategoryPackages($category_id, $filter);
104
    }
105
106
    /**
107
     * Obtain the list of category_packages from SugarDepot
108
     * @return category_packages
109
     */
110
    function getCategoryPackages($category_id = '', $filter = array()){
111
         $results = PackageManagerComm::getCategoryPackages($category_id, $filter);
112
         PackageManagerComm::errorCheck();
113
         $nodes = array();
114
115
        $nodes[$category_id]['packages'] = array();
116
        if(!empty($results['categories'])){
117
	         foreach($results['categories'] as $category){
118
	            $mycat = PackageManager::fromNameValueList($category);
119
	            $nodes[$mycat['id']] = array('id' => $mycat['id'], 'label' => $mycat['name'], 'description' => $mycat['description'], 'type' => 'cat', 'parent' => $mycat['parent_id']);
120
	            $nodes[$mycat['id']]['packages'] = array();
121
	         }
122
        }
123
         if(!empty($results['packages'])){
124
	        $uh = new UpgradeHistory();
125
	         foreach($results['packages'] as $package){
126
	            $mypack = PackageManager::fromNameValueList($package);
127
	            $nodes[$mypack['category_id']]['packages'][$mypack['id']] = array('id' => $mypack['id'], 'label' => $mypack['name'], 'description' => $mypack['description'], 'category_id' => $mypack['category_id'], 'type' => 'package');
128
	            $releases = PackageManager::getReleases($category_id, $mypack['id'], $filter);
129
	            $arr_releases = array();
130
	            $nodes[$mypack['category_id']]['packages'][$mypack['id']]['releases'] = array();
131
	            if(!empty($releases['packages'])){
132
		            foreach($releases['packages'] as $release){
133
		                 $myrelease = PackageManager::fromNameValueList($release);
134
		                 //check to see if we already this one installed
135
		                 $result = $uh->determineIfUpgrade($myrelease['id_name'], $myrelease['version']);
136
		                 $enable = false;
137
		                 if($result == true || is_array($result))
138
		                	 $enable = true;
139
		                 $nodes[$mypack['category_id']]['packages'][$mypack['id']]['releases'][$myrelease['id']] = array('id' => $myrelease['id'], 'version' => $myrelease['version'], 'label' => $myrelease['description'], 'category_id' => $mypack['category_id'], 'package_id' => $mypack['id'], 'type' => 'release', 'enable' => $enable);
140
		           	}
141
	            }
142
	            //array_push($nodes[$mypack['category_id']]['packages'], $package_arr);
143
	         }
144
         }
145
         $GLOBALS['log']->debug("NODES". var_export($nodes, true));
146
        return $nodes;
147
    }
148
149
    /**
150
     * Get a list of categories from the SugarDepot
151
     * @param category_id   the category id of parent to obtain
152
     * @param filter        an array of filters to pass to limit the query
153
     * @return array        an array of categories for display on the client
154
     */
155
    function getCategories($category_id, $filter = array()){
156
        $nodes = array();
157
        $results = PackageManagerComm::getCategories($category_id, $filter);
158
        PackageManagerComm::errorCheck();
159
        if(!empty($results['categories'])){
160
	        foreach($results['categories'] as $category){
161
	            $mycat = PackageManager::fromNameValueList($category);
162
	            $nodes[] = array('id' => $mycat['id'], 'label' => $mycat['name'], 'description' => $mycat['description'], 'type' => 'cat', 'parent' => $mycat['parent_id']);
163
	        }
164
        }
165
        return $nodes;
166
    }
167
168
    function getPackages($category_id, $filter = array()){
169
        $nodes = array();
170
        $results = PackageManagerComm::getPackages($category_id, $filter);
171
        PackageManagerComm::errorCheck();
172
        $packages = array();
173
        //$xml = '';
174
        //$xml .= '<packages>';
175
        if(!empty($results['packages'])){
176
	        foreach($results['packages'] as $package){
177
	            $mypack = PackageManager::fromNameValueList($package);
178
	            $packages[$mypack['id']] = array('package_id' => $mypack['id'], 'name' => $mypack['name'], 'description' => $mypack['description'], 'category_id' => $mypack['category_id']);
179
	            $releases = PackageManager::getReleases($category_id, $mypack['id']);
180
	            $arr_releases = array();
181
	            foreach($releases['packages'] as $release){
182
	                 $myrelease = PackageManager::fromNameValueList($release);
183
	                 $arr_releases[$myrelease['id']]  = array('release_id' => $myrelease['id'], 'version' => $myrelease['version'], 'description' => $myrelease['description'], 'category_id' => $mypack['category_id'], 'package_id' => $mypack['id']);
184
	            }
185
	            $packages[$mypack['id']]['releases'] = $arr_releases;
186
	        }
187
        }
188
        return $packages;
189
    }
190
191
    function getReleases($category_id, $package_id, $filter = array()){
192
        $releases = PackageManagerComm::getReleases($category_id, $package_id, $filter);
193
        PackageManagerComm::errorCheck();
194
        return $releases;
195
    }
196
197
    /**
198
     * Retrieve the package as specified by the $id from the heartbeat server
199
     *
200
     * @param category_id   the category_id to which the release belongs
201
     * @param package_id    the package_id to which the release belongs
202
     * @param release_id    the release_id to download
203
     * @return filename - the path to which the zip file was saved
204
     */
205
    public function download($category_id, $package_id, $release_id)
206
    {
207
        $GLOBALS['log']->debug('RELEASE _ID: '.$release_id);
208
        if(!empty($release_id)){
209
            $filename = PackageManagerComm::addDownload($category_id, $package_id, $release_id);
210
            if($filename){
211
	            $GLOBALS['log']->debug('RESULT: '.$filename);
212
	            PackageManagerComm::errorCheck();
213
	           	$filepath = PackageManagerComm::performDownload($filename);
214
	           	return $filepath;
215
            }
216
        }else{
217
            return null;
218
        }
219
    }
220
221
    /**
222
     * Given the Mambo username, password, and download key attempt to authenticate, if
223
     * successful then store these credentials
224
     *
225
     * @param username      Mambo username
226
     * @param password      Mambo password
227
     * @param systemname   the user's download key
228
     * @return              true if successful, false otherwise
229
     */
230
    function authenticate($username, $password, $systemname='', $terms_checked = true){
231
        PackageManager::setCredentials($username, $password, $systemname);
232
        PackageManagerComm::clearSession();
233
        $result = PackageManagerComm::login($terms_checked);
234
        if(is_array($result))
235
        	return $result;
236
       	else
237
        	return true;
238
    }
239
240
    function setCredentials($username, $password, $systemname){
241
242
        $admin = new Administration();
243
        $admin->retrieveSettings();
244
         $admin->saveSetting(CREDENTIAL_CATEGORY, CREDENTIAL_USERNAME, $username);
245
         $admin->saveSetting(CREDENTIAL_CATEGORY, CREDENTIAL_PASSWORD, $password);
246
         if(!empty($systemname)){
247
         	$admin->saveSetting('system', 'name', $systemname);
248
         }
249
    }
250
251
    static function getCredentials(){
252
253
        $admin = new Administration();
254
        $admin->retrieveSettings(CREDENTIAL_CATEGORY, true);
255
        $credentials = array();
256
        $credentials['username'] = '';
257
        $credentials['password'] = '';
258
		$credentials['system_name'] = '';
259
        if(!empty($admin->settings[CREDENTIAL_CATEGORY.'_'.CREDENTIAL_USERNAME])){
260
           $credentials['username'] = $admin->settings[CREDENTIAL_CATEGORY.'_'.CREDENTIAL_USERNAME];
261
        }
262
        if(!empty($admin->settings[CREDENTIAL_CATEGORY.'_'.CREDENTIAL_USERNAME])){
263
           $credentials['password'] = $admin->settings[CREDENTIAL_CATEGORY.'_'.CREDENTIAL_PASSWORD];
264
        }
265
        if(!empty($admin->settings['system_name'])){
266
           $credentials['system_name'] = $admin->settings['system_name'];
267
        }
268
        return $credentials;
269
    }
270
271
    function getTermsAndConditions(){
272
    	return PackageManagerComm::getTermsAndConditions();
273
274
    }
275
276
    /**
277
     * Retrieve documentation for the given release or package
278
     *
279
     * @param package_id	the specified package to retrieve documentation
280
     * @param release_id	the specified release to retrieve documentation
281
     *
282
     * @return documents
283
     */
284
    function getDocumentation($package_id, $release_id){
285
    	 if(!empty($release_id) || !empty($package_id)){
286
            $documents = PackageManagerComm::getDocumentation($package_id, $release_id);
287
            return $documents;
288
        }else{
289
            return null;
290
        }
291
    }
292
293
    /**
294
     * Grab the list of installed modules and send that list to the depot.
295
     * The depot will then send back a list of modules that need to be updated
296
     */
297
    function checkForUpdates(){
298
    	$lists = $this->buildInstalledReleases(array('module'), true);
0 ignored issues
show
The call to PackageManager::buildInstalledReleases() has too many arguments starting with true.

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
299
		$updates = array();
300
		if(!empty($lists)){
301
			$updates = PackageManagerComm::checkForUpdates($lists);
302
		}//fi
303
		return $updates;
304
    }
305
306
     ////////////////////////////////////////////////////////
307
     /////////// HELPER FUNCTIONS
308
    function toNameValueList($array){
309
		$list = array();
310
		foreach($array as $name=>$value){
311
			$list[] = array('name'=>$name, 'value'=>$value);
312
		}
313
		return $list;
314
	}
315
316
	function toNameValueLists($arrays){
317
		$lists = array();
318
		foreach($arrays as $array){
319
			$lists[] = PackageManager::toNameValueList($array);
320
		}
321
		return $lists;
322
	}
323
324
     function fromNameValueList($nvl){
325
        $array = array();
326
        foreach($nvl as $list){
327
            $array[$list['name']] = $list['value'];
328
        }
329
        return $array;
330
    }
331
332
    function buildInstalledReleases($types = array('module')){
333
    	//1) get list of installed modules
334
		$installeds = $this->getInstalled($types);
335
		$releases = array();
336
		foreach($installeds as $installed){
337
			$releases[] = array('name' => $installed->name, 'id_name' => $installed->id_name, 'version' => $installed->version, 'filename' => $installed->filename, 'type' => $installed->type);
338
		}
339
340
		$lists = array();
341
		$name_value_list = array();
342
		if(!empty($releases)){
343
			$lists = $this->toNameValueLists($releases);
344
		}//fi
345
		return $lists;
346
    }
347
348
    function buildPackageXML($package, $releases = array()){
349
        $xml = '<package>';
350
        $xml .= '<package_id>'.$package['id'].'</package_id>';
351
        $xml .= '<name>'.$package['name'].'</name>';
352
        $xml .= '<description>'.$package['description'].'</description>';
353
        if(!empty($releases)){
354
             $xml .= '<releases>';
355
             foreach($releases['packages'] as $release){
356
357
                 $myrelease = PackageManager::fromNameValueList($release);
358
                 $xml .= '<release>';
359
                 $xml .= '<release_id>'.$myrelease['id'].'</release_id>';
360
                 $xml .= '<version>'.$myrelease['version'].'</version>';
361
                 $xml .= '<description>'.$myrelease['description'].'</description>';
362
                 $xml .= '<package_id>'.$package['id'].'</package_id>';
363
                 $xml .= '<category_id>'.$package['category_id'].'</category_id>';
364
                 $xml .= '</release>';
365
             }
366
             $xml .= '</releases>';
367
        }
368
        $xml .= '</package>';
369
        return $xml;
370
    }
371
372
    private $cleanUpDirs = array();
373
374
    private function addToCleanup($dir)
375
    {
376
        if(empty($this->cleanUpDirs)) {
377
            register_shutdown_function(array($this, "cleanUpTempDir"));
378
        }
379
        $this->cleanUpDirs[] = $dir;
380
    }
381
382
    public function cleanUpTempDir()
383
    {
384
        foreach($this->cleanUpDirs as $dir) {
385
            rmdir_recursive($dir);
386
        }
387
    }
388
389
    //////////////////////////////////////////////////////////////////////
390
    /////////// INSTALL SECTION
391
    function extractFile( $zip_file, $file_in_zip, $base_tmp_upgrade_dir){
392
        $my_zip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
393
        $this->addToCleanup($my_zip_dir);
394
        unzip_file( $zip_file, $file_in_zip, $my_zip_dir );
395
        return( "$my_zip_dir/$file_in_zip" );
396
    }
397
398
    function extractManifest( $zip_file,$base_tmp_upgrade_dir ) {
399
        global $sugar_config;
400
        $base_upgrade_dir       = $this->upload_dir."/upgrades";
401
        $base_tmp_upgrade_dir   = "$base_upgrade_dir/temp";
402
        return $this->extractFile( $zip_file, "manifest.php",$base_tmp_upgrade_dir );
403
    }
404
405
    function validate_manifest( $manifest ){
406
    // takes a manifest.php manifest array and validates contents
407
    global $subdirs;
408
    global $sugar_version;
409
    global $sugar_flavor;
410
    global $mod_strings;
411
412
    if( !isset($manifest['type']) ){
413
        die($mod_strings['ERROR_MANIFEST_TYPE']);
414
    }
415
    $type = $manifest['type'];
416
    $GLOBALS['log']->debug("Getting InstallType");
417
    if( $this->getInstallType( "/$type/" ) == "" ){
418
        $GLOBALS['log']->debug("Error with InstallType".$type);
419
        die($mod_strings['ERROR_PACKAGE_TYPE']. ": '" . $type . "'." );
420
    }
421
    $GLOBALS['log']->debug("Passed with InstallType");
422
    if( isset($manifest['acceptable_sugar_versions']) ){
423
            $version_ok = false;
424
            $matches_empty = true;
425
            if( isset($manifest['acceptable_sugar_versions']['exact_matches']) ){
426
                $matches_empty = false;
427
                foreach( $manifest['acceptable_sugar_versions']['exact_matches'] as $match ){
428
                    if( $match == $sugar_version ){
429
                        $version_ok = true;
430
                    }
431
                }
432
            }
433
            if( !$version_ok && isset($manifest['acceptable_sugar_versions']['regex_matches']) ){
434
                $matches_empty = false;
435
                foreach( $manifest['acceptable_sugar_versions']['regex_matches'] as $match ){
436
                    if( preg_match( "/$match/", $sugar_version ) ){
437
                        $version_ok = true;
438
                    }
439
                }
440
            }
441
442
            if( !$matches_empty && !$version_ok ){
443
                die( $mod_strings['ERROR_VERSION_INCOMPATIBLE'] . $sugar_version );
444
            }
445
        }
446
447
     if( isset($manifest['acceptable_sugar_flavors']) && sizeof($manifest['acceptable_sugar_flavors']) > 0 ){
448
            $flavor_ok = false;
449
            foreach( $manifest['acceptable_sugar_flavors'] as $match ){
450
                if( $match == $sugar_flavor ){
451
                    $flavor_ok = true;
452
                }
453
            }
454
            if( !$flavor_ok ){
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
455
                //die( $mod_strings['ERROR_FLAVOR_INCOMPATIBLE'] . $sugar_flavor );
456
            }
457
        }
458
    }
459
460
    function getInstallType( $type_string ){
461
        // detect file type
462
        global $subdirs;
463
        $subdirs = array('full', 'langpack', 'module', 'patch', 'theme', 'temp');
464
465
466
        foreach( $subdirs as $subdir ){
467
            if( preg_match( "#/$subdir/#", $type_string ) ){
468
                return( $subdir );
469
            }
470
        }
471
        // return empty if no match
472
        return( "" );
473
    }
474
475
    function performSetup($tempFile, $view = 'module', $display_messages = true){
476
        global $sugar_config,$mod_strings;
477
        $base_filename = urldecode($tempFile);
478
        $GLOBALS['log']->debug("BaseFileName: ".$base_filename);
479
        $base_upgrade_dir       = $this->upload_dir.'/upgrades';
480
        $base_tmp_upgrade_dir   = "$base_upgrade_dir/temp";
481
        $manifest_file = $this->extractManifest( $base_filename,$base_tmp_upgrade_dir);
482
         $GLOBALS['log']->debug("Manifest: ".$manifest_file);
483
        if($view == 'module')
484
            $license_file = $this->extractFile($base_filename, 'LICENSE.txt', $base_tmp_upgrade_dir);
485
        if(is_file($manifest_file)){
486
            $GLOBALS['log']->debug("VALIDATING MANIFEST". $manifest_file);
487
            require_once( $manifest_file );
488
            $this->validate_manifest($manifest );
0 ignored issues
show
The variable $manifest does not exist. Did you mean $manifest_file?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
489
            $upgrade_zip_type = $manifest['type'];
0 ignored issues
show
The variable $manifest does not exist. Did you mean $manifest_file?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
490
            $GLOBALS['log']->debug("VALIDATED MANIFEST");
491
            // exclude the bad permutations
492
            if( $view == "module" ){
493
                if ($upgrade_zip_type != "module" && $upgrade_zip_type != "theme" && $upgrade_zip_type != "langpack"){
494
                    $this->unlinkTempFiles();
495
                    if($display_messages)
496
                        die($mod_strings['ERR_UW_NOT_ACCEPTIBLE_TYPE']);
497
                }
498
            }elseif( $view == "default" ){
499
                if($upgrade_zip_type != "patch" ){
500
                    $this->unlinkTempFiles();
501
                    if($display_messages)
502
                        die($mod_strings['ERR_UW_ONLY_PATCHES']);
503
                }
504
            }
505
506
            $base_filename = preg_replace( "#\\\\#", "/", $base_filename );
507
            $base_filename = basename( $base_filename );
508
            mkdir_recursive( "$base_upgrade_dir/$upgrade_zip_type" );
509
            $target_path = "$base_upgrade_dir/$upgrade_zip_type/$base_filename";
510
            $target_manifest = remove_file_extension( $target_path ) . "-manifest.php";
511
512
            if( isset($manifest['icon']) && $manifest['icon'] != "" ){
0 ignored issues
show
The variable $manifest does not exist. Did you mean $manifest_file?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
513
                $icon_location = $this->extractFile( $tempFile ,$manifest['icon'], $base_tmp_upgrade_dir );
514
                $path_parts = pathinfo( $icon_location );
515
                copy( $icon_location, remove_file_extension( $target_path ) . "-icon." . $path_parts['extension'] );
516
            }
517
518
            if( copy( $tempFile , $target_path ) ){
519
                copy( $manifest_file, $target_manifest );
520
                if($display_messages)
521
                    $messages = '<script>ajaxStatus.flashStatus("' .$base_filename.$mod_strings['LBL_UW_UPLOAD_SUCCESS'] . ', 5000");</script>';
522
            }else{
523
                if($display_messages)
524
                	$messages = '<script>ajaxStatus.flashStatus("' .$mod_strings['ERR_UW_UPLOAD_ERROR'] . ', 5000");</script>';
525
            }
526
        }//fi
527
        else{
528
            $this->unlinkTempFiles();
529
            if($display_messages)
530
                die($mod_strings['ERR_UW_NO_MANIFEST']);
531
        }
532
        if(isset($messages))
533
            return $messages;
534
    }
535
536
    function unlinkTempFiles() {
537
        global $sugar_config;
538
        @unlink($_FILES['upgrade_zip']['tmp_name']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
539
        @unlink("upload://".$_FILES['upgrade_zip']['name']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
540
    }
541
542
    function performInstall($file, $silent=true){
543
        global $sugar_config;
544
        global $mod_strings;
545
        global $current_language;
546
        $base_upgrade_dir       = $this->upload_dir.'/upgrades';
547
        $base_tmp_upgrade_dir   = "$base_upgrade_dir/temp";
548
        if(!file_exists($base_tmp_upgrade_dir)){
549
            mkdir_recursive($base_tmp_upgrade_dir, true);
550
        }
551
552
        $GLOBALS['log']->debug("INSTALLING: ".$file);
553
        $mi = new ModuleInstaller();
554
        $mi->silent = $silent;
555
        $mod_strings = return_module_language($current_language, "Administration");
556
             $GLOBALS['log']->debug("ABOUT TO INSTALL: ".$file);
557
        if(preg_match("#.*\.zip\$#", $file)) {
558
             $GLOBALS['log']->debug("1: ".$file);
559
            // handle manifest.php
560
            $target_manifest = remove_file_extension( $file ) . '-manifest.php';
561
            include($target_manifest);
562
            $GLOBALS['log']->debug("2: ".$file);
563
            $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
564
            $this->addToCleanup($unzip_dir);
565
            unzip($file, $unzip_dir );
566
            $GLOBALS['log']->debug("3: ".$unzip_dir);
567
            $id_name = $installdefs['id'];
568
			$version = $manifest['version'];
0 ignored issues
show
The variable $manifest does not exist. Did you mean $target_manifest?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
569
			$uh = new UpgradeHistory();
570
			$previous_install = array();
571
    		if(!empty($id_name) & !empty($version))
572
    			$previous_install = $uh->determineIfUpgrade($id_name, $version);
573
    		$previous_version = (empty($previous_install['version'])) ? '' : $previous_install['version'];
574
    		$previous_id = (empty($previous_install['id'])) ? '' : $previous_install['id'];
575
576
            if(!empty($previous_version)){
577
            	$mi->install($unzip_dir, true, $previous_version);
578
            }else{
579
            	$mi->install($unzip_dir);
580
            }
581
            $GLOBALS['log']->debug("INSTALLED: ".$file);
582
            $new_upgrade = new UpgradeHistory();
583
            $new_upgrade->filename      = $file;
584
            $new_upgrade->md5sum        = md5_file($file);
585
            $new_upgrade->type          = $manifest['type'];
0 ignored issues
show
The variable $manifest does not exist. Did you mean $target_manifest?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
586
            $new_upgrade->version       = $manifest['version'];
0 ignored issues
show
The variable $manifest does not exist. Did you mean $target_manifest?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
587
            $new_upgrade->status        = "installed";
588
            //$new_upgrade->author        = $manifest['author'];
589
            $new_upgrade->name          = $manifest['name'];
0 ignored issues
show
The variable $manifest does not exist. Did you mean $target_manifest?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
590
            $new_upgrade->description   = $manifest['description'];
0 ignored issues
show
The variable $manifest does not exist. Did you mean $target_manifest?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
591
            $new_upgrade->id_name		= $id_name;
592
			$serial_manifest = array();
593
			$serial_manifest['manifest'] = (isset($manifest) ? $manifest : '');
0 ignored issues
show
The variable $manifest does not exist. Did you mean $target_manifest?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
594
			$serial_manifest['installdefs'] = (isset($installdefs) ? $installdefs : '');
595
			$serial_manifest['upgrade_manifest'] = (isset($upgrade_manifest) ? $upgrade_manifest : '');
0 ignored issues
show
The variable $upgrade_manifest seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
596
			$new_upgrade->manifest		= base64_encode(serialize($serial_manifest));
597
            //$new_upgrade->unique_key    = (isset($manifest['unique_key'])) ? $manifest['unique_key'] : '';
598
            $new_upgrade->save();
599
                    //unlink($file);
600
        }//fi
601
    }
602
603
    function performUninstall($name){
604
    	$uh = new UpgradeHistory();
605
    	$uh->name = $name;
606
    	$uh->id_name = $name;
607
    	$found = $uh->checkForExisting($uh);
608
    	if($found != null){
609
    		global $sugar_config;
610
	        global $mod_strings;
611
	        global $current_language;
612
	        $base_upgrade_dir       = $this->upload_dir.'/upgrades';
613
	        $base_tmp_upgrade_dir   = "$base_upgrade_dir/temp";
614
            if(is_file($found->filename)){
615
                if(!isset($GLOBALS['mi_remove_tables']))$GLOBALS['mi_remove_tables'] = true;
616
                $unzip_dir = mk_temp_dir( $base_tmp_upgrade_dir );
617
                unzip($found->filename, $unzip_dir );
618
                $mi = new ModuleInstaller();
619
                $mi->silent = true;
620
                $mi->uninstall( "$unzip_dir");
621
                $found->delete();
0 ignored issues
show
The method delete() does not exist on SugarBean. Did you maybe mean mark_deleted()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
622
                unlink(remove_file_extension( $found->filename ) . '-manifest.php');
623
                unlink($found->filename);
624
            }else{
625
                //file(s_ have been deleted or are not found in the directory, allow database delete to happen but no need to change filesystem
626
                $found->delete();
0 ignored issues
show
The method delete() does not exist on SugarBean. Did you maybe mean mark_deleted()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
627
            }
628
    	}
629
    }
630
631
    function getUITextForType( $type ){
632
        if( $type == "full" ){
633
            return( "Full Upgrade" );
634
        }
635
        if( $type == "langpack" ){
636
            return( "Language Pack" );
637
        }
638
        if( $type == "module" ){
639
            return( "Module" );
640
        }
641
        if( $type == "patch" ){
642
            return( "Patch" );
643
        }
644
        if( $type == "theme" ){
645
            return( "Theme" );
646
        }
647
    }
648
649
    function getImageForType( $type ){
650
651
        $icon = "";
652
        switch( $type ){
653
            case "full":
654
                $icon = SugarThemeRegistry::current()->getImage("Upgrade", "" ,null,null,'.gif', "Upgrade");
655
656
                break;
657
            case "langpack":
658
                $icon = SugarThemeRegistry::current()->getImage("LanguagePacks", "",null,null,'.gif',"Language Packs" );
659
660
                break;
661
            case "module":
662
                $icon = SugarThemeRegistry::current()->getImage("ModuleLoader", "" ,null,null,'.gif', "Module Loader");
663
664
                break;
665
            case "patch":
666
                $icon = SugarThemeRegistry::current()->getImage("PatchUpgrades", "",null,null,'.gif', "Patch Upgrades" );
667
668
                break;
669
            case "theme":
670
                $icon = SugarThemeRegistry::current()->getImage("Themes", "",null,null,'.gif', "Themes" );
671
672
                break;
673
            default:
674
                break;
675
        }
676
        return( $icon );
677
    }
678
679
    function getPackagesInStaging($view = 'module'){
680
        global $sugar_config;
681
        global $current_language;
682
        $uh = new UpgradeHistory();
683
        $base_upgrade_dir       = "upload://upgrades";
684
        $uContent = findAllFiles( $base_upgrade_dir, array() , false, 'zip');
685
        $upgrade_contents = array();
686
        $content_values = array_values($uContent);
687
        $alreadyProcessed = array();
688
        foreach($content_values as $val){
689
        	if(empty($alreadyProcessed[$val])){
690
        		$upgrade_contents[] = $val;
691
        		$alreadyProcessed[$val] = true;
692
        	}
693
        }
694
695
        $upgrades_available = 0;
696
        $packages = array();
697
        $mod_strings = return_module_language($current_language, "Administration");
698
        foreach($upgrade_contents as $upgrade_content) {
699
            if(!preg_match('#.*\.zip$#', strtolower($upgrade_content)) || preg_match("#.*./zips/.*#", strtolower($upgrade_content))) {
700
                continue;
701
            }
702
703
            $the_base = basename($upgrade_content);
704
            $the_md5 = md5_file($upgrade_content);
705
            $md5_matches = $uh->findByMd5($the_md5);
706
    		$file_install = $upgrade_content;
707
            if(empty($md5_matches))
708
            {
709
                $target_manifest = remove_file_extension( $upgrade_content ) . '-manifest.php';
710
                if(file_exists($target_manifest)) {
711
	                require_once($target_manifest);
712
713
	                $name = empty($manifest['name']) ? $upgrade_content : $manifest['name'];
714
	                $version = empty($manifest['version']) ? '' : $manifest['version'];
715
	                $published_date = empty($manifest['published_date']) ? '' : $manifest['published_date'];
716
	                $icon = '';
717
	                $description = empty($manifest['description']) ? 'None' : $manifest['description'];
718
	                $uninstallable = empty($manifest['is_uninstallable']) ? 'No' : 'Yes';
719
	                $type = $this->getUITextForType( $manifest['type'] );
720
	                $manifest_type = $manifest['type'];
721
	                $dependencies = array();
722
	                if( isset( $manifest['dependencies']) ){
723
	    				$dependencies    = $manifest['dependencies'];
724
					}
725
                }
726
727
				//check dependencies first
728
				if(!empty($dependencies)) {
729
					$uh = new UpgradeHistory();
730
					$not_found = $uh->checkDependencies($dependencies);
731
					if(!empty($not_found) && count($not_found) > 0){
732
							$file_install = 'errors_'.$mod_strings['ERR_UW_NO_DEPENDENCY']."[".implode(',', $not_found)."]";
733
					}
734
				}
735
736
                if($view == 'default' && $manifest_type != 'patch') {
737
                    continue;
738
                }
739
740
                if($view == 'module'
741
                    && $manifest_type != 'module' && $manifest_type != 'theme' && $manifest_type != 'langpack') {
742
                    continue;
743
                }
744
745
                if(empty($manifest['icon'])) {
746
                    $icon = $this->getImageForType( $manifest['type'] );
747
                } else {
748
                    $path_parts = pathinfo( $manifest['icon'] );
749
                    $icon = "<img src=\"" . remove_file_extension( $upgrade_content ) . "-icon." . $path_parts['extension'] . "\">";
750
                }
751
752
                $upgrades_available++;
753
754
                $packages[] = array('name' => $name, 'version' => $version, 'published_date' => $published_date,
755
                	'description' => $description, 'uninstallable' =>$uninstallable, 'type' => $type,
756
                	'file' => fileToHash($upgrade_content), 'file_install' => fileToHash($upgrade_content), 'unFile' => fileToHash($upgrade_content));
757
            }//fi
758
        }//rof
759
        return $packages;
760
    }
761
762
    function getLicenseFromFile($file){
763
        global $sugar_config;
764
        $base_upgrade_dir       = $this->upload_dir.'/upgrades';
765
        $base_tmp_upgrade_dir   = "$base_upgrade_dir/temp";
766
        $license_file = $this->extractFile($file, 'LICENSE.txt', $base_tmp_upgrade_dir);
767
        if(is_file($license_file)){
768
            $contents = file_get_contents($license_file);
769
            return $contents;
770
        }else{
771
            return null;
772
        }
773
    }
774
775
    /**
776
     * Run the query to obtain the list of installed types as specified by the type param
777
     *
778
     * @param type	an array of types you would like to search for
779
     * 				type options include (theme, langpack, module, patch)
780
     *
781
     * @return an array of installed upgrade_history objects
782
     */
783
    function getInstalled($types = array('module')){
784
    	$uh = new UpgradeHistory();
785
    	$in = "";
786
    	for($i = 0; $i < count($types); $i++){
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
787
    		$in .= "'".$types[$i]."'";
788
    		if(($i+1) < count($types)){
789
    			$in .= ",";
790
    		}
791
    	}
792
    	$query = "SELECT * FROM ".$uh->table_name."	 WHERE type IN (".$in.")";
793
    	return $uh->getList($query);
794
    }
795
796
    function getinstalledPackages($types = array('module', 'langpack')){
797
    	global $sugar_config;
798
    	$installeds = $this->getInstalled($types);
799
    	$packages = array();
800
    	$upgrades_installed = 0;
801
    	$uh = new UpgradeHistory();
802
        $base_upgrade_dir       = $this->upload_dir.'/upgrades';
803
        $base_tmp_upgrade_dir   = "$base_upgrade_dir/temp";
804
    	foreach($installeds as $installed)
805
		{
806
			$populate = false;
807
			$filename = from_html($installed->filename);
808
			$date_entered = $installed->date_entered;
809
			$type = $installed->type;
810
			$version = $installed->version;
811
			$uninstallable = false;
812
			$link = "";
813
			$description = $installed->description;
814
			$name = $installed->name;
815
			$enabled = true;
816
			$enabled_string = 'ENABLED';
817
			//if the name is empty then we should try to pull from manifest and populate upgrade_history_table
818
			if(empty($name)){
819
				$populate = true;
820
			}
821
			$upgrades_installed++;
822
			switch($type)
823
			{
824
				case "theme":
825
				case "langpack":
826
				case "module":
827
				case "patch":
828
					if($populate){
829
						$manifest_file = $this->extractManifest($filename, $base_tmp_upgrade_dir);
830
						require_once($manifest_file);
831
						$GLOBALS['log']->info("Filling in upgrade_history table");
832
						$populate = false;
833
						if( isset( $manifest['name'] ) ){
834
    						$name = $manifest['name'];
835
    						$installed->name = $name;
836
						}
837
						if( isset( $manifest['description'] ) ){
838
						    $description = $manifest['description'];
839
						    $installed->description = $description;
840
						}
841
						if(isset($installdefs) && isset( $installdefs['id'] ) ){
842
						    $id_name  = $installdefs['id'];
843
						    $installed->id_name = $id_name;
844
						}
845
846
						$serial_manifest = array();
847
						$serial_manifest['manifest'] = (isset($manifest) ? $manifest : '');
848
						$serial_manifest['installdefs'] = (isset($installdefs) ? $installdefs : '');
849
						$serial_manifest['upgrade_manifest'] = (isset($upgrade_manifest) ? $upgrade_manifest : '');
850
						$installed->manifest = base64_encode(serialize($serial_manifest));
851
						$installed->save();
852
					}else{
853
						$serial_manifest = unserialize(base64_decode($installed->manifest));
854
						$manifest = $serial_manifest['manifest'];
855
					}
856
					if(($upgrades_installed==0 || $uh->UninstallAvailable($installeds, $installed))
857
						&& is_file($filename) && !empty($manifest['is_uninstallable']))
858
					{
859
						$uninstallable = true;
860
					}
861
					$enabled = $installed->enabled;
862
					if(!$enabled)
863
						$enabled_string = 'DISABLED';
864
					$file_uninstall = $filename;
865
					if(!$uninstallable){
866
						$file_uninstall = 'UNINSTALLABLE';
867
						$enabled_string = 'UNINSTALLABLE';
868
					} else {
869
						$file_uninstall = fileToHash( $file_uninstall );
870
					}
871
872
				$packages[] = array(
873
				    'name' => $name,
874
				    'version' => $version,
875
				    'type' => $type,
876
				    'published_date' => $date_entered,
877
				    'description' => $description,
878
				    'uninstallable' =>$uninstallable,
879
				    'file_install' =>  $file_uninstall ,
880
				    'file' =>  fileToHash($filename),
881
				    'enabled' => $enabled_string
882
				);
883
				break;
884
				default:
885
				break;
886
			}
887
888
		}//rof
889
		return $packages;
890
    }
891
 }
892
?>
893