/**
  * Parse a rss feed.
  * 
  * @param	string		$sourceURL
  * @return	array
  */
 public static function parseFeed($sourceURL)
 {
     $newsItems = array();
     $filename = FileUtil::downloadFileFromHttp($sourceURL, 'feed');
     // open & parse file
     $xml = new XML($filename);
     $data = $xml->getElementTree('channel');
     $items = $data['children'][0]['children'];
     foreach ($items as $item) {
         if ($item['name'] != 'item') {
             continue;
         }
         $newsItem = array('title' => '', 'author' => '', 'link' => '', 'guid' => '', 'pubDate' => '', 'description' => '');
         foreach ($item['children'] as $child) {
             if (!isset($child['cdata'])) {
                 continue;
             }
             $newsItem[$child['name']] = $child['cdata'];
         }
         // convert encodings
         if (CHARSET != 'UTF-8') {
             $newsItem['title'] = StringUtil::convertEncoding('UTF-8', CHARSET, $newsItem['title']);
             $newsItem['author'] = StringUtil::convertEncoding('UTF-8', CHARSET, $newsItem['author']);
             $newsItem['link'] = StringUtil::convertEncoding('UTF-8', CHARSET, $newsItem['link']);
             $newsItem['guid'] = StringUtil::convertEncoding('UTF-8', CHARSET, $newsItem['guid']);
             $newsItem['description'] = StringUtil::convertEncoding('UTF-8', CHARSET, $newsItem['description']);
         }
         @($newsItem['pubDate'] = intval(strtotime($newsItem['pubDate'])));
         $newsItems[] = $newsItem;
     }
     // delete tmp file
     @unlink($filename);
     return $newsItems;
 }
 /**
  * @see Form::validate()
  */
 public function validate()
 {
     parent::validate();
     // upload
     if ($this->optionImport && $this->optionImport['error'] != 4) {
         if ($this->optionImport['error'] != 0) {
             throw new UserInputException('optionImport', 'uploadFailed');
         }
         try {
             $xml = new XML($this->optionImport['tmp_name']);
             $optionsXML = $xml->getElementTree('options');
             foreach ($optionsXML['children'] as $option) {
                 $name = $value = '';
                 foreach ($option['children'] as $optionData) {
                     switch ($optionData['name']) {
                         case 'name':
                             $name = $optionData['cdata'];
                             break;
                         case 'value':
                             $value = $optionData['cdata'];
                             break;
                     }
                 }
                 if (!empty($name)) {
                     $this->options[$name] = $value;
                 }
             }
         } catch (SystemException $e) {
             throw new UserInputException('optionImport', 'importFailed');
         }
     } else {
         throw new UserInputException('optionImport');
     }
 }
 public static function ls($url, array $loginDetails = array(), array $options = array())
 {
     $options['asXML'] = true;
     $output = self::executeCommand('list', $url, $loginDetails, $options);
     $output = implode($output, '');
     $xml = new XML();
     $xml->loadString($output);
     return $xml->getElementTree('');
 }
 /**
  * Creates a new instance of type Configuration
  */
 public function __construct()
 {
     if (!file_exists(SDIR . 'config/config.xml')) {
         throw new Exception("Startup error: config.xml not found in " . SDIR . "config/! Aborted start!");
     }
     // load xml
     $xml = new XML(SDIR . 'config/config.xml');
     // get element array
     $data = $xml->getElementTree('config');
     // call loop
     $this->readConfiguration($this->configuration, $data);
 }
 /**
  * Loads the compiled language file.
  * Compiles the language file before if necessary.
  */
 public function loadLanguage()
 {
     $this->languageLoaded = true;
     $filename = TMP_DIR . TMP_FILE_PREFIX . $this->data['languageCode'] . '_' . $this->data['languageEncoding'] . '_wcf.setup.php';
     if (!file_exists($filename)) {
         $xml = new XML(TMP_DIR . TMP_FILE_PREFIX . 'setup_' . $this->data['languageCode'] . '.xml');
         // compile an array with XML::getElementTree
         $languageXML = $xml->getElementTree('language');
         // extract attributes (language code, language name)
         //$languageXML = array_merge($languageXML, $languageXML['attrs']);
         // get language items
         $categoriesToCache = array();
         foreach ($languageXML['children'] as $key => $languageCategory) {
             // language category does not exist yet, create it
             if (isset($languageCategory['children'])) {
                 foreach ($languageCategory['children'] as $key2 => $languageitem) {
                     $categoriesToCache[] = array('name' => $languageitem['attrs']['name'], 'cdata' => $languageitem['cdata']);
                 }
             }
         }
         // update language files here
         if (count($categoriesToCache) > 0) {
             $file = new File($filename);
             $file->write("<?php\n/**\n* WoltLab Community Framework\n* language: " . $this->data['languageCode'] . "\n* encoding: " . $this->data['languageEncoding'] . "\n* category: WCF Setup\n* generated at " . gmdate("r") . "\n* \n* DO NOT EDIT THIS FILE\n*/\n");
             foreach ($categoriesToCache as $value => $name) {
                 // simple_xml returns values always UTF-8 encoded
                 // manual decoding to charset necessary
                 if ($this->data['languageEncoding'] != 'UTF-8') {
                     $name['cdata'] = StringUtil::convertEncoding('UTF-8', $this->data['languageEncoding'], $name['cdata']);
                 }
                 $file->write("\$this->items[\$this->languageID]['" . $name['name'] . "'] = '" . str_replace("'", "\\'", $name['cdata']) . "';\n");
                 // compile dynamic language variables
                 if (strpos($name['cdata'], '{') !== false) {
                     $file->write("\$this->dynamicItems[\$this->languageID]['" . $name['name'] . "'] = '" . str_replace("'", "\\'", self::getScriptingCompiler()->compileString($name['name'], $name['cdata'])) . "';\n");
                 }
             }
             $file->write("?>");
             $file->close();
         }
     }
     include_once $filename;
     $this->setLocale();
 }
 /**
  * @see Cronjob::execute()
  */
 public function execute($data)
 {
     $filename = FileUtil::downloadFileFromHttp('http://www.woltlab.com/spiderlist/spiderlist.xml', 'spiders');
     $xml = new XML($filename);
     $spiders = $xml->getElementTree('spiderlist');
     if (count($spiders['children'])) {
         // delete old entries
         $sql = "TRUNCATE TABLE wcf" . WCF_N . "_spider";
         WCF::getDB()->sendQuery($sql);
         $inserts = '';
         foreach ($spiders['children'] as $spider) {
             $identifier = $spider['attrs']['ident'];
             // get attributes
             foreach ($spider['children'] as $values) {
                 $spider[$values['name']] = $values['cdata'];
             }
             $name = $spider['name'];
             $info = '';
             if (isset($spider['info'])) {
                 $info = $spider['info'];
             }
             if (!empty($inserts)) {
                 $inserts .= ',';
             }
             $inserts .= "('" . escapeString(StringUtil::toLowerCase($identifier)) . "', '" . escapeString($name) . "', '" . escapeString($info) . "')";
         }
         if (!empty($inserts)) {
             $sql = "INSERT IGNORE INTO\twcf" . WCF_N . "_spider\n\t\t\t\t\t\t\t\t(spiderIdentifier, spiderName, spiderURL)\n\t\t\t\t\tVALUES\t\t\t" . $inserts;
             WCF::getDB()->sendQuery($sql);
         }
         // clear spider cache
         WCF::getCache()->clear(WCF_DIR . 'cache', 'cache.spiders.php');
     }
     // delete tmp file
     @unlink($filename);
 }
 /**
  * Parses a stream containing info from a packages_update.xml.
  *
  * @param	string		$content
  * @return	array		$allNewPackages
  */
 protected static function parsePackageUpdateXML($content)
 {
     // load xml document
     $xmlObj = new XML();
     $xmlObj->loadString($content);
     // load the <section> tag (which must be the root element).
     $xml = $xmlObj->getElementTree('section');
     $encoding = $xmlObj->getEncoding();
     unset($xmlObj);
     // loop through <package> tags inside the <section> tag.
     $allNewPackages = array();
     foreach ($xml['children'] as $child) {
         // name attribute is missing, thus this package is not valid
         if (!isset($child['attrs']['name']) || !$child['attrs']['name']) {
             throw new SystemException("required 'name' attribute for 'package' tag is missing", 13001);
         }
         // the "name" attribute of this <package> tag must be a valid package identifier.
         if (!Package::isValidPackageName($child['attrs']['name'])) {
             throw new SystemException("'" . $child['attrs']['name'] . "' is not a valid package name.", 18004);
         }
         $package = $child['attrs']['name'];
         // parse packages_update.xml and fill $packageInfo.
         $packageInfo = self::parsePackageUpdateXMLBlock($child, $package);
         // convert enconding
         if ($encoding != CHARSET) {
             $packageInfo['packageName'] = StringUtil::convertEncoding($encoding, CHARSET, $packageInfo['packageName']);
             $packageInfo['packageDescription'] = StringUtil::convertEncoding($encoding, CHARSET, $packageInfo['packageDescription']);
             $packageInfo['author'] = StringUtil::convertEncoding($encoding, CHARSET, $packageInfo['author']);
             $packageInfo['authorURL'] = StringUtil::convertEncoding($encoding, CHARSET, $packageInfo['authorURL']);
         }
         $allNewPackages[$child['attrs']['name']] = $packageInfo;
     }
     unset($xml);
     return $allNewPackages;
 }
 /**
  * Reads the data of a variables.xml file.
  * 
  * @param	string		$string		contents of a variable.xml file
  * @return	array		data
  */
 public static function readVariablesData($string)
 {
     // open variables.xml
     $variablesXML = new XML();
     $variablesXML->loadString($string);
     $variablesXMLContent = $variablesXML->getElementTree('variables');
     // get variables
     $variables = array();
     foreach ($variablesXMLContent['children'] as $variable) {
         if (isset($variable['attrs']['name'])) {
             $variables[$variable['attrs']['name']] = $variable['cdata'];
         }
     }
     return $variables;
 }
 /**
  * @see CacheBuilder::getData()
  */
 public function getData($cacheResource)
 {
     list($cache, $instanceID) = explode('-', $cacheResource['cache']);
     // create array (0 => commits, 1 => api errors)
     $data = array(0 => array(), 1 => '');
     try {
         // create instance
         $instance = new InstanceableModule($instanceID);
         // create api url
         $apiUrl = 'http://github.com/api/v2/xml/commits/list/' . $instance->getOptions()->getGroup('general')->getOption('username')->getValue() . '/' . $instance->getOptions()->getGroup('general')->getOption('repository')->getValue() . '/' . $instance->getOptions()->getGroup('general')->getOption('branch')->getValue();
         // download xml
         $filename = FileUtil::downloadFileFromHttp($apiUrl);
         // create new xml instance
         $xml = new XML($filename);
         // load tree
         $commitXML = $xml->getElementTree('commits');
         // check for errors
         if (isset($commitXML['children'][0]) and $commitXML['children'][0]['name'] == 'error') {
             $data[1] = $commitXML['children'][0]['cdata'];
             return $data;
         }
         // all ok .. loop througt array
         foreach ($commitXML['children'] as $commit) {
             // create commit array
             $tmp = array('url' => 'https://github.com', 'id' => '', 'message' => '', 'author' => '', 'authorEmail' => '', 'date' => 0);
             // create information array
             $tmpInfo = array();
             // loop througt children
             foreach ($commit['children'] as $child) {
                 if ($child['name'] == 'committer') {
                     // create array for information
                     $tmpInfo['committer'] = array();
                     // loop througt children
                     foreach ($child['children'] as $cChild) {
                         // no cdata field found ... exit
                         if (!isset($cChild['cdata'])) {
                             continue;
                         }
                         // write value
                         $tmpInfo['committer'][$cChild['name']] = $cChild['cdata'];
                     }
                     // end loop
                     continue;
                 }
                 // no cdata field found ... exit
                 if (!isset($child['cdata'])) {
                     continue;
                 }
                 // write value
                 $tmpInfo[$child['name']] = $child['cdata'];
             }
             // write values
             $tmp['url'] .= $tmpInfo['url'];
             $tmp['id'] = $tmpInfo['id'];
             $tmp['message'] = $tmpInfo['message'];
             $tmp['author'] = $tmpInfo['committer']['name'];
             $tmp['authorEmail'] = $tmpInfo['committer']['email'];
             $tmp['date'] = strtotime($tmpInfo['committed-date']);
             // write tmp array
             $data[0][] = $tmp;
             // remove old tmp array
             unset($tmp);
         }
     } catch (SystemException $ex) {
         $data[1] = $ex->getMessage();
     }
     // return parsed commits
     return $data;
 }
 /**
  * Extracts information about this package (parses package.xml).
  */
 protected function readPackageInfo()
 {
     // search package.xml in package archive
     // throw error message if not found
     if ($this->tar->getIndexByFilename(self::INFO_FILE) === false) {
         throw new SystemException("package information file '" . self::INFO_FILE . "' not found in '" . $this->archive . "'", 13000);
     }
     // extract package.xml, parse with SimpleXML
     // and compile an array with XML::getElementTree()
     $xml = new XML();
     try {
         $xml->loadString($this->tar->extractToString(self::INFO_FILE));
     } catch (Exception $e) {
         // bugfix to avoid file caching problems
         $xml->loadString($this->tar->extractToString(self::INFO_FILE));
     }
     $xmlContent = $xml->getElementTree('package');
     // name attribute is missing, thus this package is not valid
     if (!isset($xmlContent['attrs']['name']) || !$xmlContent['attrs']['name']) {
         throw new SystemException("required 'name' attribute for 'package' tag is missing in " . self::INFO_FILE, 13001);
     }
     // package name is not a valid package identifier
     if (!Package::isValidPackageName($xmlContent['attrs']['name'])) {
         throw new SystemException("'" . $xmlContent['attrs']['name'] . "' is not a valid package name.", 13002);
     }
     // assign name attribute and loop through child tags
     $this->packageInfo['name'] = $xmlContent['attrs']['name'];
     foreach ($xmlContent['children'] as $child) {
         switch (StringUtil::toLowerCase($child['name'])) {
             // read in package information
             case 'packageinformation':
                 foreach ($child['children'] as $packageInformation) {
                     switch (StringUtil::toLowerCase($packageInformation['name'])) {
                         case 'packagename':
                             if (!isset($this->packageInfo['packageName'])) {
                                 $this->packageInfo['packageName'] = array();
                             }
                             if (isset($packageInformation['attrs']['language'])) {
                                 $languageCode = $packageInformation['attrs']['language'];
                             } else {
                                 if (isset($packageInformation['attrs']['languagecode'])) {
                                     $languageCode = $packageInformation['attrs']['languagecode'];
                                 } else {
                                     $languageCode = 'default';
                                 }
                             }
                             $this->packageInfo['packageName'][$languageCode] = $packageInformation['cdata'];
                             break;
                         case 'packagedescription':
                             if (!isset($this->packageInfo['packageDescription'])) {
                                 $this->packageInfo['packageDescription'] = array();
                             }
                             if (isset($packageInformation['attrs']['language'])) {
                                 $languageCode = $packageInformation['attrs']['language'];
                             } else {
                                 if (isset($packageInformation['attrs']['languagecode'])) {
                                     $languageCode = $packageInformation['attrs']['languagecode'];
                                 } else {
                                     $languageCode = 'default';
                                 }
                             }
                             $this->packageInfo['packageDescription'][$languageCode] = $packageInformation['cdata'];
                             break;
                         case 'isunique':
                             $this->packageInfo['isUnique'] = intval($packageInformation['cdata']);
                             break;
                         case 'standalone':
                             $this->packageInfo['standalone'] = intval($packageInformation['cdata']);
                             break;
                         case 'promptparent':
                         case 'plugin':
                             if ($packageInformation['cdata'] != 0 && !Package::isValidPackageName($packageInformation['cdata'])) {
                                 throw new SystemException("'" . $packageInformation['cdata'] . "' is not a valid package name.", 13002);
                             }
                             $this->packageInfo['plugin'] = $packageInformation['cdata'];
                             break;
                         case 'version':
                             $this->packageInfo['version'] = $packageInformation['cdata'];
                             break;
                         case 'date':
                             $this->packageInfo['date'] = @strtotime($packageInformation['cdata']);
                             if ($this->packageInfo['date'] === -1 || $this->packageInfo['date'] === false) {
                                 throw new SystemException("invalid dateformat '" . $packageInformation['cdata'] . "' in package.xml", 13003);
                             }
                             $this->packageInfo['date'] += 43201;
                             break;
                         case 'packageurl':
                             $this->packageInfo['packageURL'] = $packageInformation['cdata'];
                             break;
                     }
                 }
                 break;
                 // read in author information
             // read in author information
             case 'authorinformation':
                 foreach ($child['children'] as $authorInformation) {
                     switch (StringUtil::toLowerCase($authorInformation['name'])) {
                         case 'author':
                             $this->authorInfo['author'] = $authorInformation['cdata'];
                             break;
                         case 'authorurl':
                             $this->authorInfo['authorURL'] = $authorInformation['cdata'];
                             break;
                     }
                 }
                 break;
                 // read in requirements
             // read in requirements
             case 'requiredpackages':
                 foreach ($child['children'] as $requiredPackage) {
                     // reference to required package is not a valid package identifier
                     if (!Package::isValidPackageName($requiredPackage['cdata'])) {
                         throw new SystemException("'" . $requiredPackage['cdata'] . "' is not a valid package name.", 13002);
                     }
                     $this->requirements[$requiredPackage['cdata']] = array('name' => $requiredPackage['cdata']) + $requiredPackage['attrs'];
                 }
                 break;
                 // read in optionals
             // read in optionals
             case 'optionalpackages':
                 foreach ($child['children'] as $optionalPackage) {
                     // reference to optional package is not a valid package identifier
                     if (!Package::isValidPackageName($optionalPackage['cdata'])) {
                         throw new SystemException("'" . $optionalPackage['cdata'] . "' is not a valid package name.", 13002);
                     }
                     if (!isset($optionalPackage['attrs']['file']) || !$optionalPackage['attrs']['file']) {
                         throw new SystemException("required 'file' attribute for 'optionalPackage' tag is missing in " . self::INFO_FILE, 13001);
                     }
                     $this->optionals[] = array('name' => $optionalPackage['cdata']) + $optionalPackage['attrs'];
                 }
                 break;
                 // read in excluded packages
             // read in excluded packages
             case 'excludedpackages':
                 foreach ($child['children'] as $excludedPackage) {
                     // reference to excluded package is not a valid package identifier
                     if (!Package::isValidPackageName($excludedPackage['cdata'])) {
                         throw new SystemException("'" . $excludedPackage['cdata'] . "' is not a valid package name.", 13002);
                     }
                     $this->excludedPackages[$excludedPackage['cdata']] = array('name' => $excludedPackage['cdata']) + $excludedPackage['attrs'];
                 }
                 break;
                 // get installation and update instructions
             // get installation and update instructions
             case 'instructions':
                 if ($child['attrs']['type'] == 'update') {
                     if (!isset($child['attrs']['fromversion']) || !$child['attrs']['fromversion']) {
                         throw new SystemException("required 'fromversion' attribute for 'instructions type=update' tag is missing in " . self::INFO_FILE, 13001);
                     }
                     $this->update[$child['attrs']['fromversion']] = array();
                     $processData =& $this->update[$child['attrs']['fromversion']];
                 } else {
                     $this->install = array();
                     $processData =& $this->install;
                 }
                 foreach ($child['children'] as $instruction) {
                     switch ($instruction['name']) {
                         // get links to sql file
                         case 'sql':
                             $processData['sql'] = $instruction['cdata'];
                             break;
                             // get links to language files
                         // get links to language files
                         case 'languages':
                             if (!isset($processData['languages'])) {
                                 $processData['languages'] = array();
                             }
                             $processData['languages'][] = array('cdata' => $instruction['cdata']) + $instruction['attrs'];
                             break;
                             // get links to other (any but not sql) files
                         // get links to other (any but not sql) files
                         default:
                             if (!isset($processData[$instruction['name']])) {
                                 $processData[$instruction['name']] = array();
                             }
                             $processData[$instruction['name']][] = array('cdata' => $instruction['cdata']) + $instruction['attrs'];
                     }
                 }
                 foreach ($processData as $key => $val) {
                     if ($key != 'languages' && is_array($val) && count($val) == 1) {
                         $processData[$key] = array_shift($val);
                     }
                 }
                 break;
         }
     }
     // add com.woltlab.wcf to package requirements
     if (!isset($this->requirements['com.woltlab.wcf']) && $this->packageInfo['name'] != 'com.woltlab.wcf') {
         $this->requirements['com.woltlab.wcf'] = array('name' => 'com.woltlab.wcf');
     }
     // examine the right update instruction block
     if ($this->package !== null && $this->update !== null) {
         $validUpdate = null;
         foreach ($this->update as $fromVersion => $update) {
             if (Package::checkFromversion($this->package->getVersion(), $fromVersion)) {
                 $validUpdate = $update;
                 break;
             }
         }
         $this->update = $validUpdate;
     }
     // check required tags
     if (!isset($this->packageInfo['packageName'])) {
         throw new SystemException("required tag 'packageName' is missing in " . self::INFO_FILE, 13001);
     }
     if (!isset($this->packageInfo['version'])) {
         throw new SystemException("required tag 'version' is missing in " . self::INFO_FILE, 13001);
     }
     // set default values
     if (!isset($this->packageInfo['isUnique'])) {
         $this->packageInfo['isUnique'] = 0;
     }
     if (!isset($this->packageInfo['standalone'])) {
         $this->packageInfo['standalone'] = 0;
     }
     if (!isset($this->packageInfo['plugin'])) {
         $this->packageInfo['plugin'] = '';
     }
     if (!isset($this->packageInfo['packageURL'])) {
         $this->packageInfo['packageURL'] = '';
     }
     // get package name in selected language
     $this->getLocalizedInformation('packageName');
     // get package description in selected language
     if (isset($this->packageInfo['packageDescription'])) {
         $this->getLocalizedInformation('packageDescription');
     }
     if (CHARSET != 'UTF-8') {
         if (isset($this->authorInfo['author'])) {
             $this->authorInfo['author'] = StringUtil::convertEncoding('UTF-8', CHARSET, $this->authorInfo['author']);
         }
         if (isset($this->authorInfo['authorURL'])) {
             $this->authorInfo['authorURL'] = StringUtil::convertEncoding('UTF-8', CHARSET, $this->authorInfo['authorURL']);
         }
     }
     // add plugin to requirements
     if ($this->packageInfo['plugin'] && !isset($this->requirements[$this->packageInfo['plugin']])) {
         $this->requirements[$this->packageInfo['plugin']] = array('name' => $this->packageInfo['plugin']);
     }
 }
 /**
  * Imports language items from an XML file into this language.
  * Updates the relevant language files automatically.
  *
  * @param 	XML 		$xml
  * @param	integer		$packageID
  * @param 	boolean		$updateFiles	
  */
 public function updateFromXML(XML $xml, $packageID, $updateFiles = true)
 {
     // Compile an array with XML::getElementTree
     $languageXML = $xml->getElementTree('language');
     // get categories from xml
     $usedCategories = array();
     foreach ($languageXML['children'] as $languageCategory) {
         $usedCategories[$languageCategory['attrs']['name']] = 0;
     }
     // get existing categories
     if (!count($usedCategories)) {
         return;
     }
     $sql = "SELECT\t*\n\t\t\tFROM\twcf" . WCF_N . "_language_category\n\t\t\tWHERE\tlanguageCategory IN ('" . implode("','", array_map('escapeString', array_keys($usedCategories))) . "')";
     $result = WCF::getDB()->sendQuery($sql);
     while ($row = WCF::getDB()->fetchArray($result)) {
         $usedCategories[$row['languageCategory']] = $row['languageCategoryID'];
     }
     // create new categories
     foreach ($usedCategories as $name => $id) {
         if ($id == 0) {
             $sql = "INSERT INTO\twcf" . WCF_N . "_language_category\n\t\t\t\t\t\t\t(languageCategory)\n\t\t\t\t\tVALUES\t\t('" . escapeString($name) . "')";
             WCF::getDB()->sendQuery($sql);
             $usedCategories[$name] = WCF::getDB()->getInsertID();
         }
     }
     // loop categories to import items from xml
     $items = array();
     foreach ($languageXML['children'] as $languageCategory) {
         // import categories
         $categoryName = $languageCategory['attrs']['name'];
         $categoryID = $usedCategories[$categoryName];
         // import items from xml
         foreach ($languageCategory['children'] as $languageItem) {
             // get values
             $itemName = $languageItem['attrs']['name'];
             $itemValue = $languageItem['cdata'];
             // simple_xml returns values always UTF-8 encoded
             // manual decoding to charset necessary
             if ($this->data['languageEncoding'] != 'UTF-8') {
                 $itemValue = StringUtil::convertEncoding('UTF-8', CHARSET, $itemValue);
             }
             $items[$itemName] = array('name' => $itemName, 'value' => $itemValue, 'categoryID' => $categoryID);
         }
     }
     if (count($items)) {
         // find existing items
         $existingItems = array();
         $sql = "SELECT\tlanguageItem, languageItemID\n\t\t\t\tFROM\twcf" . WCF_N . "_language_item\n\t\t\t\tWHERE\tlanguageItem IN ('" . implode("','", array_map('escapeString', array_keys($items))) . "')\n\t\t\t\t\tAND packageID = " . $packageID . "\n\t\t\t\t\tAND languageID = " . $this->languageID;
         $result = WCF::getDB()->sendQuery($sql);
         while ($row = WCF::getDB()->fetchArray($result)) {
             $existingItems[strtolower($row['languageItem'])] = $row['languageItemID'];
         }
         $itemInserts = '';
         foreach ($items as $item) {
             if (isset($existingItems[strtolower($item['name'])])) {
                 // update
                 $sql = "UPDATE\twcf" . WCF_N . "_language_item\n\t\t\t\t\t\tSET\tlanguageItemValue = '" . escapeString($item['value']) . "',\n\t\t\t\t\t\t\tlanguageCategoryID = " . $item['categoryID'] . ",\n\t\t\t\t\t\t\tlanguageUseCustomValue = 0,\n\t\t\t\t\t\t\tlanguageItem = '" . escapeString($item['name']) . "'\n\t\t\t\t\t\tWHERE\tlanguageItemID = " . $existingItems[strtolower($item['name'])];
                 WCF::getDB()->sendQuery($sql);
             } else {
                 if (!empty($itemInserts)) {
                     $itemInserts .= ',';
                 }
                 $itemInserts .= "(" . $this->languageID . ", '" . escapeString($item['name']) . "', '" . escapeString($item['value']) . "', " . $item['categoryID'] . ", " . $packageID . ")";
             }
         }
         // save items
         if (!empty($itemInserts)) {
             $sql = "INSERT INTO\t\t\twcf" . WCF_N . "_language_item\n\t\t\t\t\t\t\t\t\t(languageID, languageItem, languageItemValue, languageCategoryID, packageID)\n\t\t\t\t\tVALUES\t\t\t\t" . $itemInserts;
             WCF::getDB()->sendQuery($sql);
         }
     }
     // update the relevant language files
     if ($updateFiles) {
         self::deleteLanguageFiles($this->languageID);
     }
     // delete relevant template compilations
     $this->deleteCompiledTemplates();
 }