/**
  * Parse XML
  *
  * @param	string	location of XML
  */
 public function parse($xml)
 {
     print_dots_start('<b>' . $this->vbphrase['importing_product'] . "</b>, {$this->vbphrase[please_wait]}", ':', 'dspan');
     $this->xmlobj = new vB_XML_Parser($xml);
     if ($this->xmlobj->error_no() == 1) {
         print_dots_stop();
         throw new vB_Exception_AdminStopMessage('no_xml_and_no_path');
     }
     if (!($this->productobj = $this->xmlobj->parse())) {
         print_dots_stop();
         throw new vB_Exception_AdminStopMessage(array('xml_error_x_at_line_y', $this->xmlobj->error_string(), $this->xmlobj->error_line()));
     }
     // ############## general product information
     $this->productinfo['productid'] = substr(preg_replace('#[^a-z0-9_]#', '', strtolower($this->productobj['productid'])), 0, 25);
     $this->productinfo['title'] = $this->productobj['title'];
     $this->productinfo['description'] = $this->productobj['description'];
     $this->productinfo['version'] = $this->productobj['version'];
     $this->productinfo['active'] = $this->productobj['active'];
     $this->productinfo['url'] = $this->productobj['url'];
     $this->productinfo['versioncheckurl'] = $this->productobj['versioncheckurl'];
     if (!$this->productinfo['productid']) {
         print_dots_stop();
         if (!empty($this->productobj['plugin'])) {
             throw new vB_Exception_AdminStopMessage('this_file_appears_to_be_a_plugin');
         } else {
             throw new vB_Exception_AdminStopMessage('invalid_file_specified');
         }
     }
     if (strtolower($this->productinfo['productid']) == 'vbulletin') {
         print_dots_stop();
         throw new vB_Exception_AdminStopMessage(array('product_x_installed_no_overwrite', 'vBulletin'));
     }
     // check for bitfield conflicts on install
     $bitfields = vB_Bitfield_Builder::return_data();
     if (!$bitfields) {
         $bfobj =& vB_Bitfield_Builder::init();
         if ($bfobj->errors) {
             print_dots_stop();
             throw new vB_Exception_AdminStopMessage(array('bitfield_conflicts_x', '<li>' . implode('</li><li>', $bfobj->errors) . '</li>'));
         }
     }
     return true;
 }
 /**
  * Takes a the file name of an xml file, and parses it into an xml object
  *
  * @param	string - file name (including path) of the xml file
  *
  * @return	array - parsed xml object of the file
  */
 protected function parse_xml_from_file($filename)
 {
     $xmlobj = new vB_XML_Parser(false, $filename);
     if ($xmlobj->error_no() == 1 or $xmlobj->error_no() == 2) {
         $this->errors[] = "Please ensure that the file {$filename} exists";
         return false;
     }
     if (!($parsed_xml = $xmlobj->parse())) {
         $this->errors[] = 'xml error ' . $xmlobj->error_string() . ', on line ' . $xmlobj->error_line();
         return false;
     }
     return $parsed_xml;
 }
예제 #3
0
 public static function parseFile($filepath)
 {
     $xmlobj = new vB_XML_Parser(false, $filepath);
     if ($xmlobj->error_no() == 1 or $xmlobj->error_no() == 2) {
         throw new Exception("Please ensure that the file {$filepath} exists");
     }
     if (!($parsed_xml = $xmlobj->parse())) {
         throw new Exception('xml error ' . $xmlobj->error_string() . ', on line ' . $xmlobj->error_line());
     }
     return $parsed_xml;
 }
/**
* Imports a language from a language XML file
*
* @param	string	XML language string
* @param	integer	Language to overwrite
* @param	string	Override title for imported language
* @param	boolean	Allow import of language from mismatched vBulletin version
* @param	boolean	Allow user-select of imported language
* @param	boolean	Echo output..
* @param	boolean	Read charset from XML header
*
* @return	Returns false if the custom language was not imported (used in final_upgrade) OR
*			returns the languageid if, if the custom language import was successful (also used in final_upgrade)
*/
function xml_import_language($xml = false, $languageid = -1, $title = '', $anyversion = false, $userselect = true, $output = true, $readcharset = false)
{
    global $vbulletin, $vbphrase;
    print_dots_start('<b>' . $vbphrase['importing_language'] . "</b>, {$vbphrase['please_wait']}", ':', 'dspan');
    require_once DIR . '/includes/class_xml.php';
    require_once DIR . '/includes/functions_misc.php';
    $xmlobj = new vB_XML_Parser($xml, $GLOBALS['path'], $readcharset);
    if ($xmlobj->error_no() == 1) {
        print_dots_stop();
        print_stop_message2('no_xml_and_no_path');
    } else {
        if ($xmlobj->error_no() == 2) {
            print_dots_stop();
            print_stop_message('please_ensure_x_file_is_located_at_y', 'vbulletin-language.xml', $GLOBALS['path']);
        }
    }
    if (!($arr =& $xmlobj->parse())) {
        print_dots_stop();
        print_stop_message('xml_error_x_at_line_y', $xmlobj->error_string(), $xmlobj->error_line());
    }
    if (!$arr['phrasetype']) {
        print_dots_stop();
        print_stop_message2('invalid_file_specified');
    }
    $title = empty($title) ? $arr['name'] : $title;
    $version = $arr['vbversion'];
    $master = $arr['type'] == 'master' ? 1 : 0;
    $just_phrases = $arr['type'] == 'phrases' ? 1 : 0;
    if (!empty($arr['settings'])) {
        $langinfo = $arr['settings'];
    }
    $officialcustom = false;
    //Check custom language revision. See also VBV-9215.
    if (!$master and $arr['product'] == 'vbulletin' and !empty($arr['revision']) and !empty($arr['vblangcode'])) {
        $test = $vbulletin->db->query_first("SELECT * FROM " . TABLE_PREFIX . "language WHERE vblangcode = '" . $vbulletin->db->escape_string($arr['vblangcode']) . "'");
        if ($test['languageid']) {
            if (intval($test['revision']) >= intval($arr['revision'])) {
                // Same or newer language revision has been installed
                // We shouldn't print_stop_message() as the upgrader may continue processing other custom languages
                return false;
            }
            $languageid = $test['languageid'];
        }
        $langinfo['revision'] = intval($arr['revision']);
        $langinfo['vblangcode'] = trim($arr['vblangcode']);
        $officialcustom = true;
    } else {
        $langinfo['revision'] = 0;
        $langinfo['vblangcode'] = '';
    }
    $langinfo['product'] = empty($arr['product']) ? 'vbulletin' : $arr['product'];
    // look for skipped groups
    $skipped_groups = array();
    if (!empty($arr['skippedgroups'])) {
        $skippedgroups =& $arr['skippedgroups']['skippedgroup'];
        if (!is_array($skippedgroups)) {
            $skippedgroups = array($skippedgroups);
        }
        foreach ($skippedgroups as $skipped) {
            if (is_array($skipped)) {
                $skipped_groups[] = $vbulletin->db->escape_string($skipped['value']);
            } else {
                $skipped_groups[] = $vbulletin->db->escape_string($skipped);
            }
        }
    }
    if ($skipped_groups) {
        $sql_skipped = "AND " . TABLE_PREFIX . "phrase.fieldname NOT IN ('" . implode("', '", $skipped_groups) . "')";
    } else {
        $sql_skipped = '';
    }
    foreach ($langinfo as $key => $val) {
        $langinfo["{$key}"] = $vbulletin->db->escape_string(trim($val));
    }
    $langinfo['options'] = intval($langinfo['options']);
    $langinfo['revision'] = intval($langinfo['revision']);
    if ($version != $vbulletin->options['templateversion'] and !$master) {
        if (strtok($version, '.') != strtok($vbulletin->options['templateversion'], '.')) {
            print_dots_stop();
            print_stop_message('upload_file_created_with_different_major_version', $vbulletin->options['templateversion'], $version);
        }
        if (!$anyversion) {
            print_dots_stop();
            print_stop_message('upload_file_created_with_different_version', $vbulletin->options['templateversion'], $version);
        }
    }
    //set up the phrase array
    $arr = $arr['phrasetype'];
    if (!is_array($arr[0])) {
        $arr = array($arr);
    }
    // check if we need to convert the phrases to the current board's charset.
    $convertPhrases = false;
    $boardCharset = strtolower(vB_Template_Runtime::fetchStyleVar('charset'));
    $phrasesCharset = isset($langinfo['charset']) ? strtolower($langinfo['charset']) : $boardCharset;
    if (!empty($boardCharset) and $boardCharset != $phrasesCharset) {
        $convertPhrases = true;
        $langinfo['charset'] = $boardCharset;
        // since we're converting the phrases to the board charset, make sure the inserted language uses the board's charset & informs the browser correctly.
    }
    //spin through the phrases to check validity.  We want to do this *before* we prep for import
    //so that if we abort do to an error, we haven't made any changes first
    foreach (array_keys($arr) as $key) {
        $phraseTypes =& $arr["{$key}"];
        if (is_array($phraseTypes['phrase'])) {
            foreach ($phraseTypes['phrase'] as $key2 => $phrase) {
                if (is_array($phrase)) {
                    $check = $phrase['value'];
                } else {
                    $check = $phrase;
                }
                if ($convertPhrases) {
                    // convert it from the language file's encoding to the board's encoding
                    $check = vB_String::toCharset($check, $phrasesCharset, $boardCharset);
                    if (is_array($phrase)) {
                        $arr[$key]['phrase'][$key2]['value'] = $check;
                    } else {
                        $arr[$key]['phrase'][$key2] = $check;
                    }
                }
                if (!validate_string_for_interpolation($check)) {
                    print_dots_stop();
                    print_stop_message2(array('phrase_text_not_safe', $phrase['name']));
                }
            }
        }
    }
    // prepare for import
    if ($master) {
        // lets stop it from dieing cause someone borked a previous update
        $vbulletin->db->query_write("DELETE FROM " . TABLE_PREFIX . "phrase WHERE languageid = -10");
        // master style
        if ($output and VB_AREA != 'Install' and VB_AREA != 'Upgrade') {
            echo "<h3>{$vbphrase['master_language']}</h3>\n<p>{$vbphrase['please_wait']}</p>";
            vbflush();
        }
        $vbulletin->db->query_write("\n\t\t\tUPDATE " . TABLE_PREFIX . "phrase SET\n\t\t\t\tlanguageid = -10\n\t\t\tWHERE languageid = -1\n\t\t\t\tAND (product = '" . $vbulletin->db->escape_string($langinfo['product']) . "'" . iif($langinfo['product'] == 'vbulletin', " OR product = ''") . ")\n\t\t\t\t{$sql_skipped}\n\t\t");
        $languageid = -1;
    } else {
        if ($languageid == 0) {
            // creating a new language
            if ($just_phrases) {
                print_dots_stop();
                print_stop_message2(array('language_only_phrases', $title));
            } else {
                if ($test = $vbulletin->db->query_first("SELECT languageid FROM " . TABLE_PREFIX . "language WHERE title = '" . $vbulletin->db->escape_string($title) . "'")) {
                    if ($officialcustom) {
                        // Rename the old language
                        $vbulletin->db->query_write("UPDATE " . TABLE_PREFIX . "language SET title = CONCAT(title, '_old') WHERE title = '" . $vbulletin->db->escape_string($title) . "' AND languagecode");
                    } else {
                        print_dots_stop();
                        print_stop_message2(array('language_already_exists', $title));
                    }
                }
            }
            if ($output and VB_AREA != 'Install' and VB_AREA != 'Upgrade') {
                echo "<h3><b>" . construct_phrase($vbphrase['creating_a_new_language_called_x'], $title) . "</b></h3>\n<p>{$vbphrase['please_wait']}</p>";
                vbflush();
            }
            /*insert query*/
            $vbulletin->db->query_write("\n\t\t\t\tINSERT INTO " . TABLE_PREFIX . "language (\n\t\t\t\t\ttitle, options, languagecode, charset, revision, vblangcode,\n\t\t\t\t\tdateoverride, timeoverride, decimalsep, thousandsep,\n\t\t\t\t\tregistereddateoverride, calformat1override, calformat2override, locale, logdateoverride\n\t\t\t\t) VALUES (\n\t\t\t\t\t'" . $vbulletin->db->escape_string($title) . "', {$langinfo['options']}, '{$langinfo['languagecode']}', '{$langinfo['charset']}', {$langinfo['revision']}, '" . $vbulletin->db->escape_string($langinfo['vblangcode']) . "',\n\t\t\t\t\t'{$langinfo['dateoverride']}', '{$langinfo['timeoverride']}', '{$langinfo['decimalsep']}', '{$langinfo['thousandsep']}',\n\t\t\t\t\t'{$langinfo['registereddateoverride']}', '{$langinfo['calformat1override']}', '{$langinfo['calformat2override']}', '{$langinfo['locale']}', '{$langinfo['logdateoverride']}'\n\t\t\t\t)\n\t\t\t");
            $languageid = $vbulletin->db->insert_id();
        } else {
            // overwriting an existing language
            if ($getlanguage = $vbulletin->db->query_first("SELECT title FROM " . TABLE_PREFIX . "language WHERE languageid = {$languageid}")) {
                if (!$just_phrases) {
                    if ($output and VB_AREA != 'Install' and VB_AREA != 'Upgrade') {
                        echo "<h3><b>" . construct_phrase($vbphrase['overwriting_language_x'], $getlanguage['title']) . "</b></h3>\n<p>{$vbphrase['please_wait']}</p>";
                        vbflush();
                    }
                    $vbulletin->db->query_write("\n\t\t\t\t\t\tUPDATE " . TABLE_PREFIX . "language SET\n\t\t\t\t\t\t\toptions = {$langinfo['options']},\n\t\t\t\t\t\t\tlanguagecode = '{$langinfo['languagecode']}',\n\t\t\t\t\t\t\tcharset = '{$langinfo['charset']}',\n\t\t\t\t\t\t\tlocale = '{$langinfo['locale']}',\n\t\t\t\t\t\t\timagesoverride = '{$langinfo['imagesoverride']}',\n\t\t\t\t\t\t\tdateoverride = '{$langinfo['dateoverride']}',\n\t\t\t\t\t\t\ttimeoverride = '{$langinfo['timeoverride']}',\n\t\t\t\t\t\t\tdecimalsep = '{$langinfo['decimalsep']}',\n\t\t\t\t\t\t\tthousandsep = '{$langinfo['thousandsep']}',\n\t\t\t\t\t\t\tregistereddateoverride = '{$langinfo['registereddateoverride']}',\n\t\t\t\t\t\t\tcalformat1override = '{$langinfo['calformat1override']}',\n\t\t\t\t\t\t\tcalformat2override = '{$langinfo['calformat2override']}',\n\t\t\t\t\t\t\tlogdateoverride = '{$langinfo['logdateoverride']}',\n\t\t\t\t\t\t\trevision = {$langinfo['revision']}\n\t\t\t\t\t\tWHERE languageid = {$languageid}\n\t\t\t\t\t");
                    $vbulletin->db->query_write("\n\t\t\t\t\t\tUPDATE " . TABLE_PREFIX . "phrase, " . TABLE_PREFIX . "phrase AS phrase2\n\t\t\t\t\t\tSET " . TABLE_PREFIX . "phrase.languageid = -11\n\t\t\t\t\t\tWHERE " . TABLE_PREFIX . "phrase.languageid = {$languageid}\n\t\t\t\t\t\t\tAND (" . TABLE_PREFIX . "phrase.product = '" . $vbulletin->db->escape_string($langinfo['product']) . "'" . iif($langinfo['product'] == 'vbulletin', " OR " . TABLE_PREFIX . "phrase.product = ''") . ")\n\t\t\t\t\t\t\tAND (phrase2.product = '" . $vbulletin->db->escape_string($langinfo['product']) . "'" . iif($langinfo['product'] == 'vbulletin', " OR phrase2.product = ''") . ")\n\t\t\t\t\t\t\tAND " . TABLE_PREFIX . "phrase.varname = phrase2.varname\n\t\t\t\t\t\t\tAND phrase2.languageid = 0\n\t\t\t\t\t\t\tAND " . TABLE_PREFIX . "phrase.fieldname = phrase2.fieldname\n\t\t\t\t\t\t\t{$sql_skipped}\n\t\t\t\t\t");
                    $vbulletin->db->query_write("\n\t\t\t\t\t\tUPDATE " . TABLE_PREFIX . "phrase SET\n\t\t\t\t\t\t\tlanguageid = -10\n\t\t\t\t\t\tWHERE languageid = {$languageid}\n\t\t\t\t\t\t\tAND (product = '" . $vbulletin->db->escape_string($langinfo['product']) . "'" . iif($langinfo['product'] == 'vbulletin', " OR product = ''") . ")\n\t\t\t\t\t\t\t{$sql_skipped}\n\t\t\t\t\t");
                }
            } else {
                print_stop_message2('cant_overwrite_non_existent_language');
            }
        }
    }
    // get current phrase types
    $current_phrasetypes = fetch_phrasetypes_array(false);
    if (!$master) {
        $globalPhrases = array();
        $getphrases = $vbulletin->db->query_read("\n\t\t\tSELECT varname, fieldname\n\t\t\tFROM " . TABLE_PREFIX . "phrase\n\t\t\tWHERE languageid IN (0, -1)\n\t\t");
        while ($getphrase = $vbulletin->db->fetch_array($getphrases)) {
            $globalPhrases["{$getphrase['varname']}~{$getphrase['fieldname']}"] = true;
        }
    }
    // import language
    // track new phrasetypes
    $new_phrasetypes = array();
    foreach (array_keys($arr) as $key) {
        $phraseTypes =& $arr["{$key}"];
        $sql = array();
        $strlen = 0;
        if ($phraseTypes['fieldname'] == '' or !preg_match('#^[a-z0-9_]+$#i', $phraseTypes['fieldname'])) {
            continue;
        }
        $fieldname = $phraseTypes['fieldname'];
        if (!is_array($phraseTypes['phrase'][0])) {
            $phraseTypes['phrase'] = array($phraseTypes['phrase']);
        }
        // check if the phrasetype is new
        if (!isset($current_phrasetypes[$fieldname]) and !empty($phraseTypes['phrase'])) {
            $new_phrasetypes[] = array('fieldname' => $fieldname, 'title' => $phraseTypes['name']);
        }
        // Send some output to the browser inside this loop so certain hosts
        // don't artificially kill the script. See bug #34585
        if ($output) {
            echo ' ';
            vbflush();
        }
        foreach ($phraseTypes['phrase'] as $phrase) {
            if ($master) {
                $insertLanguageId = -1;
            } else {
                if (!isset($globalPhrases["{$phrase['name']}~{$fieldname}"])) {
                    $insertLanguageId = 0;
                } else {
                    if ($phrase['custom']) {
                        // this is a custom phrase (language 0) -- we don't want it to end up in the custom language
                        continue;
                    } else {
                        $insertLanguageId = $languageid;
                    }
                }
            }
            $sql[] = "\n\t\t\t\t({$insertLanguageId},\n\t\t\t\t'" . $vbulletin->db->escape_string($fieldname) . "',\n\t\t\t\t'" . $vbulletin->db->escape_string($phrase['name']) . "',\n\t\t\t\t'" . $vbulletin->db->escape_string($phrase['value']) . "',\n\t\t\t\t'" . $vbulletin->db->escape_string($langinfo['product']) . "',\n\t\t\t\t'" . $vbulletin->db->escape_string($phrase['username']) . "',\n\t\t\t\t" . intval($phrase['date']) . ",\n\t\t\t\t'" . $vbulletin->db->escape_string($phrase['version']) . "')\n\t\t\t";
            $strlen += strlen(end($sql));
            if ($strlen > 102400) {
                // insert max of 100k of phrases at a time
                /*insert query*/
                $vbulletin->db->query_write("\n\t\t\t\t\tREPLACE INTO " . TABLE_PREFIX . "phrase\n\t\t\t\t\t\t(languageid, fieldname, varname, text, product, username, dateline, version)\n\t\t\t\t\tVALUES\n\t\t\t\t\t\t" . implode(",\n", $sql));
                $sql = array();
                $strlen = 0;
            }
            // Send some output to the browser inside this loop so certain hosts
            // don't artificially kill the script. See bug #34585
            if ($output) {
                echo ' ';
                vbflush();
            }
        }
        if ($sql) {
            /*insert query*/
            $vbulletin->db->query_write("\n\t\t\t\tREPLACE INTO " . TABLE_PREFIX . "phrase\n\t\t\t\t\t(languageid, fieldname, varname, text, product, username, dateline, version)\n\t\t\t\tVALUES\n\t\t\t\t\t" . implode(",\n", $sql));
        }
        unset($arr["{$key}"], $phraseTypes);
    }
    unset($sql, $arr, $current_phrasetypes);
    // insert any new phrasetypes
    foreach ($new_phrasetypes as $phrasetype) {
        add_phrase_type($phrasetype['fieldname'], $phrasetype['title'], $langinfo['product']);
    }
    $vbulletin->db->query_write("\n\t\tUPDATE IGNORE " . TABLE_PREFIX . "phrase\n\t\tSET " . TABLE_PREFIX . "phrase.languageid = {$languageid}\n\t\tWHERE " . TABLE_PREFIX . "phrase.languageid = -11\n\t\t\tAND (" . TABLE_PREFIX . "phrase.product = '" . $vbulletin->db->escape_string($langinfo['product']) . "'" . iif($langinfo['product'] == 'vbulletin', " OR " . TABLE_PREFIX . "phrase.product = ''") . ")\n\t\t\t{$sql_skipped}\n\t");
    // now delete any phrases that were moved into the temporary language for safe-keeping
    $vbulletin->db->query_write("\n\t\tDELETE FROM " . TABLE_PREFIX . "phrase\n\t\tWHERE languageid IN (-10, -11)\n\t\t\tAND (product = '" . $vbulletin->db->escape_string($langinfo['product']) . "'" . iif($langinfo['product'] == 'vbulletin', " OR product = ''") . ")\n\t\t\t{$sql_skipped}\n\t");
    vB_Api::instanceInternal('phrase')->setPhraseDate();
    print_dots_stop();
    return $languageid;
}
/**
* Restores a settings backup from an XML file
*
* Call as follows:
* $path = './path/to/install/vbulletin-settings.xml';
* xml_import_settings($xml);
*
* @param	mixed	Either XML string or boolean false to use $path global variable
* @param bool	Ignore blacklisted settings
*/
function xml_restore_settings($xml = false, $blacklist = true)
{
    $newsettings = array();
    $vbphrase = vB_Api::instanceInternal('phrase')->fetch(array('please_wait', 'importing_settings'));
    print_dots_start('<b>' . $vbphrase['importing_settings'] . "</b>, {$vbphrase['please_wait']}", ':', 'dspan');
    require_once DIR . '/includes/class_xml.php';
    $xmlobj = new vB_XML_Parser($xml, $GLOBALS['path']);
    if ($xmlobj->error_no() == 1) {
        print_dots_stop();
        print_stop_message2('no_xml_and_no_path');
    } else {
        if ($xmlobj->error_no() == 2) {
            print_dots_stop();
            print_stop_message('please_ensure_x_file_is_located_at_y', 'vbulletin-settings.xml', $GLOBALS['path']);
        }
    }
    if (!($newsettings = $xmlobj->parse())) {
        print_dots_stop();
        print_stop_message('xml_error_x_at_line_y', $xmlobj->error_string(), $xmlobj->error_line());
    }
    if (!$newsettings['setting']) {
        print_dots_stop();
        print_stop_message2('invalid_file_specified');
    }
    $product = empty($newsettings['product']) ? 'vbulletin' : $newsettings['product'];
    foreach ($newsettings['setting'] as $setting) {
        // Loop to update all the settings
        $conditions = array(array('field' => 'varname', 'value' => $setting['varname'], 'operator' => vB_dB_Query::OPERATOR_EQ), array('field' => 'product', 'value' => $product, 'operator' => vB_dB_Query::OPERATOR_EQ));
        if ($blacklist) {
            $conditions[] = array('field' => 'blacklist', 'value' => 0, 'operator' => vB_dB_Query::OPERATOR_EQ);
        }
        vB::getDbAssertor()->assertQuery('setting', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_UPDATE, 'value' => $setting['value'], vB_dB_Query::CONDITIONS_KEY => $conditions));
    }
    unset($newsettings);
    // rebuild the options array
    vB::getDatastore()->build_options();
    // stop the 'dots' counter feedback
    print_dots_stop();
}
/**
* Installs a product from the xml text
*
* This function depends on the vb class loader, which requires that the
* framework init is called.
*
* @return bool True if the product requires a template merge, false otherwise
*/
function install_product($xml, $allow_overwrite = false, $verbose = true)
{
    global $vbphrase;
    global $vbulletin;
    $assertor = vB::getDbAssertor();
    require_once DIR . '/includes/class_bitfield_builder.php';
    require_once DIR . '/includes/class_xml.php';
    //share some code with the main xml style import
    require_once DIR . '/includes/adminfunctions_template.php';
    if ($verbose) {
        print_dots_start('<b>' . $vbphrase['importing_product'] . "</b>, {$vbphrase['please_wait']}", ':', 'dspan');
    }
    $xmlobj = new vB_XML_Parser($xml);
    if ($xmlobj->error_no() == 1) {
        if ($verbose) {
            print_dots_stop();
        }
        throw new vB_Exception_AdminStopMessage('no_xml_and_no_path');
    }
    if (!($arr = $xmlobj->parse())) {
        if ($verbose) {
            print_dots_stop();
        }
        throw new vB_Exception_AdminStopMessage(array('xml_error_x_at_line_y', $xmlobj->error_string(), $xmlobj->error_line()));
    }
    // ############## general product information
    $info = array('productid' => substr(preg_replace('#[^a-z0-9_]#', '', strtolower($arr['productid'])), 0, 25), 'title' => $arr['title'], 'description' => $arr['description'], 'version' => $arr['version'], 'active' => $arr['active'], 'url' => $arr['url'], 'versioncheckurl' => $arr['versioncheckurl']);
    if (!$info['productid']) {
        if ($verbose) {
            print_dots_stop();
        }
        throw new vB_Exception_AdminStopMessage('invalid_file_specified');
    }
    if (strtolower($info['productid']) == 'vbulletin') {
        if ($verbose) {
            print_dots_stop();
        }
        throw new vB_Exception_AdminStopMessage(array('product_x_installed_no_overwrite', 'vBulletin'));
    }
    // check for bitfield conflicts on install
    $bitfields = vB_Bitfield_Builder::return_data();
    if (!$bitfields) {
        $bfobj =& vB_Bitfield_Builder::init();
        if ($bfobj->errors) {
            if ($verbose) {
                print_dots_stop();
            }
            throw new vB_Exception_AdminStopMessage(array('bitfield_conflicts_x', '<li>' . implode('</li><li>', $bfobj->errors) . '</li>'));
        }
    }
    // get system version info
    $system_versions = array('php' => PHP_VERSION, 'vbulletin' => $vbulletin->options['templateversion'], 'products' => fetch_product_list(true));
    $mysql_version = $assertor->getRow('mysqlVersion');
    $system_versions['mysql'] = $mysql_version['version'];
    // ############## import dependencies
    if (isset($arr['dependencies']['dependency']) and is_array($arr['dependencies']['dependency'])) {
        $dependencies =& $arr['dependencies']['dependency'];
        if (!isset($dependencies[0])) {
            $dependencies = array($dependencies);
        }
        $dependency_errors = array();
        $ignore_dependency_errors = array();
        // let's check the dependencies
        foreach ($dependencies as $dependency) {
            // if we get an error, we haven't met this dependency
            // if we go through without a problem, we have automatically met
            // all dependencies for this "class" (mysql, php, vb, a specific product, etc)
            $this_dependency_met = true;
            // build a phrase for the version compats -- will look like (minver / maxver)
            if ($dependency['minversion']) {
                $compatible_phrase = construct_phrase($vbphrase['compatible_starting_with_x'], htmlspecialchars_uni($dependency['minversion']));
            } else {
                $compatible_phrase = '';
            }
            if ($dependency['maxversion']) {
                $incompatible_phrase = construct_phrase($vbphrase['incompatible_with_x_and_greater'], htmlspecialchars_uni($dependency['maxversion']));
            } else {
                $incompatible_phrase = '';
            }
            if ($compatible_phrase or $incompatible_phrase) {
                $required_version_info = "({$compatible_phrase}";
                if ($compatible_phrase and $incompatible_phrase) {
                    $required_version_info .= ' / ';
                }
                $required_version_info .= "{$incompatible_phrase})";
            }
            // grab the appropriate installed version string
            if ($dependency['dependencytype'] == 'product') {
                // group dependencies into types -- individual products get their own group
                $dependency_type_key = "product-{$dependency['parentproductid']}";
                // undocumented feature -- you can put a producttitle attribute in a dependency so the id isn't displayed
                $parent_product_title = !empty($dependency['producttitle']) ? $dependency['producttitle'] : $dependency['parentproductid'];
                $parent_product = $system_versions['products']["{$dependency['parentproductid']}"];
                if (!$parent_product) {
                    // required product is not installed
                    $dependency_errors["{$dependency_type_key}"] = construct_phrase($vbphrase['product_x_must_be_installed'], htmlspecialchars_uni($parent_product_title), $required_version_info);
                    continue;
                    // can't do version checks if the product isn't installed
                } else {
                    if ($parent_product['active'] == 0) {
                        // product is installed, but inactive
                        $dependency_errors["{$dependency_type_key}-inactive"] = construct_phrase($vbphrase['product_x_must_be_activated'], htmlspecialchars_uni($parent_product_title));
                        $this_dependency_met = false;
                        // allow version checks to continue
                    }
                }
                $sys_version_str = $parent_product['version'];
                $version_incompatible_phrase = 'product_incompatible_version_x_product_y';
            } else {
                $dependency_type_key = $dependency['dependencytype'];
                $parent_product_title = '';
                $sys_version_str = $system_versions["{$dependency['dependencytype']}"];
                $version_incompatible_phrase = 'product_incompatible_version_x_' . $dependency['dependencytype'];
            }
            // if no version string, we are trying to do an unsupported dep check
            if ($sys_version_str == '') {
                continue;
            }
            $sys_version = fetch_version_array($sys_version_str);
            // error if installed version < minversion
            if ($dependency['minversion']) {
                $dep_version = fetch_version_array($dependency['minversion']);
                for ($i = 0; $i <= 5; $i++) {
                    if ($sys_version["{$i}"] < $dep_version["{$i}"]) {
                        // installed version is too old
                        $dependency_errors["{$dependency_type_key}"] = construct_phrase($vbphrase["{$version_incompatible_phrase}"], htmlspecialchars_uni($sys_version_str), $required_version_info, $parent_product_title);
                        $this_dependency_met = false;
                        break;
                    } else {
                        if ($sys_version["{$i}"] > $dep_version["{$i}"]) {
                            break;
                        }
                    }
                }
            }
            // error if installed version >= maxversion
            if ($dependency['maxversion']) {
                $dep_version = fetch_version_array($dependency['maxversion']);
                $all_equal = true;
                for ($i = 0; $i <= 5; $i++) {
                    if ($sys_version["{$i}"] > $dep_version["{$i}"]) {
                        // installed version is newer than the maxversion
                        $dependency_errors["{$dependency_type_key}"] = construct_phrase($vbphrase["{$version_incompatible_phrase}"], htmlspecialchars_uni($sys_version_str), $required_version_info, $parent_product_title);
                        $this_dependency_met = false;
                        break;
                    } else {
                        if ($sys_version["{$i}"] < $dep_version["{$i}"]) {
                            // not every part is the same and since we've got less we can exit
                            $all_equal = false;
                            break;
                        } else {
                            if ($sys_version["{$i}"] != $dep_version["{$i}"]) {
                                // not every part is the same
                                $all_equal = false;
                            }
                        }
                    }
                }
                if ($all_equal == true) {
                    // installed version is same as the max version, which is the first incompat version
                    $dependency_errors["{$dependency_type_key}"] = construct_phrase($vbphrase["{$version_incompatible_phrase}"], htmlspecialchars_uni($sys_version_str), $required_version_info, $parent_product_title);
                    $this_dependency_met = false;
                }
            }
            if ($this_dependency_met) {
                // we met 1 dependency for this type -- this emulates or'ing together groups
                $ignore_dependency_errors["{$dependency_type_key}"] = true;
            }
        }
        // for any group we met a dependency for, ignore any errors we might
        // have gotten for the group
        foreach ($ignore_dependency_errors as $dependency_type_key => $devnull) {
            unset($dependency_errors["{$dependency_type_key}"]);
        }
        if ($dependency_errors) {
            $dependency_errors = array_unique($dependency_errors);
            $dependency_errors = '<ol><li>' . implode('</li><li>', $dependency_errors) . '</li></ol>';
            if ($verbose) {
                print_dots_stop();
            }
            throw new vB_Exception_AdminStopMessage(array('dependencies_not_met_x', $dependency_errors));
        }
    }
    // look to see if we already have this product installed
    if ($existingprod = $assertor->getRow('product', array('productid' => $info['productid']))) {
        if (!$allow_overwrite) {
            if ($verbose) {
                print_dots_stop();
            }
            throw new vB_Exception_AdminStopMessage(array('product_x_installed_no_overwrite', $info['title']));
        }
        $active = $existingprod['active'];
        // not sure what we're deleting, so rebuild everything
        $rebuild = array('templates' => true, 'hooks' => true, 'phrases' => true, 'options' => true, 'cron' => true);
        $installed_version = $existingprod['version'];
    } else {
        $active = $info['active'] ? 1 : 0;
        $rebuild = array('templates' => false, 'hooks' => false, 'phrases' => false, 'options' => false, 'cron' => false);
        $installed_version = null;
    }
    // ############## import install/uninstall code
    if (isset($arr['codes']['code']) and is_array($arr['codes']['code'])) {
        $codes =& $arr['codes']['code'];
        if (!isset($codes[0])) {
            $codes = array($codes);
        }
        // run each of the codes
        foreach ($codes as $code) {
            // Run if: code version is * (meaning always run), no version
            //		previously installed, or if the code is for a newer version
            //		than is currently installed
            if ($code['version'] == '*' or $installed_version === null or is_newer_version($code['version'], $installed_version)) {
                eval($code['installcode']);
            }
        }
        // Clear routes from datastore
        build_datastore('routes', serialize(array()), 1);
        //assume that the product may have installed content types and purge the content type cache
        vB_Cache::instance()->purge('vb_types.types');
    }
    // dependencies checked, install code run. Now clear out the old product info;
    // settings should be retained in memory already
    delete_product($info['productid'], false, true);
    if (is_array($codes)) {
        // we've now run all the codes, if execution is still going
        // then it's going to complete fully, so insert the codes
        $productCodes = array();
        foreach ($codes as $code) {
            /* insert query */
            $productCodes[] = array('productid' => $info['productid'], 'version' => $code['version'], 'installcode' => $code['installcode'], 'uninstallcode' => $code['uninstallcode']);
        }
        $assertor->insertMultiple('productcode', array('productid', 'version', 'installcode', 'uninstallcode'), $productCodes);
    }
    if (is_array($dependencies)) {
        // dependencies met, codes run -- now we can insert the dependencies into the DB
        $productDependencies = array();
        foreach ($dependencies as $dependency) {
            /* insert query */
            $productDependencies[] = array('productid' => $info['productid'], 'dependencytype' => $dependency['dependencytype'], 'parentproductid' => $dependency['parentproductid'], 'minversion' => $dependency['minversion'], 'maxversion' => $dependency['maxversion']);
        }
        $assertor->insertMultiple('productdependency', array('productid', 'dependencytype', 'parentproductid', 'minversion', 'maxversion'), $productDependencies);
    }
    /* insert query */
    $assertor->insert('product', array('productid' => $info['productid'], 'title' => $info['title'], 'description' => $info['description'], 'version' => $info['version'], 'active' => intval($active), 'url' => $info['url'], 'versioncheckurl' => $info['versioncheckurl']));
    // ############## import templates
    if (isset($arr['templates']['template']) and is_array($arr['templates']['template'])) {
        $querybits = array();
        $querytemplates = 0;
        $templates =& $arr['templates']['template'];
        if (!isset($templates[0])) {
            $templates = array($templates);
        }
        foreach ($templates as $template) {
            $title = $template['name'];
            $template['template'] = $template['value'];
            $template['username'] = $template['username'];
            $template['templatetype'] = $template['templatetype'];
            $template['date'] = intval($template['date']);
            if ($template['templatetype'] != 'template') {
                // template is a special template
                $querybits[] = array('styleid' => -1, 'templatetype' => $template['templatetype'], 'title' => $title, 'template' => $template['template'], 'template_un' => '', 'dateline' => $template['date'], 'username' => $template['username'], 'version' => $template['version'], 'product' => $info['productid']);
            } else {
                // template is a standard template
                $querybits[] = array('styleid' => -1, 'templatetype' => $template['templatetype'], 'title' => $title, 'template' => compile_template($template['value']), 'template_un' => $template['template'], 'dateline' => $template['date'], 'username' => $template['username'], 'version' => $template['version'], 'product' => $info['productid']);
            }
            if (++$querytemplates % 20 == 0) {
                /*insert query*/
                $assertor->assertQuery('replaceValues', array('values' => $querybits, 'table' => 'template'));
                $querybits = array();
            }
            // Send some output to the browser inside this loop so certain hosts
            // don't artificially kill the script. See bug #34585
            if (VB_AREA != 'Upgrade' and VB_AREA != 'Install') {
                echo ' ';
                vbflush();
            }
        }
        // insert any remaining templates
        if (!empty($querybits)) {
            /*insert query*/
            $assertor->assertQuery('replaceValues', array('values' => $querybits, 'table' => 'template'));
        }
        unset($querybits);
        $rebuild['templates'] = true;
    }
    // ############## import stylevars
    if (isset($arr['stylevardfns']['stylevargroup']) and is_array($arr['stylevardfns']['stylevargroup'])) {
        xml_import_stylevar_definitions($arr['stylevardfns'], $info['productid']);
    }
    if (!empty($arr['stylevars']) and is_array($arr['stylevars']) and is_array($arr['stylevars']['stylevar'])) {
        xml_import_stylevars($arr['stylevars'], -1);
    }
    // ############## import hooks
    if (isset($arr['hooks']['hook']) and is_array($arr['hooks']['hook'])) {
        $hooks =& $arr['hooks']['hook'];
        if (!isset($hooks[0])) {
            $hooks = array($hooks);
        }
        foreach ($hooks as $hook) {
            $hook['product'] = $info['productid'];
            $assertor->insert('hook', $hook);
        }
        $rebuild['hooks'] = true;
    }
    // ############## import phrases
    if (isset($arr['phrases']['phrasetype']) and is_array($arr['phrases']['phrasetype'])) {
        require_once DIR . '/includes/adminfunctions_language.php';
        $master_phrasetypes = array();
        $master_phrasefields = array();
        foreach (vB_Api::instanceInternal('phrase')->fetch_phrasetypes(false) as $phrasetype) {
            $master_phrasefields["{$phrasetype['fieldname']}"] = true;
        }
        $phrasetypes =& $arr['phrases']['phrasetype'];
        if (!isset($phrasetypes[0])) {
            $phrasetypes = array($phrasetypes);
        }
        foreach ($phrasetypes as $phrasetype) {
            if (empty($phrasetype['phrase'])) {
                continue;
            }
            if ($phrasetype['fieldname'] == '' or !preg_match('#^[a-z0-9_]+$#i', $phrasetype['fieldname'])) {
                continue;
            }
            $fieldname = $master_phrasefields["{$phrasetype['fieldname']}"];
            if (!$fieldname) {
                $assertor->assertQuery('installProductPhraseTypeInsert', array('fieldname' => $phrasetype['fieldname'], 'title' => $phrasetype['name'], 'editrows' => 3, 'product' => $info['productid']));
                // need to add the column to the language table as well
                $assertor->assertQuery('addLanguageFromPackage', array('fieldname' => $phrasetype['fieldname']));
            }
            $phrases =& $phrasetype['phrase'];
            if (!isset($phrases[0])) {
                $phrases = array($phrases);
            }
            $sql = array();
            foreach ($phrases as $phrase) {
                $sql[] = array('languageid' => -1, 'fieldname' => $phrasetype['fieldname'], 'varname' => $phrase['name'], 'text' => $phrase['value'], 'product' => $info['productid'], 'username' => $phrase['username'], 'dateline' => $phrase['date'], 'version' => $phrase['version']);
            }
            /*insert query*/
            $assertor->assertQuery('replaceValues', array('values' => $sql, 'table' => 'phrase'));
        }
        $rebuild['phrases'] = true;
    }
    // ############## import settings
    if (isset($arr['options']['settinggroup']) and is_array($arr['options']['settinggroup'])) {
        $settinggroups =& $arr['options']['settinggroup'];
        if (!isset($settinggroups[0])) {
            $settinggroups = array($settinggroups);
        }
        foreach ($settinggroups as $group) {
            if (empty($group['setting'])) {
                continue;
            }
            // create the setting group if it doesn't already exist
            $check = $assertor->assertQuery('settinggroup', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'grouptitle' => $group['name']));
            if ($check->valid()) {
                $current = $check->current();
                if ($group['adminperm'] != $current['adminperm'] or $group['displayorder'] != $current['displayorder']) {
                    $assertor->assertQuery('settinggroup', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_UPDATE, 'grouptitle' => $group['name'], 'displayorder' => $group['displayorder'], 'adminperm' => $group['adminperm']));
                }
            } else {
                /*insert query*/
                $assertor->assertQuery('settinggroup', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERTIGNORE, 'grouptitle' => $group['name'], 'displayorder' => $group['displayorder'], 'volatile' => 1, 'product' => $info['productid'], 'adminperm' => $group['adminperm']));
            }
            $settings =& $group['setting'];
            if (!isset($settings[0])) {
                $settings = array($settings);
            }
            $setting_bits = array();
            foreach ($settings as $setting) {
                if (isset($vbulletin->options["{$setting['varname']}"])) {
                    $newvalue = $vbulletin->options["{$setting['varname']}"];
                } else {
                    $newvalue = $setting['defaultvalue'];
                }
                $setting_bits[] = array('varname' => $setting['varname'], 'grouptitle' => $group['name'], 'value' => trim($newvalue), 'defaultvalue' => trim($setting['defaultvalue']), 'datatype' => trim($setting['datatype']), 'optioncode' => $setting['optioncode'], 'displayorder' => $setting['displayorder'], 'advanced' => intval($setting['advanced']), 'volatile' => 1, 'validationcode' => $setting['validationcode'], 'blacklist' => $setting['blacklist'], 'ispublic' => intval($setting['public']), 'product' => $info['productid'], 'adminperm' => empty($setting['adminperm']) ? '' : $setting['adminperm']);
            }
            /*insert query*/
            $assertor->assertQuery('replaceValues', array('values' => $setting_bits, 'table' => 'setting'));
        }
        $rebuild['options'] = true;
    }
    // ############## import admin help
    if (isset($arr['helptopics']['helpscript']) and is_array($arr['helptopics']['helpscript'])) {
        $help_scripts =& $arr['helptopics']['helpscript'];
        if (!isset($help_scripts[0])) {
            $help_scripts = array($help_scripts);
        }
        foreach ($help_scripts as $help_script) {
            // Deal with single entry
            if (!is_array($help_script['helptopic'][0])) {
                $help_script['helptopic'] = array($help_script['helptopic']);
            }
            $help_sql = array();
            foreach ($help_script['helptopic'] as $topic) {
                $helpsql[] = array('script' => $help_script['name'], 'action' => $topic['act'], 'optionname' => $topic['opt'], 'displayorder' => intval($topic['disp']), 'volatile' => 1, 'product' => $info['productid']);
            }
            if (!empty($helpsql)) {
                /*insert query*/
                $assertor->assertQuery('replaceValues', array('values' => $helpsql, 'table' => 'adminhelp'));
            }
        }
    }
    // ############## import cron
    if (isset($arr['cronentries']['cron']) and is_array($arr['cronentries']['cron'])) {
        require_once DIR . '/includes/functions_cron.php';
        $cron_entries =& $arr['cronentries']['cron'];
        if (!isset($cron_entries[0])) {
            $cron_entries = array($cron_entries);
        }
        foreach ($cron_entries as $cron) {
            $cron['varname'] = preg_replace('#[^a-z0-9_]#i', '', $cron['varname']);
            if (!$cron['varname']) {
                continue;
            }
            $cron['active'] = $cron['active'] ? 1 : 0;
            $cron['loglevel'] = $cron['loglevel'] ? 1 : 0;
            $scheduling = $cron['scheduling'];
            $scheduling['weekday'] = intval($scheduling['weekday']);
            $scheduling['day'] = intval($scheduling['day']);
            $scheduling['hour'] = intval($scheduling['hour']);
            $scheduling['minute'] = explode(',', preg_replace('#[^0-9,-]#i', '', $scheduling['minute']));
            if (count($scheduling['minute']) == 0) {
                $scheduling['minute'] = array(0);
            } else {
                $scheduling['minute'] = array_map('intval', $scheduling['minute']);
            }
            /*insert query*/
            $cronSql[] = array('weekday' => $scheduling['weekday'], 'day' => $scheduling['day'], 'hour' => $scheduling['hour'], 'minute' => serialize($scheduling['minute']), 'filename' => $cron['filename'], 'loglevel' => $cron['loglevel'], 'active' => $cron['active'], 'varname' => $cron['varname'], 'volatile' => 1, 'product' => $info['productid']);
            $cronid = $assertor->assertQuery('replaceValues', array('values' => $cronSql, 'table' => 'cron', 'returnId' => true));
            if ($cronid) {
                build_cron_item($cronid);
            }
            $rebuild['cron'] = true;
        }
    }
    // ############## import faq
    if (isset($arr['faqentries']['faq']) and is_array($arr['faqentries']['faq'])) {
        $faq_entries =& $arr['faqentries']['faq'];
        if (!isset($faq_entries[0])) {
            $faq_entries = array($faq_entries);
        }
        $sql = array();
        foreach ($faq_entries as $faq) {
            $sql[] = array('faqname' => $faq['faqname'], 'faqparent' => $faq['faqparent'], 'displayorder' => intval($faq['displayorder']), 'volatile' => 1, 'product' => $info['productid']);
        }
        if ($sql) {
            /*insert query*/
            $assertor->assertQuery('replaceValues', array('values' => $sql, 'table' => 'faq'));
        }
    }
    // ############## import widgets
    if (isset($arr['widgets']['widget']) and is_array($arr['widgets']['widget'])) {
        $widgetImporter = new vB_Xml_Import_Widget($info['productid']);
        $widgetImporter->importFromParsedXML($arr['widgets']);
    }
    // ############## import pagetemplates
    if (isset($arr['pagetemplates']['pagetemplate']) and is_array($arr['pagetemplates']['pagetemplate'])) {
        $pageTemplateImporter = new vB_Xml_Import_PageTemplate($info['productid']);
        $pageTemplateImporter->importFromParsedXML($arr['pagetemplates']);
    }
    // ############## import page
    if (isset($arr['pages']['page']) and is_array($arr['pages']['page'])) {
        $pageImporter = new vB_Xml_Import_Page($info['productid']);
        $pageImporter->importFromParsedXML($arr['pages']);
    }
    // ############## import channels
    if (isset($arr['channels']['channel']) and is_array($arr['channels']['channel'])) {
        $channelImporter = new vB_Xml_Import_Channel($info['productid']);
        $channelImporter->importFromParsedXML($arr['channels']);
    }
    // ############## import routes
    if (isset($arr['routes']['route']) and is_array($arr['routes']['route'])) {
        $routeImporter = new vB_Xml_Import_Route($info['productid']);
        $routeImporter->importFromParsedXML($arr['routes']);
    }
    if (isset($routeImporter)) {
        // update pages and channels with new route ids
        if (isset($pageImporter)) {
            $pageImporter->updatePageRoutes();
        }
        if (isset($channelImporter)) {
            $channelImporter->updateChannelRoutes();
        }
    }
    // Check if the hook system is disabled. If it is, enable it.
    if (!$vbulletin->options['enablehooks']) {
        $assertor->update('setting', array('value' => 1), array('varname' => 'enablehooks'));
        $rebuild['options'] = true;
    }
    // Now rebuild everything we need...
    if ($rebuild['hooks']) {
        vB_Api::instanceInternal("Hook")->buildHookDatastore();
    }
    if ($rebuild['templates']) {
        if ($error = build_all_styles(0, 0, '', false, $verbose)) {
            return $error;
        }
    }
    if ($rebuild['phrases']) {
        require_once DIR . '/includes/adminfunctions_language.php';
        build_language();
    }
    if ($rebuild['options']) {
        vB::getDatastore()->build_options();
    }
    if ($rebuild['cron']) {
        require_once DIR . '/includes/functions_cron.php';
        build_cron_next_run();
    }
    build_product_datastore();
    // build bitfields to remove/add this products bitfields
    vB_Bitfield_Builder::save();
    if ($verbose) {
        print_dots_stop();
    }
    $info['need_merge'] = ($rebuild['templates'] and $installed_version);
    return $info;
}
예제 #7
0
 /**
  * Lists the content types the current user can create at a node.
  *
  * @param	int		the nodeid to be checked
  *
  * @return	mixed	array of contenttypes
  */
 public function getCanCreate($nodeid)
 {
     /** The create permissions are quite complex. The things that need to be considered are:
      *
      * - createpermissions from the permissions table.
      * - canpostnew, canreply, and cancomment.
      * - datastore postcommentthreads, which disables only commments- not starters or reply
      * - the commentperms, which has a different meaning in a blog or social group compared to a regular forum
      * - for attach and photo types, they look like a comment or reply if not on a thread, but aren't disabled by the comment setting above.
      * - for gallery, attach, and photo types, the global canpostattachment forum permission.
      * - the channel, which may be closed.
      * - forums in which the user can only reply to their own content.
      * - the 'canadminforums' admin permission, which allows creating channels
      **/
     static $bf_ugp = array();
     //if we've already gotten for this node, we're done.
     if (isset($this->canCreateTypes[$nodeid])) {
         return $this->canCreateTypes[$nodeid];
     }
     //make sure we have the bitfield array. We can't just access the datastore because we need to
     // have permissions before the datastore is available, especially during
     // install.
     if (empty($bf_ugp)) {
         $bf_ugp = vB::getDatastore()->getValue('bf_ugp_createpermissions');
         if (empty($bf_ugp)) {
             //This can happen during upgrade
             $xmlobj = new vB_XML_Parser(false, DIR . '/includes/xml/bitfield_vbulletin.xml');
             if ($xmlobj->error_no() == 1 or $xmlobj->error_no() == 2) {
                 throw new Exception("You are missing the " . DIR . "/includes/xml/bitfield_vbulletin.xml file. Please replace it");
             }
             $bitfields = $xmlobj->parse();
             foreach ($bitfields['bitfielddefs']['group'] as $group) {
                 if ($group['name'] == 'ugp') {
                     foreach ($group['group'] as $ugp) {
                         if ($ugp['name'] == 'createpermissions') {
                             foreach ($ugp['bitfield'] as $createPerm) {
                                 $bf_ugp[$createPerm['name']] = $createPerm['value'];
                             }
                             break;
                         }
                     }
                 }
             }
         }
     }
     $createPerms = array();
     $nodeLib = vB_Library::instance('node');
     // get the node record
     $node = $nodeLib->getNode($nodeid);
     //See if comments are enabled.
     $canalways = $this->getChannelPermission('forumpermissions2', 'canalwayspostnew', $nodeid);
     if ($canalways) {
         $commentsEnabled = true;
     } else {
         if (!$node['showpublished']) {
             //If the user doesn't have canalwayspost and the node isn't published, don't allow posting.
             return false;
         }
         $commentsEnabled = (bool) vB::getDatastore()->getOption('postcommentthreads');
     }
     //if comments have been globally disabled and the node is not a starter or channel, we can't post
     if (!$commentsEnabled and $node['starter'] > 0 and $node['starter'] != $node['nodeid']) {
         //We'll check later and see if the user can post an attachment or photo.
         $attachOnly = true;
     } else {
         $attachOnly = false;
     }
     // @TODO: This is wrong, see VBV-6725
     //If this user is superadmin, just grant them everything except maybe the image types.
     if ($this->userIsSuperAdmin) {
         foreach ($bf_ugp as $type => $bitfield) {
             if ($attachOnly and $node['userid'] != $this->userid and ($type == 'vbforum_attach' or $type != 'vbforum_photo')) {
                 $createPerms[$key] = 0;
             } else {
                 $createPerms[$type] = 1;
             }
         }
         return $createPerms;
     }
     $types = vB_Types::instance();
     $canAttach = $this->hasPermission('forumpermissions', 'canpostattachment');
     $channelType = $types->getContentTypeId('vBForum_Channel');
     //This user isn't superadmin and we don't already have this, so we need to calculate it
     foreach ($bf_ugp as $type => $bitfield) {
         $createPerms[$type] = 0;
     }
     //if this or a parent has nodeoptions[OPTION_ALLOW_POST] = 0, we are done.
     if (!empty($this->noComments) and (array_key_exists($nodeid, $this->noComments) or array_key_exists($node['parentid'], $this->noComments) or array_key_exists($node['starter'], $this->noComments))) {
         $this->canCreateTypes[$nodeid] = false;
         return false;
     }
     //if this is NOT a channel we need to test the channel.
     if ($node['contenttypeid'] != $channelType) {
         $isChannel = false;
         // try to get the channel node
         // the try/catch block is to keep the widget from crashing and burning
         // if it encounters orphaned nodes; see VBV-4198
         try {
             if ($node['nodeid'] == $node['starter']) {
                 $channel = $nodeLib->getNode($node['parentid']);
             } else {
                 $starter = $nodeLib->getNode($node['starter']);
                 $channel = $nodeLib->getNode($starter['parentid']);
             }
             $channelid = $channel['nodeid'];
         } catch (vB_Exception_Api $e) {
             $errors = $e->get_errors();
             foreach ($errors as $error) {
                 if (array_pop($error) == 'invalid_node_id') {
                     // we are likely checking permissions for the parent of an
                     // orphaned post (no parent exists) see VBV-4198
                     $this->canCreateTypes[$nodeid] = false;
                     return false;
                 }
             }
             throw $e;
             // re-throw anything else that's not invalid_node_id
         }
         //Now see if posting is enabled.
         if (($channel['nodeoptions'] & vB_Api_Node::OPTION_ALLOW_POST) > 0) {
             $this->canPost[$channelid] = 1;
         } else {
             $this->canPost[$channelid] = 0;
         }
         if ($this->canPost[$channelid] == 0) {
             //If posting is disabled, with moderator permissions the user can still post.
             if (!$this->getChannelPermission('moderatorpermissions', 'canmoderateposts', $nodeid)) {
                 //at this point createPerms is an empty array.
                 $this->canCreateTypes[$nodeid] = $createPerms;
                 $this->noComments[$node['nodeid']] = 1;
                 $this->noComments[$channel['nodeid']] = $channel['nodeid'];
                 if ($node['nodeid'] != $node['starter']) {
                     $this->noComments[$node['starter']] = 1;
                 }
                 if ($node['parentid'] != $node['starter'] and $node['parentid'] != $channel['nodeid']) {
                     $this->noComments[$node['parentid']] = 1;
                 }
                 if ($attachOnly and $canAttach and $node['userid'] == $this->userid) {
                     $createPerms['vbforum_attach'] = 1;
                     $createPerms['vbforum_photo'] = 1;
                 }
                 $this->canCreateTypes[$nodeid] = $createPerms;
                 return $createPerms;
             }
         }
     } else {
         //if the node requested in a channel, we use the settings and permissions from that.
         $isChannel = true;
         $channelid = $nodeid;
         $channel = $nodeLib->getNode($channelid);
         $this->canPost[$channelid] = 1;
         // if they have 'canadminforums', they can create channels anywhere
         if ($this->hasAdminPermission('canadminforums')) {
             $createPerms['vbforum_channel'] = 1;
         }
     }
     $attachTypes = array('vbforum_photo' => 1, 'vbforum_attach' => 1, 'vbforum_gallery' => 1);
     // Adds the usergroups in the groupInTopic for the given channel, otherwise it only has the usergroup(s) set in the user table
     $userGroups = $this->usergroups;
     if (!empty($this->groupInTopic[$channelid])) {
         foreach ($this->groupInTopic[$channelid] as $groupid) {
             $userGroups[] = $groupid;
         }
     }
     //We have special processing if this is a VM or  blog or social group channel
     //There is some additional checking for a VM that needs the data passed. That is handled in
     // the content api validate() method
     $sgapi = vB_Api::instanceInternal('socialgroup');
     $blogapi = vB_Api::instanceInternal('blog');
     $isSGChannel = $sgapi->isSGNode($channel['nodeid']);
     $isBlogChannel = $blogapi->isBlogNode($channel['nodeid']);
     if ($isBlogChannel or $isSGChannel) {
         if ($channel['commentperms'] == 0) {
             //Only blog members can contribute. We check for the channel
             if (empty($this->userid) or $blogapi->isChannelMember($channelid) != 1) {
                 //Not O.K.
                 return false;
             }
             if ($isSGChannel) {
                 // If this is a new topic/discussion check for the permission
                 if ($isChannel and !$this->hasPermission('socialgrouppermissions', 'cancreatediscussion')) {
                     return false;
                 }
             }
         } else {
             //We need to check to see if it's a blog channel
             if ($isBlogChannel) {
                 //If $channel['commentperms'] wasn't 0, then it can be 1 or 2
                 //1: Only registered users. 2: everyone
                 //If the current user is not registered they can't post
                 if ($channel['commentperms'] == 1 and empty($this->userid)) {
                     return false;
                 }
                 //We can't call the getContent methods- that can cause an endless loop.
                 //We just called getNode, which is much faster. But doesn't give
                 $channel['type'] = 'blog';
             } else {
                 //We need channel type in checkChannelSettings.
                 $channel['type'] = 'sg';
                 //If the current user is not registered they can't post
                 if (empty($this->userid)) {
                     return false;
                 }
                 // If this is a new topic/discussion check for the permission
                 if ($isChannel and !$this->hasPermission('socialgrouppermissions', 'cancreatediscussion')) {
                     return false;
                 }
             }
         }
         // below can throw a no_permission exception. Seems inconsistent with the rest (return false)..
         //handle channel-specific settings from user.
         $this->checkChannelSettings($channel, $node);
     } else {
         if ($channelid == vB_Api::instanceInternal('node')->fetchVMChannel()) {
             //If the user can't see other user's walls they can't write on them
             if (!$this->hasPermission('genericpermissions', 'canviewmembers')) {
                 return false;
             }
             // Do we have permission to write on others' walls?
             if (!vB::getUserContext()->hasPermission('visitormessagepermissions', 'canmessageothersprofile')) {
                 return false;
             }
         } else {
             if (!$canalways) {
                 // adding these permissions here allow users to *reply* to a topic
                 // with a post containing an attachemnt (vbforum_attach) or with a
                 // photo post (vbforum_photo) when they don't have permission
                 // to comment on replies in this topic. VBV-12328
                 if ($canAttach and $node['userid'] == $this->userid) {
                     //The user can add images to their posts.
                     $createPerms['vbforum_attach'] = 1;
                     $createPerms['vbforum_photo'] = 1;
                 }
             }
         }
     }
     // Per VBV-11898, the constructor should've only set the primary usergroup if allowmembergroups = "No"
     //	However, see above where groupids from groupInTopic are also added to $userGroups
     //Now we scan the  usergroups looking for permission
     foreach ($userGroups as $key => $usergroupid) {
         //First find where this groupid/channelid gets its permissions.
         if (isset($this->channelPermsFrom[$usergroupid][$channelid])) {
             $thisPermFrom = $this->channelPermsFrom[$usergroupid][$channelid];
             //If the created node would be a starter we need canpostnew
             // We also need the usergroupid set in the permissions, this is
             // because it is (very) possible that there is no record for this usergroup/node in the groupInTopic
             if ($isChannel) {
                 // they might be creating a channel
                 // createpermissions.vbforum_channel is currently only valid
                 // for creating a blog or social group. To create any other
                 // channel, you need 'canadminforums' admin permission.
                 // canadminforums is checked when $isChannel is set above, so we don't need to check it again here
                 if (($isSGChannel or $isBlogChannel) and $this->permissionContext->getChannelPerm($usergroupid, 'createpermissions', 'vbforum_channel', $thisPermFrom)) {
                     $createPerms['vbforum_channel'] = 1;
                 }
                 // they might be creating a topic starter in a channel
                 if (!$this->permissionContext->getChannelPerm($usergroupid, 'forumpermissions', 'canpostnew', $thisPermFrom)) {
                     continue;
                 }
             } else {
                 if ($node['starter'] == $nodeid) {
                     if (!$this->permissionContext->getChannelPerm($usergroupid, 'forumpermissions', 'canreply', $thisPermFrom)) {
                         continue;
                     }
                 } else {
                     if (!($this->permissionContext->getChannelPerm($usergroupid, 'forumpermissions2', 'cancomment', $thisPermFrom) and $this->permissionContext->getChannelPerm($usergroupid, 'forumpermissions', 'canreply', $thisPermFrom))) {
                         continue;
                     }
                 }
             }
             //If we got here, the current user can post.  Now we just need to check the individual permissions.
             foreach ($bf_ugp as $type => $bitfield) {
                 //Complex "IF" here. We need to have the standard permission, PLUS if the global "canpostattachment" is not set
                 // then the user can't create galleries, attachmentts, or photos. Also if $attachOnly is set we only get the attach types.
                 if ($this->permissionContext->getChannelPerm($usergroupid, 'createpermissions', $type, $thisPermFrom)) {
                     if ($attachOnly) {
                         if (($type == 'vbforum_attach' or $type == 'vbforum_photo') and $node['userid'] == $this->userid) {
                             $createPerms[$type] |= (int) $canAttach;
                         }
                     } else {
                         if (array_key_exists($type, $attachTypes)) {
                             $createPerms[$type] |= (int) $canAttach;
                         } else {
                             // skip vbforum_channel here since it's
                             // handled above in the $isChannel branch
                             if ($type != 'vbforum_channel') {
                                 $createPerms[$type] = 1;
                             }
                         }
                     }
                 }
             }
         }
     }
     //we now have all the create permissions info. Let's cache it for the next check.
     $this->canCreateTypes[$nodeid] = $createPerms;
     return $createPerms;
 }
function xml_import_help_topics($xml = false)
{
    global $vbulletin, $vbphrase;
    print_dots_start('<b>' . $vbphrase['importing_admin_help'] . "</b>, {$vbphrase['please_wait']}", ':', 'dspan');
    require_once DIR . '/includes/class_xml.php';
    $xmlobj = new vB_XML_Parser($xml, $GLOBALS['path']);
    if ($xmlobj->error_no() == 1) {
        print_dots_stop();
        print_stop_message2('no_xml_and_no_path');
    } else {
        if ($xmlobj->error_no() == 2) {
            print_dots_stop();
            print_stop_message('please_ensure_x_file_is_located_at_y', 'vbulletin-adminhelp.xml', $GLOBALS['path']);
        }
    }
    if (!($arr = $xmlobj->parse())) {
        print_dots_stop();
        print_stop_message('xml_error_x_at_line_y', $xmlobj->error_string(), $xmlobj->error_line());
    }
    if (!$arr['helpscript']) {
        print_dots_stop();
        print_stop_message2('invalid_file_specified');
    }
    $product = empty($arr['product']) ? 'vbulletin' : $arr['product'];
    $has_phrases = !empty($arr['hasphrases']);
    $arr = $arr['helpscript'];
    if ($product == 'vbulletin') {
        $product_sql = "product IN ('vbulletin', '')";
    } else {
        $product_sql = "product = '" . $vbulletin->db->escape_string($product) . "'";
    }
    $vbulletin->db->query_write("\n\t\tDELETE FROM " . TABLE_PREFIX . "adminhelp\n\t\tWHERE {$product_sql}\n\t\t\t AND volatile = 1\n\t");
    if ($has_phrases) {
        $vbulletin->db->query_write("\n\t\t\tDELETE FROM " . TABLE_PREFIX . "phrase\n\t\t\tWHERE {$product_sql}\n\t\t\t\tAND fieldname = 'cphelptext'\n\t\t\t\tAND languageid = -1\n\t\t");
    }
    // Deal with single entry
    if (!is_array($arr[0])) {
        $arr = array($arr);
    }
    foreach ($arr as $helpscript) {
        $help_sql = array();
        $phrase_sql = array();
        $help_sql_len = 0;
        $phrase_sql_len = 0;
        // Deal with single entry
        if (!is_array($helpscript['helptopic'][0])) {
            $helpscript['helptopic'] = array($helpscript['helptopic']);
        }
        foreach ($helpscript['helptopic'] as $topic) {
            $help_sql[] = "\n\t\t\t\t('" . $vbulletin->db->escape_string($helpscript['name']) . "',\n\t\t\t\t'" . $vbulletin->db->escape_string($topic['act']) . "',\n\t\t\t\t'" . $vbulletin->db->escape_string($topic['opt']) . "',\n\t\t\t\t" . intval($topic['disp']) . ",\n\t\t\t\t1,\n\t\t\t\t'" . $vbulletin->db->escape_string($product) . "')\n\t\t\t";
            $help_sql_len += strlen(end($help_sql));
            if ($has_phrases) {
                $phrase_name = fetch_help_phrase_short_name(array('script' => $helpscript['name'], 'action' => $topic['act'], 'optionname' => $topic['opt']));
                if (isset($topic['text']['value'])) {
                    $phrase_sql[] = "\n\t\t\t\t\t\t(-1,\n\t\t\t\t\t\t'cphelptext',\n\t\t\t\t\t\t'{$phrase_name}_text',\n\t\t\t\t\t\t'" . $vbulletin->db->escape_string($topic['text']['value']) . "',\n\t\t\t\t\t\t'" . $vbulletin->db->escape_string($product) . "',\n\t\t\t\t\t\t'" . $vbulletin->db->escape_string($topic['text']['username']) . "',\n\t\t\t\t\t\t" . intval($topic['text']['date']) . ",\n\t\t\t\t\t\t'" . $vbulletin->db->escape_string($topic['text']['version']) . "')\n\t\t\t\t\t";
                    $phrase_sql_len += strlen(end($phrase_sql));
                }
                if (isset($topic['title']['value'])) {
                    $phrase_sql[] = "\n\t\t\t\t\t\t(-1,\n\t\t\t\t\t\t'cphelptext',\n\t\t\t\t\t\t'{$phrase_name}_title',\n\t\t\t\t\t\t'" . $vbulletin->db->escape_string($topic['title']['value']) . "',\n\t\t\t\t\t\t'" . $vbulletin->db->escape_string($product) . "',\n\t\t\t\t\t\t'" . $vbulletin->db->escape_string($topic['title']['username']) . "',\n\t\t\t\t\t\t" . intval($topic['title']['date']) . ",\n\t\t\t\t\t\t'" . $vbulletin->db->escape_string($topic['title']['version']) . "')\n\t\t\t\t\t";
                    $phrase_sql_len += strlen(end($phrase_sql));
                }
            }
            if ($phrase_sql_len > 102400) {
                // insert max of 100k of phrases at a time
                /*insert query*/
                $vbulletin->db->query_write("\n\t\t\t\t\tREPLACE INTO " . TABLE_PREFIX . "phrase\n\t\t\t\t\t\t(languageid, fieldname, varname, text, product, username, dateline, version)\n\t\t\t\t\tVALUES\n\t\t\t\t\t\t" . implode(",\n", $phrase_sql));
                $phrase_sql = array();
                $phrase_sql_len = 0;
            }
            if ($help_sql_len > 102400) {
                // insert max of 100k of phrases at a time
                /*insert query*/
                $vbulletin->db->query_write("\n\t\t\t\t\tREPLACE INTO " . TABLE_PREFIX . "adminhelp\n\t\t\t\t\t\t(script, action, optionname, displayorder, volatile, product)\n\t\t\t\t\tVALUES\n\t\t\t\t\t\t" . implode(",\n\t", $help_sql));
                $help_sql = array();
                $help_sql_len = 0;
            }
        }
        if ($help_sql) {
            /*insert query*/
            $vbulletin->db->query_write("\n\t\t\t\tREPLACE INTO " . TABLE_PREFIX . "adminhelp\n\t\t\t\t\t(script, action, optionname, displayorder, volatile, product)\n\t\t\t\tVALUES\n\t\t\t\t\t" . implode(",\n\t", $help_sql));
        }
        if ($phrase_sql) {
            /*insert query*/
            $vbulletin->db->query_write("\n\t\t\t\t\tREPLACE INTO " . TABLE_PREFIX . "phrase\n\t\t\t\t\t\t(languageid, fieldname, varname, text, product, username, dateline, version)\n\t\t\t\t\tVALUES\n\t\t\t\t\t\t" . implode(",\n", $phrase_sql));
        }
    }
    // stop the 'dots' counter feedback
    print_dots_stop();
    require_once DIR . '/includes/adminfunctions_language.php';
    build_language();
}
/**
* Reads XML style file and imports data from it into the database
*
* @param	string	$xml		XML data
* @param	integer	$styleid	Style ID
* @param	integer	$parentid	Parent style ID
* @param	string	$title		New style title
* @param	boolean	$anyversion	Allow vBulletin version mismatch
* @param	integer	$displayorder	Display order for new style
* @param	boolean	$userselct	Allow user selection of new style
* @param  	int|null	$startat	Starting template group index for this run of importing templates (0 based). Null means all templates (single run)
* @param  	int|null	$perpage	Number of templates to import at a time
* @param	boolean	$scilent		Run silently (do not echo)
* @param	array|boolean	$parsed_xml	Parsed array of XML data. If provided the function will ignore $xml and use the provided, already parsed data.
*
* @return	array	Array of information about the imported style
*/
function xml_import_style($xml = false, $styleid = -1, $parentid = -1, $title = '', $anyversion = false, $displayorder = 1, $userselect = true, $startat = null, $perpage = null, $scilent = false, $parsed_xml = false)
{
    // $GLOBALS['path'] needs to be passed into this function or reference $vbulletin->GPC['path']
    //checking the root node name
    if (!empty($xml)) {
        $r = new XMLReader();
        if ($r->xml($xml)) {
            if ($r->read()) {
                $node_name = $r->name;
                if ($node_name != 'style') {
                    print_stop_message2('file_uploaded_not_in_right_format_error');
                }
            } else {
                //can not read the document
                print_stop_message2('file_uploaded_unreadable');
            }
        } else {
            //can not open the xml
            print_stop_message2('file_uploaded_unreadable');
        }
    }
    global $vbulletin;
    if (!$scilent) {
        $vbphrase = vB_Api::instanceInternal('phrase')->fetch(array('importing_style', 'please_wait', 'creating_a_new_style_called_x'));
        print_dots_start('<b>' . $vbphrase['importing_style'] . "</b>, {$vbphrase['please_wait']}", ':', 'dspan');
    }
    require_once DIR . '/includes/class_xml.php';
    if (empty($parsed_xml)) {
        //where is this used?  I hate having this random global value in the middle of this function
        $xmlobj = new vB_XML_Parser($xml, $vbulletin->GPC['path']);
        if ($xmlobj->error_no() == 1) {
            if ($scilent) {
                throw new vB_Exception_AdminStopMessage('no_xml_and_no_path');
            }
            print_dots_stop();
            print_stop_message2('no_xml_and_no_path');
        } else {
            if ($xmlobj->error_no() == 2) {
                if ($scilent) {
                    throw new vB_Exception_AdminStopMessage(array('please_ensure_x_file_is_located_at_y', 'vbulletin-style.xml', $vbulletin->GPC['path']));
                }
                print_dots_stop();
                print_stop_message2(array('please_ensure_x_file_is_located_at_y', 'vbulletin-style.xml', $vbulletin->GPC['path']));
            }
        }
        if (!($parsed_xml = $xmlobj->parse())) {
            if ($scilent) {
                throw new vB_Exception_AdminStopMessage(array('xml_error_x_at_line_y', $xmlobj->error_string(), $xmlobj->error_line()));
            }
            print_dots_stop();
            print_stop_message2(array('xml_error_x_at_line_y', $xmlobj->error_string(), $xmlobj->error_line()));
        }
    }
    $version = $parsed_xml['vbversion'];
    $master = $parsed_xml['type'] == 'master' ? 1 : 0;
    $title = empty($title) ? $parsed_xml['name'] : $title;
    $product = empty($parsed_xml['product']) ? 'vbulletin' : $parsed_xml['product'];
    $one_pass = (is_null($startat) and is_null($perpage));
    if (!$one_pass and (!is_numeric($startat) or !is_numeric($perpage) or $perpage <= 0 or $startat < 0)) {
        if ($scilent) {
            throw new vB_Exception_AdminStopMessage('');
        }
        print_dots_stop();
        print_stop_message2('');
    }
    $outputtext = '';
    if ($one_pass or $startat == 0) {
        require_once DIR . '/includes/adminfunctions.php';
        // version check
        $full_product_info = fetch_product_list(true);
        $product_info = $full_product_info["{$product}"];
        if ($version != $product_info['version'] and !$anyversion and !$master) {
            if ($scilent) {
                throw new vB_Exception_AdminStopMessage(array('upload_file_created_with_different_version', $product_info['version'], $version));
            }
            print_dots_stop();
            print_stop_message2(array('upload_file_created_with_different_version', $product_info['version'], $version));
        }
        //Initialize the style -- either init the master, create a new style, or verify the style to overwrite.
        if ($master) {
            $import_data = @unserialize(fetch_adminutil_text('master_style_import'));
            if (!empty($import_data) and TIMENOW - $import_data['last_import'] <= 30) {
                if ($scilent) {
                    throw new vB_Exception_AdminStopMessage(array('must_wait_x_seconds_master_style_import', vb_number_format($import_data['last_import'] + 30 - TIMENOW)));
                }
                print_dots_stop();
                print_stop_message2(array('must_wait_x_seconds_master_style_import', vb_number_format($import_data['last_import'] + 30 - TIMENOW)));
            }
            // overwrite master style
            //			if  ($printInfo AND (VB_AREA != 'Upgrade' AND VB_AREA != 'Install'))
            //			{
            //				echo "<h3>$vbphrase[master_style]</h3>\n<p>$vbphrase[please_wait]</p>";
            //				vbflush();
            //			}
            $products = array($product);
            if ($product == 'vbulletin') {
                $products[] = '';
            }
            vB::getDbAssertor()->assertQuery('vBForum:deleteProductTemplates', array('products' => $products));
            vB::getDbAssertor()->assertQuery('vBForum:updateProductTemplates', array('products' => $products));
            $styleid = -1;
        } else {
            if ($styleid == -1) {
                // creating a new style
                if (vB::getDbAssertor()->getRow('style', array('title' => $title))) {
                    if ($scilent) {
                        throw new vB_Exception_AdminStopMessage(array('style_already_exists', $title));
                    }
                    print_dots_stop();
                    print_stop_message2(array('style_already_exists', $title));
                } else {
                    if (!$scilent) {
                        if (VB_AREA != 'Upgrade' or VB_AREA != 'Install') {
                            $outputtext = construct_phrase($vbphrase['creating_a_new_style_called_x'], $title) . "<br>\n";
                        } else {
                            // this isn't compatible with the ajax installer
                            echo "<h3><b>" . construct_phrase($vbphrase['creating_a_new_style_called_x'], $title) . "</b></h3>\n<p>{$vbphrase['please_wait']}</p>";
                            vbflush();
                        }
                    }
                    /*insert query*/
                    $styleid = vB::getDbAssertor()->insert('style', array('title' => $title, 'parentid' => $parentid, 'displayorder' => $displayorder, 'userselect' => $userselect ? 1 : 0));
                    if (is_array($styleid)) {
                        $styleid = array_pop($styleid);
                    }
                }
            } else {
                // overwriting an existing style
                if (vB::getDbAssertor()->getRow('style', array('styleid' => $styleid))) {
                    //					if  ($printInfo AND (VB_AREA != 'Upgrade' AND VB_AREA != 'Install'))
                    //					{
                    //						echo "<h3><b>" . construct_phrase($vbphrase['overwriting_style_x'], $getstyle['title']) . "</b></h3>\n<p>$vbphrase[please_wait]</p>";
                    //						vbflush();
                    //					}
                } else {
                    if ($scilent) {
                        throw new vB_Exception_AdminStopMessage('cant_overwrite_non_existent_style');
                    }
                    print_dots_stop();
                    print_stop_message2('cant_overwrite_non_existent_style');
                }
            }
        }
    } else {
        //We should never get styleid = -1 unless $master is true;
        if ($styleid == -1 and !$master) {
            $stylerec = vB::getDbAssertor()->getRow('style', array('title' => $title));
            if ($stylerec and intval($stylerec['styleid'])) {
                $styleid = $stylerec['styleid'];
            } else {
                if ($scilent) {
                    throw new vB_Exception_AdminStopMessage(array('incorrect_style_setting', $title));
                }
                print_dots_stop();
                print_stop_message2(array('incorrect_style_setting', $title));
            }
        }
    }
    //load the templates
    if ($arr = $parsed_xml['templategroup']) {
        if (empty($arr[0])) {
            $arr = array($arr);
        }
        $templates_done = (is_numeric($startat) and count($arr) <= $startat);
        if ($one_pass or !$templates_done) {
            if (!$one_pass) {
                $arr = array_slice($arr, $startat, $perpage);
            }
            $outputtext .= xml_import_template_groups($styleid, $product, $arr, !$one_pass);
        }
    } else {
        $templates_done = true;
    }
    //note that templates may actually be done at this point, but templates_done is
    //only true if templates were completed in a prior step. If we are doing a multi-pass
    //process, we don't want to install stylevars in the same pass.  We aren't really done
    //until we hit a pass where the templates are done before processing.
    $done = ($one_pass or $templates_done);
    if ($done) {
        //load stylevars and definitions
        // re-import any stylevar definitions
        if ($master and !empty($parsed_xml['stylevardfns']['stylevargroup'])) {
            xml_import_stylevar_definitions($parsed_xml['stylevardfns'], 'vbulletin');
        }
        //if the tag is present but empty we'll end up with a string with whitespace which
        //is a non "empty" value.
        if (!empty($parsed_xml['stylevars']) and is_array($parsed_xml['stylevars'])) {
            xml_import_stylevars($parsed_xml['stylevars'], $styleid);
        }
        if ($master) {
            xml_import_restore_ad_templates();
            build_adminutil_text('master_style_import', serialize(array('last_import' => TIMENOW)));
        }
        if (!$scilent) {
            print_dots_stop();
        }
    }
    $fastDs = vB_FastDS::instance();
    //We want to force a fastDS rebuild, but we can't just call rebuild. There may be dual web servers,
    // and calling rebuild only rebuilds one of them.
    $options = vB::getDatastore()->getValue('miscoptions');
    $options['tmtdate'] = vB::getRequest()->getTimeNow();
    vB::getDatastore()->build('miscoptions', serialize($options), 1);
    return array('version' => $version, 'master' => $master, 'title' => $title, 'product' => $product, 'done' => $done, 'overwritestyleid' => $styleid, 'output' => $outputtext);
}