/** * Load the config file for the requested module. * In the config file we have to find disabled actions, the constructor will read the folder * and set possible actions. Other configurations will also be stored in it. */ public function loadConfig() { // check if module path is not yet defined if (!defined('BACKEND_MODULE_PATH')) { // build path for core if ($this->getModule() == 'core') { define('BACKEND_MODULE_PATH', BACKEND_PATH . '/' . $this->getModule()); } else { define('BACKEND_MODULE_PATH', BACKEND_MODULES_PATH . '/' . $this->getModule()); } } // check if the config is present? If it isn't present there is a huge problem, so we will stop our code by throwing an error if (!SpoonFile::exists(BACKEND_MODULE_PATH . '/config.php')) { throw new BackendException('The configfile for the module (' . $this->getModule() . ') can\'t be found.'); } // build config-object-name $configClassName = 'Backend' . SpoonFilter::toCamelCase($this->getModule() . '_config'); // require the config file, we validated before for existence. require_once BACKEND_MODULE_PATH . '/config.php'; // validate if class exists (aka has correct name) if (!class_exists($configClassName)) { throw new BackendException('The config file is present, but the classname should be: ' . $configClassName . '.'); } // create config-object, the constructor will do some magic $this->config = new $configClassName($this->getModule()); }
/** * Load the data. * This will also set some warnings if needed. */ private function loadData() { // inform that the theme is not installed yet if (!BackendExtensionsModel::isThemeInstalled($this->currentTheme)) { $this->warnings[] = array('message' => BL::getMessage('InformationThemeIsNotInstalled')); } // path to information file $pathInfoXml = FRONTEND_PATH . '/themes/' . $this->currentTheme . '/info.xml'; // information needs to exists if (SpoonFile::exists($pathInfoXml)) { try { // load info.xml $infoXml = @new SimpleXMLElement($pathInfoXml, LIBXML_NOCDATA, true); // convert xml to useful array $this->information = BackendExtensionsModel::processThemeXml($infoXml); // empty data (nothing useful) if (empty($this->information)) { $this->warnings[] = array('message' => BL::getMessage('InformationFileIsEmpty')); } } catch (Exception $e) { $this->warnings[] = array('message' => BL::getMessage('InformationFileCouldNotBeLoaded')); } } else { $this->warnings[] = array('message' => BL::getMessage('InformationFileIsMissing')); } }
/** * Returns the CampaignMonitor object * * @param int[optional] $listId The default list id to use. * @return CampaignMonitor */ public static function getCM($listId = null) { // campaignmonitor reference exists if (!Spoon::exists('campaignmonitor')) { // check if the CampaignMonitor class exists if (!SpoonFile::exists(PATH_LIBRARY . '/external/campaignmonitor.php')) { // the class doesn't exist, so throw an exception throw new SpoonFileException('The CampaignMonitor wrapper class is not found. Please locate and place it in /library/external'); } // require CampaignMonitor class require_once 'external/campaignmonitor.php'; // set login data $url = FrontendModel::getModuleSetting('mailmotor', 'cm_url'); $username = FrontendModel::getModuleSetting('mailmotor', 'cm_username'); $password = FrontendModel::getModuleSetting('mailmotor', 'cm_password'); // init CampaignMonitor object $cm = new CampaignMonitor($url, $username, $password, 5, self::getClientId()); // set CampaignMonitor object reference Spoon::set('campaignmonitor', $cm); // get the default list ID $listId = !empty($listId) ? $listId : self::getDefaultListID(); // set the default list ID $cm->setListId($listId); } // return the CampaignMonitor object return Spoon::get('campaignmonitor'); }
/** * Load the data. * This will also set some warnings if needed. */ private function loadData() { // inform that the module is not installed yet if (!BackendExtensionsModel::isModuleInstalled($this->currentModule)) { $this->warnings[] = array('message' => BL::getMessage('InformationModuleIsNotInstalled')); } // path to information file $pathInfoXml = BACKEND_MODULES_PATH . '/' . $this->currentModule . '/info.xml'; // information needs to exists if (SpoonFile::exists($pathInfoXml)) { try { // load info.xml $infoXml = @new SimpleXMLElement($pathInfoXml, LIBXML_NOCDATA, true); // convert xml to useful array $this->information = BackendExtensionsModel::processModuleXml($infoXml); // empty data (nothing useful) if (empty($this->information)) { $this->warnings[] = array('message' => BL::getMessage('InformationFileIsEmpty')); } // check if cronjobs are installed already if (isset($this->information['cronjobs'])) { foreach ($this->information['cronjobs'] as $cronjob) { if (!$cronjob['active']) { $this->warnings[] = array('message' => BL::getError('CronjobsNotSet')); } break; } } } catch (Exception $e) { $this->warnings[] = array('message' => BL::getMessage('InformationFileCouldNotBeLoaded')); } } else { $this->warnings[] = array('message' => BL::getMessage('InformationFileIsMissing')); } }
/** * Get warnings for active modules * * @return array */ public static function getWarnings() { // init vars $warnings = array(); $activeModules = BackendModel::getModules(true); // add warnings $warnings = array_merge($warnings, BackendModel::checkSettings()); // loop active modules foreach ($activeModules as $module) { // model class $class = 'Backend' . SpoonFilter::toCamelCase($module) . 'Model'; // model file exists if (SpoonFile::exists(BACKEND_MODULES_PATH . '/' . $module . '/engine/model.php')) { // require class require_once BACKEND_MODULES_PATH . '/' . $module . '/engine/model.php'; } // method exists if (is_callable(array($class, 'checkSettings'))) { // add possible warnings $warnings = array_merge($warnings, call_user_func(array($class, 'checkSettings'))); } } // return return (array) $warnings; }
/** * Get the file path based on the theme. * If it does not exist in the theme it will return $file. * * @return string Path to the (theme) file. * @param string $file Path to the file. */ public static function getPath($file) { // redefine $file = (string) $file; // theme name $theme = self::getTheme(); // theme in use if (FrontendModel::getModuleSetting('core', 'theme', 'core') != 'core') { // theme not yet specified if (strpos($file, 'frontend/themes/' . $theme) === false) { // add theme location $themeTemplate = str_replace(array('frontend/'), array('frontend/themes/' . $theme . '/'), $file); // check if this template exists if (SpoonFile::exists(PATH_WWW . str_replace(PATH_WWW, '', $themeTemplate))) { $file = $themeTemplate; } } } // check if the file exists if (!SpoonFile::exists(PATH_WWW . str_replace(PATH_WWW, '', $file))) { throw new FrontendException('The template (' . $file . ') doesn\'t exists.'); } // return template path return $file; }
/** * Validate if the theme can be installed. */ private function validateInstall() { // already installed if (BackendExtensionsModel::isThemeInstalled($this->currentTheme)) { $this->redirect(BackendModel::createURLForAction('themes') . '&error=already-installed&var=' . $this->currentTheme); } // no information file present if (!SpoonFile::exists(FRONTEND_PATH . '/themes/' . $this->currentTheme . '/info.xml')) { $this->redirect(BackendModel::createURLForAction('themes') . '&error=no-information-file&var=' . $this->currentTheme); } }
/** * Validate if the module can be installed. */ private function validateInstall() { // already installed if (BackendExtensionsModel::isModuleInstalled($this->currentModule)) { $this->redirect(BackendModel::createURLForAction('modules') . '&error=already-installed&var=' . $this->currentModule); } // no installer class present if (!SpoonFile::exists(BACKEND_MODULES_PATH . '/' . $this->currentModule . '/installer/installer.php')) { $this->redirect(BackendModel::createURLForAction('modules') . '&error=no-installer-file&var=' . $this->currentModule); } }
/** * Execute the action */ public function execute() { parent::execute(); // get parameters $url = SpoonFilter::getPostValue('url', null, ''); $username = SpoonFilter::getPostValue('username', null, ''); $password = SpoonFilter::getPostValue('password', null, ''); // filter out the 'http://' from the URL if (strpos($url, 'http://') !== false) { $url = str_replace('http://', '', $url); } if (strpos($url, 'https://') !== false) { $url = str_replace('https://', '', $url); } // check input if (empty($url)) { $this->output(self::BAD_REQUEST, array('field' => 'url'), BL::err('NoCMAccountCredentials')); } if (empty($username)) { $this->output(self::BAD_REQUEST, array('field' => 'username'), BL::err('NoCMAccountCredentials')); } if (empty($password)) { $this->output(self::BAD_REQUEST, array('field' => 'password'), BL::err('NoCMAccountCredentials')); } try { // check if the CampaignMonitor class exists if (!SpoonFile::exists(PATH_LIBRARY . '/external/campaignmonitor.php')) { // the class doesn't exist, so stop here $this->output(self::BAD_REQUEST, null, BL::err('ClassDoesNotExist', $this->getModule())); } // require CampaignMonitor class require_once 'external/campaignmonitor.php'; // init CampaignMonitor object new CampaignMonitor($url, $username, $password, 10); // save the new data BackendModel::setModuleSetting($this->getModule(), 'cm_url', $url); BackendModel::setModuleSetting($this->getModule(), 'cm_username', $username); BackendModel::setModuleSetting($this->getModule(), 'cm_password', $password); // account was linked BackendModel::setModuleSetting($this->getModule(), 'cm_account', true); } catch (Exception $e) { // timeout occured if ($e->getMessage() == 'Error Fetching http headers') { $this->output(self::BAD_REQUEST, null, BL::err('CmTimeout', $this->getModule())); } // other error $this->output(self::ERROR, array('field' => 'url'), sprintf(BL::err('CampaignMonitorError', $this->getModule()), $e->getMessage())); } // trigger event BackendModel::triggerEvent($this->getModule(), 'after_account_linked'); // CM was successfully initialized $this->output(self::OK, array('message' => 'account-linked'), BL::msg('AccountLinked', $this->getModule())); }
/** * Process the content of the file. * * @param string $file The file to process. * @return boolean|array */ private function processFile($file) { // if the files doesn't exists we can stop here and just return an empty string if (!SpoonFile::exists($file)) { return array(); } // fetch content from file $content = SpoonFile::getContent($file); $json = @json_decode($content, true); // skip invalid JSON if ($json === false || $json === null) { return array(); } $return = array(); // loop templates foreach ($json as $template) { // skip items without a title if (!isset($template['title'])) { continue; } if (isset($template['file'])) { if (SpoonFile::exists(PATH_WWW . $template['file'])) { $template['html'] = SpoonFile::getContent(PATH_WWW . $template['file']); } } // skip items without HTML if (!isset($template['html'])) { continue; } $image = ''; if (isset($template['image'])) { // we have to remove the first slash, because that is set in the wrapper. Otherwise the images don't work $image = ltrim($template['image'], '/'); } $temp['title'] = $template['title']; $temp['description'] = isset($template['description']) ? $template['description'] : ''; $temp['image'] = $image; $temp['html'] = $template['html']; // add the template $return[] = $temp; } return $return; }
/** * Load the datagrid * * @return void */ private function loadDataGrid() { // init var $items = array(); // get active modules $modules = BackendModel::getModules(); // loop active modules foreach ($modules as $module) { // check if their is a model-file if (SpoonFile::exists(BACKEND_MODULES_PATH . '/' . $module . '/engine/model.php')) { // require the model-file require_once BACKEND_MODULES_PATH . '/' . $module . '/engine/model.php'; // build class name $className = SpoonFilter::toCamelCase('backend_' . $module . '_model'); // check if the getByTag-method is available if (is_callable(array($className, 'getByTag'))) { // make the call and get the item $moduleItems = (array) call_user_func(array($className, 'getByTag'), $this->id); // loop items foreach ($moduleItems as $row) { // check if needed fields are available if (isset($row['url'], $row['name'], $row['module'])) { // add $items[] = array('module' => ucfirst(BL::lbl(SpoonFilter::toCamelCase($row['module']))), 'name' => $row['name'], 'url' => $row['url']); } } } } } // create datagrid $this->dgUsage = new BackendDataGridArray($items); // disable paging $this->dgUsage->setPaging(false); // hide columns $this->dgUsage->setColumnsHidden(array('url')); // set headers $this->dgUsage->setHeaderLabels(array('name' => ucfirst(BL::lbl('Title')), 'url' => '')); // set url $this->dgUsage->setColumnURL('name', '[url]', ucfirst(BL::lbl('Edit'))); // add use column $this->dgUsage->addColumn('edit', null, ucfirst(BL::lbl('Edit')), '[url]', BL::lbl('Edit')); }
public function __construct() { // store in reference so we can access it from everywhere Spoon::set('navigation', $this); // grab from the reference $this->URL = Spoon::get('url'); // check if navigation cache file exists if (!SpoonFile::exists(BACKEND_CACHE_PATH . '/navigation/navigation.php')) { $this->buildCache(); } $navigation = array(); // require navigation-file require_once BACKEND_CACHE_PATH . '/navigation/navigation.php'; // load it $this->navigation = (array) $navigation; // cleanup navigation (not needed for god user) if (!BackendAuthentication::getUser()->isGod()) { $this->navigation = $this->cleanup($this->navigation); } }
/** * Sets the headers so we may download the CSV file in question * * @param string $path The full path to the CSV file you wish to download. * @return array */ private function downloadCSV($path) { // check if the file exists if (!SpoonFile::exists($path)) { throw new SpoonFileException('The file ' . $path . ' doesn\'t exist.'); } // fetch the filename from the path string $explodedFilename = explode('/', $path); $filename = end($explodedFilename); // set headers for download $headers[] = 'Content-type: application/csv; charset=' . SPOON_CHARSET; $headers[] = 'Content-Disposition: attachment; filename="' . $filename . '"'; $headers[] = 'Pragma: no-cache'; // overwrite the headers SpoonHTTP::setHeaders($headers); // get the file contents $content = SpoonFile::getContent($path); // output the file contents echo $content; exit; }
/** * The default constructor * * @return void * @param string $title The title off the feed. * @param string $link The link of the feed. * @param string $description The description of the feed. * @param array[optional] $items An array with SpoonRSSItems. */ public function __construct($title, $link, $description, array $items = array()) { // decode $title = SpoonFilter::htmlspecialcharsDecode($title); $description = SpoonFilter::htmlspecialcharsDecode($description); // call the parent parent::__construct($title, FrontendModel::addURLParameters($link, array('utm_source' => 'feed', 'utm_medium' => 'rss', 'utm_campaign' => SpoonFilter::urlise($title))), $description, $items); // set feed properties $this->setLanguage(FRONTEND_LANGUAGE); $this->setCopyright(SpoonDate::getDate('Y') . ' ' . SpoonFilter::htmlspecialcharsDecode(FrontendModel::getModuleSetting('core', 'site_title_' . FRONTEND_LANGUAGE))); $this->setGenerator(SITE_RSS_GENERATOR); $this->setImage(SITE_URL . FRONTEND_CORE_URL . '/layout/images/rss_image.png', $title, $link); // theme was set if (FrontendModel::getModuleSetting('core', 'theme', null) != null) { // theme name $theme = FrontendModel::getModuleSetting('core', 'theme', null); // theme rss image exists if (SpoonFile::exists(PATH_WWW . '/frontend/themes/' . $theme . '/core/images/rss_image.png')) { // set rss image $this->setImage(SITE_URL . '/frontend/themes/' . $theme . '/core/images/rss_image.png', $title, $link); } } }
/** * Execute the action */ public function execute() { parent::execute(); // add js $this->header->addJS('jstree/jquery.tree.js', null, false, false, false); $this->header->addJS('jstree/lib/jquery.cookie.js', null, false, false, false); $this->header->addJS('jstree/plugins/jquery.tree.cookie.js', null, false, false, false); // add css $this->header->addCSS('/backend/modules/pages/js/jstree/themes/fork/style.css', null, true); // check if the cached files exists if (!SpoonFile::exists(PATH_WWW . '/frontend/cache/navigation/keys_' . BackendLanguage::getWorkingLanguage() . '.php')) { BackendPagesModel::buildCache(BL::getWorkingLanguage()); } if (!SpoonFile::exists(PATH_WWW . '/frontend/cache/navigation/navigation_' . BackendLanguage::getWorkingLanguage() . '.php')) { BackendPagesModel::buildCache(BL::getWorkingLanguage()); } // load the dgRecentlyEdited $this->loadDataGrids(); // parse $this->parse(); // display the page $this->display(); }
/** * Returns the mailchimp object. * * @return mailchimp */ public static function getMC() { // mailchimp reference exists if (!\Spoon::exists('mailchimp')) { // check if the mailchimp class exists if (!\SpoonFile::exists(PATH_LIBRARY . '/external/mcapi.php')) { // the class doesn't exist, so throw an exception throw new \SpoonFileException(sprintf(FL::err('ClassDoesNotExist'), 'mailchimp')); } // require mailchimp class require_once PATH_LIBRARY . '/external/mcapi.php'; // set login data $key = FrontendModel::getModuleSetting('MailMotor', 'api_key'); if (empty($key)) { throw new \Exception('Mailmotor api_key is required.'); } // init mailchimp object $mc = new \MCAPI($key); // set mailchimp object reference \Spoon::set('mailchimp', $mc); } // return the CampaignMonitor object return \Spoon::get('mailchimp'); }
/** * Autoloader for the backend * * @return void * @param string $className The name of the class to require. */ public static function autoLoader($className) { // redefine $className = strtolower((string) $className); // init var $pathToLoad = ''; // exceptions $exceptions['backend'] = BACKEND_CORE_PATH . '/engine/backend.php'; $exceptions['backendajaxaction'] = BACKEND_CORE_PATH . '/engine/ajax_action.php'; $exceptions['backendbaseajaxaction'] = BACKEND_CORE_PATH . '/engine/base.php'; $exceptions['backenddatagriddb'] = BACKEND_CORE_PATH . '/engine/datagrid.php'; $exceptions['backenddatagridarray'] = BACKEND_CORE_PATH . '/engine/datagrid.php'; $exceptions['backendbaseconfig'] = BACKEND_CORE_PATH . '/engine/base.php'; $exceptions['backendbasecronjob'] = BACKEND_CORE_PATH . '/engine/base.php'; $exceptions['backendpagesmodel'] = BACKEND_MODULES_PATH . '/pages/engine/model.php'; $exceptions['fl'] = FRONTEND_CORE_PATH . '/engine/language.php'; // is it an exception if (isset($exceptions[$className])) { $pathToLoad = $exceptions[$className]; } elseif (substr($className, 0, 7) == 'backend') { $pathToLoad = BACKEND_CORE_PATH . '/engine/' . str_replace('backend', '', $className) . '.php'; } elseif (substr($className, 0, 8) == 'frontend') { $pathToLoad = FRONTEND_CORE_PATH . '/engine/' . str_replace('frontend', '', $className) . '.php'; } // file check in core if ($pathToLoad != '' && SpoonFile::exists($pathToLoad)) { require_once $pathToLoad; } else { // we'll need the original class name again, with the uppercases $className = func_get_arg(0); // split in parts if (preg_match_all('/[A-Z][a-z0-9]*/', $className, $parts)) { // the real matches $parts = $parts[0]; // get root path constant and see if it exists $rootPath = strtoupper(array_shift($parts)) . '_PATH'; if (defined($rootPath)) { foreach ($parts as $i => $part) { // skip the first if ($i == 0) { continue; } // action $action = strtolower(implode('_', $parts)); // module $module = ''; for ($j = 0; $j < $i; $j++) { $module .= strtolower($parts[$j]) . '_'; } // fix action & module $action = substr($action, strlen($module)); $module = substr($module, 0, -1); // check the actions, engine & widgets directories foreach (array('actions', 'engine', 'widgets') as $dir) { // file to be loaded $pathToLoad = constant($rootPath) . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR . $action . '.php'; // if it exists, load it! if ($pathToLoad != '' && SpoonFile::exists($pathToLoad)) { require_once $pathToLoad; break 2; } } } } } } }
/** * Load the cached data * * @return bool */ private function getCachedData() { // no search term = no search if (!$this->term) { return false; } // debug mode = no cache if (SPOON_DEBUG) { return false; } // check if cachefile exists if (!SpoonFile::exists($this->cacheFile)) { return false; } // get cachefile modification time $cacheInfo = @filemtime($this->cacheFile); // check if cache file is recent enough (1 hour) if (!$cacheInfo || $cacheInfo < strtotime('-1 hour')) { return false; } // include cache file require_once $this->cacheFile; // set info $this->pagination = $pagination; $this->items = $items; return true; }
/** * Process the zip-file & install the module * * @return string */ private function installModule() { // list of validated files (these files will actually be unpacked) $files = array(); // shorten field variables $fileFile = $this->frm->getField('file'); // create ziparchive instance $zip = new ZipArchive(); // try and open it if ($zip->open($fileFile->getTempFileName()) !== true) { $fileFile->addError(BL::getError('CorruptedFile')); } // zip file needs to contain some files if ($zip->numFiles == 0) { $fileFile->addError(BL::getError('FileIsEmpty')); return; } // directories we are allowed to upload to $allowedDirectories = array('backend/modules/', 'frontend/modules/', 'library/external/'); // name of the module we are trying to upload $moduleName = null; // there are some complications $warnings = array(); // check every file in the zip for ($i = 0; $i < $zip->numFiles; $i++) { // get the file name $file = $zip->statIndex($i); $fileName = $file['name']; // check if the file is in one of the valid directories foreach ($allowedDirectories as $directory) { // yay, in a valid directory if (stripos($fileName, $directory) === 0) { // we have a library file if ($directory == 'library/external/') { if (!SpoonFile::exists(PATH_WWW . '/' . $fileName)) { $files[] = $fileName; } else { $warnings[] = sprintf(BL::getError('LibraryFileAlreadyExists'), $fileName); } break; } // extract the module name from the url $tmpName = trim(str_ireplace($directory, '', $fileName), '/'); if ($tmpName == '') { break; } $chunks = explode('/', $tmpName); $tmpName = $chunks[0]; // ignore hidden files if (substr(basename($fileName), 0, 1) == '.') { break; } elseif ($moduleName === null) { $moduleName = $tmpName; } elseif ($moduleName !== $tmpName) { break; } // passed all our tests, store it for extraction $files[] = $fileName; // go to next file break; } } } // after filtering no files left (nothing useful found) if (count($files) == 0) { $fileFile->addError(BL::getError('FileContentsIsUseless')); return; } // module already exists on the filesystem if (BackendExtensionsModel::existsModule($moduleName)) { $fileFile->addError(sprintf(BL::getError('ModuleAlreadyExists'), $moduleName)); return; } // installer in array? if (!in_array('backend/modules/' . $moduleName . '/installer/installer.php', $files)) { $fileFile->addError(sprintf(BL::getError('NoInstallerFile'), $moduleName)); return; } // unpack module files $zip->extractTo(PATH_WWW, $files); // run installer BackendExtensionsModel::installModule($moduleName, $warnings); // return the files return $moduleName; }
/** * Get the widgets * * @return void */ private function getWidgets() { // get all active modules $modules = BackendModel::getModules(true); // loop all modules foreach ($modules as $module) { // you have sufficient rights? if (BackendAuthentication::isAllowedModule($module)) { // build pathName $pathName = BACKEND_MODULES_PATH . '/' . $module; // check if the folder exists if (SpoonDirectory::exists($pathName . '/widgets')) { // get widgets $widgets = (array) SpoonFile::getList($pathName . '/widgets', '/(.*)\\.php/i'); // loop through widgets foreach ($widgets as $widget) { // require the classes require_once $pathName . '/widgets/' . $widget; // init var $widgetName = str_replace('.php', '', $widget); // build classname $className = 'Backend' . SpoonFilter::toCamelCase($module) . 'Widget' . SpoonFilter::toCamelCase($widgetName); // validate if the class exists if (!class_exists($className)) { // throw exception throw new BackendException('The widgetfile is present, but the classname should be: ' . $className . '.'); } else { // add to array $this->widgetInstances[] = array('module' => $module, 'widget' => $widgetName, 'className' => $className); // create reflection class $reflection = new ReflectionClass('Backend' . SpoonFilter::toCamelCase($module) . 'Widget' . SpoonFilter::toCamelCase($widgetName)); // get the offset $offset = strpos($reflection->getDocComment(), '*', 7); // get the first sentence $description = substr($reflection->getDocComment(), 0, $offset); // replacements $description = str_replace('*', '', $description); $description = trim(str_replace('/', '', $description)); } // check if model file exists if (SpoonFile::exists($pathName . '/engine/model.php')) { // require model require_once $pathName . '/engine/model.php'; } // add to array $this->widgets[] = array('label' => SpoonFilter::toCamelCase($widgetName), 'value' => $widgetName, 'description' => $description); } } } } }
/** * Get all data for a given revision. * * @return array * @param string[optional] $language The language to use. */ public static function getLinkList($language = null) { // redefine $language = $language !== null ? (string) $language : BackendLanguage::getWorkingLanguage(); // there is no cache file if (!SpoonFile::exists(FRONTEND_CACHE_PATH . '/navigation/tinymce_link_list_' . $language . '.js')) { return array(); } // read the cache file $cacheFile = SpoonFile::getContent(FRONTEND_CACHE_PATH . '/navigation/tinymce_link_list_' . $language . '.js'); // get the array preg_match('/new Array\\((.*)\\);$/s', $cacheFile, $matches); // no matched if (empty($matches)) { return array(); } // create array $matches = explode('],', str_replace('[', '', $matches[count($matches) - 1])); // init vars $cacheList = array(); // loop list foreach ($matches as $item) { // trim item $item = explode('", "', trim($item, " \n\r\t\"")); // build cache list $cacheList[$item[1]] = $item[0]; } // return cache list return $cacheList; }
/** * Execute the action * We will build the classname, require the class and call the execute method. */ protected function execute() { // build action-class-name $actionClassName = 'Backend' . SpoonFilter::toCamelCase($this->getModule() . '_cronjob_' . $this->getAction()); if ($this->getModule() == 'core') { // check if the file is present? If it isn't present there is a huge problem, so we will stop our code by throwing an error if (!SpoonFile::exists(BACKEND_CORE_PATH . '/cronjobs/' . $this->getAction() . '.php')) { // set correct headers SpoonHTTP::setHeadersByCode(500); // throw exception throw new BackendException('The cronjobfile for the module (' . $this->getAction() . '.php) can\'t be found.'); } // require the config file, we know it is there because we validated it before (possible actions are defined by existance of the file). require_once BACKEND_CORE_PATH . '/cronjobs/' . $this->getAction() . '.php'; } else { // check if the file is present? If it isn't present there is a huge problem, so we will stop our code by throwing an error if (!SpoonFile::exists(BACKEND_MODULES_PATH . '/' . $this->getModule() . '/cronjobs/' . $this->getAction() . '.php')) { // set correct headers SpoonHTTP::setHeadersByCode(500); // throw exception throw new BackendException('The cronjobfile for the module (' . $this->getAction() . '.php) can\'t be found.'); } // require the config file, we know it is there because we validated it before (possible actions are defined by existance of the file). require_once BACKEND_MODULES_PATH . '/' . $this->getModule() . '/cronjobs/' . $this->getAction() . '.php'; } // validate if class exists (aka has correct name) if (!class_exists($actionClassName)) { // set correct headers SpoonHTTP::setHeadersByCode(500); // throw exception throw new BackendException('The cronjobfile is present, but the classname should be: ' . $actionClassName . '.'); } // create action-object $object = new $actionClassName(); $object->setModule($this->getModule()); $object->setAction($this->getAction()); $object->execute(); }
/** * Installs the required and optional modules */ private function installModules() { // The default extras to add to every page after installation of all modules and to add to the default templates. $defaultExtras = array(); // init var $warnings = array(); /** * First we need to install the core. All the linked modules, settings and sql tables are * being installed. */ require_once PATH_WWW . '/backend/core/installer/installer.php'; // create the core installer $installer = new CoreInstaller($this->db, SpoonSession::get('languages'), SpoonSession::get('interface_languages'), SpoonSession::get('example_data'), array('default_language' => SpoonSession::get('default_language'), 'default_interface_language' => SpoonSession::get('default_interface_language'), 'spoon_debug_email' => SpoonSession::get('email'), 'api_email' => SpoonSession::get('email'), 'site_domain' => isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'fork.local', 'site_title' => 'Fork CMS', 'smtp_server' => '', 'smtp_port' => '', 'smtp_username' => '', 'smtp_password' => '')); // install the core $installer->install(); // add the warnings $moduleWarnings = $installer->getWarnings(); if (!empty($moduleWarnings)) { $warnings[] = array('module' => 'core', 'warnings' => $moduleWarnings); } // add the default extras $moduleDefaultExtras = $installer->getDefaultExtras(); if (!empty($moduleDefaultExtras)) { array_merge($defaultExtras, $moduleDefaultExtras); } // variables passed to module installers $variables = array(); $variables['email'] = SpoonSession::get('email'); $variables['default_interface_language'] = SpoonSession::get('default_interface_language'); // modules to install (required + selected) $modules = array_unique(array_merge($this->modules['required'], SpoonSession::get('modules'))); // loop required modules foreach ($modules as $module) { // install exists if (SpoonFile::exists(PATH_WWW . '/backend/modules/' . $module . '/installer/installer.php')) { // users module needs custom variables if ($module == 'users') { $variables['password'] = SpoonSession::get('password'); } // load installer file require_once PATH_WWW . '/backend/modules/' . $module . '/installer/installer.php'; // build installer class name $class = SpoonFilter::toCamelCase($module) . 'Installer'; // create installer $installer = new $class($this->db, SpoonSession::get('languages'), SpoonSession::get('interface_languages'), SpoonSession::get('example_data'), $variables); // install the module $installer->install(); // add the warnings $moduleWarnings = $installer->getWarnings(); if (!empty($moduleWarnings)) { $warnings[] = array('module' => $module, 'warnings' => $moduleWarnings); } // add the default extras $moduleDefaultExtras = $installer->getDefaultExtras(); if (!empty($moduleDefaultExtras)) { $defaultExtras = array_merge($defaultExtras, $moduleDefaultExtras); } } } // loop default extras foreach ($defaultExtras as $extra) { // get pages without this extra $revisionIds = $this->db->getColumn('SELECT i.revision_id FROM pages AS i WHERE i.revision_id NOT IN ( SELECT DISTINCT b.revision_id FROM pages_blocks AS b WHERE b.extra_id = ? GROUP BY b.revision_id )', array($extra['id'])); // build insert array for this extra $insertExtras = array(); foreach ($revisionIds as $revisionId) { $insertExtras[] = array('revision_id' => $revisionId, 'position' => $extra['position'], 'extra_id' => $extra['id'], 'created_on' => gmdate('Y-m-d H:i:s'), 'edited_on' => gmdate('Y-m-d H:i:s'), 'visible' => 'Y'); } // insert block $this->db->insert('pages_blocks', $insertExtras); } // parse the warnings $this->tpl->assign('warnings', $warnings); }
/** * Copies a file/folder. * * @return bool True if the file/directory was copied, false if not. * @param string $source The full path to the source file/folder. * @param bool[optional] $overwrite If the destination already exists, should we overwrite? * @param string $destination The full path to the destination. * @param bool[optional] $strict If strict is true, exceptions will be thrown when an error occures. * @param int[optional] $chmod Mode that will be applied on the file/directory. */ public static function copy($source, $destination, $overwrite = true, $strict = true, $chmod = 0777) { // redefine vars $source = (string) $source; $destination = (string) $destination; $return = true; // validation if ($strict) { if (!@file_exists($source)) { throw new SpoonDirectoryException('The given path (' . $source . ') doesn\'t exist.'); } if (!$overwrite && @file_exists($destination)) { throw new SpoonDirectoryException('The given path (' . $destination . ') already exists.'); } } // is a directory if (is_dir($source)) { // create dir if (!self::exists($destination)) { // create dir $return = self::create($destination, $chmod); // check if (!$return) { if ($strict) { throw new SpoonDirectoryException('The directory-structure couldn\'t be created.'); } return false; } } // get content $contentList = (array) self::getList($source, true); // loop content foreach ($contentList as $item) { // copy dir (recursive) if (is_dir($source . '/' . $item)) { self::copy($source . '/' . $item, $destination . '/' . $item); } else { // delete the file if needed if ($overwrite && SpoonFile::exists($destination . '/' . $item)) { SpoonFile::delete($destination . '/' . $item); } // copy file if (!SpoonFile::exists($destination . '/' . $item)) { // copy file $return = @copy($source . '/' . $item, $destination . '/' . $item); // check if (!$return) { if ($strict) { throw new SpoonDirectoryException('The directory/file (' . $source . '/' . $item . ') couldn\'t be copied.'); } return false; } // chmod @chmod($destination . '/' . $item, $chmod); } } } } else { // delete the file if needed if ($overwrite && SpoonFile::exists($destination)) { SpoonFile::delete($destination); } // copy file if (!SpoonFile::exists($destination)) { // copy file $return = @copy($source, $destination); // check if (!$return) { if ($strict) { throw new SpoonDirectoryException('The directory/file (' . $source . ') couldn\'t be copied.'); } return false; } // chmod @chmod($destination, $chmod); } } // return return true; }
/** * Default constructor * * @return void */ public function __construct() { // simulate $_REQUEST $parameters = array_merge($_GET, $_POST); // validate parameters if (!isset($parameters['method'])) { self::output(self::BAD_REQUEST, array('message' => 'No method-parameter provided.')); } // check GET $method = SpoonFilter::getValue($parameters['method'], null, ''); // validate if ($method == '') { self::output(self::BAD_REQUEST, array('message' => 'No method-parameter provided.')); } // process method $chunks = (array) explode('.', $method, 2); // validate method if (!isset($chunks[1])) { self::output(self::BAD_REQUEST, array('message' => 'Invalid method.')); } // build the path to the backend API file if ($chunks[0] == 'core') { $path = BACKEND_CORE_PATH . '/engine/api.php'; } else { $path = BACKEND_MODULES_PATH . '/' . $chunks[0] . '/engine/api.php'; } // check if the fille is present? If it isn't present there is a problem if (!SpoonFile::exists($path)) { self::output(self::BAD_REQUEST, array('message' => 'Invalid method.')); } // build config-object-name $className = 'Backend' . SpoonFilter::toCamelCase($chunks[0]) . 'API'; $methodName = SpoonFilter::toCamelCase($chunks[1], '.', true); // require the class require_once $path; // validate if the method exists if (!is_callable(array($className, $methodName))) { self::output(self::BAD_REQUEST, array('message' => 'Invalid method.')); } // call the method try { // init var $arguments = null; // create reflection method $reflectionMethod = new ReflectionMethod($className, $methodName); $parameterDocumentation = array(); // get data from docs $matches = array(); preg_match_all('/@param[\\s\\t]+(.*)[\\s\\t]+\\$(.*)[\\s\\t]+(.*)$/Um', $reflectionMethod->getDocComment(), $matches); // documentation found if (!empty($matches[0])) { // loop matches foreach ($matches[0] as $i => $row) { // set documentation $parameterDocumentation[$matches[2][$i]] = array('type' => str_replace('[optional]', '', $matches[1][$i]), 'optional' => substr_count($matches[1][$i], '[optional]') > 0, 'description' => $matches[3][$i]); } } // loop parameters foreach ($reflectionMethod->getParameters() as $parameter) { // init var $name = $parameter->getName(); // check if the parameter is available if (!$parameter->isOptional() && !isset($parameters[$name])) { self::output(self::BAD_REQUEST, array('message' => 'No ' . $name . '-parameter provided.')); } // add not-passed arguments if ($parameter->isOptional() && !isset($parameters[$name])) { $arguments[] = $parameter->getDefaultValue(); } elseif (isset($parameterDocumentation[$name]['type'])) { // get default value $defaultValue = null; if ($parameter->isOptional()) { $defaultValue = $parameter->getDefaultValue(); } // add argument $arguments[] = SpoonFilter::getValue($parameters[$name], null, $defaultValue, $parameterDocumentation[$name]['type']); } else { $arguments[] = $parameters[$name]; } } // get the return $data = (array) call_user_func_array(array($className, $methodName), (array) $arguments); // output self::output(self::OK, $data); } catch (Exception $e) { // if we are debugging we should see the exceptions if (SPOON_DEBUG) { if (isset($parameters['debug']) && $parameters['debug'] == 'false') { // do nothing } else { throw $e; } } // output self::output(500, array('message' => $e->getMessage())); } }
/** * Set the busy file * * @return void */ protected function setBusyFile() { // do not set busy file in debug mode if (SPOON_DEBUG) { return; } // build path $path = BACKEND_CACHE_PATH . '/cronjobs/' . $this->getId() . '.busy'; // init var $isBusy = false; // does the busy file already exists. if (SpoonFile::exists($path)) { $isBusy = true; // grab counter $counter = (int) SpoonFile::getContent($path); // check the counter if ($counter > 9) { // build class name $className = 'Backend' . SpoonFilter::toCamelCase($this->getModule() . '_cronjob_' . $this->getAction()); // notify user throw new BackendException('Cronjob (' . $className . ') is still busy after 10 runs, check it out!'); } } else { $counter = 0; } // increment counter $counter++; // store content SpoonFile::setContent($path, $counter, true, false); // if the cronjob is busy we should NOT proceed if ($isBusy) { exit; } }
/** * Autoloader for the frontend * * @return void * @param string $className The name of the class to require. */ public static function autoLoader($className) { // redefine $className = strtolower((string) $className); // init var $pathToLoad = ''; // exceptions $exceptions = array(); $exceptions['frontend'] = FRONTEND_CORE_PATH . '/engine/frontend.php'; $exceptions['frontendbaseajaxaction'] = FRONTEND_CORE_PATH . '/engine/base.php'; $exceptions['frontendbaseconfig'] = FRONTEND_CORE_PATH . '/engine/base.php'; $exceptions['frontendbaseobject'] = FRONTEND_CORE_PATH . '/engine/base.php'; $exceptions['frontendblockextra'] = FRONTEND_CORE_PATH . '/engine/block.php'; $exceptions['frontendblockwidget'] = FRONTEND_CORE_PATH . '/engine/block.php'; $exceptions['frontendtemplatecompiler'] = FRONTEND_CORE_PATH . '/engine/template_compiler.php'; // is it an exception if (isset($exceptions[$className])) { $pathToLoad = $exceptions[$className]; } elseif (substr($className, 0, 8) == 'frontend') { $pathToLoad = FRONTEND_CORE_PATH . '/engine/' . str_replace('frontend', '', $className) . '.php'; } // file check in core if ($pathToLoad != '' && SpoonFile::exists($pathToLoad)) { require_once $pathToLoad; } else { // we'll need the original class name again, with the uppercases $className = func_get_arg(0); // split in parts if (preg_match_all('/[A-Z][a-z0-9]*/', $className, $parts)) { // the real matches $parts = $parts[0]; // doublecheck that we are looking for a frontend class $root = array_shift($parts); if (strtolower($root) == 'frontend') { foreach ($parts as $i => $part) { // skip the first if ($i == 0) { continue; } // action $action = strtolower(implode('_', $parts)); // module $module = ''; for ($j = 0; $j < $i; $j++) { $module .= strtolower($parts[$j]) . '_'; } // fix action & module $action = substr($action, strlen($module)); $module = substr($module, 0, -1); // check the actions, engine & widgets directories foreach (array('actions', 'engine', 'widgets') as $dir) { // file to be loaded $pathToLoad = FRONTEND_PATH . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR . $action . '.php'; // if it exists, load it! if ($pathToLoad != '' && SpoonFile::exists($pathToLoad)) { require_once $pathToLoad; break; } } } } } } }
/** * Autoloader for the backend * * @param string $className The name of the class to require. */ public static function autoLoader($className) { // redefine $className = strtolower((string) $className); // init var $pathToLoad = ''; // exceptions $exceptions = array(); $exceptions['bl'] = BACKEND_CORE_PATH . '/engine/language.php'; $exceptions['api'] = API_CORE_PATH . '/1.0/engine/api.php'; // is it an exception if (isset($exceptions[$className])) { $pathToLoad = $exceptions[$className]; } elseif (substr($className, 0, 7) == 'backend') { $pathToLoad = BACKEND_CORE_PATH . '/engine/' . str_replace('backend', '', $className) . '.php'; } elseif (substr($className, 0, 8) == 'frontend') { $pathToLoad = FRONTEND_CORE_PATH . '/engine/' . str_replace('frontend', '', $className) . '.php'; } // file check in core if ($pathToLoad != '' && SpoonFile::exists($pathToLoad)) { require_once $pathToLoad; } else { // we'll need the original class name again, with the uppercases $className = func_get_arg(0); // split in parts if (preg_match_all('/[A-Z][a-z0-9]*/', $className, $parts)) { // the real matches $parts = $parts[0]; // get root path constant and see if it exists $rootPath = strtoupper(array_shift($parts)) . '_PATH'; if (defined($rootPath)) { foreach ($parts as $i => $part) { // skip the first if ($i == 0) { continue; } // action $action = strtolower(implode('_', $parts)); // module $module = ''; for ($j = 0; $j < $i; $j++) { $module .= strtolower($parts[$j]) . '_'; } // fix action & module $action = substr($action, strlen($module)); $module = substr($module, 0, -1); // file to be loaded $pathToLoad = constant($rootPath) . '/modules/' . $module . '/engine/' . $action . '.php'; // if it exists, load it! if ($pathToLoad != '' && SpoonFile::exists($pathToLoad)) { require_once $pathToLoad; break; } } } } } }
/** * Display the output. * * @param string $template The filename of the template that you want to display. */ public function display($template) { // redefine $template = (string) $template; // validate name if (trim($template) == '' || !SpoonFile::exists($template)) { throw new SpoonTemplateException('Please provide an existing template.'); } // compiled name $compileName = $this->getCompileName((string) $template); // compiled if needed if ($this->forceCompile || !SpoonFile::exists($this->compileDirectory . '/' . $compileName)) { // create compiler $compiler = new SpoonTemplateCompiler((string) $template, $this->variables); // set some options $compiler->setCacheDirectory($this->cacheDirectory); $compiler->setCompileDirectory($this->compileDirectory); $compiler->setForceCompile($this->forceCompile); $compiler->setForms($this->forms); // compile & save $compiler->parseToFile(); } // load template require $this->compileDirectory . '/' . $compileName; }
/** * Parse all user-defined constants */ private function parseConstants() { // constants that should be protected from usage in the template $notPublicConstants = array('DB_TYPE', 'DB_DATABASE', 'DB_HOSTNAME', 'DB_PORT', 'DB_USERNAME', 'DB_PASSWORD'); // get all defined constants $constants = get_defined_constants(true); // init var $realConstants = array(); // remove protected constants aka constants that should not be used in the template foreach ($constants['user'] as $key => $value) { if (!in_array($key, $notPublicConstants)) { $realConstants[$key] = $value; } } // we should only assign constants if there are constants to assign if (!empty($realConstants)) { $this->assign($realConstants); } // we use some abbrviations and common terms, these should also be assigned $this->assign('LANGUAGE', BackendLanguage::getWorkingLanguage()); if ($this->URL instanceof BackendURL) { // assign the current module $this->assign('MODULE', $this->URL->getModule()); // assign the current action if ($this->URL->getAction() != '') { $this->assign('ACTION', $this->URL->getAction()); } } // is the user object filled? if (BackendAuthentication::getUser()->isAuthenticated()) { // assign the authenticated users secret key $this->assign('SECRET_KEY', BackendAuthentication::getUser()->getSecretKey()); // assign the authentiated users preferred interface language $this->assign('INTERFACE_LANGUAGE', (string) BackendAuthentication::getUser()->getSetting('interface_language')); } // assign some variable constants (such as site-title) $this->assign('SITE_TITLE', BackendModel::getModuleSetting('core', 'site_title_' . BackendLanguage::getWorkingLanguage(), SITE_DEFAULT_TITLE)); // theme if (BackendModel::getModuleSetting('core', 'theme') !== null) { $this->assign('THEME', BackendModel::getModuleSetting('core', 'theme')); $this->assign('THEME_PATH', FRONTEND_PATH . '/themes/' . BackendModel::getModuleSetting('core', 'theme')); $this->assign('THEME_HAS_CSS', SpoonFile::exists(FRONTEND_PATH . '/themes/' . BackendModel::getModuleSetting('core', 'theme') . '/core/layout/css/screen.css')); $this->assign('THEME_HAS_EDITOR_CSS', SpoonFile::exists(FRONTEND_PATH . '/themes/' . BackendModel::getModuleSetting('core', 'theme') . '/core/layout/css/editor_content.css')); } }