* @copyright (c) 2015, conlite.org * @license http://www.gnu.de/documents/gpl.en.html GPL v3 (english version) * @license http://www.gnu.de/documents/gpl.de.html GPL v3 (deutsche Version) * @link http://www.conlite.org ConLite.org * * $Id$ */ if (!defined('CON_FRAMEWORK')) { die('Illegal call'); } cInclude('includes', 'functions.upl.php'); class cApiModuleCollection extends ItemCollection { /** * Constructor Function * @param none */ public function __construct() { global $cfg; parent::__construct($cfg["tab"]["mod"], "idmod"); $this->_setItemClass("cApiModule"); } /** * Creates a new communication item */ public function create($name) { global $auth, $client; $item = parent::createNewItem(); $item->set("idclient", $client); $item->set("name", $name); $item->set("author", $auth->auth["uid"]); $item->set("created", date("Y-m-d H:i:s"), false); $item->store(); return $item; } public function delete($iIdMod) { /* @var $oMod cApiModule */ $oMod = $this->_itemClassInstance; $oMod->_bNoted = TRUE; $oMod->loadByPrimaryKey($iIdMod); if ($oMod->isLoaded()) { if ($oMod->hasModuleFolder()) { $oMod->deleteModuleFolder(); } } unset($oMod); return parent::delete($iIdMod); } } /** * Module access class */ class cApiModule extends Item { protected $_error; /** * Assoziative package structure array * @var array */ protected $_packageStructure; protected $_bOutputFromFile = false; protected $_bInputFromFile = false; /** * @var array */ private $aUsedTemplates = array(); /** * Configuration Array of ModFileEdit * array is set with entries in local config file * * @var array */ private $_aModFileEditConf = array( 'use' => false, 'modFolderName' => 'data/modules' ); /** * * @var string */ private $_sModAlias; /** * * @var string */ private $_sModPath; private $_aModDefaultStruct = array( 'css', 'js', 'php', 'template', 'image', 'lang', 'xml' ); /** * Constructor Function * @param mixed $mId Specifies the ID of item to load */ public function __construct($mId = false) { global $cfg, $cfgClient, $client; parent::__construct($cfg["tab"]["mod"], "idmod"); // Using no filters is just for compatibility reasons. // That's why you don't have to stripslashes values if you store them // using ->set. You have to add slashes, if you store data directly // (data not from a form field) $this->setFilters(array(), array()); $this->_packageStructure = array("jsfiles" => $cfgClient[$client]["js"]["path"], "tplfiles" => $cfgClient[$client]["tpl"]["path"], "cssfiles" => $cfgClient[$client]["css"]["path"]); if (isset($cfg['dceModEdit']) && is_array($cfg['dceModEdit'])) { $this->_aModFileEditConf['clientPath'] = $cfgClient[$client]["path"]["frontend"]; $this->_aModFileEditConf = array_merge($this->_aModFileEditConf, $cfg['dceModEdit']); if (!isset($cfg['dceModEdit']['modPath']) || empty($cfg['dceModEdit']['modPath'])) { $this->_aModFileEditConf['modPath'] = $cfgClient[$client]["path"]["frontend"] . $this->_aModFileEditConf['modFolderName'] . "/"; } } $oClient = new cApiClient($client); $aClientProp = $oClient->getPropertiesByType('modfileedit'); if (count($aClientProp) > 0) { $this->_aModFileEditConf = array_merge($this->_aModFileEditConf, $aClientProp); } if ($mId !== false) { $this->loadByPrimaryKey($mId); } } public function createModuleFolder() { //echo $this->_aModFileEditConf['modPath']; $sPathErrorLog = cRegistry::getConfigValue('path', 'logs').'errorlog.txt'; if (is_writable($this->_aModFileEditConf['clientPath']) && !file_exists($this->_aModFileEditConf['modPath'])) { try { mkdir($this->_aModFileEditConf['modPath'], 0777, true); } catch (Exception $ex) { $oWriter = cLogWriter::factory("File", array('destination' => $sPathErrorLog)); $oLog = new cLog($oWriter); $oLog->log($ex->getFile() . " (" . $ex->getLine() . "): " . $ex->getMessage(), cLog::WARN); } } if ($this->_aModFileEditConf['use'] == true && is_writable($this->_aModFileEditConf['modPath'])) { if (!is_dir($this->getModulePath())) { $this->_oldumask = umask(0); try { mkdir($this->getModulePath(), 0777); } catch (Exception $ex) { $oWriter = cLogWriter::factory("File", array('destination' => $sPathErrorLog)); $oLog = new cLog($oWriter); $oLog->log($ex->getFile() . " (" . $ex->getLine() . "): " . $ex->getMessage(), cLog::WARN); } if (is_writable($this->getModulePath())) { return $this->_createModuleStruct(); } umask($this->_oldumask); } } else { $oWriter = cLogWriter::factory("File", array('destination' => $sPathErrorLog)); $oLog = new cLog($oWriter); $oLog->log(__FILE__ . " (" . __LINE__ . "): " . 'Error: Cannot create mod path '.$this->getModulePath(), cLog::WARN); } return FALSE; } public function deleteModuleFolder() { if ($this->_aModFileEditConf['use'] == TRUE && is_writable($this->_aModFileEditConf['modPath'])) { if (is_dir($this->getModulePath())) { return $this->_recursiveRemoveDirectory($this->getModulePath()); } } return FALSE; } public function getModuleAlias() { return $this->_sModAlias; } public function hasModuleFolder() { $sOldPath = $this->_aModFileEditConf['modPath'] . uplCreateFriendlyName($this->get("name")); return (file_exists($this->getModulePath()) || file_exists($sOldPath)); } public function getModulePath() { if (empty($this->_sModPath)) { $this->_setModulePath(); } return $this->_sModPath; } protected function _setModulePath() { $this->_sModPath = $this->_aModFileEditConf['modPath'] . $this->getModuleAlias() . "/"; } /** * Returns the translated name of the module if a translation exists. * * @param none * @return string Translated module name or original */ public function getTranslatedName() { global $lang; // If we're not loaded, return if ($this->virgin == true) { return false; } $modname = $this->getProperty("translated-name", $lang); if ($modname === false) { return $this->get("name"); } else { return $modname; } } /** * Sets the translated name of the module * * @param $name string Translated name of the module * @return none */ public function setTranslatedName($name) { global $lang; $this->setProperty("translated-name", $lang, $name); } /** * Parses the module for mi18n strings and returns them in an array * * @return array Found strings for this module */ public function parseModuleForStrings() { if ($this->virgin == true) { return false; } // Fetch the code, append input to output $code = $this->get("output"); $code .= $this->get("input"); // Initialize array $strings = array(); // Split the code into mi18n chunks $varr = preg_split('/mi18n([\s]*)\(([\s]*)"/', $code, -1); if (count($varr) > 1) { foreach ($varr as $key => $value) { // Search first closing $closing = strpos($value, '")'); if ($closing === false) { $closing = strpos($value, '" )'); } if ($closing !== false) { $value = substr($value, 0, $closing) . '")'; } // Append mi18n again $varr[$key] = 'mi18n("' . $value; // Parse for the mi18n stuff preg_match_all('/mi18n([\s]*)\("(.*)"\)/', $varr[$key], $results); // Append to strings array if there are any results if (is_array($results[1]) && count($results[2]) > 0) { $strings = array_merge($strings, $results[2]); } // Unset the results for the next run unset($results); } } // adding dynamically new module translations by content types // this function was introduced with contenido 4.8.13 // checking if array is set to prevent crashing the module translation page if (is_array($cfg['translatable_content_types']) && count($cfg['translatable_content_types']) > 0) { // iterate over all defines cms content types foreach ($cfg['translatable_content_types'] as $sContentType) { // check if the content type exists and include his class file if (file_exists($cfg['contenido']['path'] . "classes/class." . strtolower($sContentType) . ".php")) { cInclude("classes", "class." . strtolower($sContentType) . ".php"); // if the class exists, has the method "addModuleTranslations" // and the current module contains this cms content type we // add the additional translations for the module if (class_exists($sContentType) && method_exists($sContentType, 'addModuleTranslations') && preg_match('/' . strtoupper($sContentType) . '\[\d+\]/', $code)) { $strings = call_user_func(array($sContentType, 'addModuleTranslations'), $strings); } } } } // Make the strings unique return array_unique($strings); } /** * Checks if the module is in use * @return bool Specifies if the module is in use */ public function moduleInUse($module, $bSetData = false) { global $cfg; $db = new DB_ConLite(); $sql = "SELECT c.idmod, c.idtpl, t.name FROM " . $cfg["tab"]["container"] . " as c, " . $cfg["tab"]["tpl"] . " as t WHERE c.idmod = '" . Contenido_Security::toInteger($module) . "' AND t.idtpl=c.idtpl GROUP BY c.idtpl ORDER BY t.name"; $db->query($sql); if ($db->nf() == 0) { return false; } else { $i = 0; // save the datas of used templates in array if ($bSetData === true) { while ($db->next_record()) { $this->aUsedTemplates[$i]['tpl_name'] = $db->f('name'); $this->aUsedTemplates[$i]['tpl_id'] = (int) $db->f('idmod'); $i++; } } return true; } } /** * Get the informations of used templates * @return array template data */ public function getUsedTemplates() { return $this->aUsedTemplates; } /** * Checks if the module is a pre-4.3 module * @return boolean true if this module is an old one */ public function isOldModule() { // Keywords to scan $scanKeywords = array('$cfgTab', 'idside', 'idsidelang'); $input = $this->get("input"); $output = $this->get("output"); foreach ($scanKeywords as $keyword) { if (strstr($input, $keyword)) { return true; } if (strstr($output, $keyword)) { return true; } } } public function getField($field) { $value = parent::getField($field); switch ($field) { case "name": if ($value == "") { $value = i18n("- Unnamed Module -"); } } return ($value); } public function store($bJustStore = false) { global $cfg; /* dceModFileEdit (c)2009-2011 www.dceonline.de */ if ($this->_aModFileEditConf['use'] == true && ($this->_aModFileEditConf['allModsFromFile'] == true || in_array($this->get('idmod'), $this->_aModFileEditConf['modsFromFile']))) { $this->modifiedValues['output'] = true; $this->modifiedValues['input'] = true; } /* End dceModFileEdit (c)2009-2011 www.dceonline.de */ if ($bJustStore) { // Just store changes, e.g. if specifying the mod package parent::store(); } else { cInclude("includes", "functions.con.php"); parent::store(); conGenerateCodeForAllArtsUsingMod($this->get("idmod")); if ($this->_shouldStoreToFile()) { if ($this->_makeFileDirectoryStructure()) { $sRootPath = $cfg['path']['contenido'] . $cfg['path']['modules'] . $this->get("idclient") . "/"; file_put_contents($sRootPath . $this->get("idmod") . ".xml", $this->export($this->get("idmod") . ".xml", true)); } } } } public function getModFileEditConf() { return $this->_aModFileEditConf; } protected function _recursiveRemoveDirectory($directory) { foreach (glob("{$directory}/*") as $file) { if (is_dir($file)) { $this->_recursiveRemoveDirectory($file); } else { unlink($file); } } return rmdir($directory); } protected function _makeFileDirectoryStructure() { global $cfg; $sRootPath = $cfg['path']['contenido'] . $cfg['path']['modules']; if (!is_dir($sRootPath)) { @mkdir($sRootPath); } $sRootPath = $cfg['path']['contenido'] . $cfg['path']['modules'] . $this->get("idclient") . "/"; if (!is_dir($sRootPath)) { @mkdir($sRootPath); } if (is_dir($sRootPath)) { return true; } else { return false; } } protected function _shouldStoreToFile() { if (getSystemProperty("modules", "storeasfiles") == "true") { return true; } else { return false; } } protected function _shouldLoadFromFiles() { if (getSystemProperty("modules", "loadfromfiles") == "true") { return true; } else { return false; } } /** * Parse import xml file, stores data in global variable (-> event handler functions) * * @param string $sFile Filename including path of import xml file * @param string $sType Import type, "module" or "package" * @return bool Returns true, if file has been parsed */ private function _parseImportFile($sFile, $sType = "module", $sEncoding = "ISO-8859-1") { global $_mImport; $oParser = new XmlParser($sEncoding); if ($sType == "module") { $oParser->setEventHandlers(array("/module/name" => "cHandler_ModuleData", "/module/description" => "cHandler_ModuleData", "/module/type" => "cHandler_ModuleData", "/module/input" => "cHandler_ModuleData", "/module/output" => "cHandler_ModuleData")); } else { $aHandler = array("/modulepackage/guid" => "cHandler_ModuleData", #"/modulepackage/repository_guid" => "cHandler_ModuleData", "/modulepackage/module/name" => "cHandler_ModuleData", "/modulepackage/module/description" => "cHandler_ModuleData", "/modulepackage/module/type" => "cHandler_ModuleData", "/modulepackage/module/input" => "cHandler_ModuleData", "/modulepackage/module/output" => "cHandler_ModuleData", "/modulepackage/module/input" => "cHandler_ModuleData"); // Add file handler (e.g. js, css, templates) foreach ($this->_packageStructure As $sFileType => $sFilePath) { // Note, that $aHandler["/modulepackage/" . $sFileType] and using // a handler which uses the node name (here: FileType) doesn't work, // as the event handler for the filetype node will be fired // after the node has been successfully parsed, not before. // So, we have a little redundancy here, but maybe we need // this in the future. $aHandler["/modulepackage/" . $sFileType . "/area"] = "cHandler_ItemArea"; $aHandler["/modulepackage/" . $sFileType . "/name"] = "cHandler_ItemName"; $aHandler["/modulepackage/" . $sFileType . "/content"] = "cHandler_ItemData"; } // Layouts $aHandler["/modulepackage/layouts/area"] = "cHandler_ItemArea"; $aHandler["/modulepackage/layouts/name"] = "cHandler_ItemName"; $aHandler["/modulepackage/layouts/description"] = "cHandler_ItemData"; $aHandler["/modulepackage/layouts/content"] = "cHandler_ItemData"; // Translations $aHandler["/modulepackage/translations/language"] = "cHandler_ItemArea"; $aHandler["/modulepackage/translations/string/original"] = "cHandler_ItemName"; $aHandler["/modulepackage/translations/string/translation"] = "cHandler_Translation"; $oParser->setEventHandlers($aHandler); } if ($oParser->parseFile($sFile)) { return true; } else { $this->_error = $oParser->error; return false; } } /** * Imports the a module from a XML file * Uses xmlparser and callbacks * * @param string $file Filename of data file (full path) */ public function import($sFile) { global $_mImport; if ($this->_parseImportFile($sFile, "module")) { $bStore = false; foreach ($_mImport["module"] as $key => $value) { if ($this->get($key) != $value) { $this->set($key, addslashes($value)); $bStore = true; } } if ($bStore == true) { $this->store(); } return true; } else { return false; } } /** * Exports the specified module strings to a file * * @param $filename string Filename to return * @param $return boolean if false, the result is immediately sent to the browser */ public function export($filename, $return = false) { $tree = new XmlTree('1.0', 'ISO-8859-1'); $root = & $tree->addRoot('module'); $root->appendChild("name", clHtmlSpecialChars($this->get("name"))); $root->appendChild("description", clHtmlSpecialChars($this->get("description"))); $root->appendChild("type", clHtmlSpecialChars($this->get("type"))); $root->appendChild("input", clHtmlSpecialChars($this->get("input"))); $root->appendChild("output", clHtmlSpecialChars($this->get("output"))); if ($return == false) { ob_end_clean(); header("Content-Type: text/xml"); header("Etag: " . md5(mt_rand())); header("Content-Disposition: attachment;filename=\"$filename\""); $tree->dump(false); } else { return stripslashes($tree->dump(true)); } } public function getPackageOverview($sFile) { global $_mImport; if ($this->_parseImportFile($sFile, "package")) { $aData = array(); $aData["guid"] = $_mImport["module"]["guid"]; $aData["repository_guid"] = $_mImport["module"]["repository_guid"]; $aData["name"] = $_mImport["module"]["name"]; // Files foreach ($this->_packageStructure as $sFileType => $sFilePath) { if (is_array($_mImport["items"][$sFileType])) { $aData[$sFileType] = array_keys($_mImport["items"][$sFileType]); } } // Layouts if (is_array($_mImport["items"]["layouts"])) { $aData["layouts"] = array_keys($_mImport["items"]["layouts"]); } // Translation languages if (is_array($_mImport["translations"])) { $aData["translations"] = array_keys($_mImport["translations"]); } return $aData; } else { return false; } } /** * Imports a module package from a XML file Uses xmlparser and callbacks * * @param string $sFile Filename of data file (including path) * @param array $aOptions Optional. An array of arrays specifying, how the items * of the xml file will be imported. If specified, has to * contain an array of this structure: * * $aOptions["items"][][] = "skip", "append" or "overwrite"; * $aOptions["translations"][] = ; * * If a file is not mentioned in the $aOptions["items"][] * array, it is new and will be imported. * * If a is not found in $aOptions["translations"], * then the translations for this language will be ignored * * @return bool Returns true, if import has been successfully finished */ public function importPackage($sFile, $aOptions = array()) { global $_mImport, $client; cInclude("includes", "functions.file.php"); cInclude("includes", "functions.lay.php"); // You won't believe the code in there (or what is missing in class.layout.php...) // Ensure correct options structure foreach ($this->_packageStructure as $sFileType => $sFilePath) { if (!is_array($aOptions["items"][$sFileType])) { $aOptions["items"][$sFileType] = array(); } } // Layouts if (!is_array($aOptions["items"]["layouts"])) { $aOptions["items"]["layouts"] = array(); } // Translations if (!is_array($aOptions["translations"])) { $aOptions["translations"] = array(); } // Parse file if ($this->_parseImportFile($sFile, "package")) { // Import data // Module foreach ($_mImport["module"] as $sKey => $sData) { if ($this->get($sKey) != $sData) { $this->set($sKey, addslashes($sData)); $bStore = true; } } if ($bStore == true) { $this->store(); } // Files foreach ($this->_packageStructure as $sFileType => $sFilePath) { if (is_array($_mImport["items"][$sFileType])) { foreach ($_mImport["items"][$sFileType] as $sFileName => $aContent) { if (!array_key_exists(clHtmlSpecialChars($sFileName), $aOptions["items"][$sFileType]) || $aOptions["items"][$sFileType][clHtmlSpecialChars($sFileName)] == "overwrite") { if (!file_exists($sFilePath . $sFileName)) { createFile($sFileName, $sFilePath); } fileEdit($sFileName, $aContent["content"], $sFilePath); } else if ($aOptions["items"][$sFileType][clHtmlSpecialChars($sFileName)] == "append") { $sOriginalContent = getFileContent($sFileName, $sFilePath); fileEdit($sFileName, $sOriginalContent . $aContent["content"], $sFilePath); } } } } // Layouts if (is_array($_mImport["items"]["layouts"])) { foreach ($_mImport["items"]["layouts"] as $sLayout => $aContent) { if (!array_key_exists(clHtmlSpecialChars($sLayout), $aOptions["items"]["layouts"]) || $aOptions["items"]["layouts"][clHtmlSpecialChars($sLayout)] == "overwrite") { $oLayouts = new cApiLayoutCollection; $oLayouts->setWhere("idclient", $client); $oLayouts->setWhere("name", $sLayout); $oLayouts->query(); if (!$oLayout = $oLayouts->next()) { layEditLayout(false, addslashes($sLayout), addslashes($aContent["description"]), addslashes($aContent["content"])); } else { layEditLayout($oLayout->get($oLayout->primaryKey), addslashes($sLayout), addslashes($aContent["description"]), addslashes($aContent["content"])); } } elseif ($aOptions["items"]["layouts"][clHtmlSpecialChars($sLayout)] == "append") { $oLayouts = new cApiLayoutCollection; $oLayouts->setWhere("idclient", $client); $oLayouts->setWhere("name", $sLayout); $oLayouts->query(); if (!$oLayout = $oLayouts->next()) { layEditLayout(false, addslashes($sLayout), addslashes($aContent["description"]), addslashes($aContent["content"])); } else { layEditLayout($oLayout->get($oLayout->primaryKey), addslashes($sLayout), addslashes($oLayout->get("description") . $aContent["description"]), addslashes($oLayout->get("code") . $aContent["content"])); } } } } // Translations if (is_array($_mImport["translations"])) { $oTranslations = new cApiModuleTranslationCollection(); $iID = $this->get($this->primaryKey); foreach ($_mImport["translations"] as $sPackageLang => $aTranslations) { if (array_key_exists($sPackageLang, $aOptions["translations"])) { foreach ($_mImport["translations"][$sPackageLang] as $sOriginal => $sTranslation) { $oTranslations->create($iID, $aOptions["translations"][$sPackageLang], $sOriginal, $sTranslation); } } } } return true; } else { return false; } } /** * Exports the specified module and attached files to a file * * @param string $sPackageFileName Filename to return * @param bool $bReturn if false, the result is immediately sent to the browser */ public function exportPackage($sPackageFileName, $bReturn = false) { global $cfgClient, $client; cInclude("includes", "functions.file.php"); $oTree = new XmlTree('1.0', 'ISO-8859-1'); $oRoot = & $oTree->addRoot('modulepackage'); $oRoot->appendChild("package_guid", $this->get("package_guid")); $oRoot->appendChild("package_data", $this->get("package_data")); // This is serialized and more or less informal data $aData = unserialize($this->get("package_data")); if (!is_array($aData)) { $aData = array(); $aData["repository_guid"] = ""; $aData["jsfiles"] = array(); $aData["tplfiles"] = array(); $aData["cssfiles"] = array(); $aData["layouts"] = array(); $aData["translations"] = array(); } // Export basic module $oNodeModule = & $oRoot->appendChild("module"); $oNodeModule->appendChild("name", clHtmlSpecialChars($this->get("name"))); $oNodeModule->appendChild("description", clHtmlSpecialChars($this->get("description"))); $oNodeModule->appendChild("type", clHtmlSpecialChars($this->get("type"))); $oNodeModule->appendChild("input", clHtmlSpecialChars($this->get("input"))); $oNodeModule->appendChild("output", clHtmlSpecialChars($this->get("output"))); // Export files (e.g. js, css, templates) foreach ($this->_packageStructure As $sFileType => $sFilePath) { $oNodeFiles = & $oRoot->appendChild($sFileType); if (count($aData[$sFileType]) > 0) { foreach ($aData[$sFileType] as $sFileName) { if (is_readable($sFilePath . $sFileName)) { $sContent = getFileContent($sFileName, $sFilePath); $oNodeFiles->appendChild("area", clHtmlSpecialChars($sFileType)); $oNodeFiles->appendChild("name", clHtmlSpecialChars($sFileName)); $oNodeFiles->appendChild("content", clHtmlSpecialChars($sContent)); } } } } unset($sContent); // Export layouts $oNodeLayouts = & $oRoot->appendChild("layouts"); $oLayouts = new cApiLayoutCollection; $oLayouts->setWhere("idclient", $client); $oLayouts->query(); while ($oLayout = $oLayouts->next()) { if (in_array($oLayout->get($oLayout->primaryKey), $aData["layouts"])) { $oNodeLayouts->appendChild("area", "layouts"); $oNodeLayouts->appendChild("name", clHtmlSpecialChars($oLayout->get("name"))); $oNodeLayouts->appendChild("description", clHtmlSpecialChars($oLayout->get("description"))); $oNodeLayouts->appendChild("content", clHtmlSpecialChars($oLayout->get("code"))); } } unset($oLayout); unset($oLayouts); // Export translations $oLangs = new cApiLanguageCollection(); $oLangs->setOrder("idlang"); $oLangs->query(); if ($oLangs->count() > 0) { $iIDMod = $this->get($this->primaryKey); while ($oLang = $oLangs->next()) { $iID = $oLang->get($oLang->primaryKey); if (in_array($iID, $aData["translations"])) { $oNodeTrans = & $oRoot->appendChild("translations"); // This is nice, but it doesn't help so much, // as this data is available too late on import ... $oNodeTrans->setNodeAttribs(array("origin-language-id" => $iID, "origin-language-name" => clHtmlSpecialChars($oLang->get("name")))); // ... so we store the important information with the data $oNodeTrans->appendChild("language", clHtmlSpecialChars($oLang->get("name"))); $oTranslations = new cApiModuleTranslationCollection; $oTranslations->setWhere("idmod", $iIDMod); $oTranslations->setWhere("idlang", $iID); $oTranslations->query(); while ($oTranslation = $oTranslations->next()) { $oNodeString = & $oNodeTrans->appendChild("string"); $oNodeString->appendChild("original", clHtmlSpecialChars($oTranslation->get("original"))); $oNodeString->appendChild("translation", clHtmlSpecialChars($oTranslation->get("translation"))); } } } } unset($oLangs); unset($oLang); if ($bReturn == false) { ob_end_clean(); header("Content-Type: text/xml"); header("Etag: " . md5(mt_rand())); header("Content-Disposition: attachment;filename=\"$sPackageFileName\""); $oTree->dump(false); } else { return stripslashes($oTree->dump(true)); } } /* dceModFileEdit (c)2009-2012 www.dceonline.de */ /** * Overridden parent method for hooking dceModFileEdit * * @return void */ protected function _onLoad() { $this->_sModAlias = strtolower(uplCreateFriendlyName($this->get('name'))); $this->_sModAliasOld = uplCreateFriendlyName($this->get('name')); $this->_setOutputFromPhpFile(); $this->_setInputFromPhpFile(); } /** * Use a PHP-file, if present, for module output * * @return boolean */ private function _setOutputFromPhpFile() { // dceModEdit not enabled or not present if ($this->_aModFileEditConf['use'] !== true) { return false; } return $this->_setFieldFromFile('output', $this->_sModAlias . "_output.php"); } /** * Use a PHP-file, if present, for module input * * @return boolean */ private function _setInputFromPhpFile() { cInclude('includes', 'functions.upl.php'); // dceModEdit not enabled or not present if ($this->_aModFileEditConf['use'] !== true) { return false; } return $this->_setFieldFromFile('input', $this->_sModAlias . "_input.php"); } private function _displayNoteFromFile($bIsOldPath = FALSE) { if (isset($this->_bNoted) && $this->_bNoted === true) { return; } global $frame, $area; if ($frame == 4 && $area == 'mod_edit') { $sAddMess = ''; if ($bIsOldPath) { $sAddMess .= "
" . i18n("Using old CamelCase for name of modulefolder. You may lowercase the name for modulefolder"); } $oNote = new Contenido_Notification(); $oNote->displayNotification('warning', i18n("Module uses Output- and/or InputFromFile. Editing and Saving may not be possible in backend.") . $sAddMess); $this->_bNoted = true; } } /** * read file and set an object field * * @param string $sFile * @param string $sField * @return boolean */ private function _setFieldFromFile($sField, $sFile) { $bIsOldPath = TRUE; $sFile = strtolower($sFile); if (FALSE === strstr($sFile, $this->_aModFileEditConf['modPath'])) { $sFile = $this->_aModFileEditConf['modPath'] . $sFile; } // check for new struct since CL 2.0 if (is_dir($this->_aModFileEditConf['modPath'] . $this->_sModAlias) && is_writable($this->_aModFileEditConf['modPath'] . $this->_sModAlias) && file_exists($this->_aModFileEditConf['modPath'] . $this->_sModAlias . "/php/" . $this->_sModAlias . "_" . $sField . ".php")) { $sFile = $this->_aModFileEditConf['modPath'] . $this->_sModAlias . "/php/" . $this->_sModAlias . "_" . $sField . ".php"; $bIsOldPath = FALSE; } if (is_file($sFile) && is_readable($sFile)) { $iFileSize = (int) filesize($sFile); if ($iFileSize > 0 && $fh = fopen($sFile, 'r')) { $this->set($sField, fread($fh, $iFileSize), false); fclose($fh); switch ($sField) { case "output": $this->_bOutputFromFile = true; break; case "input": $this->_bInputFromFile = true; default: break; } $this->_displayNoteFromFile($bIsOldPath); return true; } } else { switch ($sField) { case "output": $this->_bOutputFromFile = false; break; case "input": $this->_bInputFromFile = false; default: break; } } return false; } public function isLoadedFromFile($sWhat = "all") { switch ($sWhat) { case "all": return (($this->_bOutputFromFile || $this->_bInputFromFile) ? TRUE : FALSE); break; case "output": return $this->_bOutputFromFile; case "input": return $this->_bInputFromFile; default: return false; } } /* End dceModFileEdit (c)2009-2012 www.dceonline.de */ private function _createModuleStruct() { $bDone = FALSE; if ($this->_aModFileEditConf['use'] == TRUE && is_writable($this->_sModPath)) { $bDone = TRUE; foreach ($this->_aModDefaultStruct as $sFolder) { $bDone = $bDone && mkdir($this->_sModPath . $sFolder); } } $this->_createModulePhpFiles(); umask($this->_oldumask); return $bDone; } private function _createModulePhpFiles() { $sPath = $this->_sModPath . "php/"; $aFileTpl = array( 'output' => "", 'input' => "?>_sModAlias . "_output.php"; $sInputFile = $sPath . $this->_sModAlias . "_input.php"; if (!file_exists($sOutputFile)) { $rFileHandler = fopen($sOutputFile, "w"); if (is_resource($rFileHandler)) { if ($this->getField('output') == "") { fwrite($rFileHandler, $aFileTpl['output']); } else { fwrite($rFileHandler, $this->getField('output')); } fclose($rFileHandler); } } if (!file_exists($sInputFile)) { $rFileHandler = fopen($sInputFile, "w"); if (is_resource($rFileHandler)) { if ($this->getField('input') == "") { fwrite($rFileHandler, $aFileTpl['input']); } else { fwrite($rFileHandler, $this->getField('input')); } fclose($rFileHandler); } } } } } // end class class cApiModuleTranslationCollection extends ItemCollection { protected $_error; protected $f_obj; /** * Constructor Function * @param none */ public function __construct() { global $cfg; parent::__construct($cfg["tab"]["mod_translations"], "idmodtranslation"); $this->_setItemClass("cApiModuleTranslation"); } /** * Creates a new module translation item */ public function create($idmod, $idlang, $original, $translation = false) { // Check if the original already exists. If it does, // update the translation if passed $mod = new cApiModuleTranslation(); $sorg = $mod->_inFilter($original); $this->select("idmod = '$idmod' AND idlang = '$idlang' AND original = '$sorg'"); if ($item = $this->next()) { if ($translation !== false) { $item->set("translation", $translation); $item->store(); } return $item; } else { $item = parent::createNewItem(); $item->set("idmod", $idmod); $item->set("idlang", $idlang); $item->set("original", $original); $item->set("translation", $translation); $item->store(); return $item; } } /** * Fetches a translation * * @param $module int Module ID * @param $lang int Language ID * @param $string string String to lookup */ public function fetchTranslation($module, $lang, $string) { // If the f_obj does not exist, create one if (!is_object($this->f_obj)) { $this->f_obj = new cApiModuleTranslation(); } // Create original string $sorg = $this->_itemClassInstance->_inFilter($string); // Look up $this->select("idmod = '$module' AND idlang='$lang' AND original = '$sorg'"); if ($t = $this->next()) { $translation = $t->get("translation"); if ($translation != "") { return $translation; } else { return $string; } } else { return $string; } } public function import($idmod, $idlang, $file) { global $_mImport; $parser = new XmlParser("ISO-8859-1"); $parser->setEventHandlers(array("/module/translation/string/original" => "cHandler_ItemName", "/module/translation/string/translation" => "cHandler_Translation")); $_mImport["current_item_area"] = "current"; // Pre-specification, as this won't be set from the XML file (here) if ($parser->parseFile($file)) { foreach ($_mImport["translations"]["current"] as $sOriginal => $sTranslation) { $this->create($idmod, $idlang, $sOriginal, $sTranslation); } return true; } else { $this->_error = $parser->error; return false; } } /** * Exports the specified module strings to a file * * @param $idmod int Module ID * @param $idlang int Language ID * @param $filename string Filename to return * @param $return boolean if false, the result is immediately sent to the browser */ public function export($idmod, $idlang, $filename, $return = false) { $langobj = new cApiLanguage($idlang); #$langstring = $langobj->get("name") . ' ('.$idlang.')'; $translations = new cApiModuleTranslationCollection; $translations->select("idmod = '$idmod' AND idlang='$idlang'"); $tree = new XmlTree('1.0', 'ISO-8859-1'); $root = & $tree->addRoot('module'); $translation = & $root->appendChild('translation'); $translation->setNodeAttribs(array("origin-language-id" => $idlang, "origin-language-name" => $langobj->get("name"))); while ($otranslation = $translations->next()) { $string = &$translation->appendChild("string"); $string->appendChild("original", clHtmlSpecialChars($otranslation->get("original"))); $string->appendChild("translation", clHtmlSpecialChars($otranslation->get("translation"))); } if ($return == false) { header("Content-Type: text/xml"); header("Etag: " . md5(mt_rand())); header("Content-Disposition: attachment;filename=\"$filename\""); $tree->dump(false); } else { return $tree->dump(true); } } } /** * Module access class */ class cApiModuleTranslation extends Item { /** * Constructor Function * @param $loaditem Item to load */ public function __construct($loaditem = false) { global $cfg; parent::__construct($cfg["tab"]["mod_translations"], "idmodtranslation"); if ($loaditem !== false) { $this->loadByPrimaryKey($loaditem); } } public function useInFilter($sValue) { return $this->_inFilter($sValue); } } function cHandler_ModuleData($sName, $aAttribs, $sContent) { global $_mImport; $_mImport["module"][$sName] = $sContent; } // The following three functions references all file data (e.g. for css, // js and template files) and layout data // Note, that first the type is specified (from the "area" information // in the xml file). // Second, filename is specified based on "name" node content. // Third, file content is stored using type, name and node content. // You will have to specify individual handler functions, if one of // the file areas may store additional data (e.g. a description) function cHandler_ItemArea($sName, $aAttribs, $sContent) { global $_mImport; $_mImport["current_item_area"] = $sContent; } function cHandler_ItemName($sName, $aAttribs, $sContent) { global $_mImport; $_mImport["current_item_name"] = $sContent; } function cHandler_ItemData($sName, $aAttribs, $sContent) { global $_mImport; $_mImport["items"][$_mImport["current_item_area"]][$_mImport["current_item_name"]][$sName] = $sContent; } // Separate language area, as someone may specify "cssfiles" or something // as language name, funny guy... function cHandler_Translation($sName, $aAttribs, $sContent) { global $_mImport; $_mImport["translations"][$_mImport["current_item_area"]][$_mImport["current_item_name"]] = $sContent; }