protected function extractThemeFiles($arrFiles, $arrDbFields)
{
foreach ($arrFiles as $strZipFile) {
$xml = null;
// Open the archive
$objArchive = new \ZipReader($strZipFile);
// Extract all files
while ($objArchive->next()) {
// Load the XML file
if ($objArchive->file_name == 'theme.xml') {
$xml = new \DOMDocument();
$xml->preserveWhiteSpace = false;
$xml->loadXML($objArchive->unzip());
continue;
}
// Limit file operations to files and the templates directory
if (strncmp($objArchive->file_name, 'files/', 6) !== 0 && strncmp($objArchive->file_name, 'tl_files/', 9) !== 0 && strncmp($objArchive->file_name, 'templates/', 10) !== 0) {
\Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidFile'], $objArchive->file_name));
continue;
}
// Extract the files
try {
\File::putContent($this->customizeUploadPath($objArchive->file_name), $objArchive->unzip());
} catch (\Exception $e) {
\Message::addError($e->getMessage());
}
}
// Continue if there is no XML file
if (!$xml instanceof \DOMDocument) {
\Message::addError(sprintf($GLOBALS['TL_LANG']['tl_theme']['missing_xml'], basename($strZipFile)));
continue;
}
$arrMapper = array();
$tables = $xml->getElementsByTagName('table');
$arrNewFolders = array();
// Extract the folder names from the XML file
for ($i = 0; $i < $tables->length; $i++) {
if ($tables->item($i)->getAttribute('name') == 'tl_theme') {
$fields = $tables->item($i)->childNodes->item(0)->childNodes;
for ($k = 0; $k < $fields->length; $k++) {
if ($fields->item($k)->getAttribute('name') == 'folders') {
$arrNewFolders = \StringUtil::deserialize($fields->item($k)->nodeValue);
break;
}
}
break;
}
}
// Sync the new folder(s)
if (!empty($arrNewFolders) && is_array($arrNewFolders)) {
foreach ($arrNewFolders as $strFolder) {
$strCustomized = $this->customizeUploadPath($strFolder);
if (\Dbafs::shouldBeSynchronized($strCustomized)) {
\Dbafs::addResource($strCustomized);
}
}
}
// Lock the tables
$arrLocks = array('tl_files' => 'WRITE', 'tl_theme' => 'WRITE', 'tl_style_sheet' => 'WRITE', 'tl_style' => 'WRITE', 'tl_module' => 'WRITE', 'tl_layout' => 'WRITE', 'tl_image_size' => 'WRITE', 'tl_image_size_item' => 'WRITE');
// Load the DCAs of the locked tables (see #7345)
foreach (array_keys($arrLocks) as $table) {
$this->loadDataContainer($table);
}
$this->Database->lockTables($arrLocks);
// Get the current auto_increment values
$tl_files = $this->Database->getNextId('tl_files');
$tl_theme = $this->Database->getNextId('tl_theme');
$tl_style_sheet = $this->Database->getNextId('tl_style_sheet');
$tl_style = $this->Database->getNextId('tl_style');
$tl_module = $this->Database->getNextId('tl_module');
$tl_layout = $this->Database->getNextId('tl_layout');
$tl_image_size = $this->Database->getNextId('tl_image_size');
$tl_image_size_item = $this->Database->getNextId('tl_image_size_item');
// Build the mapper data (see #8326)
for ($i = 0; $i < $tables->length; $i++) {
$rows = $tables->item($i)->childNodes;
$table = $tables->item($i)->getAttribute('name');
// Skip invalid tables
if (!in_array($table, array_keys($arrLocks))) {
continue;
}
// Loop through the rows
for ($j = 0; $j < $rows->length; $j++) {
$fields = $rows->item($j)->childNodes;
// Loop through the fields
for ($k = 0; $k < $fields->length; $k++) {
// Increment the ID
if ($fields->item($k)->getAttribute('name') == 'id') {
$arrMapper[$table][$fields->item($k)->nodeValue] = ${$table}++;
break;
}
}
}
}
// Loop through the tables
for ($i = 0; $i < $tables->length; $i++) {
$rows = $tables->item($i)->childNodes;
$table = $tables->item($i)->getAttribute('name');
// Skip invalid tables
if (!in_array($table, array_keys($arrLocks))) {
continue;
}
// Get the order fields
$objDcaExtractor = \DcaExtractor::getInstance($table);
$arrOrder = $objDcaExtractor->getOrderFields();
// Loop through the rows
for ($j = 0; $j < $rows->length; $j++) {
$set = array();
$fields = $rows->item($j)->childNodes;
// Loop through the fields
for ($k = 0; $k < $fields->length; $k++) {
$value = $fields->item($k)->nodeValue;
$name = $fields->item($k)->getAttribute('name');
// Skip NULL values
if ($value == 'NULL') {
continue;
} elseif ($name == 'id') {
$value = $arrMapper[$table][$value];
} elseif ($name == 'pid') {
if ($table == 'tl_style') {
$value = $arrMapper['tl_style_sheet'][$value];
} elseif ($table == 'tl_image_size_item') {
$value = $arrMapper['tl_image_size'][$value];
} else {
$value = $arrMapper['tl_theme'][$value];
}
} elseif ($name == 'fallback') {
$value = '';
} elseif ($table == 'tl_layout' && $name == 'stylesheet') {
$stylesheets = \StringUtil::deserialize($value);
if (is_array($stylesheets)) {
foreach (array_keys($stylesheets) as $key) {
$stylesheets[$key] = $arrMapper['tl_style_sheet'][$stylesheets[$key]];
}
$value = serialize($stylesheets);
}
} elseif ($table == 'tl_layout' && $name == 'modules') {
$modules = \StringUtil::deserialize($value);
if (is_array($modules)) {
foreach ($modules as $key => $mod) {
if ($mod['mod'] > 0) {
$modules[$key]['mod'] = $arrMapper['tl_module'][$mod['mod']];
}
}
$value = serialize($modules);
}
} elseif (($table == 'tl_theme' || $table == 'tl_style_sheet') && $name == 'name') {
$objCount = $this->Database->prepare("SELECT COUNT(*) AS count FROM " . $table . " WHERE name=?")->execute($value);
if ($objCount->count > 0) {
$value = preg_replace('/( |\\-)[0-9]+$/', '', $value);
$value .= ($table == 'tl_style_sheet' ? '-' : ' ') . ${$table};
}
} elseif (($table == 'tl_style_sheet' || $table == 'tl_style' || $table == 'tl_files' && $name == 'path') && strpos($value, 'files') !== false) {
$tmp = \StringUtil::deserialize($value);
if (is_array($tmp)) {
foreach ($tmp as $kk => $vv) {
$tmp[$kk] = $this->customizeUploadPath($vv);
}
$value = serialize($tmp);
} else {
$value = $this->customizeUploadPath($value);
}
} elseif ($GLOBALS['TL_DCA'][$table]['fields'][$name]['inputType'] == 'fileTree' && !$GLOBALS['TL_DCA'][$table]['fields'][$name]['eval']['multiple']) {
if (!$value) {
$value = null;
// Contao >= 3.2
} else {
// Do not use the FilesModel here – tables are locked!
$objFile = $this->Database->prepare("SELECT uuid FROM tl_files WHERE path=?")->limit(1)->execute($this->customizeUploadPath($value));
$value = $objFile->uuid;
}
} elseif ($GLOBALS['TL_DCA'][$table]['fields'][$name]['inputType'] == 'fileTree' || in_array($name, $arrOrder)) {
$tmp = \StringUtil::deserialize($value);
if (is_array($tmp)) {
foreach ($tmp as $kk => $vv) {
// Do not use the FilesModel here – tables are locked!
$objFile = $this->Database->prepare("SELECT uuid FROM tl_files WHERE path=?")->limit(1)->execute($this->customizeUploadPath($vv));
$tmp[$kk] = $objFile->uuid;
}
$value = serialize($tmp);
}
} elseif ($GLOBALS['TL_DCA'][$table]['fields'][$name]['inputType'] == 'imageSize') {
$imageSizes = \StringUtil::deserialize($value, true);
if (!empty($imageSizes)) {
if (is_numeric($imageSizes[2])) {
$imageSizes[2] = $arrMapper['tl_image_size'][$imageSizes[2]];
}
}
$value = serialize($imageSizes);
}
$set[$name] = $value;
}
// Skip fields that are not in the database (e.g. because of missing extensions)
foreach ($set as $k => $v) {
if (!in_array($k, $arrDbFields[$table])) {
unset($set[$k]);
}
}
// Create the templates folder even if it is empty (see #4793)
if ($table == 'tl_theme' && isset($set['templates']) && strncmp($set['templates'], 'templates/', 10) === 0 && !is_dir(TL_ROOT . '/' . $set['templates'])) {
new \Folder($set['templates']);
}
// Update tl_files (entries have been created by the Dbafs class)
if ($table == 'tl_files') {
$this->Database->prepare("UPDATE {$table} %s WHERE path=?")->set($set)->execute($set['path']);
} else {
$this->Database->prepare("INSERT INTO {$table} %s")->set($set)->execute();
}
}
}
// Unlock the tables
$this->Database->unlockTables();
// Update the style sheets
$this->import('StyleSheets');
$this->StyleSheets->updateStyleSheets();
// Notify the user
\Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_theme']['theme_imported'], basename($strZipFile)));
// HOOK: add custom logic
if (isset($GLOBALS['TL_HOOKS']['extractThemeFiles']) && is_array($GLOBALS['TL_HOOKS']['extractThemeFiles'])) {
$intThemeId = empty($arrMapper['tl_theme']) ? null : reset($arrMapper['tl_theme']);
foreach ($GLOBALS['TL_HOOKS']['extractThemeFiles'] as $callback) {
\System::importStatic($callback[0])->{$callback[1]}($xml, $objArchive, $intThemeId, $arrMapper);
}
}
unset($tl_files, $tl_theme, $tl_style_sheet, $tl_style, $tl_module, $tl_layout, $tl_image_size, $tl_image_size_item);
}
\System::setCookie('BE_PAGE_OFFSET', 0, 0);
/** @var SessionInterface $objSession */
$objSession = \System::getContainer()->get('session');
$objSession->remove('uploaded_themes');
// Redirect
$this->redirect(str_replace('&key=importTheme', '', \Environment::get('request')));
}