/** * 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; }
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; }
/** * 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); }