onycro

panel_preupgrade_checker.php

Jul 6th, 2012
698
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 140.86 KB | None | 0 0
  1. #!/usr/local/psa/admin/bin/php
  2. <?php
  3. /** GERMAN VERSION
  4.  * Due to the changes in business model in PP10 release, not all previous accounts settings
  5.  * will be portable from the previous Plesk releases. Some business schemas will be lost for hosters
  6.  * and their clients. This tool could be launched prior to upgrade for the purpose of getting
  7.  * a report on potential problems with the upgrade. Based on the report a hoster can decide
  8.  * whether upgrade to PP10 is suitable for him.
  9.  *
  10.  * Requirements: script supports PHP4/PHP5 in case where installed PHP4 only
  11.  */
  12.  
  13. define('APP_PATH', dirname(__FILE__));
  14. define('DEBUG', 0); // allow to dump sql logs to output
  15. define('PRE_UPGRADE_SCRIPT_VERSION', '11.0.9.0'); //script version
  16. define('PLESK_VERSION', '11.0.9'); // latest Plesk version
  17. define('AI_VERSION', '3.12.0'); // latest autoinstaller version
  18. @date_default_timezone_set(@date_default_timezone_get());
  19.  
  20. if (!defined('PHP_EOL')) {
  21.     define('PHP_EOL', "\n", true);
  22. }
  23.  
  24. $phpType = php_sapi_name();
  25. if (substr($phpType, 0, 3) == 'cgi') {
  26.     //:INFO: set max execution time 1hr
  27.     @set_time_limit(3600);
  28. }
  29.  
  30. class Plesk10BusinessModel
  31. {
  32.     function validate()
  33.     {
  34.         if (!PleskInstallation::isInstalled()) {
  35.             //:INFO: Plesk installation is not found. You will have no problems with upgrade, go on and install Plesk Panel 10
  36.             return;
  37.         }
  38.        
  39.         if (PleskVersion::is8x() || PleskVersion::is9x()) {
  40.             //:INFO: Clients owned by Administrator (Client control over domain resources)
  41.             $this->_diagnoseClientsHaveMoreDomainsThanOneOwnedByAdmin();
  42.             $this->_diagnoseClientsHaveDomainAdministratorsOwnedByAdmin();
  43.             $this->_diagnoseClientsHaveNoDomainsOwnedByAdmin();
  44.             $this->_diagnoseClientPermissions();
  45.         }
  46.        
  47.         if (PleskVersion::is9x()) {
  48.             //:INFO: Clients owned by Resellers (Client control over domain resources)
  49.             $this->_diagnoseClientsHaveMoreDomainsThanOneOwnedByReseller();
  50.             $this->_diagnoseClientsHaveDomainAdministratorsOwnedByReseller();
  51.             $this->_diagnoseClientsHaveNoDomainsOwnedByReseller();
  52.            
  53.             //:INFO: Domain Administrators owned by Admin
  54.             $this->_diagnoseDomainAdmsOwnedByAdministrator();
  55.            
  56.             //:INFO: Domain Administrators owned by Resellers
  57.             $this->_diagnoseDomainAdmsOwnedByResellers();
  58.  
  59.             //:INFO: Domain owned by non-existent Clients
  60.             $this->_diagnoseDomainOwnersDontExist();
  61.         }
  62.     }
  63.    
  64.     /**
  65.      * Domain Administrators owned by Hoster
  66.      */
  67.     function _diagnoseDomainAdmsOwnedByAdministrator()
  68.     {
  69.         //:INFO: Admin can create own domains since Plesk 9.x
  70.         Log::step('Calculate domains belonging to admin with defined domain administrators', true);
  71.        
  72.         $domains = $this->_getAdminDomains();
  73.        
  74.         $details = 'The following domains have domain administrator: ' . PHP_EOL . PHP_EOL;
  75.         foreach ($domains as $domainOwnedByAdmin) {
  76.             $details .= "'{$domainOwnedByAdmin['name']}'" . PHP_EOL;
  77.         }
  78.        
  79.         if (sizeof($domains)>0) {
  80.             $logPath = APP_PATH.'/admin_domains_with_dom_admins.log';
  81.             Log::write($logPath, $details, 'w');
  82.            
  83.             $warn = 'You have '.sizeof($domains).' domains with separate Domain Administrators. ';
  84.             $warn .= 'In Plesk 10.x these users will see all your domains. ';
  85.             $warn .= 'You should consider converting them to Customers after upgrade to avoid security problem.';
  86.             Log::warning($warn);
  87.            
  88.             Log::info('See details in log ' . $logPath);
  89.             Log::resultWarning();
  90.            
  91.             return;
  92.         }
  93.         Log::resultOk();
  94.     }
  95.    
  96.     /**
  97.      * Domain Administrators owned by Resellers
  98.      */
  99.     function _diagnoseDomainAdmsOwnedByResellers()
  100.     {
  101.         //:INFO: Reseller role was defined since 9.0
  102.         Log::step('Calculate domains belonging to resellers with defined domain administrators', true);
  103.        
  104.         $resellerDomains = $this->_getResellerDomains();
  105.         $details = '';
  106.         $totalDomains = 0;
  107.         foreach ($resellerDomains as $reseller => $domains) {
  108.             $details .= "Reseller '{$reseller}' has " . sizeof($domains) . " domain administrators" . PHP_EOL . PHP_EOL;
  109.             $totalDomains += sizeof($domains);
  110.         }
  111.        
  112.         if (sizeof($resellerDomains)>0) {
  113.             $logPath = APP_PATH.'/reseller_domains_with_dom_admins.log';
  114.             Log::write($logPath, $details, 'w');
  115.            
  116.             $warn = 'You have '.sizeof($resellerDomains).' resellers with '.$totalDomains.' domains with separate domain administrators. ';
  117.             $warn .= 'In Plesk 10.x these users will see all your domains of their Resellers. ';
  118.             $warn .= 'You should consider converting them to customers after upgrade to avoid security problem.';
  119.             Log::warning($warn);
  120.            
  121.             Log::info('See details in log ' . $logPath);
  122.             Log::resultWarning();
  123.            
  124.             return;
  125.         }
  126.         Log::resultOk();
  127.     }
  128.    
  129.     /**
  130.      * The diagnosed situation is:
  131.      * Client limit has more than 1 domain
  132.      * Client can create domains
  133.      * Client can manage domain limits
  134.      */
  135.     function _diagnoseClientsHaveMoreDomainsThanOneOwnedByAdmin()
  136.     {
  137.         Log::step('Calculate clients owned by administrator who have more than a one domain', true);
  138.        
  139.         $clientsOwnedByAdmin = $this->_getClientsOwnedByAdmin();
  140.         $total = sizeof($clientsOwnedByAdmin);
  141.         $details = '';
  142.        
  143.         foreach ($clientsOwnedByAdmin as $clientOwnedByAdmin) {
  144.             $details .= "Client '{$clientOwnedByAdmin['pname']}' has {$clientOwnedByAdmin['count_dom']} domains" . PHP_EOL . PHP_EOL;
  145.         }
  146.        
  147.         //:INFO: count of clients > 0
  148.         if ($total) {
  149.             $logPath = APP_PATH.'/admin_clients_have_domains.log';
  150.             Log::write($logPath, $details, 'w');
  151.            
  152.             $warn = 'You have '.$total.' clients who are free to manage resources on their domains themselves within the resource limits that you gave them.';
  153.             $warn.= ' In Plesk 10.x the resources are defined in a subscription.';
  154.             $warn.= ' The Customer cannot redistribute resources between his/her subscriptions.';
  155.             $warn.= ' If you want to leave the same degree of flexibility for these Customers, you should consider converting them to Resellers after upgrade.';
  156.             Log::warning($warn);
  157.            
  158.             Log::info('See details in log ' . $logPath);
  159.             Log::resultWarning();
  160.            
  161.             return;
  162.         }
  163.        
  164.         Log::resultOk();
  165.     }
  166.    
  167.     /**
  168.      * The diagnosed situation is:
  169.      * Client has created Domain Administrators for several domains
  170.      */    
  171.     function _diagnoseClientsHaveDomainAdministratorsOwnedByAdmin()
  172.     {
  173.         Log::step('Calculate clients owned by administrator who have domain administrators', true);
  174.        
  175.         $clients = $this->_getClientsHaveDomAdminsOwnedByAdmin();
  176.        
  177.         $details = '';
  178.         foreach ($clients as $client) {
  179.             $details .= "Client '{$client['pname']}' has {$client['count_dom_adm']} domain administrators" . PHP_EOL . PHP_EOL;
  180.         }
  181.        
  182.         if (sizeof($clients)) {
  183.             $logPath = APP_PATH.'/admin_clients_have_domain_administators.log';
  184.             Log::write($logPath, $details, 'w');
  185.            
  186.             $warn = 'Your have '.sizeof($clients).' clients with Domain Administrators defined on more than one domain.';
  187.             $warn.= ' After transitions these Clients will have problems, because in Plesk 10.x users belonging to a Customer have access to all Customer’s subscriptions.';
  188.             $warn.= ' You will avoid the problem if after upgrade the Clients will be upgraded to Resellers and Domain Administrators to the Customers.';
  189.             Log::warning($warn);
  190.            
  191.             Log::info('See details in log ' . $logPath);
  192.             Log::resultWarning();
  193.            
  194.             return;
  195.         }
  196.         Log::resultOk();
  197.     }
  198.    
  199.     /**
  200.      * The diagnosed situation is:
  201.      * Client has no domains
  202.      */
  203.     function _diagnoseClientsHaveNoDomainsOwnedByAdmin()
  204.     {
  205.         Log::step('Calculate clients owned by administrator who have no domains', true);
  206.        
  207.         $clients = $this->_getClientsHaveNoDomainsOwnedByAdmin();
  208.        
  209.         $details = '';
  210.         foreach ($clients as $client) {
  211.             $details .= "Client '{$client['pname']}' has no domains" . PHP_EOL . PHP_EOL;
  212.         }
  213.        
  214.         if (sizeof($clients)) {
  215.             $logPath = APP_PATH.'/admin_clients_have_no_domains.log';
  216.             Log::write($logPath, $details, 'w');
  217.            
  218.             $warn  = 'Your have ' . sizeof($clients) . ' clients with no domains defined.';
  219.             $warn .= ' After transitions these Clients will not be able to login into the control panel until you create a subscription for them.';
  220.             $warn .= ' An alternative solution is upgrading them to resellers after conversion.';
  221.             Log::warning($warn);
  222.            
  223.             Log::info('See details in log ' . $logPath);
  224.             Log::resultWarning();
  225.            
  226.             return;
  227.         }
  228.         Log::resultOk();
  229.     }
  230.    
  231.     /**
  232.      * The diagnosed situation is:
  233.      * Client has default permissions
  234.      */
  235.     function _diagnoseClientPermissions()
  236.     {
  237.         Log::step('Calculate clients who have default permissions', true);
  238.        
  239.         $db = PleskDb::getInstance();
  240.        
  241.         $where = 'WHERE perm_id is NULL';
  242.         if (PleskVersion::is9x()) {
  243.             $where = "WHERE perm_id is NULL AND id<>".$this->_getAdminId();
  244.         }
  245.         //Get client list where perm_id is null. It means that client never modified permissions and have default permissions
  246.         $sql = "SELECT clients.pname FROM clients {$where}";
  247.         $clients = $db->fetchAll($sql);
  248.        
  249.         if (sizeof($clients)) {
  250.             $details = 'Client list where perm_id is null. It means that client never modified permissions and has default permissions' . PHP_EOL . PHP_EOL;
  251.             foreach ($clients as $client) {
  252.                 $details .= "Client '{$client['pname']}' has default permissions" . PHP_EOL . PHP_EOL;
  253.             }
  254.             $logPath = APP_PATH.'/clients_have_default_permissions.log';
  255.             Log::write($logPath, $details, 'w');
  256.  
  257.             $warn = 'You have client '.sizeof($clients).' with default permissions.';
  258.             $warn .= ' Due to the changes in business model in PP10 release, default permissions are different from other versions. ';
  259.             $warn .= 'You should go to the Client/Reseller permission page and save changes in order to permission values were saved in database.';
  260.             Log::warning($warn);
  261.            
  262.             Log::info('See details in log ' . $logPath);
  263.             Log::resultWarning();
  264.            
  265.             return;
  266.         }
  267.         Log::resultOk();
  268.     }
  269.    
  270.     /**
  271.      * The diagnosed situation is:
  272.      * Client limit has more than 1 domain
  273.      * Client can create domains
  274.      * Client can manage domain limits
  275.      */
  276.     function _diagnoseClientsHaveMoreDomainsThanOneOwnedByReseller()
  277.     {
  278.         Log::step('Calculate clients owned by reseller who have more than a one domain', true);
  279.        
  280.         $resellers = $this->_getClientsOwnedByReseller();
  281.        
  282.         $totalResellers = sizeof($resellers);
  283.         $totalClients = 0;
  284.         $details = '';
  285.         foreach ($resellers as $reseller => $clients) {
  286.             $details .= "Reseller with login '{$reseller}' has " . sizeof($clients) . ' clients' . PHP_EOL;
  287.             $totalClients += sizeof($clients);
  288.             foreach ($clients as $client) {
  289.                 $details .= "----Client '{$client['pname']}' has {$client['count_dom']} domains" . PHP_EOL;
  290.             }
  291.         }
  292.        
  293.         if ($totalResellers) {
  294.             $logPath = APP_PATH.'/reseller_clients_have_domains.log';
  295.             Log::write($logPath, $details, 'w');
  296.            
  297.             $warn = 'You have '.$totalResellers.' resellers with '.$totalClients.' clients who are free to manage resources on their domains themselves within the resource limits that you gave them.';
  298.             $warn.= ' In Plesk 10.x the resources are defined in a subscription.';
  299.             $warn.= ' The Customer cannot redistribute resources between his/her subscriptions.';
  300.             $warn.= ' After upgrade you will be suggested to redistribute Clients’ resources between the existing subscriptions (current domains).';
  301.             Log::warning($warn);
  302.            
  303.             Log::info('See details in log ' . $logPath);
  304.             Log::resultWarning();
  305.            
  306.             return;
  307.         }
  308.        
  309.         Log::resultOk();
  310.     }
  311.    
  312.     /**
  313.      * The diagnosed situation is:
  314.      * Client has created Domain Administrators for several domains
  315.      */    
  316.     function _diagnoseClientsHaveDomainAdministratorsOwnedByReseller()
  317.     {
  318.         Log::step('Calculate clients owned by reseller who have domain administrators', true);
  319.        
  320.         $resellers = $this->_getClientsWithDomAdminsOwnedByReseller();
  321.  
  322.         $totalResellers = sizeof($resellers);
  323.         $totalClients = 0;
  324.         $details = '';
  325.         foreach ($resellers as $reseller => $clients) {
  326.             $details .= "Reseller with login '{$reseller}' has " . sizeof($clients) . ' clients' . PHP_EOL;
  327.             $totalClients += sizeof($clients);
  328.             foreach ($clients as $client) {
  329.                 $details .= "----Client '{$client['pname']}' has {$client['count_dom_adm']} domain administrators" . PHP_EOL;
  330.             }
  331.         }
  332.        
  333.         if ($totalResellers) {
  334.             $logPath = APP_PATH.'/reseller_clients_have_domain_administators.log';
  335.             Log::write($logPath, $details, 'w');
  336.            
  337.             $warn = 'You have '.$totalResellers.' resellers with '.$totalClients.' clients with Domain Administrators defined on more than one domain.';
  338.             $warn.= ' After transitions these Clients will have problems, because in Plesk 10.x users belonging to a Customer have access to all Customer’s subscriptions.';
  339.             $warn.= ' Probably you should consult with your resellers of the path forward for these customers.';
  340.             Log::warning($warn);
  341.            
  342.             Log::info('See details in log ' . $logPath);
  343.             Log::resultWarning();
  344.            
  345.             return;
  346.         }
  347.  
  348.         Log::resultOk();
  349.     }
  350.    
  351.     /**
  352.      * The diagnosed situation is:
  353.      * Client has no domains
  354.      */
  355.     function _diagnoseClientsHaveNoDomainsOwnedByReseller()
  356.     {
  357.         Log::step('Calculate clients owned by reseller who have no domains', true);
  358.        
  359.         $resellers = $this->_getClientsHaveNoDomainsOwnedByReseller();
  360.        
  361.         $totalResellers = sizeof($resellers);
  362.         $totalClients = 0;
  363.         $details = '';
  364.         foreach ($resellers as $reseller => $clients) {
  365.             $details .= "Reseller with login '{$reseller}' has " . sizeof($clients) . ' clients' . PHP_EOL;
  366.             $totalClients += sizeof($clients);
  367.             foreach ($clients as $client) {
  368.                 $details .= "----Client '{$client['pname']}' has no domains" . PHP_EOL;
  369.             }
  370.         }
  371.        
  372.         if ($totalResellers) {
  373.             $logPath = APP_PATH.'/reseller_clients_have_no_domains.log';
  374.             Log::write($logPath, $details, 'w');
  375.            
  376.             $warn = 'You have '.$totalResellers.' resellers with '.$totalClients.' clients that have no domains defined.';
  377.             $warn.= ' After transitions these Clients will not be able to login into the control panel until you or Reseller create a subscription for them.';
  378.             Log::warning($warn);
  379.            
  380.             Log::info('See details in log ' . $logPath);
  381.             Log::resultWarning();
  382.            
  383.             return;
  384.         }
  385.        
  386.         Log::resultOk();
  387.     }
  388.    
  389.     function _diagnoseDomainOwnersDontExist()
  390.     {
  391.     Log::step('Checking if there are domains owned by non-existent users', true);
  392.     $db = PleskDb::getInstance();
  393.     $sql = 'SELECT name FROM domains AS d LEFT JOIN clients AS c ON c.id = d.cl_id WHERE c.id IS NULL;';
  394.         $domains = $db->fetchAll($sql);
  395.  
  396.     $details = 0;
  397.     $totalDomains = 0;
  398.     foreach ($domains as $key => $domain)
  399.     {
  400.         $details .= "----Domain '{$domain['name']}' belongs to owner that does not exist" . PHP_EOL;
  401.         $totalDomains++;
  402.     }
  403.  
  404.     if ($totalDomains > 0)
  405.     {
  406.             $logPath = APP_PATH.'/domain_owners_dont_exists.log';
  407.             Log::write($logPath, $details, 'w');
  408.         $warn = 'You have '.$totalDomains.' domains whose owners do not exist.';
  409.         Log::warning($warn);
  410.             Log::info('See details in log ' . $logPath);
  411.             Log::resultWarning();
  412.             return;
  413.     }
  414.  
  415.         Log::resultOk();
  416.     }
  417.  
  418.     function _getClientsOwnedByAdmin()
  419.     {
  420.         $db = PleskDb::getInstance();
  421.         $filterOwnedByAdmin = '';
  422.         if (PleskVersion::is9x()) {
  423.             $filterOwnedByAdmin = "WHERE type='client' AND parent_id=".$this->_getAdminId();
  424.         }
  425.         $sql = 'SELECT clients.id, clients.pname, clients.perm_id, count(domains.id) as count_dom FROM clients
  426.            INNER JOIN domains ON(domains.cl_id = clients.id)
  427.            '.$filterOwnedByAdmin.'
  428.            GROUP BY clients.id, clients.pname, clients.perm_id
  429.            HAVING count(domains.id) > 1
  430.        ';
  431.         $clients = $db->fetchAll($sql);
  432.        
  433.         foreach ($clients as $key => $client) {
  434.             if (empty($client['perm_id'])) {
  435.                 //:INFO: client permissions based on default template
  436.                 unset($clients[$key]);
  437.                 continue;
  438.             }
  439.            
  440.             $sql = "SELECT count(*) FROM Permissions
  441.                WHERE id={$client['perm_id']} AND value='true' AND
  442.                (permission = 'create_domains' OR permission = 'change_limits')
  443.            ";
  444.             $count = $db->fetchOne($sql);
  445.            
  446.             //:INFO: Client has no permissions and we unset him.
  447.             if ($count != 2) {
  448.                 unset($clients[$key]);
  449.             }
  450.         }
  451.         return $clients;
  452.     }
  453.    
  454.     function _getClientsHaveDomAdminsOwnedByAdmin()
  455.     {
  456.         $filterOwnedByAdmin = '';
  457.         if (PleskVersion::is9x()) {
  458.             $filterOwnedByAdmin = "WHERE type='client' AND parent_id=".$this->_getAdminId();
  459.         }
  460.        
  461.         $db = PleskDb::getInstance();
  462.         $sql ='SELECT clients.id, clients.pname, count(domains.name) AS count_dom_adm  
  463.            FROM ((clients
  464.            INNER JOIN domains ON (clients.id=domains.cl_id))
  465.            INNER JOIN dom_level_usrs ON(domains.id=dom_level_usrs.dom_id))
  466.            '.$filterOwnedByAdmin.'
  467.            GROUP BY clients.id, clients.pname
  468.            HAVING count(domains.name) > 1
  469.        ';
  470.         $clients = $db->fetchAll($sql);
  471.        
  472.         return $clients;
  473.     }
  474.    
  475.     function _getClientsHaveNoDomainsOwnedByAdmin()
  476.     {
  477.         $filterOwnedByAdmin = '';
  478.         if (PleskVersion::is9x()) {
  479.             $filterOwnedByAdmin = "AND type='client' AND parent_id=".$this->_getAdminId();
  480.         }
  481.         $db = PleskDb::getInstance();
  482.         $sql = 'SELECT clients.id, clients.pname FROM clients
  483.            WHERE id NOT IN (SELECT cl_id FROM domains) '.$filterOwnedByAdmin.'
  484.        ';
  485.         $clients = $db->fetchAll($sql);
  486.         return $clients;
  487.     }
  488.    
  489.     function _getClientsOwnedByReseller()
  490.     {
  491.         $db = PleskDb::getInstance();
  492.         $sql = "SELECT clients.id, clients.login, clients.pname FROM clients WHERE type='reseller'";
  493.         $resellers = $db->fetchAll($sql);
  494.        
  495.         //:INFO: Get list of resellers with clients who have more than one domain
  496.         $resellerMatched = array();
  497.         foreach ($resellers as $reseller) {
  498.             $sql = 'SELECT clients.id, clients.login, clients.perm_id, clients.pname, count(domains.id) as count_dom FROM clients
  499.                INNER JOIN domains ON(domains.cl_id = clients.id AND clients.parent_id = '.$reseller['id'].')
  500.                GROUP BY clients.id, clients.login, clients.perm_id, clients.pname
  501.                HAVING count(domains.id) > 1
  502.            ';
  503.             $clients = $db->fetchAll($sql);
  504.             if (sizeof($clients) > 0) {
  505.                 $resellerMatched[$reseller['login']] = $clients;
  506.             }
  507.         }
  508.  
  509.         //:INFO: Check that clients has permissions 'create_domains' and 'change_limits'
  510.         foreach ($resellerMatched as $key => $clients) {
  511.             foreach ($clients as $cl_key => $client) {
  512.                 if (empty($client['perm_id'])) {
  513.                     //:INFO: client permissions based on default template
  514.                     unset($resellerMatched[$key][$cl_key]);
  515.                     continue;
  516.                 }
  517.                
  518.                 $sql = "SELECT count(*) FROM Permissions
  519.                    WHERE id={$client['perm_id']} AND value='true' AND
  520.                    (permission = 'create_domains' OR permission = 'change_limits')
  521.                ";
  522.                 $count = $db->fetchOne($sql);
  523.                 if ($count != 2) {
  524.                     //:INFO: Client has no permissions and we unset him.
  525.                     unset($resellerMatched[$key][$cl_key]);
  526.                 }
  527.             }
  528.             //:INFO: unset reseller if client list is empty
  529.             if (!sizeof($resellerMatched[$key])) {
  530.                 unset($resellerMatched[$key]);
  531.             }
  532.         }
  533.        
  534.         return $resellerMatched;
  535.     }
  536.    
  537.     function _getClientsWithDomAdminsOwnedByReseller()
  538.     {
  539.         $db = PleskDb::getInstance();
  540.         $sql = "SELECT clients.id, clients.login, clients.pname FROM clients WHERE type='reseller'";
  541.         $resellers = $db->fetchAll($sql);
  542.        
  543.         $resellerMatched = array();
  544.         foreach ($resellers as $reseller) {
  545.             $sql ='SELECT clients.id, clients.pname, count(domains.name) AS count_dom_adm
  546.                FROM ((clients
  547.                INNER JOIN domains ON (clients.id=domains.cl_id AND clients.parent_id = '.$reseller['id'].'))
  548.                INNER JOIN dom_level_usrs ON(domains.id=dom_level_usrs.dom_id))
  549.                GROUP BY clients.id, clients.pname
  550.                HAVING count(domains.name) > 1
  551.            ';
  552.             $clients = $db->fetchAll($sql);
  553.            
  554.             if (sizeof($clients) > 0) {
  555.                 $resellerMatched[$reseller['login']] = $clients;
  556.             }
  557.         }
  558.  
  559.         return $resellerMatched;
  560.     }
  561.    
  562.     function _getClientsHaveNoDomainsOwnedByReseller()
  563.     {
  564.         $db = PleskDb::getInstance();
  565.         $sql = "SELECT clients.id, clients.login, clients.pname FROM clients WHERE type='reseller'";
  566.         $resellers = $db->fetchAll($sql);
  567.        
  568.         $resellerMatched = array();
  569.         foreach ($resellers as $reseller) {
  570.             $sql = 'SELECT clients.id, clients.pname FROM clients
  571.                WHERE parent_id='.$reseller['id'].' AND id NOT IN (SELECT cl_id FROM domains)
  572.            ';
  573.             $clients = $db->fetchAll($sql);
  574.            
  575.             if (sizeof($clients) > 0) {
  576.                 $resellerMatched[$reseller['login']] = $clients;
  577.             }
  578.         }
  579.         return $resellerMatched;
  580.     }
  581.    
  582.     function _getAdminDomains()
  583.     {
  584.         $db = PleskDb::getInstance();
  585.         $sql = 'SELECT domains.name FROM domains
  586.            INNER JOIN dom_level_usrs ON(domains.id=dom_level_usrs.dom_id)
  587.            WHERE domains.cl_id='.$this->_getAdminId()
  588.         ;
  589.  
  590.         $domains = $db->fetchAll($sql);
  591.         if (sizeof($domains) <= 1) {
  592.             return array();
  593.         }
  594.         return $domains;
  595.     }
  596.    
  597.     function _getResellerDomains()
  598.     {
  599.         $db = PleskDb::getInstance();
  600.         $sql = "SELECT clients.id, clients.login FROM clients WHERE type='reseller'";
  601.         $resellers = $db->fetchAll($sql);
  602.        
  603.         $resellerMatched = array();
  604.         foreach ($resellers as $reseller) {
  605.             $sql = "SELECT domains.name FROM domains
  606.                INNER JOIN dom_level_usrs ON(domains.id=dom_level_usrs.dom_id)
  607.                WHERE cl_id = {$reseller['id']}";
  608.             $domains = $db->fetchAll($sql);
  609.            
  610.             if (sizeof($domains) > 1) {
  611.                 $resellerMatched[$reseller['login']] = $domains;
  612.             }
  613.         }
  614.         return $resellerMatched;
  615.     }
  616.    
  617.     function _getAdminId()
  618.     {
  619.         $db = PleskDb::getInstance();
  620.         $sql = "SELECT id FROM clients WHERE type='admin'";
  621.         $adminId = $db->fetchOne($sql);
  622.        
  623.         if (empty($adminId)) {
  624.             Log::fatal('Unable to find Plesk administrator. Please check SQL: ' . $sql);
  625.         }
  626.        
  627.         return $adminId;
  628.     }
  629.    
  630.     function _getAdminEmail()
  631.     {
  632.         $db = PleskDb::getInstance();
  633.         $sql = "SELECT val FROM misc WHERE param='admin_email'";
  634.         $adminEmail = $db->fetchOne($sql);
  635.  
  636.         return $adminEmail;
  637.     }
  638.    
  639.     //:INFO: Domain's type can be 'none','vrt_hst','std_fwd','frm_fwd'
  640.     function _getDomainsByHostingType($type = 'vrt_hst')
  641.     {
  642.         $db = PleskDb::getInstance();
  643.         $sql = 'SELECT name FROM domains WHERE htype="' . $type . '"';
  644.         $domains = $db->fetchAll($sql);
  645.    
  646.         return $domains;
  647.     }
  648. }
  649.  
  650. class Plesk10Requirements
  651. {
  652.     function validate()
  653.     {
  654.         //:INFO: Make sure that offline management is switched off before upgrading to Plesk 10.x
  655.         if (PleskInstallation::isInstalled() && (PleskVersion::is8x() || PleskVersion::is9x())) {
  656.             $this->_checkOfflineManagement();
  657.         }
  658.  
  659.         //:INFO: Check that Linux security module is swicthed off
  660.         $this->_checkApparmorService();
  661.        
  662.         //:INFO: Server should have properly configured hostname and it should be resolved locally
  663.         $this->_resolveHostname();
  664.     }
  665.    
  666.     function _checkApparmorService()
  667.     {
  668.         if (Util::isLinux()) {
  669.             Log::step('Detecting if the apparmor service is switched off...', true);
  670.            
  671.             $apparmorPath = '/etc/init.d/apparmor';
  672.             if (file_exists($apparmorPath)) {
  673.                 $apparmor_status = Util::exec('/etc/init.d/apparmor status', $code);
  674.                 if (preg_match('/(complain|enforce)/', $apparmor_status)) {
  675.                     $warn = 'The \'Apparmor\' security module for the Linux kernel is turned on. ';
  676.                     $warn .= 'Turn the module off before continuing work with Parallels Plesk Panel. Please check http://kb.parallels.com/en/112903 for more details.';
  677.                     Log::warning($warn);
  678.                     Log::resultWarning();
  679.                     return;
  680.                 }
  681.             }
  682.             Log::resultOk();
  683.         }
  684.     }
  685.    
  686.     function _checkOfflineManagement()
  687.     {
  688.         Log::step('Detect virtualization', true);
  689.  
  690.         //:INFO: There is no ability to detect offline management inside VZ container
  691.         if (Util::isVz()) {
  692.             $warn = 'Virtuozzo is detected in your system. ';
  693.             $warn .= 'Make sure that offline management is switched off for the container before installing or upgrading to ' . PleskVersion::getLatestPleskVersionAsString();
  694.             Log::info($warn);
  695.            
  696.             return;
  697.         }
  698.  
  699.         Log::resultOk();
  700.     }
  701.    
  702.     function _resolveHostname()
  703.     {
  704.         Log::step('Validate hostname', true);
  705.        
  706.         $hostname = Util::getHostname();
  707.        
  708.         //Get the IPv address corresponding to a given Internet host name
  709.         $ip = gethostbyname($hostname);
  710.         if (!PleskValidator::isValidIp($ip)) {
  711.             $warn = "Hostname '{$hostname}' is not resolved locally.";
  712.             $warn .= 'Make sure that server should have properly configured hostname and it should be resolved locally before installing or upgrading to Plesk Billing';
  713.             Log::warning($warn);
  714.             Log::resultWarning();
  715.            
  716.             return;
  717.         }
  718.         Log::resultOk();
  719.     }
  720. }
  721.  
  722. class Plesk10MailServer
  723. {
  724.     function validate()
  725.     {
  726.         if (!PleskInstallation::isInstalled()) {
  727.             return;
  728.         }
  729.        
  730.         $this->_checkPostfixDnsLookup();
  731.     }
  732.    
  733.     function _checkPostfixDnsLookup()
  734.     {
  735.         if (Util::isLinux()) {
  736.             Log::step('Detecting if mail server type is Postfix...', true);
  737.            
  738.             if ($this->_isPostfix()) {
  739.                 Log::info('Postfix is current mail server');
  740.                 $cmd = Util::lookupCommand('postconf') . ' disable_dns_lookups';
  741.                 $output = Util::exec($cmd, $code);
  742.                 if (preg_match('/disable_dns_lookups[\s]{0,}=[\s]{0,}yes/', $output)) {
  743.                     $warn = "Parameter 'disable_dns_lookups' is disabled in Postfix configuration (/etc/postfix/main.cf). ";
  744.                     $warn .= "By default this parameter is set to 'no' by Parallels Plesk. ";
  745.                     $warn .= "Need to set param value disable_dns_lookups=yes";
  746.                     Log::warning($warn);
  747.                     Log::resultWarning();
  748.                    
  749.                     return;
  750.                 }
  751.             } else {
  752.                 Log::info('Qmail is current mail server');
  753.             }
  754.        
  755.             Log::resultOk();
  756.         }
  757.     }
  758.    
  759.     function _isPostfix()
  760.     {
  761.         $res = Util::lookupCommand(
  762.             'postconf',
  763.             '/usr/bin:/usr/local/bin:/usr/sbin:/bin:/sbin:/usr/local/sbin',
  764.             false
  765.         );
  766.        
  767.         return $res;
  768.     }
  769.    
  770.     function CurrentWinMailServer()
  771.     {    
  772.         if (Util::isWindows()) {
  773.             $currentMailServer = Util::regQuery('\PLESK\PSA Config\Config\Packages\mailserver', '/ve', true);
  774.             Log::info('Current mail server is: ' . $currentMailServer);        
  775.             return $currentMailServer;
  776.         }
  777.     }
  778.    
  779. }
  780.  
  781. class Plesk10Skin
  782. {
  783.     function validate()
  784.     {
  785.         if (!PleskInstallation::isInstalled()) {
  786.             //:INFO: Plesk installation is not found. You will have no problems with upgrade, go on and install Plesk Panel 10
  787.             return;
  788.         }
  789.        
  790.         if (PleskVersion::is8x() || PleskVersion::is9x()) {
  791.             Log::step('Notify about skins in ' . PleskVersion::getLatestPleskVersionAsString());
  792.            
  793.             $warn = 'Parallels Plesk Panel 10 is shipped with only one graphical user interface appearance theme, ';
  794.             $warn .= 'so all the appearance settings will be ignored after upgrade and the default theme will be used for all users. ';
  795.             $warn .= 'If you want to change the default Panel 10 appearance, create and use custom appearance themes as described ';
  796.             $warn .= 'in the Guide to Customizing Panel Appearance and Branding (http://www.parallels.com/products/plesk/documentation/). ';
  797.             $warn .= 'Deploying custom themes is available since Plesk 10.1.';
  798.             Log::info($warn);
  799.         }
  800.     }
  801. }
  802.  
  803. class Plesk10Permissions
  804. {
  805.     function validate()
  806.     {
  807.         $this->_validatePHPSessionDir();
  808.     }
  809.    
  810.     function _validatePHPSessionDir()
  811.     {
  812.         if (Util::isLinux()) {
  813.             Log::step('Validating permissions of the PHP session directory...', true);
  814.            
  815.             $phpbinary = Util::getSettingFromPsaConf('CLIENT_PHP_BIN');
  816.             $cmd = $phpbinary . " -r 'echo ini_get(\"session.save_path\");'";
  817.             $path = Util::exec($cmd, $code);
  818.  
  819.             $cmd = 'su nobody -m -c "' . $phpbinary . ' -r \'@session_start();\' 2>&1"';
  820.             $realResult = `$cmd`;
  821.                        
  822.             Log::info("session.save_path = $path");
  823.            
  824.             if (!file_exists($path)) {
  825.                 // TODO no need to fail in this case, right?
  826.                 //Log::warning("No such directory {$path}");
  827.                 //Log::resultWarning();
  828.                 Log::info("No such directory '{$path}'");
  829.                 Log::resultOk();
  830.                 return;
  831.             }
  832.            
  833.             $perms = (int)substr(decoct( fileperms($path) ), 2);
  834.             Log::info('Permissions: '   . $perms);
  835.            
  836.             //:INFO: PHP on domains running via CGI/FastCGI can't use session by default http://kb.parallels.com/en/7056
  837.             if (preg_match('/Permission\sdenied/', $realResult, $match)) {
  838.                 $warn = "If a site uses default PHP settings and PHP is in CGI/FastCGI mode, site applications are unable to create user sessions. This is because the apps run on behalf of a subscription owner who does not have permissions to the directory which stores session files, " . $path . ". Please check http://kb.parallels.com/en/7056 for more details.";
  839.                 Log::warning($warn);
  840.                 Log::resultWarning();
  841.                 return;
  842.             }
  843.            
  844.             Log::resultOk();
  845.         }
  846.     }
  847. }
  848.  
  849. class Plesk10KnownIssues
  850. {
  851.     function validate()
  852.     {
  853.         if (!PleskInstallation::isInstalled()) {
  854.             //:INFO: Plesk installation is not found. You will have no problems with upgrade, go on and install Plesk Panel 10
  855.             return;
  856.         }
  857.                
  858.         //:INFO: Validate known OS specific issues with recommendation to avoid bugs in Plesk
  859.         if (Util::isLinux()
  860.             && Util::isVz()
  861.             && Util::getArch() == 'x86_64'
  862.             && PleskOS::isSuse103()
  863.         ) {
  864.             $this->_diagnoseKavOnPlesk10x();
  865.         }
  866.        
  867.         //:INFO: Prevent potential problem with E: Couldn't configure pre-depend plesk-core for psa-firewall, probably a dependency cycle.
  868.         if (PleskVersion::is8x()
  869.             && Util::isLinux()
  870.             && Util::isVz()
  871.             && PleskOS::isUbuntu804()
  872.         ) {
  873.             $this->_diagnoseDependCycleOfModules();
  874.         }
  875.        
  876.         if (Util::isLinux()) {
  877.            
  878.             $this->_checkMainIP(); //:INFO: Checking for main IP address http://kb.parallels.com/en/112417
  879.             $this->_checkCBMrelayURL(); //:INFO: Checking for hostname in Customer & Business Manager relay URL http://kb.parallels.com/en/111500
  880.             $this->_checkMySQLDatabaseUserRoot(); //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin http://kb.parallels.com/en/112779
  881.             $this->_checkPAMConfigsInclusionConsistency();  //:INFO: Check that non-existent PAM services are not referenced by other services, i.e. that PAM configuration array is consistent http://kb.parallels.com/en/112944
  882.             //:INFO: FIXED in 11.0.0 $this->_checkZendExtensionsLoadingOrder(); //:INFO:#100253 Wrong order of loading Zend extensions ionCube declaraion in php.ini can cause to Apache fail http://kb.parallels.com/en/1520
  883.             $this->_checkDumpTmpDvalue(); //:INFO: #101168 If DUMP_TMP_D in /etc/psa/psa.conf contains extra space character at the end of string backup procedure will fails permanently http://kb.parallels.com/113474
  884.             $this->_checkProftpdIPv6(); //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled http://kb.parallels.com/en/113504
  885.             //:INFO: FIXED in 11.0.0 $this->_checkModificationOfCustomizedDNSzones(); //:INFO: # http://kb.parallels.com/en/113725
  886.             //:INFO: FIXED in 11.0.0 $this->_checkBindInitScriptPermission(); //:INFO: #105806 If there is no execute permission on named(bind) init file upgrade will fail
  887.             $this->_checkMysqlclient15Release(); //:INFO: #105256 http://kb.parallels.com/en/113737
  888.             $this->_checkNsRecordInDnsTemplate(); //:INFO: #94544  http://kb.parallels.com/en/113119
  889.             $this->_checkMysqlOdbcConnectorVersion(); //:INFO: #102516 http://kb.parallels.com/en/113620
  890.             $this->_checkSwCollectdIntervalSetting(); //:INFO: #105405 http://kb.parallels.com/en/113711
  891.            
  892.             if (PLeskVersion::is10x()) {
  893.                 $this->_checkIpAddressReferenceForForwardingDomains(); //:INFO: #72945 Checking for IP address references in Plesk database http://kb.parallels.com/en/113475
  894.             }
  895.            
  896.             if (PleskVersion::is10_0()) {
  897.                 $this->_oldBackupsRestoringWarningAfterUpgradeTo11x(); //:INFO: #58303  http://kb.parallels.com/en/114041
  898.             }
  899.            
  900.             if (PleskVersion::is10_1_or_below()) {
  901.                 $this->_checkCustomizedCnameRecordsInDnsTemplate(); //:INFO: Customized CNAME records in server's DNS template could lead to misconfiguration of BIND http://kb.parallels.com/en/113118
  902.             }
  903.            
  904.             if (PleskVersion::is10_2_or_above()) {
  905.                 $this->_checkSsoStartScriptsPriority(); //:INFO: Checking for conflicting of SSO start-up scripts http://kb.parallels.com/en/112666
  906.                 $this->_checkIpcollectionReference(); //:INFO: #72751 http://kb.parallels.com/en/113826
  907.             }
  908.            
  909.             if (PleskVersion::is10_3_or_above()) {
  910.                 $this->_checkApsApplicationContext(); //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration  http://kb.parallels.com/en/112815
  911.             }
  912.  
  913.             if (!PleskVersion::is10_4_or_above()) {
  914.                 $this->_checkCustomPhpIniOnDomains(); //:INFO: Check for custom php.ini on domains http://kb.parallels.com/en/111697
  915.             }
  916.            
  917.             if (PleskOS::isDebLike()) {
  918.                 $this->_checkSymLinkToOptPsa(); //:INFO: Check that symbolic link /usr/local/psa actually exists on Debian-like OSes http://kb.parallels.com/en/112214
  919.             }
  920.            
  921.             if (Util::isVz()) {
  922.                 $this->_checkUserBeancounters(); //:INFO: Checking that limits are not exceeded in /proc/user_beancounters http://kb.parallels.com/en/112522
  923.             }
  924.         }
  925.  
  926.         $this->_checkForCryptPasswords();
  927.         $this->_checkAutoinstallerVersion(); //:INFO: Checking for old version of autoinstaller http://kb.parallels.com/en/112166
  928.         $this->_checkMysqlServersTable(); //:INFO: Checking existing table mysql.servers
  929.         $this->_checkUserHasSameEmailAsAdmin(); //:INFO: If user has the same address as the admin it should be changed to another http://kb.parallels.com/en/111985
  930.         //:INFO: FIXED in 11.0.0       $this->_checkDefaultMySQLServerMode(); //:INFO:#66278,70525 Checking SQL mode of default client's MySQL server http://kb.parallels.com/en/112453
  931.         //:INFO: FIXED in 10.4.4 MU#19 $this->_checkUserHasSameEmailAsEmailAccount(); //:INFO: Users with same e-mails as e-mail accounts will have problems with changing personal contact information http://kb.parallels.com/en/112032
  932.         $this->_checkPleskTCPPorts(); //:INFO: Check the availability of Plesk Panel TCP ports http://kb.parallels.com/en/391
  933.         $this->_checkFreeMemory(); //:INFO: Check for free memory http://kb.parallels.com/en/112522
  934.         $this->_checkPanelAccessForLocalhost(); //:INFO: Upgrade of Customer & Business Manager failed in case of 127.0.0.1 is restricted for administrative access http://kb.parallels.com/en/113096
  935.         //:INFO: FIXED in 11.0.0       $this->_checkCustomDNSrecordsEqualToExistedSubdomains(); //:INFO: Customized DNS records with host equal host of existing subdomain will lost after upgrade to Plesk version above 10.4.4 http://kb.parallels.com/en/113310
  936.         $this->_checkForwardingURL(); //:INFO: Wrong GUI behavior if forwarding URL hasn't "http://" after upgrade to Plesk version above 10.4.4 http://kb.parallels.com/en/113359
  937.        
  938.        
  939.         //:INFO:  
  940.         if (PleskVersion::is9x()
  941.             || PleskVersion::is8x()
  942.         ) {
  943.             //:INFO: FIXED in 11.0.0 $this->_notificationChangePasswordForEmailAccount(); //:INFO: Notification about how to change password for the mail account after upgrade http://kb.parallels.com/en/9454
  944.             if (Util::isLinux()) {
  945.                 $this->_checkJkWorkersFileDirective(); //:INFO: JkWorkersFile directive in Apache configuration can lead to failed Apache configs re-generation during and after upgrade procedure http://kb.parallels.com/en/113210
  946.             }
  947.             if (Util::isWindows()) {
  948.                 $this->_hMailServerWarningOnUpgradeTo10x(); //:INFO: Plesk 10 version does not support hMailserver http://kb.parallels.com/en/9609
  949.                 $this->_unsupportedFtpServersWarningOnUpgradeTo10x(); //:INFO: Plesk 10.2 version does not support Gene6 http://kb.parallels.com/en/111816
  950.                 $this->_unsupportedDNSServersWarningOnUpgradeTo10x(); //:INFO: Plesk 10.x version does not support SimpleDNS http://kb.parallels.com/en/112280
  951.                 $this->_mDaemonServerWarningOnUpgradeTo10x(); //:INFO: Plesk 10 version does not support MDaemon http://kb.parallels.com/en/112356
  952.                
  953.             }
  954.         }
  955.        
  956.         if (PleskVersion::is10x()
  957.             && !PleskVersion::is10_2_or_above()
  958.         ) {
  959.             $this->_checkCBMlicense(); //:INFO: Check for Customer and Business Manager license http://kb.parallels.com/en/111143
  960.         }
  961.        
  962.         if (PleskVersion::is10_4()) {
  963.             $this->_notificationSubDomainsHaveOwnDNSZoneSince104(); //:INFO: Notification about after upgrade all subdomains will have own DNS zone http://kb.parallels.com/en/112966
  964.         }
  965.        
  966.         if (Util::isWindows()) {
  967.             $this->_unknownISAPIfilters(); //:INFO: Checking for unknown ISAPI filters and show warning http://kb.parallels.com/en/111908
  968.             $this->_checkMSVCR(); //:INFO: Just warning about possible issues related to Microsoft Visual C++ Redistributable Packages http://kb.parallels.com/en/111891
  969.             $this->_checkConnectToClientMySQL(); //:INFO: Checking possibility to connect to client's MySQL server http://kb.parallels.com/en/111983
  970.             $this->_checkIisFcgiDllVersion(); //:INFO: Check iisfcgi.dll file version http://kb.parallels.com/en/112606
  971.             $this->_checkCDONTSmailrootFolder(); //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, http://kb.parallels.com/en/111194
  972.             $this->_checkWindowsAuthForPleskControlPanel(); //:INFO: Check windows authentication for PleskControlPanel web site http://kb.parallels.com/en/113253
  973.             if (Util::isVz()) {
  974.                 $this->_checkDotNetFrameworkIssue(); //:INFO: Check that .net framework installed properly http://kb.parallels.com/en/111448
  975.             }
  976.             if (PleskVersion::is10x()) {
  977.                 $this->_checkSmarterMailOpenPorts(); //:INFO: #98549 Plesk doesn't bind Smartermail 8 ports on new IPs http://kb.parallels.com/en/113330
  978.             }
  979.         }      
  980.     }
  981.    
  982.     //:INFO: #58303 http://kb.parallels.com/en/114041
  983.     function _oldBackupsRestoringWarningAfterUpgradeTo11x()
  984.     {
  985.         Log::warning('Error messages can appear at restoring backups created in Plesk 10.0.1. Please check http://kb.parallels.com/en/114041 for details.');
  986.         Log::resultWarning();
  987.     }
  988.    
  989.     //:INFO: #105405 http://kb.parallels.com/en/113711
  990.     function _checkSwCollectdIntervalSetting()
  991.     {
  992.         Log::step("Checking 'Interval' setting in swcollectd config file...", true);
  993.    
  994.         $collectd_config = '/etc/sw-collectd/collectd.conf';
  995.         if (file_exists($collectd_config)) {
  996.             if (!is_file($collectd_config) || !is_readable($collectd_config))
  997.             return;
  998.    
  999.             $config_content = Util::readfileToArray($collectd_config);
  1000.             if ($config_content) {
  1001.                 foreach ($config_content as $line) {
  1002.                     if (preg_match('/Interval\s*\d+$/', $line, $match)) {
  1003.                         if (preg_match('/Interval\s*10$/', $line, $match)) {
  1004.                             Log::warning('Much CPU time can be consumed if default value of "Interval" setting used in ' . $collectd_config . ' . Please check http://kb.parallels.com/en/113711 for details.');
  1005.                             Log::resultWarning();
  1006.                             return;
  1007.                         }
  1008.                         Log::resultOk();
  1009.                         return;
  1010.                     }
  1011.                 }
  1012.                 Log::warning('Much CPU time can be consumed if default value of "Interval" setting used in ' . $collectd_config . ' . Please check http://kb.parallels.com/en/113711 for details.');
  1013.                 Log::resultWarning();
  1014.                 return;
  1015.             }
  1016.         }
  1017.     }
  1018.    
  1019.     //:INFO: #94544  http://kb.parallels.com/en/113119
  1020.     function _checkNsRecordInDnsTemplate()
  1021.     {
  1022.         Log::step("Checking for NS type record in server DNS template...", true);
  1023.    
  1024.         $mysql = PleskDb::getInstance();
  1025.         $sql = "SELECT 1 FROM dns_recs_t WHERE type='NS'";
  1026.         $nsRecord = $mysql->fetchAll($sql);
  1027.            
  1028.         if (empty($nsRecord)) {
  1029.             Log::warning('There is no NS type record in server DNS template, it can break BIND server configuration. Please check http://kb.parallels.com/en/113119 for details.');
  1030.             Log::resultWarning();
  1031.             return;
  1032.         }
  1033.          
  1034.         Log::resultOk();
  1035.     }
  1036.    
  1037.     //:INFO: #102516 http://kb.parallels.com/en/113620
  1038.     function _checkMysqlOdbcConnectorVersion()
  1039.     {
  1040.         Log::step("Checking for MySQL ODBC package version...", true);
  1041.         if (PleskOS::isRedHatLike() || PleskOS::isSuseLike()) {
  1042.             $package = 'mysql-connector-odbc';
  1043.         } else {
  1044.             $package = 'libmyodbc';
  1045.         }
  1046.        
  1047.         $version = Package::getVersion($package);
  1048.        
  1049.         if ($version === false) {
  1050.             return;
  1051.         }
  1052.    
  1053.         if (preg_match('/\d+\.\d+\.\d+/', $version, $match) && version_compare($match[0], '3.51.21', '<')) {
  1054.             Log::warning('Old version of ' . $package . ' is installed. Please check http://kb.parallels.com/en/113620 for details.');
  1055.             Log::resultWarning();
  1056.             return;
  1057.         }
  1058.        
  1059.         Log::resultOk();
  1060.     }
  1061.    
  1062.     //:INFO: #72751  http://kb.parallels.com/en/113826
  1063.     function _checkIpcollectionReference()
  1064.     {
  1065.         Log::step("Checking for corrupted reference between IP collections and IP addresses...", true);
  1066.    
  1067.         $mysql = PleskDb::getInstance();
  1068.         $sql = "SELECT 1 FROM ip_pool, clients, IpAddressesCollections, domains, DomainServices, IP_Addresses WHERE DomainServices.ipCollectionId = IpAddressesCollections.ipCollectionId AND domains.id=DomainServices.dom_id AND clients.id=domains.cl_id AND ipAddressId NOT IN (select id from IP_Addresses) AND IP_Addresses.id = ip_pool.ip_address_id AND pool_id = ip_pool.id GROUP BY pool_id";
  1069.         $brokenIps = $mysql->fetchAll($sql);
  1070.         $sql = "select 1 from DomainServices, domains, clients, ip_pool where ipCollectionId not in (select IpAddressesCollections.ipCollectionId from IpAddressesCollections) and domains.id=DomainServices.dom_id and clients.id = domains.cl_id and ip_pool.id = clients.pool_id and DomainServices.type='web' group by ipCollectionId";
  1071.         $brokenCollections = $mysql->fetchAll($sql);
  1072.          
  1073.         if (!empty($brokenIps) || !empty($brokenCollections)) {
  1074.             Log::warning('Reference between some IP collections and IP addresses has been broken. Please check http://kb.parallels.com/en/113826 for details.');
  1075.             Log::resultWarning();
  1076.             return;
  1077.         }
  1078.        
  1079.         Log::resultOk();
  1080.     }
  1081.  
  1082.     //:INFO: #105256 http://kb.parallels.com/en/113737
  1083.     function _checkMysqlclient15Release()
  1084.     {
  1085.         Log::step("Checking for mysqlclient15 package version...", true);
  1086.         if (PleskOS::isRedHatLike()) {
  1087.             $release = Package::getRelease('mysqlclient15');
  1088.            
  1089.             if ($release === false) {
  1090.                 return;
  1091.             }
  1092.            
  1093.             if (preg_match('/1\.el5\.art/', $release)) {
  1094.                 Log::emergency('Old version of mysqlclient15 is installed, which can lead to upgrade fail. You can apply workaround from article http://kb.parallels.com/en/113737');
  1095.                 Log::resultWarning();
  1096.                 return;
  1097.             }
  1098.         }
  1099.         Log::resultOk();
  1100.     }
  1101.  
  1102.     //:INFO: #105806 If there is no execute permission on named(bind) init file upgrade will fail
  1103.     function _checkBindInitScriptPermission()
  1104.     {
  1105.         Log::step("Checking for permissions on BIND init script...", true);
  1106.  
  1107.         $redhat = '/etc/init.d/named';
  1108.         $debian = '/etc/init.d/bind9';
  1109.         $suse = '/etc/init.d/named';
  1110.         $bindInitFile = 'unknown';
  1111.        
  1112.         if (PleskOS::isRedHatLike()) {
  1113.             $bindInitFile = $redhat;
  1114.         }
  1115.         if (PleskOS::isDebLike()) {
  1116.             $bindInitFile = $debian;
  1117.         }
  1118.         if (PleskOS::isSuseLike()) {
  1119.             $bindInitFile = $suse;
  1120.         }
  1121.        
  1122.         $perms = Util::Exec('ls -l ' . $bindInitFile, $code);
  1123.        
  1124.         if (!preg_match('/^.+x.+\s/', $perms)
  1125.             && $code === 0) {
  1126.             Log::emergency('There is no execute permission on ' . $bindInitFile . ' file, which can lead to upgrade fail. You can apply workaround from article http://kb.parallels.com/en/113733');
  1127.             Log::resultWarning();
  1128.             return;
  1129.         }
  1130.          
  1131.         Log::resultOk();
  1132.     }
  1133.      
  1134.     //:INFO: #101351 #101690 #103125 #104527 #104528 http://kb.parallels.com/en/113725
  1135.     function _checkModificationOfCustomizedDNSzones()
  1136.     {
  1137.         Log::step("Checking for customized DNS zones which will be modified during upgrade...", true);
  1138.    
  1139.         $mysql = PleskDb::getInstance();
  1140.         if (PleskVersion::is10_2_or_above()) {
  1141.             $ipv4 = "SELECT dns_zone.id, dns_zone.name, dns_recs.val, ip_address from dns_zone, dns_recs, DomainServices, IpAddressesCollections, IP_Addresses, domains where domains.dns_zone_id = dns_zone.id AND dns_zone.id = dns_recs.dns_zone_id AND dns_recs.type = 'A' AND dns_recs.host = concat(domains.name,'.') AND domains.id = DomainServices.dom_id AND DomainServices.type = 'web' AND DomainServices.ipCollectionId = IpAddressesCollections.ipCollectionId AND IpAddressesCollections.ipAddressId = IP_Addresses.id AND IP_Addresses.ip_address not like '%:%' AND dns_recs.val not like '%:%' AND IP_Addresses.ip_address <> dns_recs.val";
  1142.             $ipv6 = "SELECT dns_zone.id, dns_zone.name, dns_recs.val, ip_address from dns_zone, dns_recs, DomainServices, IpAddressesCollections, IP_Addresses, domains where domains.dns_zone_id = dns_zone.id AND dns_zone.id = dns_recs.dns_zone_id AND dns_recs.type = 'A' AND dns_recs.host = concat(domains.name,'.') AND domains.id = DomainServices.dom_id AND DomainServices.type = 'web' AND DomainServices.ipCollectionId = IpAddressesCollections.ipCollectionId AND IpAddressesCollections.ipAddressId = IP_Addresses.id AND IP_Addresses.ip_address like '%:%' AND dns_recs.val like '%:%'  AND IP_Addresses.ip_address <> dns_recs.val";
  1143.             $ipv4_zones = $mysql->fetchAll($ipv4);
  1144.             $ipv6_zones = $mysql->fetchAll($ipv6);
  1145.             $dns_zones = array_merge($ipv4_zones, $ipv6_zones);
  1146.         } else {
  1147.             $fwd = "SELECT dns_zone.id, dns_zone.name, dns_recs.val, ip_address AS hosts from dns_zone, dns_recs, forwarding, IP_Addresses, domains where domains.dns_zone_id = dns_zone.id AND dns_zone.id = dns_recs.dns_zone_id AND dns_recs.type = 'A' AND dns_recs.host = concat(domains.name,'.') AND domains.id = forwarding.dom_id AND forwarding.ip_address_id = IP_Addresses.id AND IP_Addresses.ip_address <> dns_recs.val";
  1148.             $hst = "SELECT dns_zone.id, dns_zone.name, dns_recs.val, ip_address AS hosts from dns_zone, dns_recs, hosting, IP_Addresses, domains where domains.dns_zone_id = dns_zone.id AND dns_zone.id = dns_recs.dns_zone_id AND dns_recs.type = 'A' AND dns_recs.host = concat(domains.name,'.') AND domains.id = hosting.dom_id AND hosting.ip_address_id = IP_Addresses.id AND IP_Addresses.ip_address <> dns_recs.val";
  1149.             $fwd_zones = $mysql->fetchAll($fwd);
  1150.             $hst_zones = $mysql->fetchAll($hst);
  1151.             $dns_zones = array_merge($fwd_zones, $hst_zones);
  1152.         }
  1153.    
  1154.         $warning = false;
  1155.         foreach ($dns_zones as $zone) {
  1156.             $subdomains = $mysql->fetchAll('SELECT subdomains.name FROM domains, subdomains WHERE subdomains.dom_id = domains.id AND domains.dns_zone_id=' . $zone['id']);
  1157.             if (!empty($subdomains)) {
  1158.                 Log::info('A or AAAA records in DNS zone ' . $zone['name'] . ' will be modified or deleted after upgrade.');
  1159.                 $warning = true;
  1160.             }
  1161.         }
  1162.          
  1163.         if ($warning) {
  1164.             Log::warning('A or AAAA records in DNS zones will be modified or deleted after upgrade. Please check http://kb.parallels.com/en/113725 and ' . APP_PATH . '/plesk10_preupgrade_checker.log for details.');
  1165.             Log::resultWarning();
  1166.             return;
  1167.         }
  1168.    
  1169.         Log::resultOk();
  1170.     }
  1171.  
  1172.     //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration http://kb.parallels.com/en/112815
  1173.     function _checkApsApplicationContext()
  1174.     {
  1175.         Log::step("Checking for links between APS applications and subscriptions...", true);
  1176.         $mysql = PleskDb::getInstance();
  1177.         $sql = "SELECT * FROM apsContexts WHERE (pleskType = 'hosting' OR pleskType = 'subdomain') AND subscriptionId = 0";
  1178.         $brokenContexts = $mysql->fetchAll($sql);
  1179.    
  1180.         if (!empty($brokenContexts)) {
  1181.             Log::warning('Reference between several subscriptions and APS applications has been broken. Please check http://kb.parallels.com/en/112815 for details.');
  1182.             Log::resultWarning();
  1183.             return;
  1184.         }
  1185.         Log::resultOk();
  1186.     }
  1187.    
  1188.     //:INFO: #98549 Plesk doesn't bind Smartermail 8 ports on new IPs http://kb.parallels.com/en/113330
  1189.     function _checkSmarterMailOpenPorts()
  1190.     {
  1191.         Log::step("Checking SmarterMail open ports...", true);
  1192.        
  1193.         if (Plesk10MailServer::CurrentWinMailServer() == 'smartermail') {
  1194.             $ip_addresses = Util::getIPListOnWindows();
  1195.            
  1196.             $mysql = PleskDb::getInstance();
  1197.             $sql = "select ip_address from IP_Addresses";
  1198.             $ip_addresses = $mysql->fetchAll($sql);
  1199.            
  1200.             foreach ($ip_addresses as $ip) {
  1201.                 if (PleskValidator::validateIPv4($ip['ip_address'])) {
  1202.                     $fp = @fsockopen($ip['ip_address'], 25, $errno, $errstr, 1);
  1203.                 } elseif (PleskValidator::validateIPv6($ip['ip_address'])) {
  1204.                     $fp = @fsockopen('[' . $ip['ip_address'] . ']', 25, $errno, $errstr, 1);
  1205.                 } else {
  1206.                     Log::warning('The IP address is invalid: ' . $ip['ip_address']);
  1207.                     Log::resultWarning();
  1208.                     return;
  1209.                 }
  1210.                 if (!$fp) {
  1211.                     // $errno 110 means "timed out", 111 means "refused"
  1212.                     Log::info('Unable to connect to the SMTP port 25 on the IP address ' . $ip['ip_address'] . ': ' . $errstr);
  1213.                     $warning = true;
  1214.                 }
  1215.             }
  1216.             if ($warning) {
  1217.                 Log::warning('SmarterMail is unable to use some of the IP addresses because they are not associated with the SmarterMail ports. Please check http://kb.parallels.com/en/113330 for details.');
  1218.                 Log::resultWarning();
  1219.                 return;
  1220.             }
  1221.         }
  1222.  
  1223.         Log::resultOk();
  1224.     }
  1225.    
  1226.     //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled http://kb.parallels.com/en/113504
  1227.     function _checkProftpdIPv6()
  1228.     {
  1229.         Log::step("Checking proftpd settings...", true);
  1230.  
  1231.         $inet6 = '/proc/net/if_inet6';
  1232.         if (!file_exists($inet6)) {
  1233.             $proftpd_config = '/etc/xinetd.d/ftp_psa';
  1234.             if (!is_file($proftpd_config) || !is_readable($proftpd_config))
  1235.                 return null;
  1236.            
  1237.             $config_content = Util::readfileToArray($proftpd_config);
  1238.             if ($config_content) {
  1239.                 for ($i=0; $i<=count($config_content)-1; $i++) {
  1240.                     if (preg_match('/flags.+IPv6$/', $config_content[$i], $match)) {
  1241.                         Log::warning('The proftpd FTP service will fail to start in case the support for IPv6 is disabled on the server. Please check http://kb.parallels.com/en/113504 for details.');
  1242.                         Log::resultWarning();
  1243.                         return;
  1244.                     }
  1245.                 }
  1246.             }
  1247.         }
  1248.         Log::resultOk();
  1249.     }
  1250.    
  1251.     //:INFO: #72945 Checking for IP address references in Plesk database http://kb.parallels.com/en/113475
  1252.     function _checkIpAddressReferenceForForwardingDomains()
  1253.     {
  1254.         Log::step("Checking associations between domains and IP addresses...", true);
  1255.         $mysql = PleskDb::getInstance();
  1256.         if (PleskVersion::is10_2_or_above()) {
  1257.             $sql = "SELECT * FROM IpAddressesCollections WHERE ipAddressId = 0";
  1258.         } else {
  1259.             $sql = "SELECT * FROM forwarding WHERE ip_address_id = 0";
  1260.         }
  1261.         $domains = $mysql->fetchAll($sql);
  1262.  
  1263.         if (!empty($domains)) {
  1264.             Log::warning('There is a number of domains which are not associated with any IP address. This may be caused by an error in the IP address database. Please check http://kb.parallels.com/en/113475 for details.');
  1265.             Log::resultWarning();
  1266.             return;
  1267.         }
  1268.         Log::resultOk();
  1269.     }
  1270.    
  1271.     //:INFO: #101168 If DUMP_TMP_D in /etc/psa/psa.conf contains extra space character at the end of string backup procedure will fails permanently http://kb.parallels.com/113474
  1272.     function _checkDumpTmpDvalue()
  1273.     {
  1274.         Log::step("Checking the /etc/psa/psa.conf file for consistency...", true);
  1275.  
  1276.         $file = '/etc/psa/psa.conf';
  1277.         if (!is_file($file) || !is_readable($file))
  1278.             return null;
  1279.         $lines = file($file);
  1280.         if ($lines === false)
  1281.             return null;
  1282.         foreach ($lines as $line) {
  1283.             if (preg_match('/^DUMP_TMP_D\s.+\w $/', $line, $match_setting)) {
  1284.                 Log::warning('The DUMP_TMP_D variable in /etc/psa/psa.conf contains odd characters. This can cause backup tasks to fail on this server. Please check http://kb.parallels.com/113474 for details.');
  1285.                 Log::resultWarning();
  1286.                 return;
  1287.             }
  1288.         }
  1289.         Log::resultOk();
  1290.     }
  1291.    
  1292.     //:INFO: Wrong order of loading Zend extensions ionCube declaraion in php.ini can cause to Apache fail http://kb.parallels.com/en/1520
  1293.     function _checkZendExtensionsLoadingOrder()
  1294.     {
  1295.         Log::step("Checking for the Zend extension declaraion in php.ini...", true);
  1296.        
  1297.         $phpini = Util::getPhpIni();
  1298.         if ($phpini) {
  1299.             foreach ($phpini as $line) {
  1300.                 if (preg_match('/^\s*zend_extension(_debug)?(_ts)?\s*=/i', $line, $match)) {
  1301.                     Log::warning('The server-wide php.ini file contains the declaration of the Zend extension. As a result, the Apache server may fail to start after the upgrade. Please check http://kb.parallels.com/en/1520 for more details.');
  1302.                     Log::resultWarning();
  1303.                     return;
  1304.                 }
  1305.             }
  1306.         }
  1307.         Log::resultOk();
  1308.     }
  1309.    
  1310.     //:INFO: JkWorkersFile directive in Apache configuration can lead to failed Apache configs re-generation during and after upgrade procedure http://kb.parallels.com/en/113210
  1311.     function _checkJkWorkersFileDirective()
  1312.     {
  1313.         Log::step("Checking for the JkWorkersFile directive in the Apache configuration...", true);
  1314.  
  1315.         $httpd_include_d = Util::getSettingFromPsaConf('HTTPD_INCLUDE_D') . '/';
  1316.         if (empty($httpd_include_d)) {
  1317.             $warn = 'Unable to open /etc/psa/psa.conf';
  1318.             Log::warning($warn);
  1319.             Log::resultWarning();
  1320.             return;
  1321.         }
  1322.        
  1323.         $handle = @opendir($httpd_include_d);
  1324.         if (!$handle) {
  1325.             $warn = 'Unable to open dir ' . $httpd_include_d;
  1326.             Log::warning($warn);
  1327.             Log::resultWarning();
  1328.             return;
  1329.             }
  1330.        
  1331.         $configs = array();
  1332.         while ( false !== ($file = readdir($handle)) ) {
  1333.             if (preg_match('/^\./', $file) || preg_match('/zz0.+/i', $file) || is_dir($httpd_include_d . $file))
  1334.             continue;
  1335.             $configs[] = $file;
  1336.         }
  1337.        
  1338.         closedir($handle);
  1339.         $warning = false;
  1340.  
  1341.         foreach ($configs as $config) {
  1342.             $config_content = Util::readfileToArray($httpd_include_d . '/' . $config);
  1343.             if ($config_content) {
  1344.                 for ($i=0; $i<=count($config_content)-1; $i++) {
  1345.                     if (preg_match('/^JkWorkersFile.+/', $config_content[$i], $match)) {
  1346.                         Log::warning('The Apache configuration file "' . $httpd_include_d . $config . '" contains the "' . $match[0] . '" directive.' );
  1347.                         $warning = true;
  1348.                     }
  1349.                 }
  1350.             }
  1351.         }
  1352.    
  1353.         if ($warning) {
  1354.             Log::warning('The JkWorkersFile directive may cause problems during the Apache reconfiguration after the upgrade. Please check http://kb.parallels.com/en/113210 for more details.');
  1355.             Log::resultWarning();
  1356.             return;
  1357.         }
  1358.         Log::resultOk();
  1359.     }
  1360.    
  1361.    
  1362.    
  1363.     //:INFO: Wrong GUI behavior if forwarding URL hasn't "http://" after upgrade to Plesk version above 10.4.4 http://kb.parallels.com/en/113359
  1364.     function _checkForwardingURL()
  1365.     {
  1366.         Log::step("Checking domain URLs...", true);
  1367.        
  1368.         $mysql = PleskDb::getInstance();
  1369.         $sql = "SELECT htype, redirect FROM domains, forwarding WHERE domains.id=forwarding.dom_id AND forwarding.redirect NOT LIKE 'https://%' AND forwarding.redirect NOT LIKE 'http://%'";
  1370.         $domains_with_wrong_url = $mysql->fetchAll($sql);
  1371.          
  1372.         if (count($domains_with_wrong_url)>0) {
  1373.             Log::warning('There are domains registered in Panel which URL does not have the http:// prefix. Such domains will not be shown on the Domains page. Check http://kb.parallels.com/en/113359 for more details.');
  1374.             Log::resultWarning();
  1375.             return;
  1376.         }
  1377.         Log::resultOk();
  1378.     }
  1379.    
  1380.     //:INFO: Customized DNS records with host equal host of existing subdomain will lost after upgrade to Plesk version above 10.4.4
  1381.     function _checkCustomDNSrecordsEqualToExistedSubdomains()
  1382.     {
  1383.         Log::step("Checking DNS records of subdomains...", true);
  1384.          
  1385.         $mysql = PleskDb::getInstance();
  1386.        
  1387.         if (PleskVersion::is10_2_or_above()) {
  1388.             $sql = "SELECT DISTINCT dns_recs.dns_zone_id, dns_recs.type, host, val, opt FROM dns_recs, subdomains, domains WHERE host = concat(subdomains.name,'.', domains.name,'.') AND dns_recs.dns_zone_id IN ( SELECT dns_recs.dns_zone_id FROM dns_recs, subdomains, domains, hosting, IP_Addresses, DomainServices, IpAddressesCollections WHERE host = concat(subdomains.name,'.', domains.name,'.') AND subdomains.dom_id = domains.id AND domains.id = DomainServices.dom_id AND DomainServices.type = 'web' AND DomainServices.ipCollectionId = IpAddressesCollections.ipCollectionId AND IpAddressesCollections.ipAddressId = IP_Addresses.id AND IP_Addresses.ip_address <> dns_recs.val)";
  1389.         } else {
  1390.             $sql = "SELECT DISTINCT dns_recs.dns_zone_id, dns_recs.type, host, val, opt FROM dns_recs, subdomains, domains WHERE host = concat(subdomains.name,'.', domains.name,'.') AND dns_recs.dns_zone_id IN ( SELECT dns_recs.dns_zone_id FROM dns_recs, subdomains, domains, hosting, IP_Addresses WHERE host = concat(subdomains.name,'.', domains.name,'.') AND subdomains.dom_id = domains.id AND domains.id = hosting.dom_id AND hosting.ip_address_id = IP_Addresses.id AND IP_Addresses.ip_address <> dns_recs.val)";
  1391.         }
  1392.        
  1393.         if (Util::isWindows()) {
  1394.             $dbprovider = Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME');
  1395.             if ($dbprovider <> 'MySQL') {
  1396.                 $sql = "SELECT DISTINCT dns_recs.dns_zone_id, dns_recs.type, host, val, opt FROM dns_recs, subdomains, domains WHERE host = (subdomains.name + '.' + domains.name + '.') AND dns_recs.dns_zone_id IN ( SELECT dns_recs.dns_zone_id FROM dns_recs, subdomains, domains, hosting, IP_Addresses WHERE host = (subdomains.name + '.' + domains.name + '.') AND subdomains.dom_id = domains.id AND domains.id = hosting.dom_id AND hosting.ip_address_id = IP_Addresses.id AND IP_Addresses.ip_address <> dns_recs.val)";
  1397.             }
  1398.         }
  1399.         $problem_dns_records = $mysql->fetchAll($sql);
  1400.  
  1401.         if (count($problem_dns_records)>0) {
  1402.             Log::warning('There is a number of DNS records for the subdomains that you manually added to domain DNS zones. If you upgrade to Panel 10.4.4, these records will be lost. Check http://kb.parallels.com/en/113310 for more details.');
  1403.             Log::resultWarning();
  1404.             return;
  1405.         }
  1406.         Log::resultOk();
  1407.     }
  1408.    
  1409.     //:INFO: Check windows authentication for PleskControlPanel web site http://kb.parallels.com/en/113253
  1410.     function _checkWindowsAuthForPleskControlPanel()
  1411.     {
  1412.         Log::step('Checking the authentication settings of the PleskControlPanel website in IIS...', true);
  1413.        
  1414.         $PleskControlPanel = 'PleskControlPanel';
  1415.         $cmd = 'wmic.exe /namespace:\\\\root\\MicrosoftIISv2 path IIsWebServerSetting where "ServerComment = \'' . $PleskControlPanel . '\'" get name /VALUE';
  1416.         $output = Util::exec($cmd, $code);
  1417.         if (preg_match_all('/Name=(.+)/', $output, $siteName)) {
  1418.             $cmd = 'wmic.exe /namespace:\\\\root\\MicrosoftIISv2 path IIsWebVirtualDirSetting where "Name = \'' . $siteName[1][0] . '/ROOT\'" get AuthNTLM /VALUE';
  1419.             $output = Util::exec($cmd, $code);
  1420.             if (preg_match_all('/AuthNTLM=FALSE/', $output, $matches)) {
  1421.                 Log::warning('Windows authentication for the PleskControlPanel website in IIS is disabled. Check http://kb.parallels.com/en/113253 for more details.');
  1422.                 Log::resultWarning();
  1423.                 return;
  1424.             }
  1425.            
  1426.         }
  1427.         Log::resultOk();
  1428.     }
  1429.    
  1430.     //:INFO: Notification about after upgrade all subdomains will have own DNS zone http://kb.parallels.com/en/112966
  1431.     function _notificationSubDomainsHaveOwnDNSZoneSince104()
  1432.     {
  1433.         Log::step('Checking for subdomains...', true);
  1434.         $mysql = PleskDb::getInstance();
  1435.         $sql = "select val from misc where param='subdomain_own_zones'";
  1436.         $subdomain_own_zones = $mysql->fetchOne($sql);
  1437.  
  1438.         if ($subdomain_own_zones == "true") {
  1439.             Log::warning('Since Panel 10.4, all subdomains have their own DNS zone. Check http://kb.parallels.com/en/112966 for more details.');
  1440.             Log::resultWarning();
  1441.             return;
  1442.         }
  1443.         Log::resultOk();
  1444.     }
  1445.    
  1446.     //:INFO: Customized CNAME records in server's DNS template could lead to misconfiguration of BIND http://kb.parallels.com/en/113118
  1447.     function _checkCustomizedCnameRecordsInDnsTemplate()
  1448.     {
  1449.         Log::step("Checking for CNAME records added to the initial Panel DNS template...", true);
  1450.        
  1451.         $mysql = PleskDb::getInstance();
  1452.         $sql = "select * from dns_recs_t where type='CNAME' and host in ('<domain>.','ns.<domain>.','mail.<domain>.','ipv4.<domain>.','ipv6.<domain>.','webmail.<domain>.')";
  1453.         $records = $mysql->fetchOne($sql);
  1454.         if (!empty($records)) {
  1455.             Log::warning("There are CNAME records that were added to the initial Panel DNS template. These records may cause incorrect BIND operation after upgrade. Please check http://kb.parallels.com/en/113118 for more details.");
  1456.             Log::resultWarning();
  1457.             return;
  1458.         }
  1459.         Log::resultOk();
  1460.     }
  1461.    
  1462.     //:INFO: Upgrade of Customer & Business Manager failed in case of 127.0.0.1 is restricted for administrative access http://kb.parallels.com/en/113096
  1463.     function _checkPanelAccessForLocalhost()
  1464.     {
  1465.         Log::step('Checking for restriction policy...', true);
  1466.  
  1467.         $mysql = PleskDb::getInstance();
  1468.         $sql = "select val from cl_param where param='ppb-url'";
  1469.         $url = $mysql->fetchOne($sql);
  1470.         if (!empty($url)) {
  1471.             $sql = "select val from misc where param='access_policy'";
  1472.             $policy = $mysql->fetchOne($sql);
  1473.             $sql = "select netaddr from misc m,cp_access c where m.param='access_policy' and m.val='allow' and c.netaddr='127.0.0.1' and c.type='allow';";
  1474.             $allow = $mysql->fetchOne($sql);
  1475.             $sql = "select netaddr from misc m,cp_access c where m.param='access_policy' and m.val='deny' and c.netaddr='127.0.0.1' and c.type='deny';";
  1476.             $deny = $mysql->fetchOne($sql);
  1477.            
  1478.             if (!empty($allow)
  1479.                 || (empty($deny) && $policy == 'deny')) {
  1480.                 Log::warning('The IP address 127.0.0.1 is restricted for administrative access. Upgrade of the Customer & Business Manager component will be impossible. Please check http://kb.parallels.com/en/113096 for more details.');
  1481.                 Log::resultWarning();
  1482.                 return;
  1483.             }
  1484.         }
  1485.         Log::resultOk();
  1486.     }
  1487.    
  1488.     //:INFO: Checking that limits are not exceeded in /proc/user_beancounters
  1489.     function _checkUserBeancounters()
  1490.     {
  1491.         Log::step("Checking that limits are not exceeded in /proc/user_beancounters ...", true);
  1492.         $warning = false;
  1493.         $user_beancounters = Util::readfileToArray('/proc/user_beancounters');
  1494.         if ($user_beancounters) {
  1495.             for ($i=2; $i<=count($user_beancounters)-1; $i++) {
  1496.                 if (preg_match('/\d{1,}$/', $user_beancounters[$i], $match)
  1497.                 && $match[0]>0) {
  1498.                     if (preg_match('/^.+?:?.+?\b(\w+)\b/', $user_beancounters[$i], $limit_name)) {
  1499.                         Log::warning('Virtuozzo Container limit "' . trim($limit_name[1]) . '" was exceeded ' . $match[0] . ' times.');
  1500.                     }
  1501.                     $warning = true;
  1502.                 }
  1503.             }
  1504.         }
  1505.    
  1506.         if ($warning) {
  1507.             Log::warning('Limits set by Parallels Virtuozzo Container are exceeded. Please, check http://kb.parallels.com/en/112522 for more details.');
  1508.             Log::resultWarning();
  1509.             return;
  1510.         }
  1511.        
  1512.         Log::resultOk();
  1513.     }
  1514.    
  1515.     //:INFO: Checking for available free memory for the upgrade procedure http://kb.parallels.com/en/112522
  1516.     function _checkFreeMemory()
  1517.     {
  1518.         Log::step('Checking for available free memory for the upgrade procedure ...', true);
  1519.        
  1520.         $freeMem = Util::GetFreeSystemMemory();
  1521.         if (!empty($freeMem)
  1522.             && $freeMem < 200000) {
  1523.             Log::warning('Not enough memory to perform the upgrade: You should have at least 200 megabytes free. The current amount of free memory is: ' . $freeMem . ' Kb');
  1524.             Log::resultWarning();
  1525.         }
  1526.         Log::resultOk();
  1527.     }
  1528.    
  1529.     //:INFO: Check for Customer and Business Manager property in license key  http://kb.parallels.com/en/111143
  1530.     function _checkCBMlicense()
  1531.     {
  1532.         Log::step('Checking if the license key includes support for Customer and Business Manager ...', true);
  1533.        
  1534.         $mysql = PleskDb::getInstance();
  1535.         $sql = "select val from cl_param where param='ppb-url'";
  1536.         $url = $mysql->fetchOne($sql);
  1537.         $warning = false;
  1538.         if (!empty($url)) {
  1539.             if (Util::isLinux()) {
  1540.                 $license_folder = '/etc/sw/keys/keys/';
  1541.             } else {
  1542.                 $license_folder = Util::getPleskRootPath() . 'admin\\repository\\keys\\';
  1543.             }
  1544.             $license_files = scandir($license_folder);
  1545.             for ($i = 2; $i <= count($license_files) - 1; $i++) {
  1546.                 $file = file_get_contents($license_folder . $license_files[$i]);
  1547.  
  1548.                 if (preg_match('/modernbill.+\>(.+)\<.+modernbill/', $file, $accounts)) {
  1549.                     if ($accounts[1] > 0) {
  1550.                         Log::resultOk();
  1551.                         return;
  1552.                     }
  1553.                 }
  1554.             }
  1555.            
  1556.             Log::warning('If you had not purchased the Customer and Business Manager License you can not use it after the upgrade. Check the article http://kb.parallels.com/en/111143 for more details.');
  1557.             Log::resultWarning();
  1558.         }
  1559.        
  1560.  
  1561.     }
  1562.    
  1563.     //:INFO: Check the availability of Plesk Panel TCP ports
  1564.     function _checkPleskTCPPorts()
  1565.     {
  1566.         Log::step('Checking the availability of Plesk Panel TCP ports...', true);
  1567.         $plesk_ports = array('8880' => 'Plesk Panel non-secure HTTP port', '8443' => 'Plesk Panel secure HTTPS port');
  1568.          
  1569.          
  1570.         $mysql = PleskDb::getInstance();
  1571.         $sql = "select ip_address from IP_Addresses";
  1572.         $ip_addresses = $mysql->fetchAll($sql);
  1573.         $warning = false;
  1574.         if (count($ip_addresses)>0) {
  1575.             if (Util::isLinux()) {
  1576.                 $ipv4 = Util::getIPv4ListOnLinux();
  1577.                 $ipv6 = Util::getIPv6ListOnLinux();
  1578.                 if ($ipv6) {
  1579.                     $ipsInSystem = array_merge($ipv4, $ipv6);
  1580.                 } else {
  1581.                     $ipsInSystems = $ipv4;
  1582.                 }
  1583.             } else {
  1584.                 $ipsInSystem = Util::getIPListOnWindows();
  1585.             }
  1586.             foreach ($ip_addresses as $ip) {
  1587.                 foreach ($plesk_ports as $port => $description) {
  1588.                     if (PleskValidator::validateIPv4($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) {
  1589.                         $fp = @fsockopen($ip['ip_address'], $port, $errno, $errstr, 1);
  1590.                     } elseif (PleskValidator::validateIPv6($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) {
  1591.                         $fp = @fsockopen('[' . $ip['ip_address'] . ']', $port, $errno, $errstr, 1);
  1592.                     } else {
  1593.                         Log::warning('IP address registered in Plesk is invalid or broken: ' . $ip['ip_address']);
  1594.                         Log::resultWarning();
  1595.                         return;
  1596.                     }
  1597.                     if (!$fp) {
  1598.                         // $errno 110 means "timed out", 111 means "refused"
  1599.                         Log::info('Unable to connect to IP address ' . $ip['ip_address'] . ' on ' . $description . ' ' . $port . ': ' . $errstr);
  1600.                         $warning = true;
  1601.                     }
  1602.                 }
  1603.             }
  1604.         }
  1605.         if ($warning) {
  1606.             Log::warning('Unable to connect to some Plesk ports. See ' . APP_PATH . '/plesk10_preupgrade_checker.log for details. Find the full list of the required open ports at http://kb.parallels.com/en/391 ');
  1607.             Log::resultWarning();
  1608.             return;
  1609.         }
  1610.         Log::resultOk();
  1611.     }
  1612.    
  1613.     function _getPAMServiceIncludes($serviceFile)
  1614.     {
  1615.         // Get array of PAM services that are included from a given PAM configuration file.
  1616.         $lines = file($serviceFile);
  1617.         $includes = array();
  1618.    
  1619.         foreach ($lines as $line) {
  1620.             // Note: we do not support here line continuations and syntax variants for old unsupported systems.
  1621.             $line = trim( preg_replace('/#.*$/', '', $line) );
  1622.             if (empty($line))
  1623.                 continue;
  1624.    
  1625.             // See PAM installation script source for info on possible syntax variants.
  1626.             $tokens = preg_split('/\s+/', $line);
  1627.             $ref = null;
  1628.             if ($tokens[0] == '@include') {
  1629.                 $ref = $tokens[1];
  1630.             } elseif ($tokens[1] == 'include' || $tokens[1] == 'substack') {
  1631.                 $ref = $tokens[2];
  1632.             }
  1633.    
  1634.             if (!empty($ref)) {
  1635.                 $includes[] = $ref;
  1636.             }
  1637.         }
  1638.    
  1639.         return $includes;
  1640.     }
  1641.    
  1642.     //:INFO: Check that non-existent PAM services are not referenced by other services, i.e. that PAM configuration array is consistent http://kb.parallels.com/en/112944
  1643.     function _checkPAMConfigsInclusionConsistency()
  1644.     {
  1645.         Log::step('Checking PAM configuration array consistency...', true);
  1646.    
  1647.         $pamDir = "/etc/pam.d/";
  1648.         $handle = @opendir($pamDir);
  1649.         if (!$handle) {
  1650.             $warn = 'Unable to open the PAM configuration directory "' . $pamDir . '". Check http://kb.parallels.com/en/112944 for more details.';
  1651.             Log::warning($warn);
  1652.             Log::resultWarning();
  1653.             return;
  1654.         }
  1655.    
  1656.         $services = array();
  1657.         while ( false !== ($file = readdir($handle)) ) {
  1658.             if (preg_match('/^\./', $file) || preg_match('/readme/i', $file) || is_dir($pamDir . $file))
  1659.                 continue;
  1660.             $services[] = $file;
  1661.         }
  1662.    
  1663.         closedir($handle);
  1664.    
  1665.         $allIncludes = array();
  1666.         foreach ($services as $service) {
  1667.             $includes = $this->_getPamServiceIncludes($pamDir . $service);
  1668.             $allIncludes = array_unique(array_merge($allIncludes, $includes));
  1669.         }
  1670.    
  1671.         $missingIncludes = array_diff($allIncludes, $services);
  1672.    
  1673.         if (!empty($missingIncludes)) {
  1674.             $warn  = 'The PAM configuration is in inconsistent state. ';
  1675.             $warn .= 'If you proceed with the installation, the required PAM modules will not be installed. This will cause problems during the authentication. ';
  1676.             $warn .= 'Some PAM services reference the following nonexistent services: ' . implode(', ', $missingIncludes) . '. ';
  1677.             $warn .= 'Check http://kb.parallels.com/en/112944 for more details.';
  1678.    
  1679.             Log::warning($warn);
  1680.             Log::resultWarning();
  1681.             return;
  1682.         }
  1683.    
  1684.         Log::resultOk();
  1685.     }
  1686.    
  1687.     //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin http://kb.parallels.com/en/112779
  1688.     function _checkMySQLDatabaseUserRoot()
  1689.     {
  1690.         Log::step('Checking existence of Plesk user "root" for MySQL database servers ...', true);
  1691.        
  1692.         $psaroot = Util::getSettingFromPsaConf('PRODUCT_ROOT_D');
  1693.         $phpMyAdminConfFile = $psaroot . '/admin/htdocs/domains/databases/phpMyAdmin/libraries/config.default.php';
  1694.         if (file_exists($phpMyAdminConfFile)) {
  1695.             $phpMyAdminConfFileContent = file_get_contents($phpMyAdminConfFile);
  1696.             if (!preg_match("/\[\'AllowRoot\'\]\s*=\s*true\s*\;/", $phpMyAdminConfFileContent)) {
  1697.                 $mysql = PleskDb::getInstance();
  1698.                 $sql = "select login, data_bases.name as db_name, displayName as domain_name from db_users, data_bases, domains where db_users.db_id = data_bases.id and data_bases.dom_id = domains.id and data_bases.type = 'mysql' and login = 'root'";
  1699.                 $dbusers = $mysql->fetchAll($sql);
  1700.                
  1701.                 foreach ($dbusers as $user) {
  1702.                     Log::warning('The database user "' . $user['login'] . '"  (database "' . $user['db_name'] . '" at "' . $user['domain_name'] . '") has no access to phpMyAdmin. Please check http://kb.parallels.com/en/112779 for more details.');
  1703.                     Log::resultWarning();
  1704.                     return;
  1705.                 }
  1706.             }
  1707.         }
  1708.  
  1709.         Log::resultOk();
  1710.     }
  1711.    
  1712.     //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, http://kb.parallels.com/en/111194
  1713.     function _checkCDONTSmailrootFolder()
  1714.     {
  1715.         Log::step('Checking for CDONTS mailroot folder ...', true);
  1716.         $mailroot = Util::getSystemDisk() . 'inetpub\mailroot\pickup';
  1717.    
  1718.         if (is_dir($mailroot)) {
  1719.             Log::warning('After upgrade you have to add write pemissions to psacln group on folder ' . $mailroot . '. Please, check http://kb.parallels.com/en/111194 for more details.');
  1720.             Log::resultWarning();
  1721.             return;
  1722.         }
  1723.         Log::resultOk();
  1724.     }
  1725.    
  1726.     //:INFO: Checking for conflicting of SSO start-up scripts http://kb.parallels.com/en/112666
  1727.     function _checkSsoStartScriptsPriority()
  1728.     {
  1729.         Log::step('Checking for SSO start-up script priority ...', true);
  1730.         $sso_script = '/etc/sw-cp-server/applications.d/00-sso-cpserver.conf';
  1731.         $sso_folder = '/etc/sso';
  1732.    
  1733.         if (!file_exists($sso_script)
  1734.         && is_dir($sso_folder)) {
  1735.             Log::warning('SSO start-up script has wrong execution priority. Please, check http://kb.parallels.com/en/112666 for more details.');
  1736.             Log::resultWarning();
  1737.             return;
  1738.         }
  1739.         Log::resultOk();
  1740.     }
  1741.    
  1742.     //:INFO: Check iisfcgi.dll file version http://kb.parallels.com/en/112606
  1743.     function _checkIisFcgiDllVersion()
  1744.     {
  1745.         Log::step("Checking the iisfcgi.dll file version ...", true);
  1746.         $windir = Util::getSystemRoot();
  1747.         $iisfcgi = $windir . '\system32\inetsrv\iisfcgi.dll';
  1748.         if (file_exists($iisfcgi)) {
  1749.             $version = Util::getFileVersion($iisfcgi);
  1750.             if (version_compare($version, '7.5.0', '>')
  1751.                 && version_compare($version, '7.5.7600.16632', '<')) {
  1752.                 Log::warning('File iisfcgi.dll version ' . $version . ' is outdated. Please, check article http://kb.parallels.com/en/112606 for details');
  1753.                 return;
  1754.             }
  1755.         }
  1756.         Log::resultOk();
  1757.     }
  1758.    
  1759.     //:INFO: Notification about how to change password for the mail account after upgrade http://kb.parallels.com/en/9454
  1760.     function _notificationChangePasswordForEmailAccount()
  1761.     {
  1762.         Log::step("Checking for mailnames with access to Panel ...", true);
  1763.        
  1764.         $mysql = PleskDb::getInstance();
  1765.         $sql = "select count(mail_name) as num from mail m, Permissions p where p.value='true' and p.id=m.perm_id and p.permission='cp_access'";
  1766.         $mailnames = $mysql->fetchOne($sql);
  1767.         if ($mailnames > 0) {
  1768.             $warn = 'You have ' . $mailnames . ' mailbox users that will be converted to subscription-level auxiliary users after upgrading to Panel 10. Learn how to change passwords for such users in http://kb.parallels.com/en/9454';
  1769.             Log::warning($warn);
  1770.             return;
  1771.         }
  1772.         Log::resultOk();
  1773.     }
  1774.  
  1775.     //:INFO: Users with same e-mails as e-mail accounts will have problems with changing personal contact information http://kb.parallels.com/en/112032
  1776.     function _checkUserHasSameEmailAsEmailAccount()
  1777.     {
  1778.         Log::step("Checking for users with same e-mail address as e-mail account ...", true);
  1779.        
  1780.         $mysql = PleskDb::getInstance();
  1781.         $sql = "select login, email from clients where email in (select concat(m.mail_name, '@', d.displayName) from domains d, mail m, Permissions p where m.perm_id=p.id and (p.permission='cp_access' and value='true'))";
  1782.         if (Util::isWindows()) {
  1783.             $dbprovider = Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME');
  1784.             if ($dbprovider <> 'MySQL') {
  1785.                 $sql = "select login, email from clients where email in (select (m.mail_name + '@' + d.displayName) from domains d, mail m, Permissions p where m.perm_id=p.id and (p.permission='cp_access' and value='true'))";
  1786.             }
  1787.         }
  1788.         if (PleskVersion::is10x()) {
  1789.             $sql = "select count(login) users, email from smb_users where email in (select email from smb_users group by email having count(email)>1) and email != '' group by email";
  1790.         }
  1791.  
  1792.         $problem_clients = $mysql->fetchAll($sql);
  1793.        
  1794.         if (PleskVersion::is8x()
  1795.             || PleskVersion::is9x()) {
  1796.             $sql = "select d.name domain_name, c.email domain_admin_email from domains d, dom_level_usrs dl, Cards c where c.id=dl.card_id and dl.dom_id=d.id and c.email in (select concat(m.mail_name, '@', d.displayName) from domains d, mail m, Permissions p where m.perm_id=p.id and (p.permission='cp_access' and value='true'))";
  1797.             if (Util::isWindows()) {
  1798.                 $dbprovider = Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME');
  1799.                 if ($dbprovider <> 'MySQL') {
  1800.                     $sql = "select d.name as domain_name, c.email as domain_admin_email from domains d, dom_level_usrs dl, Cards c where c.id=dl.card_id and dl.dom_id=d.id and c.email in (select (m.mail_name + '@' + d.displayName) from domains d, mail m, Permissions p where d.id=m.dom_id and m.perm_id=p.id and (p.permission='cp_access' and value='true'))";
  1801.                 }
  1802.             }
  1803.         }
  1804.         $problem_domain_admins = $mysql->fetchAll($sql);
  1805.        
  1806.         if (count($problem_clients)>0
  1807.             || count($problem_domain_admins)>0) {
  1808.             foreach ($problem_clients as $client) {
  1809.                 if (PleskVersion::is10x()) {
  1810.                     $info = 'There are ' . $client['users'] . ' users with the same contact e-mail address ' . $client['email'];
  1811.                 } else {
  1812.                     $info = 'User ' . $client['login'] . ' has contact mail address as e-mail account ' . $client['email'];
  1813.                 }
  1814.                 Log::info($info);
  1815.             }
  1816.             foreach ($problem_domain_admins as $domain_admin) {
  1817.                 $info = 'Domain administrator of domain ' . $domain_admin['domain_name'] . ' has contact mail address as e-mail account ' . $domain_admin['domain_admin_email'];
  1818.                 Log::info($info);
  1819.             }
  1820.             if (PleskVersion::is10x()) {
  1821.                 Log::warning('There are a number of Panel users that have the same contact email. See the ' . APP_PATH . '/plesk10_preupgrade_checker.log for details.  You will not be able to change personal information (including passwords) of these users. Learn more at http://kb.parallels.com/en/112032.');
  1822.             } else {
  1823.                 Log::warning('There are some users found with email matches mailboxes with permission to access Control Panel. See the ' . APP_PATH . '/plesk10_preupgrade_checker.log for details.  If a client\'s or domain administrator\'s e-mail address (in the profile) matches a mailbox in Plesk and the mailbox has the permission to access Control Panel, the upgrade procedure will create two auxiliarily user accounts (with the same e-mail) for such customers and Panel will not allow to change personal information (including passwords) for them. Please, check http://kb.parallels.com/en/112032 for more details.');
  1824.             }
  1825.            
  1826.             Log::resultWarning();
  1827.             return;
  1828.         }
  1829.        
  1830.         Log::resultOk();
  1831.     }
  1832.    
  1833.     //:INFO: Checking for main IP address http://kb.parallels.com/en/112417
  1834.     function _checkMainIP()
  1835.     {
  1836.         Log::step("Checking for main IP address ...", true);
  1837.         $mysql = PleskDb::getInstance();
  1838.         $sql = 'select * from IP_Addresses';
  1839.         $ips = $mysql->fetchAll($sql);
  1840.         $mainexists = false;
  1841.         foreach ($ips as $ip) {
  1842.             if (isset($ip['main'])) {
  1843.                 if ($ip['main'] == 'true') {
  1844.                     $mainexists = true;
  1845.                 }
  1846.             } else {
  1847.                 Log::info('No field "main" in table IP_Addresses.');
  1848.                 Log::resultOk();
  1849.                 return;
  1850.             }
  1851.         }
  1852.          
  1853.         if (!$mainexists) {
  1854.             $warn = 'Unable to find "main" IP address in psa database. Please, check http://kb.parallels.com/en/112417 for more details.';
  1855.             Log::warning($warn);
  1856.             Log::resultWarning();
  1857.             return;
  1858.         }
  1859.         Log::resultOk();
  1860.     }
  1861.    
  1862.     //:INFO: Checking for hostname in Customer & Business Manager relay URL http://kb.parallels.com/en/111500
  1863.     function _checkCBMrelayURL()
  1864.     {
  1865.         Log::step("Checking for hostname in Customer & Business Manager relay URL...", true);
  1866.    
  1867.         $mysql = PleskDb::getInstance();
  1868.         $sql = "select val from cl_param where param='ppb-url'";
  1869.         $url = $mysql->fetchOne($sql);
  1870.         if (preg_match("/\/\/(.*):/i", $url, $result)) {
  1871.             if (!PleskValidator::isValidIp($result[1])) {
  1872.                 $ip = Util::resolveHostname($result[1]);
  1873.                 if (!Util::isFQDN($result[1])
  1874.                 || !PleskValidator::isValidIp($ip)) {
  1875.                     $warn = 'In case you get the 404 error when trying to access Customer & Business Manager, refer to the article http://kb.parallels.com/en/111500 for resoultion details.';
  1876.                     Log::warning($warn);
  1877.                     Log::resultWarning();
  1878.                     return;
  1879.                 }
  1880.             }
  1881.         }
  1882.         Log::resultOk();
  1883.     }
  1884.    
  1885.     //:INFO:#66278,70525 Checking SQL mode of default client's MySQL server http://kb.parallels.com/en/112453
  1886.     function _checkDefaultMySQLServerMode()
  1887.     {
  1888.         Log::step("Checking SQL mode of default client's MySQL server...", true);
  1889.    
  1890.         $credentials = Util::getDefaultClientMySQLServerCredentials();
  1891.         if (!empty($credentials)) {
  1892.             $mysql = new DbClientMysql('localhost', $credentials['admin_login'], $credentials['admin_password'] , 'mysql', 3306);
  1893.             if (!$mysql->hasErrors()) {
  1894.                 $sql = 'SELECT @@sql_mode';
  1895.                 $sqlmode = $mysql->fetchOne($sql);
  1896.                 if (preg_match("/STRICT_/i", $sqlmode, $match)) {
  1897.                     $warn = 'Please, switch off strict mode for MySQL server. Read carefully article http://kb.parallels.com/en/112453 for details.';
  1898.                     Log::warning($warn);
  1899.                     Log::resultWarning();
  1900.                     return;
  1901.                 }
  1902.             }
  1903.         }
  1904.    
  1905.         Log::resultOk();
  1906.     }
  1907.    
  1908.     //:INFO: If user has the same address as the admin it should be changed to another http://kb.parallels.com/en/111985
  1909.     function _checkUserHasSameEmailAsAdmin()
  1910.     {
  1911.         Log::step('Checking for users with the same e-mail address as the administrator...', true);
  1912.         $adminEmail = Plesk10BusinessModel::_getAdminEmail();
  1913.         if (!empty($adminEmail)) {
  1914.             $db = PleskDb::getInstance();
  1915.             if (PleskVersion::is10x_or_above()) {
  1916.                 $sql = "SELECT login, email FROM smb_users WHERE login<>'admin' and email='" . $adminEmail . "'";
  1917.                 $clients = $db->fetchAll($sql);
  1918.             } else {
  1919.                 $sql = "SELECT login, email FROM clients WHERE login<>'admin' and email='" . $adminEmail . "'";
  1920.                 $clients = $db->fetchAll($sql);
  1921.             }
  1922.             if (!empty($clients)) {
  1923.                 foreach ($clients as $client) {
  1924.                     Log::info('The customer with the username ' . $client['login'] . ' has the same e-mail address as the Panel administrator: ' .  $client["email"]);
  1925.                 }
  1926.                 Log::warning('Some customers have e-mail addresses coinciding with the Panel administrator\'s e-mail address. See the ' . APP_PATH . '/plesk10_preupgrade_checker.log and check http://kb.parallels.com/en/111985 for details.');
  1927.                 Log::resultWarning();
  1928.                 return;
  1929.             }
  1930.         }
  1931.         Log::resultOk();
  1932.     }
  1933.    
  1934.     //:INFO: Check that .net framework installed properly http://kb.parallels.com/en/111448
  1935.     function _checkDotNetFrameworkIssue()
  1936.     {
  1937.         Log::step('Checking that .NET framework installed properly...', true);
  1938.         $pleskCpProvider = Util::regPleskQuery('PLESKCP_PROVIDER_NAME', true);
  1939.         if ($pleskCpProvider == 'iis') {
  1940.             $cmd = '"' . Util::regPleskQuery('PRODUCT_ROOT_D', true) . 'admin\bin\websrvmng" --list-wdirs --vhost-name=pleskcontrolpanel';
  1941.             $output = Util::exec($cmd, $code);
  1942.             if (!preg_match("/wdirs/i", trim($output), $matches)) {
  1943.                 Log::warning('There is a problem with .NET framework.  Please, check http://kb.parallels.com/en/111448 for details.');
  1944.                 Log::resultWarning();
  1945.                 return;
  1946.             }
  1947.         }
  1948.         Log::resultOk();
  1949.          
  1950.     }
  1951.    
  1952.     //:INFO: Check for custom php.ini on domains http://kb.parallels.com/en/111697
  1953.     function _checkCustomPhpIniOnDomains()
  1954.     {
  1955.         Log::step('Checking for custom php.ini on domains...', true);
  1956.          
  1957.         $domains = Plesk10BusinessModel::_getDomainsByHostingType('vrt_hst');
  1958.         if (empty($domains)) {
  1959.             Log::resultOk();
  1960.             return;
  1961.         }
  1962.         $vhost = Util::getSettingFromPsaConf('HTTPD_VHOSTS_D');
  1963.         if (empty($vhost)) {
  1964.             $warn = 'Unable to read /etc/psa/psa.conf';
  1965.             Log::warning($warn);
  1966.             Log::resultWarning();
  1967.             return;
  1968.         }
  1969.         $flag = false;
  1970.         foreach ($domains as $domain) {
  1971.             $filename = $vhost . '/' . $domain['name'] . '/conf/php.ini';
  1972.             if (file_exists($filename)) {
  1973.                 $warn = 'Custom php.ini is used for domain ' . $domain['name'] . '.';
  1974.                 Log::warning($warn);
  1975.                 $flag = true;
  1976.             }
  1977.         }
  1978.          
  1979.         if ($flag) {
  1980.             $warn = 'After upgrade, Panel will not apply changes to certain website-level PHP settings due to they are predefined in /var/www/vhosts/DOMAINNAME/conf/php.ini. Please check http://kb.parallels.com/en/111697 for details.';
  1981.             Log::warning($warn);
  1982.             Log::resultWarning();
  1983.             return;
  1984.         }
  1985.          
  1986.         Log::resultOk();
  1987.     }
  1988.    
  1989.     //:INFO: Plesk 10 version does not support Mdaemon mail server http://kb.parallels.com/en/112356
  1990.     function _mDaemonServerWarningOnUpgradeTo10x()
  1991.     {
  1992.         Log::step('Checking for MDaemon mail server...', true);
  1993.    
  1994.         if (Plesk10MailServer::CurrentWinMailServer() == 'mdaemon') {
  1995.             $warn = 'Plesk 10 version does not support MDaemon. Please, check http://kb.parallels.com/en/112356 for more details.';
  1996.             Log::warning($warn);
  1997.             Log::resultWarning();
  1998.    
  1999.             return;
  2000.         }
  2001.         Log::resultOk();
  2002.     }
  2003.    
  2004.     //:INFO: Checking existing table mysql.servers http://kb.parallels.com/en/112290
  2005.     function _checkMysqlServersTable()
  2006.     {
  2007.         Log::step('Checking table "servers" in database "mysql"...', true);
  2008.         $mySQLServerVersion = Util::getMySQLServerVersion();
  2009.         if (version_compare($mySQLServerVersion, '5.1.0', '>=')) {
  2010.             $credentials = Util::getDefaultClientMySQLServerCredentials();
  2011.             $mysql = new DbClientMysql('localhost', $credentials['admin_login'], $credentials['admin_password'] , 'information_schema', 3306);
  2012.             if (!$mysql->hasErrors()) {
  2013.                 $sql = 'SELECT * FROM information_schema.TABLES  WHERE TABLE_SCHEMA="mysql" and TABLE_NAME="servers"';
  2014.                 $servers = $mysql->fetchAll($sql);
  2015.                 if (empty($servers)) {
  2016.                     $warn = 'Table "servers" in database "mysql" does not exists. Please, check  http://kb.parallels.com/en/112290 for more details.';
  2017.                     Log::warning($warn);
  2018.                     Log::resultWarning();
  2019.                     return;
  2020.                 }
  2021.             }
  2022.         }
  2023.         Log::resultOk();
  2024.     }
  2025.    
  2026.     //:INFO: Plesk 10.x version does not support SimpleDNS http://kb.parallels.com/en/112280
  2027.     function _unsupportedDNSServersWarningOnUpgradeTo10x()
  2028.     {
  2029.         Log::step('Detecting current DNS server...', true);
  2030.         $dnsServer = PleskComponent::CurrentWinDNSServer();
  2031.         if ($dnsServer == 'simpledns') {
  2032.             $warn = 'Since Parallels Plesk Panel version 10 Simple DNS server is no longer supported. Please, check http://kb.parallels.com/en/112280 for more details.';
  2033.             Log::warning($warn);
  2034.             Log::resultWarning();
  2035.    
  2036.             return;
  2037.         }
  2038.         Log::resultOk();
  2039.     }
  2040.    
  2041.     //:INFO: Check that there is symbolic link /usr/local/psa on /opt/psa on Debian-like Oses http://kb.parallels.com/en/112214
  2042.     function _checkSymLinkToOptPsa()
  2043.     {
  2044.         Log::step('Checking symbolic link /usr/local/psa on /opt/psa...', true);
  2045.  
  2046.         $link = @realpath('/usr/local/psa/version');
  2047.         if (!preg_match('/\/opt\/psa\/version/', $link, $macthes)) {
  2048.             $warn = "The symbolic link /usr/local/psa does not exists or has wrong destination. Read article http://kb.parallels.com/en/112214 to fix the issue.";
  2049.             Log::warning($warn);
  2050.             Log::resultWarning();
  2051.             return;
  2052.         }
  2053.         Log::resultOk();
  2054.     }
  2055.    
  2056.     //:INFO: Checking for old version of autoinstaller http://kb.parallels.com/en/112166
  2057.     function _checkAutoinstallerVersion()
  2058.     {
  2059.         Log::step('Checking autoinstaller version...', true);
  2060.    
  2061.         if (getenv('AUTOINSTALLER_VERSION')) {
  2062.             Log::resultOk();
  2063.             return;
  2064.         }
  2065.        
  2066.         if (Util::isWindows()) {
  2067.             if  (PleskVersion::is9x()
  2068.             || PleskVersion::is8x()
  2069.             ) {
  2070.                 Log::resultOk();
  2071.                 return;
  2072.             }
  2073.         }
  2074.    
  2075.         $installed_ai_version = Util::getAutoinstallerVersion();
  2076.         if (version_compare($installed_ai_version, AI_VERSION, '<')) {
  2077.             $warn = 'Your autoinstaller version '. $installed_ai_version .' is outdated. Please refer to article http://kb.parallels.com/en/112166 on how to obtain latest version of autoinstaller.';
  2078.             Log::warning($warn);
  2079.             return;
  2080.         }
  2081.         Log::resultOk();
  2082.     }
  2083.    
  2084.     //:INFO: Checking possibility to connect to client's MySQL server
  2085.     function _checkConnectToClientMySQL()
  2086.     {
  2087.         Log::step('Checking connection to client MySQL server...', true);
  2088.  
  2089.         $credentials = Util::getDefaultClientMySQLServerCredentials();
  2090.  
  2091.         if ($credentials == NULL) {
  2092.             $installedMySQLserver55 = Util::regQuery('\MySQL AB\MySQL Server 5.5', '/v version', true);
  2093.             $installedMySQLserver51 = Util::regQuery('\MySQL AB\MySQL Server 5.1', '/v version', true);
  2094.             $installedMySQLserver50 = Util::regQuery('\MySQL AB\MySQL Server 5.0', '/v version', true);
  2095.            
  2096.             if ($installedMySQLserver55
  2097.                 || $installedMySQLserver51
  2098.                 || $installedMySQLserver50
  2099.             ) {
  2100.                 $warn = 'Default MySQL server is not registered in Parallels Plesk Panel. If you use custom MySQL instances you should register one at least according to article http://kb.parallels.com/en/111983.';
  2101.                 Log::warning($warn);
  2102.                 Log::resultWarning();
  2103.                 return;                
  2104.             }
  2105.         }
  2106.  
  2107.         $mysql = new DbClientMysql('localhost', $credentials['admin_login'], $credentials['admin_password'] , 'mysql', 3306);
  2108.         if ($mysql->hasErrors()) {
  2109.             $warn = 'Unable to connect to local default MySQL server. Read carefully article http://kb.parallels.com/en/111983 for details.';
  2110.             Log::warning($warn);
  2111.             Log::resultWarning();
  2112.             return;
  2113.         }
  2114.         Log::info('Connected sucessfully', true);
  2115.         $result = $mysql->query('CREATE DATABASE IF NOT EXISTS pre_upgrade_checker_test_db');
  2116.        
  2117.         if (!$result) {
  2118.             $warn = 'User has not enough privileges. Read article http://kb.parallels.com/en/111983 for details.';
  2119.             Log::warning($warn);
  2120.             Log::resultWarning();              
  2121.             return;
  2122.         }  
  2123.         $result = $mysql->query('DROP DATABASE IF EXISTS pre_upgrade_checker_test_db');
  2124.          
  2125.         if (!$result) {
  2126.             $warn = 'User has not enough privileges. Read article http://kb.parallels.com/en/111983 for details.';
  2127.             Log::warning($warn);
  2128.             Log::resultWarning();
  2129.             return;
  2130.         }
  2131.         Log::resultOk();
  2132.        
  2133.     }
  2134.    
  2135.     //:INFO: Checking for unknown ISAPI filters and show warning http://kb.parallels.com/en/111908
  2136.     function _unknownISAPIfilters()
  2137.     {
  2138.         Log::step('Detecting installed ISAPI filters...', true);
  2139.         if (Util::isUnknownISAPIfilters()) {
  2140.             $warn = 'Please read carefully article http://kb.parallels.com/en/111908, for avoiding possible problems caused by unknown ISAPI filters.';
  2141.             Log::warning($warn);
  2142.             Log::resultWarning();
  2143.    
  2144.             return;
  2145.         }
  2146.         Log::resultOk();
  2147.     }
  2148.    
  2149.     //:INFO: Warning about possible issues related to Microsoft Visual C++ Redistributable Packages ?http://kb.parallels.com/en/111891
  2150.     function _checkMSVCR()
  2151.     {
  2152.         Log::step('Microsoft Visual C++ Redistributable Packages', true);
  2153.         $warn = 'Please read carefully article http://kb.parallels.com/en/111891, for avoiding possible problems caused by Microsoft Visual C++ Redistributable Packages.';
  2154.         Log::info($warn);
  2155.  
  2156.         return;
  2157.     }    
  2158.    
  2159.     //:INFO: Plesk 10.x version does not support Gene6 and Serv-U http://kb.parallels.com/en/111816, http://kb.parallels.com/en/111894
  2160.     function _unsupportedFtpServersWarningOnUpgradeTo10x()
  2161.     {
  2162.         Log::step('Detecting current FTP server...', true);
  2163.         $ftpserver = PleskComponent::CurrentWinFtpServer();
  2164.         if ( $ftpserver == 'gene6'
  2165.             || $ftpserver == 'servu'
  2166.         ) {
  2167.             $warn = 'Since Parallels Plesk Panel version 10 Gene6 and Serv-U FTP servers are no longer supported. Please, check http://kb.parallels.com/en/111816 and http://kb.parallels.com/en/111894 for more details.';
  2168.             Log::warning($warn);
  2169.             Log::resultWarning();
  2170.    
  2171.             return;
  2172.         }
  2173.         Log::resultOk();
  2174.     }    
  2175.    
  2176.     //:INFO: Plesk 10 version does not support hMailserver http://kb.parallels.com/en/9609
  2177.     function _hMailServerWarningOnUpgradeTo10x()
  2178.     {
  2179.         Log::step('Detecting current mail server...', true);
  2180.        
  2181.         if (Plesk10MailServer::CurrentWinMailServer() == 'hmailserver') {
  2182.             $warn = 'Plesk 10 version does not support hMailserver. Please, check http://kb.parallels.com/en/9609 for more details.';
  2183.             Log::warning($warn);
  2184.             Log::resultWarning();
  2185.            
  2186.             return;
  2187.         }
  2188.         Log::resultOk();
  2189.     }
  2190.    
  2191.     function _diagnoseKavOnPlesk10x()
  2192.     {
  2193.         Log::step('Detecting if antivirus is Kaspersky...', true);
  2194.        
  2195.         $pleskComponent = new PleskComponent();
  2196.         $isKavInstalled = $pleskComponent->isInstalledKav();
  2197.        
  2198.         Log::info('Kaspersky antivirus: ' . ($isKavInstalled ? ' installed' : ' not installed'));
  2199.        
  2200.         if (Util::isVz() && $isKavInstalled) {
  2201.             $warn = 'An old version of Kasperskiy antivirus is detected. ';
  2202.             $warn .= 'If you are upgrading to the Panel 10 using EZ templates, update the template of Kaspersky antivirus on hardware node to the latest version, and then upgrade the container.';
  2203.             Log::warning($warn);
  2204.             Log::resultWarning();
  2205.            
  2206.             return;
  2207.         }
  2208.         Log::resultOk();
  2209.     }
  2210.    
  2211.     function _diagnoseDependCycleOfModules()
  2212.     {
  2213.         //:INFO: Prevent potential problem with E: Couldn't configure pre-depend plesk-core for psa-firewall, probably a dependency cycle.
  2214.         Log::step('Detecting if Plesk modules are installed...', true);
  2215.        
  2216.         if (Util::isVz()
  2217.             && PleskModule::isInstalledWatchdog()
  2218.             && PleskModule::isInstalledVpn()
  2219.             && PleskModule::isInstalledFileServer()
  2220.             && PleskModule::isInstalledFirewall()
  2221.         ) {
  2222.             $warn = 'Plesk modules "watchdog, fileserver, firewall, vpn" were installed on container. ';
  2223.             $warn .= 'If you are upgrading to the Panel 10 using EZ templates, remove the modules, and then upgrade the container.';
  2224.             Log::warning($warn);
  2225.             Log::resultWarning();
  2226.            
  2227.             return;
  2228.         }
  2229.         Log::resultOk();
  2230.     }
  2231.  
  2232.     function _checkForCryptPasswords()
  2233.     {
  2234.         //:INFO: Prevent potential problem with E: Couldn't configure pre-depend plesk-core for psa-firewall, probably a dependency cycle.
  2235.         Log::step('Detecting if encrypted passwords are used...', true);
  2236.  
  2237.         $db = PleskDb::getInstance();
  2238.         $sql = "SELECT COUNT(*) AS cnt FROM accounts WHERE type='crypt';";
  2239.         $r = $db->fetchAll($sql);
  2240.  
  2241.     if ($r[0]['cnt'] != '0')
  2242.         {
  2243.             $warn = 'There are ' . $r[0]['cnt'] . ' accounts with encrypted passwords. Please refer to http://kb.parallels.com/en/112391 on how to change the passwords\' type to plain.';
  2244.  
  2245.             Log::warning($warn);
  2246.             Log::resultWarning();
  2247.             return;
  2248.         }
  2249.         Log::resultOk();
  2250.     }
  2251. }
  2252.  
  2253. class PleskComponent
  2254. {
  2255.     function isInstalledKav()
  2256.     {
  2257.         return $this->_isInstalled('kav');
  2258.     }
  2259.    
  2260.     function _isInstalled($component)
  2261.     {
  2262.         $sql = "SELECT * FROM Components WHERE name LIKE '%{$component}%'";
  2263.  
  2264.         $pleskDb = PleskDb::getInstance();
  2265.         $row = $pleskDb->fetchRow($sql);
  2266.  
  2267.         return (empty($row) ? false : true);
  2268.     }
  2269.    
  2270.     function CurrentWinFTPServer()
  2271.     {
  2272.         if (Util::isWindows()) {
  2273.             $currentFTPServer = Util::regQuery('\PLESK\PSA Config\Config\Packages\ftpserver', '/ve', true);
  2274.             Log::info('Current FTP server is: ' . $currentFTPServer);
  2275.             return $currentFTPServer;
  2276.         }
  2277.     }
  2278.    
  2279.     function CurrentWinDNSServer()
  2280.     {
  2281.         if (Util::isWindows()) {
  2282.             $currentDNSServer = Util::regQuery('\PLESK\PSA Config\Config\Packages\dnsserver', '/ve', true);
  2283.             Log::info('Current DNS server is: ' . $currentDNSServer);
  2284.             return $currentDNSServer;
  2285.         }
  2286.     }
  2287.    
  2288.     function getPackageVersion($package_name)
  2289.     {
  2290.         if (Util::isWindows()) {
  2291.             $cmd = '"' . Util::getPleskRootPath() . 'admin\bin\packagemng" ' . $package_name;
  2292.         } else {
  2293.             if (PleskVersion::is10_4_or_above()) {
  2294.                 $cmd = '/usr/local/psa/admin/bin/packagemng -l';
  2295.             } else {
  2296.                 $cmd = '/usr/local/psa/admin/bin/packagemng ' . $package_name . ' 2>/dev/null';
  2297.             }
  2298.         }
  2299.         /* packagemng <package name> - returns "<package name>:<package version>" on Windows all versions and Unix till Plesk 10.4 versions
  2300.          * since Plesk 10.4 on linux packagemng -l should be used to return list of all packages
  2301.          * if <package name> doesn't exists OR not installed on Windows output will be "<package name>:"
  2302.          * if <package name> doesn't installed on Linux output will be "<package name>:not_installed"
  2303.          * if <package name> doesn't exists on Linux output will be "packagemng: Package <package name> is not found in Components table"
  2304.          */
  2305.         $output = Util::exec($cmd, $code);
  2306.         if (preg_match('/' . $package_name .  '\:(.+)/', $output, $version)) {
  2307.             if ($version[1] <> 'not_installed') {
  2308.                 return $version[1];
  2309.             }
  2310.         }
  2311.         return null;
  2312.     }
  2313. }
  2314.  
  2315. class PleskModule
  2316. {
  2317.     function isInstalledWatchdog()
  2318.     {
  2319.         return PleskModule::_isInstalled('watchdog');
  2320.     }
  2321.    
  2322.     function isInstalledFileServer()
  2323.     {
  2324.         return PleskModule::_isInstalled('fileserver');
  2325.     }
  2326.  
  2327.     function isInstalledFirewall()
  2328.     {
  2329.         return PleskModule::_isInstalled('firewall');
  2330.     }
  2331.  
  2332.     function isInstalledVpn()
  2333.     {
  2334.         return PleskModule::_isInstalled('vpn');
  2335.     }
  2336.    
  2337.     function _isInstalled($module)
  2338.     {
  2339.         $sql = "SELECT * FROM Modules WHERE name = '{$module}'";
  2340.  
  2341.         $pleskDb = PleskDb::getInstance();
  2342.         $row = $pleskDb->fetchRow($sql);
  2343.  
  2344.         return (empty($row) ? false : true);
  2345.     }
  2346. }
  2347.  
  2348. class PleskInstallation
  2349. {
  2350.     function validate()
  2351.     {
  2352.         if (!$this->isInstalled()) {
  2353.             Log::step('Plesk installation is not found. You will have no problems with upgrade, go on and install '.PleskVersion::getLatestPleskVersionAsString().' (http://www.parallels.com/products/plesk/)');
  2354.             return;
  2355.         }
  2356.         $this->_detectVersion();
  2357.     }
  2358.    
  2359.     function isInstalled()
  2360.     {
  2361.         $rootPath = Util::getPleskRootPath();
  2362.         if (empty($rootPath) || !file_exists($rootPath)) {
  2363.             //Log::fatal('Plesk is not installed. Please install Plesk Panel at first.');
  2364.             return false;
  2365.         }
  2366.         return true;
  2367.     }
  2368.    
  2369.     function _detectVersion()
  2370.     {
  2371.         Log::step('Installed Plesk version/build: ' . PleskVersion::getVersionAndBuild());
  2372.        
  2373.         $currentVersion = PleskVersion::getVersion();
  2374.         if (version_compare($currentVersion, PLESK_VERSION, 'eq')) {
  2375.             $err = 'You have already installed the latest version ' . PleskVersion::getLatestPleskVersionAsString() . '. ';
  2376.             $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.';
  2377.             // TODO either introduce an option to suppress fatal error here, or always exit with 0 here.
  2378.             //Log::fatal($err);
  2379.             Log::info($err);
  2380.             exit(0);
  2381.         }
  2382.        
  2383.         if (!PleskVersion::is8x() && !PleskVersion::is9x() && !PleskVersion::is10x() && !PleskVersion::is11x()) {
  2384.             $err = 'Unable to find Plesk 8.x, Plesk 9.x, Plesk 10.x or Plesk 11.x. ';
  2385.             $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.';
  2386.             Log::fatal($err);
  2387.         }
  2388.     }
  2389. }
  2390.  
  2391. class PleskVersion
  2392. {
  2393.     function is8x()
  2394.     {
  2395.         $version = PleskVersion::getVersion();
  2396.         return version_compare($version, '8.0.0', '>=') && version_compare($version, '9.0.0', '<');
  2397.     }
  2398.  
  2399.     function is9x()
  2400.     {
  2401.         $version = PleskVersion::getVersion();
  2402.         return version_compare($version, '9.0.0', '>=') && version_compare($version, '10.0.0', '<');
  2403.     }
  2404.  
  2405.     function is10x()
  2406.     {
  2407.         $version = PleskVersion::getVersion();
  2408.         return version_compare($version, '10.0.0', '>=') && version_compare($version, '11.0.0', '<');
  2409.     }
  2410.    
  2411.     function is11x()
  2412.     {
  2413.         $version = PleskVersion::getVersion();
  2414.         return version_compare($version, '11.0.0', '>=') && version_compare($version, '12.0.0', '<');
  2415.     }
  2416.    
  2417.     function is10_0()
  2418.     {
  2419.         $version = PleskVersion::getVersion();
  2420.         return version_compare($version, '10.0.0', '>=') && version_compare($version, '10.1.0', '<');
  2421.     }
  2422.    
  2423.     function is10x_or_above()
  2424.     {
  2425.         $version = PleskVersion::getVersion();
  2426.         return version_compare($version, '10.0.0', '>=');
  2427.     }
  2428.    
  2429.     function is10_1_or_below()
  2430.     {
  2431.         $version = PleskVersion::getVersion();
  2432.         return version_compare($version, '10.1.1', '<=');
  2433.     }
  2434.    
  2435.     function is10_2_or_above()
  2436.     {
  2437.         $version = PleskVersion::getVersion();
  2438.         return version_compare($version, '10.2.0', '>=');
  2439.     }
  2440.    
  2441.     function is10_3_or_above()
  2442.     {
  2443.         $version = PleskVersion::getVersion();
  2444.         return version_compare($version, '10.3.0', '>=');
  2445.     }
  2446.    
  2447.     function is10_4()
  2448.     {
  2449.         $version = PleskVersion::getVersion();
  2450.         return version_compare($version, '10.4.0', '>=') && version_compare($version, '10.5.0', '<');
  2451.     }
  2452.    
  2453.     function is10_4_or_above()
  2454.     {
  2455.         $version = PleskVersion::getVersion();
  2456.         return version_compare($version, '10.4.0', '>=');
  2457.     }
  2458.    
  2459.     function getVersion()
  2460.     {
  2461.         $version = PleskVersion::getVersionAndBuild();
  2462.         if (!preg_match('/([0-9]+[.][0-9]+[.][0-9])/', $version, $macthes)) {
  2463.             Log::fatal("Incorrect Plesk version format. Current version: {$version}");
  2464.         }
  2465.         return $macthes[1];
  2466.     }
  2467.    
  2468.     function getVersionAndBuild()
  2469.     {
  2470.         $versionPath = Util::getPleskRootPath().'/version';
  2471.         if (!file_exists($versionPath)) {
  2472.             Log::fatal("Plesk version file is not exists $versionPath");
  2473.         }
  2474.         $version = file_get_contents($versionPath);
  2475.         $version = trim($version);
  2476.         return $version;
  2477.     }
  2478.    
  2479.     function getLatestPleskVersionAsString()
  2480.     {
  2481.         return 'Parallels Panel ' . PLESK_VERSION;
  2482.     }
  2483. }
  2484.  
  2485. class Log
  2486. {
  2487.     function Log()
  2488.     {
  2489.         $this->_logFile = APP_PATH . '/plesk10_preupgrade_checker.log';
  2490.         @unlink($this->_logFile);
  2491.     }
  2492.    
  2493.     function _getInstance()
  2494.     {
  2495.         static $_instance = null;
  2496.         if (is_null($_instance)) {
  2497.             $_instance = new Log();
  2498.         }
  2499.         return $_instance;
  2500.     }
  2501.    
  2502.     function fatal($msg)
  2503.     {
  2504.         $log = Log::_getInstance();
  2505.         $log->_log($msg, 'FATAL_ERROR');
  2506.     }
  2507.    
  2508.     function error($msg)
  2509.     {
  2510.         $log = Log::_getInstance();
  2511.         $log->_log($msg, 'ERROR');
  2512.     }
  2513.    
  2514.     function warning($msg)
  2515.     {
  2516.         $log = Log::_getInstance();
  2517.         $log->_log($msg, 'WARNING');
  2518.     }
  2519.    
  2520.     function emergency($msg)
  2521.     {
  2522.         $log = Log::_getInstance();
  2523.         $log->_log($msg, 'EMERGENCY');
  2524.     }
  2525.    
  2526.     function step($msg, $useNumber=false)
  2527.     {
  2528.         static $step = 1;
  2529.        
  2530.         if ($useNumber) {
  2531.             $msg = "==> STEP " . $step . ": {$msg}";
  2532.             $step++;
  2533.         } else {
  2534.             $msg = "==> {$msg}";
  2535.         }
  2536.        
  2537.         $log = Log::_getInstance();
  2538.         $log->_log($msg, 'INFO', PHP_EOL);
  2539.     }
  2540.    
  2541.     function resultOk()
  2542.     {
  2543.         $msg = 'Result: OK';
  2544.         Log::info($msg);
  2545.     }
  2546.    
  2547.     function resultWarning()
  2548.     {
  2549.         $msg = 'Result: Warning';
  2550.         Log::info($msg);
  2551.     }
  2552.    
  2553.     function resultError()
  2554.     {
  2555.         $msg = 'Result: Error';
  2556.         Log::info($msg);
  2557.     }
  2558.    
  2559.     function info($msg)
  2560.     {
  2561.         $log = Log::_getInstance();
  2562.         $log->_log($msg, 'INFO');
  2563.     }
  2564.    
  2565.     function dumpStatistics()
  2566.     {
  2567.         global $errors, $warnings;
  2568.        
  2569.         $str = 'Found errors: ' . $errors
  2570.             . '; Found Warnings: ' . $warnings
  2571.         ;
  2572.         echo PHP_EOL . $str . PHP_EOL . PHP_EOL;
  2573.     }
  2574.    
  2575.     function _log($msg, $type, $newLine='')
  2576.     {
  2577.         global $errors, $warnings, $emergency;
  2578.  
  2579.         // TODO modern PHP (from 5.3) issues warning:
  2580.         //  PHP Warning:  date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting
  2581.         //  or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most
  2582.         //  likely misspelled the timezone identifier. We selected 'America/New_York' for 'EDT/-4.0/DST' instead in
  2583.         //  panel_preupgrade_checker.php on line 1282
  2584.         if (getenv('AUTOINSTALLER_VERSION')) {
  2585.             $log = $newLine . "{$type}: {$msg}" . PHP_EOL;
  2586.         } else {
  2587.             $date = date('Y-m-d h:i:s');
  2588.             $log = $newLine . "[{$date}][{$type}] {$msg}" . PHP_EOL;
  2589.         }
  2590.         if ($type == 'EMERGENCY') {
  2591.             $emergency++;
  2592.             fwrite(STDERR, $log);
  2593.         } elseif ($type == 'ERROR' || $type == 'FATAL_ERROR') {
  2594.             $errors++;
  2595.             fwrite(STDERR, $log);
  2596.         } elseif ($type == 'WARNING') {
  2597.             $warnings++;
  2598.             fwrite(STDERR, $log);
  2599.         } elseif ($type == 'INFO') {
  2600.             //:INFO: Dump to output and write log to the file
  2601.             echo $log;
  2602.         }
  2603.        
  2604.         Log::write($this->_logFile, $log);
  2605.        
  2606.         //:INFO: Terminate the process if have the fatal error
  2607.         if ($type == 'FATAL_ERROR') {
  2608.             exit(1);
  2609.         }
  2610.     }
  2611.    
  2612.     function write($file, $content, $mode='a+')
  2613.     {
  2614.         $fp = fopen($file, $mode);
  2615.         fwrite($fp, $content);
  2616.         fclose($fp);
  2617.     }
  2618. }
  2619.  
  2620. class PleskDb
  2621. {
  2622.     var $_db = null;
  2623.    
  2624.     function PleskDb($dbParams)
  2625.     {
  2626.         switch($dbParams['db_type']) {
  2627.             case 'mysql':
  2628.                 $this->_db = new DbMysql(
  2629.                     $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port']
  2630.                 );
  2631.                 break;
  2632.                
  2633.             case 'jet':
  2634.                 $this->_db = new DbJet($dbParams['db']);
  2635.                 break;
  2636.                
  2637.             case 'mssql':
  2638.                 $this->_db = new DbMsSql(
  2639.                     $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port']
  2640.                 );
  2641.                 break;
  2642.  
  2643.             default:
  2644.                 Log::fatal("{$dbParams['db_type']} is not implemented yet");
  2645.                 break;
  2646.         }
  2647.     }
  2648.    
  2649.     function getInstance()
  2650.     {
  2651.         global $options;
  2652.         static $_instance = array();
  2653.        
  2654.         $dbParams['db_type']= Util::getPleskDbType();
  2655.         $dbParams['db']     = Util::getPleskDbName();
  2656.         $dbParams['port']   = Util::getPleskDbPort();
  2657.         $dbParams['login']  = Util::getPleskDbLogin();
  2658.         $dbParams['passwd'] = $options->getDbPasswd();
  2659.         $dbParams['host']   = 'localhost';
  2660.        
  2661.         $dbId = md5(implode("\n", $dbParams));
  2662.  
  2663.         $_instance[$dbId] = new PleskDb($dbParams);
  2664.        
  2665.         return $_instance[$dbId];
  2666.     }
  2667.    
  2668.     function fetchOne($sql)
  2669.     {
  2670.         if (DEBUG) {
  2671.             Log::info($sql);
  2672.         }
  2673.         return $this->_db->fetchOne($sql);
  2674.     }
  2675.    
  2676.     function fetchRow($sql)
  2677.     {
  2678.         $res = $this->fetchAll($sql);
  2679.         if (is_array($res) && isset($res[0])) {
  2680.             return $res[0];
  2681.         }
  2682.         return array();
  2683.     }
  2684.    
  2685.     function fetchAll($sql)
  2686.     {
  2687.         if (DEBUG) {
  2688.             Log::info($sql);
  2689.         }
  2690.         return $this->_db->fetchAll($sql);
  2691.     }
  2692. }
  2693.  
  2694. class DbMysql
  2695. {
  2696.     var $_dbHandler = null;
  2697.    
  2698.     function DbMysql($host, $user, $passwd, $database, $port)
  2699.     {
  2700.         if ( extension_loaded('mysql') ) {
  2701.             $this->_dbHandler = @mysql_connect("{$host}:{$port}", $user, $passwd);
  2702.             if (!is_resource($this->_dbHandler)) {
  2703.                 $mysqlError = mysql_error();
  2704.                 if (stristr($mysqlError, 'access denied for user')) {
  2705.                     $errMsg = 'Given <password> is incorrect. ' . $mysqlError;
  2706.                 } else {
  2707.                     $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL;
  2708.                 }
  2709.                 $this->_logError($errMsg);
  2710.             }
  2711.             @mysql_select_db($database, $this->_dbHandler);
  2712.         } else if ( extension_loaded('mysqli') ) {
  2713.  
  2714.             $this->_dbHandler = @mysqli_connect($host, $user, $passwd, $database, $port);
  2715.             if (!$this->_dbHandler) {
  2716.                 $mysqlError = mysqli_connect_error();
  2717.                 if (stristr($mysqlError, 'access denied for user')) {
  2718.                     $errMsg = 'Given <password> is incorrect. ' . $mysqlError;
  2719.                 } else {
  2720.                     $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL;
  2721.                 }
  2722.                 $this->_logError($errMsg);
  2723.             }
  2724.         } else {
  2725.             Log::fatal("No MySQL extension is available");
  2726.         }
  2727.     }
  2728.    
  2729.     function fetchAll($sql)
  2730.     {
  2731.         if ( extension_loaded('mysql') ) {
  2732.             $res = mysql_query($sql, $this->_dbHandler);
  2733.             if (!is_resource($res)) {
  2734.                 $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler));
  2735.             }
  2736.             $rowset = array();
  2737.             while ($row = mysql_fetch_assoc($res)) {
  2738.                 $rowset[] = $row;
  2739.             }
  2740.             return $rowset;
  2741.         } else if ( extension_loaded('mysqli') ) {
  2742.             $res = $this->_dbHandler->query($sql);
  2743.             if ($res === false) {
  2744.                 $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler));
  2745.             }
  2746.             $rowset = array();
  2747.             while ($row = mysqli_fetch_assoc($res)) {
  2748.                 $rowset[] = $row;
  2749.             }
  2750.             return $rowset;
  2751.         } else {
  2752.             Log::fatal("No MySQL extension is available");
  2753.         }
  2754.     }
  2755.    
  2756.     function fetchOne($sql)
  2757.     {
  2758.         if ( extension_loaded('mysql') ) {
  2759.             $res = mysql_query($sql, $this->_dbHandler);
  2760.             if (!is_resource($res)) {
  2761.                 $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler));
  2762.             }
  2763.             $row = mysql_fetch_row($res);
  2764.             return $row[0];
  2765.         } else if ( extension_loaded('mysqli') ) {
  2766.             $res = $this->_dbHandler->query($sql);
  2767.             if ($res === false) {
  2768.                 $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler));
  2769.             }
  2770.             $row = mysqli_fetch_row($res);
  2771.             return $row[0];
  2772.         } else {
  2773.             Log::fatal("No MySQL extension is available");
  2774.         }
  2775.     }    
  2776.    
  2777.     function query($sql)
  2778.     {
  2779.         if ( extension_loaded('mysql') ) {
  2780.             $res = mysql_query($sql, $this->_dbHandler);
  2781.             if ($res === false ) {
  2782.                 $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler) );
  2783.             }
  2784.             return $res;
  2785.         } else if ( extension_loaded('mysqli') ) {
  2786.             $res = $this->_dbHandler->query($sql);
  2787.             if ($res === false ) {
  2788.                 $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler) );
  2789.             }
  2790.             return $res;
  2791.         } else {
  2792.             Log::fatal("No MySQL extension is available");
  2793.         }
  2794.     }    
  2795.    
  2796.     function _logError($message)
  2797.     {
  2798.         $message = "[MYSQL ERROR] $message";
  2799.         Log::fatal($message);
  2800.     }
  2801. }
  2802.  
  2803. class DbClientMysql extends DbMysql
  2804. {
  2805.     var $errors = array();
  2806.  
  2807.     function _logError($message)
  2808.     {
  2809.         $message = "[MYSQL ERROR] $message";
  2810.         Log::warning($message);
  2811.         $this->errors[] = $message;
  2812.     }
  2813.  
  2814.     function hasErrors() {
  2815.         return count($this->errors) > 0;
  2816.     }
  2817. }
  2818.  
  2819. class DbJet
  2820. {
  2821.     var $_dbHandler = null;
  2822.    
  2823.     function DbJet($dbPath)
  2824.     {
  2825.         $dsn = "Provider='Microsoft.Jet.OLEDB.4.0';Data Source={$dbPath}";
  2826.         $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8);
  2827.         if (!$this->_dbHandler) {
  2828.             $this->_logError('Unable to init ADODB.Connection');
  2829.         }
  2830.        
  2831.         $this->_dbHandler->open($dsn);
  2832.     }
  2833.    
  2834.     function fetchAll($sql)
  2835.     {
  2836.         $result_id = $this->_dbHandler->execute($sql);
  2837.         if (!$result_id) {
  2838.             $this->_logError('Unable to execute sql query ' . $sql);
  2839.         }
  2840.         if ($result_id->BOF && !$result_id->EOF) {
  2841.             $result_id->MoveFirst();
  2842.         }
  2843.         if ($result_id->EOF) {
  2844.             return array();
  2845.         }
  2846.        
  2847.         $rowset = array();
  2848.         while(!$result_id->EOF) {
  2849.             $row = array();
  2850.             for ($i=0;$i<$result_id->Fields->count;$i++) {
  2851.                 $field = $result_id->Fields($i);
  2852.                 $row[$field->Name] = (string)$field->value;
  2853.             }
  2854.             $result_id->MoveNext();
  2855.             $rowset[] = $row;
  2856.         }
  2857.         return $rowset;
  2858.     }
  2859.    
  2860.     function fetchOne($sql)
  2861.     {
  2862.         $result_id = $this->_dbHandler->execute($sql);
  2863.         if (!$result_id) {
  2864.             $this->_logError('Unable to execute sql query ' . $sql);
  2865.         }
  2866.         if ($result_id->BOF && !$result_id->EOF) {
  2867.             $result_id->MoveFirst();
  2868.         }
  2869.         if ($result_id->EOF) {
  2870.             //Log::fatal('Unable to find row');
  2871.             return null;
  2872.         }
  2873.         $field = $result_id->Fields(0);
  2874.         $result = $field->value;
  2875.        
  2876.         return (string)$result;
  2877.     }
  2878.    
  2879.     function _logError($message)
  2880.     {
  2881.         $message = "[JET ERROR] $message";
  2882.         Log::fatal($message);
  2883.     }
  2884. }
  2885.  
  2886. class DbMsSql extends DbJet
  2887. {
  2888.     function DbMsSql($host, $user, $passwd, $database, $port)
  2889.     {
  2890.         $dsn = "Provider=SQLOLEDB.1;Initial Catalog={$database};Data Source={$host}";
  2891.         $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8);
  2892.         if (!$this->_dbHandler) {
  2893.             $this->_logError('Unable to init ADODB.Connection');
  2894.         }
  2895.         $this->_dbHandler->open($dsn, $user, $passwd);
  2896.     }
  2897.    
  2898.     function _logError($message)
  2899.     {
  2900.         $message = "[MSSQL ERROR] $message";
  2901.         Log::fatal($message);
  2902.     }
  2903. }
  2904.  
  2905. class Util
  2906. {
  2907.     function isWindows()
  2908.     {
  2909.         if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
  2910.             return true;
  2911.         }
  2912.         return false;
  2913.     }
  2914.    
  2915.     function isLinux()
  2916.     {
  2917.         return !Util::isWindows();
  2918.     }
  2919.    
  2920.     function isVz()
  2921.     {
  2922.         $vz = false;
  2923.         if (Util::isLinux()) {
  2924.             if (file_exists('/proc/vz/veredir')) {
  2925.                 $vz = true;
  2926.             }
  2927.         } else {
  2928.             $reg = 'REG QUERY "HKLM\SOFTWARE\SWsoft\Virtuozzo" 2>nul';
  2929.             Util::exec($reg, $code);
  2930.             if ($code==0) {
  2931.                 $vz = true;
  2932.             }
  2933.         }
  2934.         return $vz;
  2935.     }
  2936.    
  2937.     function getArch()
  2938.     {
  2939.         global $arch;
  2940.         if (!empty($arch))
  2941.             return $arch;
  2942.  
  2943.         $arch = 'i386';
  2944.         if (Util::isLinux()) {
  2945.             $cmd = 'uname -m';
  2946.             $x86_64 = 'x86_64';
  2947.             $output = Util::exec($cmd, $code);
  2948.             if (!empty($output) && stristr($output, $x86_64)) {
  2949.                 $arch = 'x86_64';
  2950.             }
  2951.         } else {
  2952.             $cmd = 'systeminfo';
  2953.             $output = Util::exec($cmd, $code);
  2954.             if (preg_match('/System Type:[\s]+(.*)/', $output, $macthes) && stristr($macthes[1], '64')) {
  2955.                 $arch = 'x86_64';
  2956.             }
  2957.         }
  2958.         return $arch;
  2959.     }
  2960.    
  2961.     function getHostname()
  2962.     {
  2963.         if (Util::isLinux()) {
  2964.             $cmd = 'hostname -f';
  2965.         } else {
  2966.             $cmd = 'hostname';
  2967.         }
  2968.         $hostname = Util::exec($cmd, $code);
  2969.        
  2970.         if (empty($hostname)) {
  2971.             $err = 'Command: ' . $cmd . ' returns: ' . $hostname . "\n";
  2972.             $err .= 'Hostname is not defined and configured. Unable to get hostname. Server should have properly configured hostname and it should be resolved locally.';
  2973.             Log::fatal($err);
  2974.         }
  2975.        
  2976.         return $hostname;
  2977.     }
  2978.    
  2979.     function isFQDN($string)
  2980.     {
  2981.         $tld_list = array(
  2982.                 'aero', 'asia', 'biz', 'cat', 'com', 'coop', 'edu', 'gov', 'info', 'int', 'jobs', 'mil', 'mobi', 'museum', 'name', 'net',
  2983.                 'org', 'pro', 'tel', 'travel', 'xxx', 'ac', 'ad', 'ae', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'as', 'at',
  2984.                 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv',
  2985.                 'bw', 'by', 'bz', 'ca', 'cc', 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'cr', 'cs', 'cu', 'cv', 'cx',
  2986.                 'cy', 'cz', 'dd', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'ee', 'eg', 'eh', 'er', 'es', 'et', 'eu', 'fi', 'fj', 'fk',
  2987.                 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gl', 'gm', 'gn', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu',
  2988.                 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm',
  2989.                 'jo', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls',
  2990.                 'lt', 'lu', 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mk', 'ml', 'mm', 'mn', 'mo', 'mp', 'mq', 'mr', 'ms', 'mt',
  2991.                 'mu', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'nc', 'ne', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'pa',
  2992.                 'pe', 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'ps', 'pt', 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa',
  2993.                 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'ss', 'st', 'su', 'sv', 'sy', 'sz',
  2994.                 'tc', 'td', 'tf', 'tg', 'th', 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'tt', 'tv', 'tw', 'tz', 'ua', 'ug', 'uk',
  2995.                 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'za', 'zm', 'zw' );
  2996.    
  2997.         $label = '[a-zA-Z0-9\-]{1,62}\.';
  2998.         $tld = '[\w]+';
  2999.         if(preg_match( '/^(' . $label. ')+(' . $tld . ')$/', $string, $match ) && in_array( $match[2], $tld_list )) {
  3000.             return TRUE;
  3001.         } else {
  3002.             return FALSE;
  3003.         }
  3004.    
  3005.     }
  3006.    
  3007.     function resolveHostname($hostname)
  3008.     {
  3009.         $dns_record = dns_get_record($hostname, DNS_A | DNS_AAAA);
  3010.  
  3011.         if (isset($dns_record[0]['ip'])) {
  3012.             return $dns_record[0]['ip'];
  3013.         }
  3014.         if (isset($dns_record[0]["ipv6"])) {
  3015.             return $dns_record[0]['ipv6'];
  3016.         }
  3017.        
  3018.         return null;
  3019.     }
  3020.  
  3021.     function getIP()
  3022.     {
  3023.         $list = Util::getIPList();
  3024.         return $list[0]; //main IP
  3025.     }
  3026.    
  3027.     function getIPList($lo=false)
  3028.     {
  3029.         if (Util::isLinux()) {
  3030.             $ifconfig = Util::lookupCommand('ifconfig');
  3031.             $output = Util::exec("{$ifconfig} -a", $code);
  3032.             if (!preg_match_all('/inet Adresse:([0-9\.]+)/', $output, $matches)) {
  3033.                 Log::fatal('Unable to get IP address');
  3034.             }
  3035.             $ipList = $matches[1];
  3036.             foreach ($ipList as $key => $ip) {
  3037.                 if (!$lo && substr($ip, 0, 3) == '127') {
  3038.                     unset($ipList[$key]);
  3039.                     continue;
  3040.                 }
  3041.                 trim($ip);
  3042.             }
  3043.             $ipList = array_values($ipList);
  3044.         } else {
  3045.             $cmd = 'hostname';
  3046.             $hostname = Util::exec($cmd, $code);
  3047.             $ip = gethostbyname($hostname);
  3048.             $res = ($ip != $hostname) ? true : false;
  3049.             if (!$res) {
  3050.                 Log::fatal('Unable to retrieve IP address');
  3051.             }
  3052.             $ipList = array(trim($ip));
  3053.         }
  3054.         return $ipList;
  3055.     }
  3056.    
  3057.     function getIPv6ListOnLinux()
  3058.     {
  3059.         $ifconfig = Util::lookupCommand('ifconfig');
  3060.         $output = Util::exec("{$ifconfig} -a", $code);
  3061.         if (!preg_match_all('/inet6-Adresse: ?([^ ][^\/]+)/', $output, $matches)) {
  3062.             return;
  3063.         }
  3064.         return $matches[1];
  3065.     }
  3066.    
  3067.     function getIPv4ListOnLinux()
  3068.     {
  3069.         $ifconfig = Util::lookupCommand('ifconfig');
  3070.         $output = Util::exec("{$ifconfig} -a", $code);
  3071.         if (!preg_match_all('/inet Adresse: ?([^ ]+)/', $output, $matches)) {
  3072.             Log::fatal('Unable to get IP address');
  3073.         }
  3074.         return $matches[1];
  3075.     }
  3076.    
  3077.     function getIPListOnWindows()
  3078.     {
  3079.         $cmd = 'wmic.exe path win32_NetworkAdapterConfiguration get IPaddress';
  3080.         $output = Util::exec($cmd, $code);
  3081.         if (!preg_match_all('/"(.*?)"/', $output, $matches)) {
  3082.             Log::fatal('Unable to get IP address');
  3083.         }
  3084.         return $matches[1];
  3085.     }
  3086.    
  3087.     function getPleskRootPath()
  3088.     {
  3089.         global $_pleskRootPath;
  3090.         if (empty($_pleskRootPath)) {
  3091.             if (Util::isLinux()) {
  3092.                 if (PleskOS::isDebLike()) {
  3093.                     $_pleskRootPath = '/opt/psa';
  3094.                 } else {
  3095.                     $_pleskRootPath = '/usr/local/psa';
  3096.                 }
  3097.             }
  3098.             if (Util::isWindows()) {
  3099.                 $_pleskRootPath = Util::regPleskQuery('PRODUCT_ROOT_D', true);
  3100.             }
  3101.         }
  3102.         return $_pleskRootPath;
  3103.     }
  3104.    
  3105.     function getPleskDbName()
  3106.     {
  3107.         $dbName = 'psa';
  3108.         if (Util::isWindows()) {
  3109.             $dbName = Util::regPleskQuery('mySQLDBName');
  3110.         }
  3111.         return $dbName;
  3112.     }
  3113.    
  3114.     function getPleskDbLogin()
  3115.     {
  3116.         $dbLogin = 'admin';
  3117.         if (Util::isWindows()) {
  3118.             $dbLogin = Util::regPleskQuery('PLESK_DATABASE_LOGIN');
  3119.         }
  3120.         return $dbLogin;
  3121.     }
  3122.    
  3123.     function getPleskDbType()
  3124.     {
  3125.         $dbType = 'mysql';
  3126.         if (Util::isWindows()) {
  3127.             $dbType = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME'));
  3128.         }
  3129.         return $dbType;
  3130.     }
  3131.    
  3132.     function getPleskDbPort()
  3133.     {
  3134.         $dbPort = '3306';
  3135.         if (Util::isWindows()) {
  3136.             $dbPort = Util::regPleskQuery('MYSQL_PORT');
  3137.         }
  3138.         return $dbPort;
  3139.     }    
  3140.    
  3141.     function regPleskQuery($key, $returnResult=false)
  3142.     {
  3143.         $arch = Util::getArch();
  3144.         if ($arch == 'x86_64') {
  3145.             $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node\Plesk\Psa Config\Config" /v '.$key;
  3146.         } else {
  3147.             $reg = 'REG QUERY "HKLM\SOFTWARE\Plesk\Psa Config\Config" /v '.$key;
  3148.         }
  3149.         $output = Util::exec($reg, $code);
  3150.        
  3151.         if ($returnResult && $code!=0) {
  3152.             return false;
  3153.         }
  3154.        
  3155.         if ($code!=0) {
  3156.             Log::info($reg);
  3157.             Log::info($output);
  3158.             Log::fatal("Unable to get '$key' from registry");
  3159.         }
  3160.         if (!preg_match("/\w+\s+REG_SZ\s+(.*)/i", trim($output), $matches)) {
  3161.             Log::fatal('Unable to macth registry value by key '.$key.'. Output: ' .  trim($output));
  3162.         }
  3163.        
  3164.         return $matches[1];
  3165.     }
  3166.    
  3167.     function regQuery($path, $key, $returnResult=false)
  3168.     {
  3169.         $arch = Util::getArch();
  3170.         if ($arch == 'x86_64') {
  3171.             $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node' . $path .  '" '.$key;
  3172.         } else {
  3173.             $reg = 'REG QUERY "HKLM\SOFTWARE' . $path .  '" '.$key;
  3174.         }
  3175.         $output = Util::exec($reg, $code);
  3176.    
  3177.         if ($returnResult && $code!=0) {
  3178.             return false;
  3179.         }
  3180.    
  3181.         if ($code!=0) {
  3182.             Log::info($reg);
  3183.             Log::info($output);
  3184.             Log::fatal("Unable to get '$key' from registry");
  3185.         }
  3186.         if (!preg_match("/\s+REG_SZ\s+(.*)/i", trim($output), $matches)) {
  3187.             Log::fatal('Unable to match registry value by key '.$key.'. Output: ' .  trim($output));
  3188.         }
  3189.    
  3190.         return $matches[1];
  3191.     }    
  3192.    
  3193.     function getAutoinstallerVersion()
  3194.     {
  3195.         if (Util::isLinux()) {
  3196.             $rootPath = Util::getPleskRootPath();
  3197.             $cmd = $rootPath . '/admin/sbin/autoinstaller --version';
  3198.             $output = Util::exec($cmd, $code);
  3199.         } else {
  3200.             $cmd = '"' . Util::regPleskQuery('PRODUCT_ROOT_D', true) . 'admin\bin\ai.exe" --version';
  3201.             $output = Util::exec($cmd, $code);
  3202.         }
  3203.         if (!preg_match("/\d+\.\d+\.\d+/", trim($output), $matches)) {
  3204.             Log::fatal('Unable to match autoinstaller version. Output: ' .  trim($output));
  3205.         }
  3206.         return $matches[0];
  3207.     }
  3208.    
  3209.     function lookupCommand($cmd, $path = '/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/local/sbin', $exit = true)
  3210.     {
  3211.         $dirs = explode(':', $path);
  3212.         foreach ($dirs as $dir) {
  3213.             $util = $dir . '/' . $cmd;
  3214.             if (is_executable($util)) {
  3215.                 return $util;
  3216.             }
  3217.         }
  3218.         if ($exit) {
  3219.             Log::fatal("{$cmd}: command not found");
  3220.         }
  3221.     }
  3222.    
  3223.     function getSystemDisk()
  3224.     {
  3225.         $cmd = 'echo %SYSTEMROOT%';
  3226.         $output = Util::exec($cmd, $code);
  3227.         return substr($output, 0, 3);
  3228.     }
  3229.    
  3230.     function getSystemRoot()
  3231.     {
  3232.         $cmd = 'echo %SYSTEMROOT%';
  3233.         $output = Util::exec($cmd, $code);
  3234.         return $output;
  3235.     }
  3236.    
  3237.     function getFileVersion($file)
  3238.     {
  3239.         $fso = new COM("Scripting.FileSystemObject");
  3240.         $version = $fso->GetFileVersion($file);
  3241.         $fso = null;
  3242.         return $version;
  3243.     }
  3244.    
  3245.     function isUnknownISAPIfilters()
  3246.     {
  3247.         $isUnknownISAPI = false;
  3248.         $knownISAPI = array ("ASP\\.Net.*", "sitepreview", "COMPRESSION", "jakarta");
  3249.  
  3250.         foreach ($knownISAPI as &$value) {
  3251.             $value = strtoupper($value);
  3252.         }
  3253.         $cmd='cscript ' . Util::getSystemDisk() . 'inetpub\AdminScripts\adsutil.vbs  ENUM W3SVC/FILTERS';
  3254.         $output = Util::exec($cmd,  $code);
  3255.        
  3256.         if ($code!=0) {
  3257.             Log::info("Unable to get ISAPI filters. Error: " . $output);
  3258.             return false;
  3259.         }
  3260.         if (!preg_match_all('/FILTERS\/(.*)]/', trim($output), $matches)) {
  3261.             Log::info($output);
  3262.             Log::info("Unable to get ISAPI filters from output: " . $output);
  3263.             return false;
  3264.         }
  3265.         foreach ($matches[1] as $ISAPI) {
  3266.             $valid = false;
  3267.             foreach ($knownISAPI as $knownPattern) {
  3268.                 if (preg_match("/$knownPattern/i", $ISAPI)) {
  3269.                     $valid = true;
  3270.                     break;
  3271.                 }
  3272.             }
  3273.             if (! $valid ) {
  3274.                 Log::warning("Unknown ISAPI filter detected in IIS: " . $ISAPI);
  3275.                 $isUnknownISAPI = true;
  3276.             }
  3277.         }
  3278.  
  3279.         return $isUnknownISAPI;
  3280.     }
  3281.    
  3282.     function getMySQLServerVersion()
  3283.     {
  3284.         $credentials = Util::getDefaultClientMySQLServerCredentials();
  3285.    
  3286.         $mysql = new DbClientMysql('localhost', $credentials['admin_login'], $credentials['admin_password'] , 'information_schema', 3306);
  3287.         if (!$mysql->hasErrors()) {
  3288.             $sql = 'select version()';
  3289.             $mySQLversion = $mysql->fetchOne($sql);
  3290.             if (!preg_match("/(\d{1,})\.(\d{1,})\.(\d{1,})/", trim($mySQLversion), $matches)) {
  3291.                 Log::fatal('Unable to match MySQL server version.');
  3292.             }
  3293.             return $matches[0];
  3294.         }
  3295.     }
  3296.    
  3297.     function getDefaultClientMySQLServerCredentials()
  3298.     {
  3299.         $db = PleskDb::getInstance();
  3300.         $sql = "SELECT DatabaseServers.admin_login, DatabaseServers.admin_password FROM DatabaseServers WHERE type='mysql' AND host='localhost'";
  3301.         $clientDBServerCredentials = $db->fetchAll($sql);
  3302.         if (Util::isLinux()) {
  3303.             $clientDBServerCredentials[0]['admin_password'] = Util::retrieveAdminMySQLDbPassword();
  3304.         }
  3305.         return $clientDBServerCredentials[0];
  3306.     }
  3307.  
  3308.     function retrieveAdminMySQLDbPassword()
  3309.     {
  3310.         if (Util::isLinux())
  3311.             return trim( Util::readfile("/etc/psa/.psa.shadow") );
  3312.         else
  3313.             return null;
  3314.     }
  3315.    
  3316.     function exec($cmd, &$code)
  3317.     {
  3318.         exec($cmd, $output, $code);
  3319.         return trim(implode("\n", $output));
  3320.     }
  3321.  
  3322.     function readfile($file)
  3323.     {
  3324.         if (!is_file($file) || !is_readable($file))
  3325.             return null;
  3326.         $lines = file($file);
  3327.         if ($lines === false)
  3328.             return null;
  3329.         return trim(implode("\n", $lines));
  3330.     }
  3331.    
  3332.     function readfileToArray($file)
  3333.     {
  3334.         if (!is_file($file) || !is_readable($file))
  3335.             return null;
  3336.         $lines = file($file);
  3337.         if ($lines === false)
  3338.             return null;
  3339.         return $lines;
  3340.     }
  3341.    
  3342.     function getSettingFromPsaConf($setting)
  3343.     {
  3344.         $file = '/etc/psa/psa.conf';
  3345.         if (!is_file($file) || !is_readable($file))
  3346.             return null;
  3347.         $lines = file($file);
  3348.         if ($lines === false)
  3349.             return null;
  3350.         foreach ($lines as $line) {
  3351.             if (preg_match("/^{$setting}\s.*/", $line, $match_setting)) {
  3352.                 if (preg_match("/[\s].*/i", $match_setting[0], $match_value)) {
  3353.                     $value = trim($match_value[0]);
  3354.                     return $value;
  3355.                 }
  3356.             }
  3357.         }
  3358.         return null;
  3359.     }
  3360.    
  3361.     function GetFreeSystemMemory()
  3362.     {
  3363.         if (Util::isLinux()) {
  3364.             $cmd = 'cat /proc/meminfo';
  3365.             $output = Util::exec($cmd, $code);
  3366.             if (preg_match("/MemFree:.+?(\d+)/", $output, $MemFree)) {
  3367.                 if (preg_match("/SwapFree:.+?(\d+)/", $output, $SwapFree)) {
  3368.                     return $MemFree[1] + $SwapFree[1]; // returns value in Kb
  3369.                 }
  3370.             }
  3371.         } else {
  3372.             $cmd = 'wmic.exe OS get FreePhysicalMemory';
  3373.             $output = Util::exec($cmd, $code);
  3374.             if (preg_match("/\d+/", $output, $FreePhysicalMemory)) {
  3375.                 $cmd = 'wmic.exe PAGEFILE get AllocatedBaseSize';
  3376.                 $output = Util::exec($cmd, $code);
  3377.                 if (preg_match("/\d+/", $output, $SwapAllocatedBaseSize)) {
  3378.                     $cmd = 'wmic.exe PAGEFILE get CurrentUsage';
  3379.                     $output = Util::exec($cmd, $code);
  3380.                     if (preg_match("/\d+/", $output, $SwapCurrentUsage)) {
  3381.                         return $FreePhysicalMemory[0] + ($SwapAllocatedBaseSize[0] - $SwapCurrentUsage[0]) * 1000; // returns value in Kb
  3382.                     }
  3383.                 }
  3384.             }
  3385.         }
  3386.     }
  3387.    
  3388.     function getPhpIni()
  3389.     {
  3390.         if (Util::isLinux()) {
  3391.             // Debian/Ubuntu  /etc/php5/apache2/php.ini /etc/php5/conf.d/
  3392.             // SuSE  /etc/php5/apache2/php.ini /etc/php5/conf.d/
  3393.             // CentOS 4/5 /etc/php.ini /etc/php.d
  3394.             if (PleskOS::isRedHatLike()) {
  3395.                 $phpini = Util::readfileToArray('/etc/php.ini');
  3396.             } else {
  3397.                 $phpini = Util::readfileToArray('/etc/php5/apache2/php.ini');
  3398.             }
  3399.         }
  3400.        
  3401.         return $phpini;
  3402.     }
  3403. }
  3404.  
  3405. class Package
  3406. {
  3407.     function getManager($field, $package)
  3408.     {
  3409.         $redhat = 'rpm -q --queryformat \'%{' . $field . '}\n\' ' . $package;
  3410.         $debian = 'dpkg-query --show --showformat=\'${' . $field . '}\n\' '. $package;
  3411.         $suse = 'rpm -q --queryformat \'%{' . $field . '}\n\' ' . $package;
  3412.         $manager = false;
  3413.        
  3414.         if (PleskOS::isRedHatLike()) {
  3415.             $manager = $redhat;
  3416.         } elseif (PleskOS::isDebLike()) {
  3417.             $manager = $debian;
  3418.         } elseif (PleskOS::isSuseLike()) {
  3419.             $manager = $suse;
  3420.         } else {
  3421.             return false;
  3422.         }
  3423.        
  3424.         return $manager;
  3425.     }
  3426.    
  3427.     /* DPKG doesn't supports ${Release}
  3428.      *  
  3429.      */
  3430.  
  3431.     function getRelease($package)
  3432.     {
  3433.         $release = false;
  3434.        
  3435.         $manager = Package::getManager('Release', $package);
  3436.        
  3437.         if (!$manager) {
  3438.             return false;
  3439.         }      
  3440.        
  3441.         $release = Util::exec($manager, $code);
  3442.         if (!$code === 0) {
  3443.             return false;
  3444.         }
  3445.         return $release;
  3446.     }
  3447.    
  3448.     function getVersion($package)
  3449.     {
  3450.         $version = false;
  3451.        
  3452.         $manager = Package::getManager('Version', $package);
  3453.        
  3454.         if (!$manager) {
  3455.             return false;
  3456.         }
  3457.        
  3458.         $version = Util::exec($manager, $code);
  3459.         if (!$code === 0) {
  3460.             return false;
  3461.         }
  3462.         return $version;
  3463.     }
  3464.    
  3465. }
  3466.  
  3467. class PleskOS
  3468. {
  3469.     function isSuse103()
  3470.     {
  3471.         return PleskOS::_detectOS('suse', '10.3');
  3472.     }
  3473.    
  3474.     function isUbuntu804()
  3475.     {
  3476.         return PleskOS::_detectOS('ubuntu', '8.04');
  3477.     }
  3478.    
  3479.     function isDebLike()
  3480.     {
  3481.         if (PleskOS::_detectOS('ubuntu', '.*')
  3482.         || PleskOS::_detectOS('debian', '.*')
  3483.         ) {
  3484.             return true;
  3485.         }
  3486.         return false;
  3487.     }
  3488.    
  3489.     function isSuseLike()
  3490.     {
  3491.         if (PleskOS::_detectOS('suse', '.*')) {
  3492.             return true;
  3493.         }
  3494.         return false;
  3495.     }
  3496.    
  3497.     function isRedHatLike()
  3498.     {
  3499.         if (PleskOS::_detectOS('centos', '.*')
  3500.         || PleskOS::_detectOS('red hat', '.*')
  3501.         ) {
  3502.             return true;
  3503.         }
  3504.         return false;
  3505.     }
  3506.    
  3507.    
  3508.     function isRedHat()
  3509.     {
  3510.         if (PleskOS::_detectOS('red hat', '.*')) {
  3511.             return true;
  3512.         }
  3513.         return false;
  3514.     }
  3515.    
  3516.     function isCentOS()
  3517.     {
  3518.         if (PleskOS::_detectOS('centos', '.*')) {
  3519.             return true;
  3520.         }
  3521.         return false;
  3522.     }
  3523.    
  3524.    
  3525.     function _detectOS($name, $version)
  3526.     {
  3527.         $output = PleskOS::catEtcIssue();
  3528.         if (!preg_match("/{$name}[\s]+$version/i", $output)) {
  3529.             return false;
  3530.         }
  3531.         return true;
  3532.     }
  3533.      
  3534.     function catEtcIssue()
  3535.     {
  3536.         $cmd = 'cat /etc/issue';
  3537.         $output = Util::exec($cmd, $code);
  3538.        
  3539.         return $output;
  3540.     }
  3541.    
  3542.     function detectSystem()
  3543.     {
  3544.         Log::step('Detect system configuration');
  3545.        
  3546.         Log::info('OS: ' . (Util::isLinux() ? PleskOS::catEtcIssue() : 'Windows'));
  3547.         Log::info('Arch: ' . Util::getArch());
  3548.     }
  3549. }
  3550.  
  3551. class PleskValidator
  3552. {
  3553.     function isValidIp($value)
  3554.     {
  3555.         if (!is_string($value)) {
  3556.             return false;
  3557.         }
  3558.         if (!PleskValidator::validateIPv4($value) && !PleskValidator::validateIPv6($value)) {
  3559.             return false;
  3560.         }
  3561.         return true;
  3562.     }
  3563.    
  3564.     function validateIPv4($value)
  3565.     {
  3566.         $ip2long = ip2long($value);
  3567.         if ($ip2long === false) {
  3568.             return false;
  3569.         }
  3570.  
  3571.         return $value == long2ip($ip2long);
  3572.     }
  3573.  
  3574.     function validateIPv6($value)
  3575.     {
  3576.         if (strlen($value) < 3) {
  3577.             return $value == '::';
  3578.         }
  3579.  
  3580.         if (strpos($value, '.')) {
  3581.             $lastcolon = strrpos($value, ':');
  3582.             if (!($lastcolon && PleskValidator::validateIPv4(substr($value, $lastcolon + 1)))) {
  3583.                 return false;
  3584.             }
  3585.  
  3586.             $value = substr($value, 0, $lastcolon) . ':0:0';
  3587.         }
  3588.  
  3589.         if (strpos($value, '::') === false) {
  3590.             return preg_match('/\A(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}\z/i', $value);
  3591.         }
  3592.  
  3593.         $colonCount = substr_count($value, ':');
  3594.         if ($colonCount < 8) {
  3595.             return preg_match('/\A(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?\z/i', $value);
  3596.         }
  3597.  
  3598.         // special case with ending or starting double colon
  3599.         if ($colonCount == 8) {
  3600.             return preg_match('/\A(?:::)?(?:[a-f0-9]{1,4}:){6}[a-f0-9]{1,4}(?:::)?\z/i', $value);
  3601.         }
  3602.        
  3603.         return false;
  3604.     }
  3605. }
  3606.  
  3607. class CheckRequirements
  3608. {
  3609.     function validate()
  3610.     {
  3611.         if (!PleskInstallation::isInstalled()) {
  3612.             //:INFO: skip chking mysql extension if plesk is not installed
  3613.             return;
  3614.         }
  3615.          
  3616.         $reqExts = array();
  3617.         foreach ($reqExts as $name) {
  3618.             $status = extension_loaded($name);
  3619.             if (!$status) {
  3620.                 $this->_fail("PHP extension {$name} is not installed");
  3621.             }
  3622.         }
  3623.     }
  3624.    
  3625.     function _fail($errMsg)
  3626.     {
  3627.         echo '===Checking requirements===' . PHP_EOL;
  3628.         echo PHP_EOL . 'Error: ' . $errMsg . PHP_EOL;
  3629.         exit(1);
  3630.     }
  3631. }
  3632.  
  3633. class GetOpt
  3634. {
  3635.     var $_argv = null;
  3636.     var $_adminDbPasswd = null;
  3637.    
  3638.     function GetOpt()
  3639.     {
  3640.         $this->_argv = $_SERVER['argv'];
  3641.         if (empty($this->_argv[1]) && Util::isLinux())
  3642.             $this->_adminDbPasswd = Util::retrieveAdminMySQLDbPassword();
  3643.         else
  3644.             $this->_adminDbPasswd = $this->_argv[1];
  3645.     }
  3646.    
  3647.     function validate()
  3648.     {
  3649.         if (empty($this->_adminDbPasswd) && PleskInstallation::isInstalled()) {
  3650.             echo 'Please specify Plesk database password';
  3651.             $this->_helpUsage();
  3652.         }
  3653.     }
  3654.    
  3655.     function getDbPasswd()
  3656.     {
  3657.         return $this->_adminDbPasswd;
  3658.     }
  3659.    
  3660.     function _helpUsage()
  3661.     {
  3662.         echo PHP_EOL . "Usage: {$this->_argv[0]} <plesk_db_admin_password>" . PHP_EOL;
  3663.         exit(1);
  3664.     }
  3665. }
  3666.  
  3667. $emergency = 0;
  3668. $errors = $warnings = 0;
  3669.  
  3670. //:INFO: Validate options
  3671. $options = new GetOpt();
  3672. $options->validate();
  3673.  
  3674. //:INFO: Validate PHP requirements, need to make sure that PHP extensions are installed
  3675. $checkRequirements = new CheckRequirements();
  3676. $checkRequirements->validate();
  3677.  
  3678. //:INFO: Validate Plesk installation
  3679. $pleskInstallation = new PleskInstallation();
  3680. $pleskInstallation->validate();
  3681.  
  3682. //:INFO: Detect system
  3683. $pleskOs = new PleskOS();
  3684. $pleskOs->detectSystem();
  3685.  
  3686. //:INFO: Need to make sure that given db password is valid
  3687. if (PleskInstallation::isInstalled()) {
  3688.     Log::step('Validation of given db password');
  3689.     $pleskDb = PleskDb::getInstance();
  3690.     Log::resultOk();
  3691. }
  3692.  
  3693. //:INFO: Dump script version
  3694. Log::step('Pre-Upgrade analyzer version: ' . PRE_UPGRADE_SCRIPT_VERSION);
  3695.  
  3696. //:INFO: Check potential problems you may encounter during transition to Plesk 10 model.
  3697. $pleskBusinessModel = new Plesk10BusinessModel();
  3698. $pleskBusinessModel->validate();
  3699.  
  3700. //:INFO: Validate Plesk requirements before installation/upgrade
  3701. $pleskRequirements = new Plesk10Requirements();
  3702. $pleskRequirements->validate();
  3703.  
  3704. //:INFO: Validate issues related to Mail system
  3705. $pleskMailServer = new Plesk10MailServer();
  3706. $pleskMailServer->validate();
  3707.  
  3708. //:INFO: Validate issues related to Skin
  3709. $pleskSkin = new Plesk10Skin();
  3710. $pleskSkin->validate();
  3711.  
  3712. //:INFO: Validate issues related to Permissions
  3713. $pleskPermissions = new Plesk10Permissions();
  3714. $pleskPermissions->validate();
  3715.  
  3716. //:INFO: Validate known OS specific issues with recommendation to avoid bugs in Plesk
  3717. $pleskKnownIssues = new Plesk10KnownIssues();
  3718. $pleskKnownIssues->validate();
  3719.  
  3720. Log::dumpStatistics();
  3721.  
  3722. if ($emergency > 0) {
  3723.     exit(2);
  3724. }
  3725.  
  3726. if ($errors > 0 || $warnings > 0) {
  3727.     exit(1);
  3728. }
Add Comment
Please, Sign In to add comment