/**
  * Plugin un-installer with best effort depending on what it finds.
  *
  * @param  int      $pluginId  Plugin id to uninstall
  * @param  string   $option    Option request of component
  * @return boolean             Success
  */
 function uninstall($pluginId, $option)
 {
     global $_CB_framework, $_CB_database;
     $db = false;
     $success = false;
     if (!$this->checkPluginGetXml($pluginId, $option)) {
         return false;
     }
     if ($this->i_xmldocument !== null && count($this->i_xmldocument->children()) > 0) {
         $cbInstallXML = $this->i_xmldocument;
         // get the element name:
         $e = $cbInstallXML->getElementByPath('name');
         $this->elementName($e->data());
         // $cleanedElementName = strtolower(str_replace(array(" ","."),array("","_"),$this->elementName()));
         // get the files element
         $files_element = $cbInstallXML->getElementByPath('files');
         if ($files_element !== false) {
             if (count($files_element->children())) {
                 foreach ($files_element->children() as $file) {
                     if ($file->attributes("plugin")) {
                         $this->elementSpecial($file->attributes("plugin"));
                         break;
                     }
                 }
             }
             $cleanedMainFileName = strtolower(str_replace(array(" ", "."), array("", "_"), $this->elementSpecial()));
             // Is there an uninstallfile
             $uninstallfile_elemet = $cbInstallXML->getElementByPath('uninstallfile');
             if ($uninstallfile_elemet !== false) {
                 if (is_file($this->i_elementdir . $uninstallfile_elemet->data())) {
                     global $_PLUGINS;
                     // needed for the require_once below !
                     /** @noinspection PhpIncludeInspection */
                     require_once $this->i_elementdir . $uninstallfile_elemet->data();
                     $ret = call_user_func_array("plug_" . $cleanedMainFileName . "_uninstall", array());
                     if ($ret != '') {
                         $this->setError(0, $ret);
                     }
                 }
             }
             $adminFS = cbAdminFileSystem::getInstance();
             $installFileName = basename($this->i_installfilename);
             $this->deleteFiles($files_element, $adminFS, $installFileName);
             // Are there any CBLib libraries ?
             $libraries_element = $cbInstallXML->getElementByPath('libraries');
             if ($libraries_element !== false) {
                 foreach ($libraries_element->children() as $library) {
                     if ($library->getName() != 'library') {
                         continue;
                     }
                     // Delete files from library package:
                     $savePackage = $this->i_xmldocument;
                     $subFolder = $library->attributes('name');
                     $saveElement = $this->elementDir();
                     $this->elementDir($_CB_framework->getCfg('absolute_path') . '/components/com_comprofiler/plugin/libraries/' . ($subFolder ? $subFolder . '/' : null));
                     $this->i_xmldocument = $library;
                     $this->deleteFiles($library->getElementByPath('files'), $adminFS, null);
                     $this->i_xmldocument = $savePackage;
                     $this->elementDir($saveElement);
                 }
             }
             // Are there any SQL queries??
             $query_element = $cbInstallXML->getElementByPath('uninstall/queries');
             if ($query_element !== false) {
                 foreach ($query_element->children() as $query) {
                     $_CB_database->setQuery(trim($query->data()));
                     if (!$_CB_database->query()) {
                         $this->setError(1, "SQL Error " . $_CB_database->getErrorMsg());
                         return false;
                     }
                 }
             }
             // Are there any Database statements ??
             $db = $cbInstallXML->getElementByPath('database');
             if ($db !== false && count($db->children()) > 0) {
                 $sqlUpgrader = new DatabaseUpgrade(null, false);
                 //$sqlUpgrader->setDryRun( true );
                 $success = $sqlUpgrader->checkXmlDatabaseDescription($db, $cleanedMainFileName, 'drop', null, null);
                 /*
                 var_dump( $success );
                 echo "<br>\nERRORS: " . $sqlUpgrader->getErrors( "<br /><br />\n\n", "<br />\n" );
                 echo "<br>\nLOGS: " . $sqlUpgrader->getLogs( "<br /><br />\n\n", "<br />\n" );
                 exit;
                 */
                 if (!$success) {
                     $this->setError(1, "Plugin database XML SQL Error " . $sqlUpgrader->getErrors());
                     return false;
                 }
             }
             // Delete tabs and private fields of plugin:
             $this->deleteTabAndFieldsOfPlugin($pluginId);
             // remove XML file from front
             $xmlRemoveResult = $adminFS->unlink(_cbPathName($this->i_installfilename, false));
             $filesRemoveResult = true;
             /*					// define folders that should not be removed
             								$sysFolders = array(
             								'content',
             								'search'
             								);
             								if ( ! in_array( $row->folder, $sysFolders ) ) {
             				*/
             // delete the non-system folders if empty
             if (count(cbReadDirectory($this->i_elementdir)) < 1) {
                 $filesRemoveResult = $adminFS->deldir($this->i_elementdir);
             }
             /*					}
              */
             if (!$xmlRemoveResult) {
                 self::renderInstallMessage('Could not delete XML file: ' . _cbPathName($this->i_installfilename, false) . ' due to permission error. Please remove manually.', 'Uninstall -  warning', $this->returnTo($option, 'showPlugins'));
             }
             if (!$filesRemoveResult) {
                 self::renderInstallMessage('Could not delete directory: ' . $this->i_elementdir . ' due to permission error. Please remove manually.', 'Uninstall -  warning', $this->returnTo($option, 'showPlugins'));
             }
         }
     }
     $_CB_database->setQuery("DELETE FROM #__comprofiler_plugin WHERE id = " . (int) $pluginId);
     if (!$_CB_database->query()) {
         $msg = $_CB_database->getErrorMsg();
         self::renderInstallMessage('Cannot delete plugin database entry due to error: ' . $msg, 'Uninstall -  error', $this->returnTo($option, 'showPlugins'));
         return false;
     }
     if ($this->i_xmldocument !== null && $db !== false && count($db->children()) > 0) {
         CBDatabaseChecker::renderDatabaseResults($sqlUpgrader, true, false, $success, array(), array(), $this->elementName(), 1, false);
     }
     return true;
 }
function fixcbdb($dryRun, $dbId = 0)
{
    global $_CB_database, $ueConfig, $_PLUGINS;
    // Try extending time, as unziping/ftping took already quite some... :
    @set_time_limit(240);
    $dryRun = $dryRun == 1;
    if ($dbId == 0) {
        // Fix mandatory basics of core CB:
        cbimport('cb.dbchecker');
        $dbName = CBTxt::T('Core CB mandatory basics');
        $dbChecker = new CBDatabaseChecker();
        $result = $dbChecker->checkCBMandatoryDb(true, $dryRun);
        $messagesAfter = array();
        $messagesBefore = array();
        ob_start();
        CBDatabaseChecker::renderDatabaseResults($dbChecker, true, $dryRun, $result, $messagesBefore, $messagesAfter, $dbName, $dbId);
        $html = ob_get_contents();
        ob_end_clean();
        // Fix core CB:
        $_PLUGINS->loadPluginGroup('user');
        $dbName = CBTxt::T('Core CB');
        $messagesBefore = $_PLUGINS->trigger('onBeforeFixDb', array($dryRun));
        $messagesBefore[] = $html;
        $dbChecker = new CBDatabaseChecker();
        $result = $dbChecker->checkDatabase(true, $dryRun);
        $messagesAfter = $_PLUGINS->trigger('onAfterFixDb', array($dryRun));
        // adapt published fields to global CB config (regarding name type)
        _cbAdaptNameFieldsPublished($ueConfig);
    } elseif ($dbId == 1) {
        // Fix plugin $dbId:
        $dbName = CBTxt::T('CB plugin');
        $messagesBefore = array();
        $messagesAfter = array();
        $result = true;
        cbimport('cb.installer');
        $sql = 'SELECT `id`, `name` FROM `#__comprofiler_plugin` ORDER BY `ordering`';
        $_CB_database->setQuery($sql);
        $plugins = $_CB_database->loadObjectList();
        if (!$_CB_database->getErrorNum()) {
            $cbInstaller = new cbInstallerPlugin();
            foreach ($plugins as $plug) {
                $result = $cbInstaller->checkDatabase($plug->id, true, $dryRun);
                if (is_bool($result)) {
                    CBDatabaseChecker::renderDatabaseResults($cbInstaller, true, $dryRun, $result, $messagesBefore, $messagesAfter, $dbName . ' "' . $plug->name . '"', $dbId, false);
                } elseif (is_string($result)) {
                    echo '<div class="form-group cb_form_line clearfix text-warning">' . $dbName . ' "' . $plug->name . '"' . ': ' . $result . '</div>';
                } else {
                    echo '<div class="form-group cb_form_line clearfix">' . sprintf(CBTxt::T('%s "%s": no database or no database description.'), $dbName, $plug->name) . '</div>';
                }
            }
        }
        $dbName = CBTxt::T('CB plugins');
    } elseif ($dbId == 3) {
        // adapt published fields to global CB config (regarding name type)
        _cbAdaptNameFieldsPublished($ueConfig);
        $_PLUGINS->loadPluginGroup('user');
        $messagesBefore = $_PLUGINS->trigger('onBeforeFixFieldsDb', array($dryRun));
        $strictcolumns = cbGetParam($_REQUEST, 'strictcolumns', 0) == 1;
        // Check fields db:
        cbimport('cb.dbchecker');
        $dbChecker = new CBDatabaseChecker();
        $result = $dbChecker->checkAllCBfieldsDb(true, $dryRun, $strictcolumns);
        $dbName = CBTxt::T('CB fields data storage');
        $messagesAfter = array();
        if ($strictcolumns) {
            $dbId = $dbId . '&strictcolumns=1';
        }
    } else {
        $dbName = CBTxt::T('DATABASE_CHECK_NO_DATABASE_SPECIFIED', 'No Database Specified');
        $result = $dbName;
        $messagesBefore = array();
        $messagesAfter = array();
    }
    _CBsecureAboveForm('fixcbdb');
    outputCbTemplate(2);
    outputCbJs(2);
    global $_CB_Backend_Title;
    $_CB_Backend_Title = array(0 => array('fa fa-wrench', sprintf(CBTxt::T("CB Tools: Fix %s database: "), $dbName) . ($dryRun ? CBTxt::T('Dry-run:') : CBTxt::T('Fixed:')) . " " . CBTXT::T("Results")));
    CBDatabaseChecker::renderDatabaseResults($dbChecker, true, $dryRun, $result, $messagesBefore, $messagesAfter, $dbName, $dbId);
}
 /**
  * Shows result of database check or fix (with or without dryrun)
  *
  * @param  DatabaseUpgrade|CBDatabaseChecker|cbInstallerPlugin  $dbChecker
  * @param  boolean                                              $upgrade
  * @param  boolean                                              $dryRun
  * @param  boolean                                              $result
  * @param  array                                                $messagesBefore
  * @param  array                                                $messagesAfter
  * @param  string                                               $dbName
  * @param  int                                                  $dbId
  * @param  boolean                                              $showConclusion
  */
 public static function renderDatabaseResults(&$dbChecker, $upgrade, $dryRun, $result, $messagesBefore, $messagesAfter, $dbName, $dbId, $showConclusion = true)
 {
     global $_CB_framework;
     static $JS_LOADED = 0;
     if (!$JS_LOADED++) {
         $js = "\$( '.cbDbResultsLogShow' ).on( 'click', function() {" . "\$( this ).addClass( 'hidden' );" . "\$( this ).siblings( '.cbDbResultsLogHide' ).removeClass( 'hidden' );" . "\$( this ).siblings( '.cbDbResultsLogMsgs' ).slideDown();" . "});" . "\$( '.cbDbResultsLogHide' ).on( 'click', function() {" . "\$( this ).addClass( 'hidden' );" . "\$( this ).siblings( '.cbDbResultsLogShow' ).removeClass( 'hidden' );" . "\$( this ).siblings( '.cbDbResultsLogMsgs' ).slideUp();" . "});" . "\$( '.cbDbResultsLogMsgs' ).hide();";
         $_CB_framework->outputCbJQuery($js);
     }
     $cbSpoofField = cbSpoofField();
     $cbSpoofString = cbSpoofString(null, 'plugin');
     $return = '<div class="cbDbResults">';
     if ($messagesBefore) {
         $return .= '<div class="form-group cb_form_line clearfix cbDbResultsMsgs">';
         foreach ($messagesBefore as $msg) {
             if ($msg) {
                 $return .= '<div class="cbDbResultsMsg">' . $msg . '</div>';
             }
         }
         $return .= '</div>';
     }
     if ($dbChecker !== null) {
         $return .= '<div class="form-group cb_form_line clearfix cbDbResultsCheck">';
         if ($result == true) {
             $return .= '<div class="text-success cbDbResultsSuccess">';
             if ($upgrade) {
                 if ($dryRun) {
                     $return .= CBTxt::T('NAME_DATABASE_ADJS_DRY_SUCCESS', '[name] database adjustments dryrun is successful. See results below.', array('[name]' => $dbName));
                 } else {
                     $return .= CBTxt::T('NAME_DATABASE_ADJS_SUCCESS', '[name] database adjustments have been performed successfully.', array('[name]' => $dbName));
                 }
             } else {
                 $return .= CBTxt::T('ALL_NAME_DATABASE_UPTODATE', 'All [name] database is up to date.', array('[name]' => $dbName));
             }
             $return .= '</div>';
         } elseif (is_string($result)) {
             $return .= '<div class="text-danger">' . $result . '</div>';
         } else {
             $return .= '<div class="text-danger cbDbResultsErrors">';
             if ($upgrade) {
                 $return .= CBTxt::T('NAME_DATABASE_ADJS_ERRORS', '[name] database adjustments errors:', array('[name]' => $dbName));
             } else {
                 $return .= CBTxt::T('NAME_DATABASE_STRUCT_DIFF', '[name] database structure differences:', array('[name]' => $dbName));
             }
             foreach ($dbChecker->getErrors(false) as $error) {
                 $return .= '<div class="text-large cbDbResultsError">' . htmlspecialchars($error[0]) . ($error[1] ? '<div class="text-small">' . htmlspecialchars($error[1]) . '</div>' : null) . '</div>';
             }
             $return .= '</div>';
             if (!$upgrade) {
                 $return .= '<div class="text-danger cbDbResultsErrorsFix">' . CBTxt::T('NAME_DATABASE_STRUCT_FIX', 'The [name] database structure differences can be fixed (adjusted) by clicking here:', array('[name]' => $dbName)) . ' <span class="alert alert-sm alert-danger text-large">' . '<a href="' . $_CB_framework->backendUrl("index.php?option=com_comprofiler&view=fixcbdb&dryrun=0&databaseid={$dbId}&{$cbSpoofField}={$cbSpoofString}") . '">' . CBTxt::T('NAME_DATABASE_DIFF_FIX_CLICK_HERE', 'Click here to fix (adjust) all [name] database differences listed above', array('[name]' => $dbName)) . '</a>' . '</span> ' . CBTxt::T('DATABASE_STRUCT_DRY_CLICK_HERE', '(you can also <a href="[url]">Click here to preview fixing (adjusting) queries in a dry-run</a>), but <strong class="text-large text-underline">in all cases you need to backup database first</strong> as this adjustment is changing the database structure to match the needed structure for the installed version.', array('[url]' => $_CB_framework->backendUrl("index.php?option=com_comprofiler&view=fixcbdb&dryrun=1&databaseid={$dbId}&{$cbSpoofField}={$cbSpoofString}"))) . '</div>';
             }
         }
         $logs = $dbChecker->getLogs(false);
         if (count($logs) > 0) {
             $return .= '<div class="cbDbResultsLog">' . '<a href="javascript:void(0);" class="cbDbResultsLogShow">' . CBTxt::T('Click here to show details') . ' <span class="fa fa-caret-down"></span></a>' . '<a href="javascript:void(0);" class="cbDbResultsLogHide hidden">' . CBTxt::T('Click here to hide details') . ' <span class="fa fa-caret-up"></span></a>' . '<div class="text-success cbDbResultsLogMsgs" style="display: none;">';
             foreach ($logs as $log) {
                 $return .= '<div class="text-large cbDbResultsLogMsg">' . htmlspecialchars($log[0]) . ($log[1] ? '<div class="text-small">' . htmlspecialchars($log[1]) . '</div>' : null) . '</div>';
             }
             $return .= '</div>' . '</div>';
         }
         $return .= '</div>';
     }
     if ($showConclusion) {
         if ($upgrade) {
             if ($dryRun) {
                 $return .= '<div class="form-group cb_form_line clearfix cbDbResultsConclusion">' . CBTxt::T('NAME_DATABASE_ADJS_DRY', 'Dry-run of [name] database adjustments done. None of the queries listed in details have been performed.', array('[name]' => $dbName)) . '<br />' . CBTxt::T('NAME_DATABASE_ADJS_FIX', 'The [name] database adjustments listed above can be applied by clicking here:', array('[name]' => $dbName)) . ' <span class="alert alert-sm alert-danger text-large">' . '<a href="' . $_CB_framework->backendUrl("index.php?option=com_comprofiler&view=fixcbdb&dryrun=0&databaseid={$dbId}&{$cbSpoofField}={$cbSpoofString}") . '">' . CBTxt::T('NAME_DATABASE_DIFF_FIX_CLICK_HERE', 'Click here to fix (adjust) all [name] database differences listed above', array('[name]' => $dbName)) . '</a>' . '</span> ' . CBTxt::T('DATABASE_FIX_BACKUP_FIRST', '<strong class="text-danger text-large text-underline">You need to backup database first</strong> as this fixing/adjusting is changing the database structure to match the needed structure for the installed version.') . '</div>';
             } else {
                 $return .= '<div class="form-group cb_form_line clearfix cbDbResultsConclusion">' . CBTxt::T('NAME_DATABASE_ADJS_DONE', 'The [name] database adjustments have been done. If all lines above are in green, database adjustments completed successfully. Otherwise, if some lines are red, please report exact errors and queries to authors forum, and try checking database again.', array('[name]' => $dbName)) . '<br />' . CBTxt::T('NAME_DATABASE_STRUCT_CHECK', 'The [name] database structure can be checked again by clicking here:', array('[name]' => $dbName)) . ' <span class="alert alert-sm alert-warning text-large">' . '<a href="' . $_CB_framework->backendUrl("index.php?option=com_comprofiler&view=checkcbdb&databaseid={$dbId}&{$cbSpoofField}={$cbSpoofString}") . '">' . CBTxt::T('NAME_DATABASE_DIFF_CHECK_CLICK_HERE', 'Click here to check [name] database', array('[name]' => $dbName)) . '</a>' . '</span> ' . '</div>';
             }
         } else {
             $return .= '<div class="form-group cb_form_line clearfix cbDbResultsConclusion">' . CBTxt::T('NAME_DATABASE_CHECKS_DONE', '[name] database checks done. If all lines above are in green, test completed successfully. Otherwise, please take corrective measures proposed in red.', array('[name]' => $dbName)) . '</div>';
         }
     }
     if ($messagesAfter) {
         $return .= '<div class="form-group cb_form_line clearfix cbDbResultsMsgs">';
         foreach ($messagesAfter as $msg) {
             if ($msg) {
                 $return .= '<div class="cbDbResultsMsg">' . $msg . '</div>';
             }
         }
         $return .= '</div>';
     }
     $return .= '</div>';
     echo $return;
 }