/** * Smarty {implode} function plugin * * Name: implode<br> * Purpose: glue an array together as a string, with supplied string glue, and assign it to the template * @link http://smarty.php.net/manual/en/language.function.implode.php {implode} * (Smarty online manual) * @author Will Mason <will at dontblinkdesign dot com> * @param array $params * @param UInterface $smarty * @return null|string */ function smarty_function_implode($params, &$smarty) { if (!isset($params['subject'])) { $smarty->trigger_error("implode: missing 'subject' parameter"); return; } if (!isset($params['glue'])) { $params['glue'] = ", "; } $subject = $params['subject']; $implodedValue = null; if (is_array($subject)) { if (isset($params['sort'])) { sort($subject); } $implodedValue = implode($params['glue'], $subject); } else { $implodedValue = $subject; } if (!isset($params['assign'])) { return $implodedValue; } else { $smarty->assign($params['assign'], $implodedValue); } }
/** * Send scheduled alerts * * @return void */ public function send() { global $configArray; global $interface; global $translator; $iso8601 = 'Y-m-d\\TH:i:s\\Z'; ini_set('display_errors', true); $configArray = $mainConfig = readConfig(); $datasourceConfig = getExtraConfigArray('datasources'); $siteLocal = $configArray['Site']['local']; // Set up time zone. N.B. Don't use msg() or other functions requiring date before this. date_default_timezone_set($configArray['Site']['timezone']); $this->msg('Sending scheduled alerts'); // Setup Local Database Connection ConnectionManager::connectToDatabase(); // Initialize Mailer $mailer = new VuFindMailer(); // Find all scheduled alerts $sql = 'SELECT * FROM "search" WHERE "schedule" > 0 ORDER BY user_id'; $s = new SearchEntry(); $s->query($sql); $this->msg('Processing ' . $s->N . ' searches'); $user = false; $interface = false; $institution = false; $todayTime = new DateTime(); while ($s->fetch()) { $lastTime = new DateTime($s->last_executed); if ($s->schedule == 1) { // Daily if ($todayTime->format('Y-m-d') == $lastTime->format('Y-m-d')) { $this->msg('Bypassing search ' . $s->id . ': previous execution too recent (daily, ' . $lastTime->format($iso8601) . ')'); continue; } } elseif ($s->schedule == 2) { // Weekly $diff = $todayTime->diff($lastTime); if ($diff->days < 6) { $this->msg('Bypassing search ' . $s->id . ': previous execution too recent (weekly, ' . $lastTime->format($iso8601) . ')'); continue; } } else { $this->msg('Search ' . $s->id . ': unknown schedule: ' . $s->schedule); continue; } if ($user === false || $s->user_id != $user->id) { $user = User::staticGet($s->user_id); } if (!$user->email || trim($user->email) == '') { $this->msg('User ' . $user->username . ' does not have an email address, bypassing alert ' . $s->id); continue; } $userInstitution = reset(explode(':', $user->username, 2)); if (!$institution || $institution != $userInstitution) { $institution = $userInstitution; if (!isset($datasourceConfig[$institution])) { foreach ($datasourceConfig as $code => $values) { if (isset($values['institution']) && strcasecmp($values['institution'], $institution) == 0) { $institution = $code; break; } } } if (!($configArray = $this->readInstitutionConfig($institution))) { continue; } $configArray['Site']['url'] = $s->schedule_base_url; // Start Interface $interface = new UInterface($siteLocal); $validLanguages = array_keys($configArray['Languages']); $dateFormat = new VuFindDate(); } $language = $user->language; if (!in_array($user->language, $validLanguages)) { $language = $configArray['Site']['language']; } $translator = new I18N_Translator(array($configArray['Site']['local'] . '/lang', $configArray['Site']['local'] . '/lang_local'), $language, $configArray['System']['debug']); $interface->setLanguage($language); $minSO = unserialize($s->search_object); // Check minified search object type $searchObject = SearchObjectFactory::deminify($minSO); if (!$searchObject instanceof SearchObject_Solr) { $this->msg('Search ' . $s->id . ': search object type not supported'); continue; } // Create a new search object to avoid cached defaults for e.g. // hidden filters. $searchObject = SearchObjectFactory::initSearchObject(); $searchObject->deminify($minSO); $searchObject->setSort('first_indexed desc'); $searchTime = time(); $searchDate = gmdate($iso8601, time()); $searchObject->setLimit(50); $searchObject->disableLogging(); $results = $searchObject->processSearch(); if (PEAR::isError($results)) { $this->msg('Search ' . $s->id . ' failed: ' . $results->getMessage()); continue; } if ($searchObject->getResultTotal() < 1) { $this->msg('No results found for search ' . $s->id); continue; } $newestRecordDate = date($iso8601, strtotime($results['response']['docs'][0]['first_indexed'])); $lastExecutionDate = $lastTime->format($iso8601); if ($newestRecordDate < $lastExecutionDate) { $this->msg('No new results for search ' . $s->id . ": {$newestRecordDate} < {$lastExecutionDate}"); } else { $this->msg('New results for search ' . $s->id . ": {$newestRecordDate} >= {$lastExecutionDate}"); $interface->assign('summary', $searchObject->getResultSummary()); $interface->assign('searchDate', $dateFormat->convertToDisplayDate("U", floor($searchTime))); $interface->assign('lastSearchDate', $dateFormat->convertToDisplayDate("U", floor($lastTime->getTimestamp()))); $records = array(); foreach ($results['response']['docs'] as &$doc) { $docDate = date($iso8601, strtotime($doc['first_indexed'])); if ($docDate < $lastExecutionDate) { break; } $record = RecordDriverFactory::initRecordDriver($doc); $records[] = $interface->fetch($record->getSearchResult('email')); } $interface->assign('recordSet', $records); $key = $this->getSecret($user, $s->id); $params = array('id' => $s->id, 'type' => 'alert', 'key' => $key); $unsubscribeUrl = $configArray['Site']['url'] . '/MyResearch/Unsubscribe?' . http_build_query($params); $interface->assign('info', array('time' => $dateFormat->convertToDisplayDate("U", floor($searchObject->getStartTime())), 'url' => $searchObject->renderSearchUrl(), 'searchId' => $searchObject->getSearchId(), 'description' => $searchObject->displayQuery(), 'filters' => $searchObject->getFilterList(), 'hits' => $searchObject->getResultTotal(), 'speed' => round($searchObject->getQuerySpeed(), 2) . "s", 'schedule' => $s->schedule, 'last_executed' => $s->last_executed, 'recordCount' => count($records), 'unsubscribeUrl' => $unsubscribeUrl)); $searchObject->close(); // Load template $message = $interface->fetch('MyResearch/alert-email.tpl'); if (strstr($message, 'Warning: Smarty error:')) { $this->msg("Message template processing failed: {$message}"); continue; } $result = $mailer->send($user->email, $configArray['Site']['email'], translate('Scheduled Alert Results'), $message); if (PEAR::isError($result)) { $this->msg("Failed to send message to {$user->email}: " . $result->getMessage()); continue; } } // Update search date $s->changeLastExecuted($searchDate); } $this->reportErrors(); $this->msg('Scheduled alerts execution completed'); }
/** * Handle an error raised by pear * * @var PEAR_Error $error; * @var string $method * * @return null */ function handlePEARError($error, $method = null) { global $errorHandlingEnabled; if (isset($errorHandlingEnabled) && $errorHandlingEnabled == false) { return; } global $configArray; // It would be really bad if an error got raised from within the error handler; // we would go into an infinite loop and run out of memory. To avoid this, // we'll set a static value to indicate that we're inside the error handler. // If the error handler gets called again from within itself, it will just // return without doing anything to avoid problems. We know that the top-level // call will terminate execution anyway. static $errorAlreadyOccurred = false; if ($errorAlreadyOccurred) { return; } else { $errorAlreadyOccurred = true; } //Clear any output that has been generated so far so the user just gets the error message. if (!$configArray['System']['debug']) { @ob_clean(); header("Content-Type: text/html"); } // Display an error screen to the user: global $interface; if (!isset($interface) || $interface == false) { $interface = new UInterface(); } global $analytics; if ($analytics) { $analytics->addEvent('Unexpected Error', 'Unexpected Error', $error, $method); } $interface->assign('error', $error); $interface->assign('debug', $configArray['System']['debug']); $interface->setTemplate('../error.tpl'); $interface->display('layout.tpl'); // Exceptions we don't want to log $doLog = true; // Microsoft Web Discussions Toolbar polls the server for these two files // it's not script kiddie hacking, just annoying in logs, ignore them. if (strpos($_SERVER['REQUEST_URI'], "cltreq.asp") !== false) { $doLog = false; } if (strpos($_SERVER['REQUEST_URI'], "owssvr.dll") !== false) { $doLog = false; } // If we found any exceptions, finish here if (!$doLog) { exit; } // Log the error for administrative purposes -- we need to build a variety // of pieces so we can supply information at five different verbosity levels: $baseError = $error->toString(); $basicServer = " (Server: IP = {$_SERVER['REMOTE_ADDR']}, " . "Referer = " . (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '') . ", " . "User Agent = " . (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '') . ", " . "Request URI = {$_SERVER['REQUEST_URI']})"; $detailedServer = "\nServer Context:\n" . print_r($_SERVER, true); $basicBacktrace = "\nBacktrace:\n"; if (is_array($error->backtrace)) { foreach ($error->backtrace as $line) { $basicBacktrace .= (isset($line['file']) ? $line['file'] : 'none') . " line " . (isset($line['line']) ? $line['line'] : 'none') . " - " . "class = " . (isset($line['class']) ? $line['class'] : 'none') . ", function = " . (isset($line['function']) ? $line['function'] : 'none') . "\n"; } } $detailedBacktrace = "\nBacktrace:\n" . print_r($error->backtrace, true); $errorDetails = array(1 => $baseError, 2 => $baseError . $basicServer, 3 => $baseError . $basicServer . $basicBacktrace, 4 => $baseError . $detailedServer . $basicBacktrace, 5 => $baseError . $detailedServer . $detailedBacktrace); global $logger; $logger->log($errorDetails, PEAR_LOG_ERR); exit; }
/** * Process transactions. Try to register unregistered transactions * and inform on expired transactions. * * @return void * @access public */ public function process() { global $configArray; global $interface; ini_set('display_errors', true); $configArray = $mainConfig = readConfig(); $datasourceConfig = getExtraConfigArray('datasources'); // Set up time zone. N.B. Don't use msg() or other // functions requiring date before this. date_default_timezone_set($configArray['Site']['timezone']); $this->msg("OnlinePayment monitor started"); // Setup Local Database Connection ConnectionManager::connectToDatabase(); // Initialize Mailer $mailer = new VuFindMailer(); $now = new DateTime(); $expiredCnt = 0; $failedCnt = 0; $registeredCnt = 0; $remindCnt = 0; $user = false; $report = array(); // Attempt to re-register paid transactions whose registration has failed. $tr = new Transaction(); foreach ($tr->getFailedTransactions() as $t) { $this->msg(" Registering transaction id {$t->id} / {$t->transaction_id}"); // check if the transaction has not been registered for too long $paid_time = new DateTime($t->paid); $diff = $now->diff($paid_time); $diffHours = $diff->days * 24 + $diff->h; if ($diffHours > $this->expireHours) { if (!isset($report[$t->driver])) { $report[$t->driver] = 0; } $report[$t->driver]++; $expiredCnt++; if (!$t->setTransactionReported($t->transaction_id)) { $this->err(' Failed to update transaction ' . $t->transaction_id . 'as reported'); } $transaction = clone $t; $transaction->complete = Transaction::STATUS_REGISTRATION_EXPIRED; if ($transaction->update($t) === false) { $this->err(' Failed to update transaction ' . $t->transaction_id . 'as expired.'); } else { $this->msg(' Transaction ' . $t->transaction_id . ' expired.'); } } else { if ($user === false || $t->user_id != $user->id) { $user = User::staticGet($t->user_id); } $catalog = ConnectionManager::connectToCatalog(); if ($catalog && $catalog->status) { $account = new User_account(); $account->user_id = $t->user_id; $account->cat_username = $t->cat_username; if ($account->find(true)) { if (!($patron = $catalog->patronLogin($t->cat_username, $account->cat_password))) { $this->err(' Could not perform patron login for transaction ' . $t->transaction_id); $failedCnt++; continue; } } $res = $catalog->markFeesAsPaid($patron, $t->amount); if ($res === true) { if (!$t->setTransactionRegistered($t->transaction_id)) { $this->err(' Failed to update transaction ' . $t->transaction_id . 'as registered'); } $registeredCnt++; } else { $t->setTransactionRegistrationFailed($t->transaction_id, $res); $failedCnt++; $this->msg(' Registration of transaction ' . $t->transaction_id . ' failed'); $this->msg(" {$res}"); } } else { $this->err("Failed to connect to catalog ({$patronId})"); continue; } } } // Report paid and unregistered transactions whose registration // can not be re-tried: $tr = new Transaction(); foreach ($tr->getUnresolvedTransactions($this->reportIntervalHours) as $t) { $this->msg(" Transaction id {$t->transaction_id} still unresolved."); if (!$t->setTransactionReported($t->transaction_id)) { $this->err(' Failed to update transaction ' . $t->transaction_id . ' as reported'); } if (!isset($report[$t->driver])) { $report[$t->driver] = 0; } $report[$t->driver]++; $remindCnt++; } if ($registeredCnt) { $this->msg(" Total registered: {$registeredCnt}"); } if ($expiredCnt) { $this->msg(" Total expired: {$expiredCnt}"); } if ($failedCnt) { $this->msg(" Total failed: {$failedCnt}"); } if ($remindCnt) { $this->msg(" Total to be reminded: {$remindCnt}"); } $configArray = readConfig(); $siteLocal = $configArray['Site']['local']; $interface = new UInterface($siteLocal); // Send report of transactions that need to be resolved manually: foreach ($report as $driver => $cnt) { if ($cnt) { $settings = getExtraConfigArray("VoyagerRestful_{$driver}"); if (!$settings || !isset($settings['OnlinePayment']['errorEmail'])) { $this->err(" Error email for expired transactions not defined for driver {$driver} ({$cnt} expired transactions)"); continue; } $email = $settings['OnlinePayment']['errorEmail']; $this->msg(" [{$driver}] Inform {$cnt} expired transactions for driver {$driver} to {$email}"); $mailer = new VuFindMailer(); $subject = "Finna: ilmoitus tietokannan {$driver} epäonnistuneista verkkomaksuista"; $interface->assign('driver', $driver); $interface->assign('cnt', $cnt); $msg = $interface->fetch('Emails/online-payment-error.tpl'); if (!($result = $mailer->send($email, $this->fromEmail, $subject, $msg))) { $this->err(" Failed to send error email to customer: {$email}"); } } } $this->msg("OnlinePayment monitor completed"); $this->reportErrors(); }
*/ /** CORE APPLICATION CONTROLLER **/ require_once 'bootstrap.php'; //Do additional tasks that are only needed when running the full website loadModuleActionId(); spl_autoload_register('vufind_autoloader'); initializeSession(); if (isset($_REQUEST['test_role'])) { if ($_REQUEST['test_role'] == '') { setcookie('test_role', $_REQUEST['test_role'], time() - 1000, '/'); } else { setcookie('test_role', $_REQUEST['test_role'], 0, '/'); } } // Start Interface $interface = new UInterface(); global $timer; $timer->logTime('Create interface'); if (isset($configArray['Site']['responsiveLogo'])) { $interface->assign('responsiveLogo', $configArray['Site']['responsiveLogo']); } if (isset($configArray['Site']['smallLogo'])) { $interface->assign('smallLogo', $configArray['Site']['smallLogo']); } if (isset($configArray['Site']['largeLogo'])) { $interface->assign('largeLogo', $configArray['Site']['largeLogo']); } //Set focus to the search box by default. $interface->assign('focusElementId', 'lookfor'); //Set footer information /** @var Location $locationSingleton */
/** * Callback function to handle any PEAR errors that are thrown. * * @param PEAR_Error $error The error object. * * @return void */ function handlePEARError($error) { global $configArray; // It would be really bad if an error got raised from within the error handler; // we would go into an infinite loop and run out of memory. To avoid this, // we'll set a static value to indicate that we're inside the error handler. // If the error handler gets called again from within itself, it will just // return without doing anything to avoid problems. We know that the top-level // call will terminate execution anyway. static $errorAlreadyOccurred = false; if ($errorAlreadyOccurred) { return; } else { $errorAlreadyOccurred = true; } // Set appropriate HTTP header based on error (404 for missing record, 500 for // other problems): $msg = $error->getMessage(); if ($msg == 'Record Does Not Exist' || stristr($msg, 'cannot access record')) { header('HTTP/1.1 404 Not Found'); } else { header('HTTP/1.1 500 Internal Server Error'); } // Display an error screen to the user: $interface = new UInterface(); $interface->assign('error', $error); $interface->assign('debug', $configArray['System']['debug']); $interface->display('error.tpl'); // Exceptions we don't want to log $doLog = true; // Microsoft Web Discussions Toolbar polls the server for these two files // it's not script kiddie hacking, just annoying in logs, ignore them. if (strpos($_SERVER['REQUEST_URI'], "cltreq.asp") !== false) { $doLog = false; } if (strpos($_SERVER['REQUEST_URI'], "owssvr.dll") !== false) { $doLog = false; } // If we found any exceptions, finish here if (!$doLog) { exit; } // Log the error for administrative purposes -- we need to build a variety // of pieces so we can supply information at five different verbosity levels: $baseError = $error->toString(); $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : 'none'; $basicServer = " (Server: IP = {$_SERVER['REMOTE_ADDR']}, " . "Referer = {$referer}, " . "User Agent = {$_SERVER['HTTP_USER_AGENT']}, " . "Request URI = {$_SERVER['REQUEST_URI']})"; $detailedServer = "\nServer Context:\n" . print_r($_SERVER, true); $basicBacktrace = "\nBacktrace:\n"; if (is_array($error->backtrace)) { foreach ($error->backtrace as $line) { $basicBacktrace .= "{$line['file']} line {$line['line']} - " . "class = {$line['class']}, function = {$line['function']}\n"; } } $detailedBacktrace = "\nBacktrace:\n" . print_r($error->backtrace, true); $errorDetails = array(1 => $baseError, 2 => $baseError . $basicServer, 3 => $baseError . $basicServer . $basicBacktrace, 4 => $baseError . $detailedServer . $basicBacktrace, 5 => $baseError . $detailedServer . $detailedBacktrace); $logger = new Logger(); $logger->log($errorDetails, PEAR_LOG_ERR); exit; }
/** * Send due date reminders * * @return void */ public function send() { global $configArray; global $interface; global $translator; $iso8601 = 'Y-m-d\\TH:i:s\\Z'; ini_set('display_errors', true); $configArray = $mainConfig = readConfig(); $datasourceConfig = getExtraConfigArray('datasources'); $siteLocal = $configArray['Site']['local']; // Set up time zone. N.B. Don't use msg() or other functions requiring date before this. date_default_timezone_set($configArray['Site']['timezone']); $this->msg('Sending due date reminders'); // Setup Local Database Connection ConnectionManager::connectToDatabase(); // And index $db = ConnectionManager::connectToIndex(); // Initialize Mailer $mailer = new VuFindMailer(); // Find all scheduled alerts $sql = 'SELECT * FROM "user" WHERE "due_date_reminder" > 0 ORDER BY id'; $user = new User(); $user->query($sql); $this->msg('Processing ' . $user->N . ' users'); $interface = false; $institution = false; $todayTime = new DateTime(); $catalog = ConnectionManager::connectToCatalog(); while ($user->fetch()) { if (!$user->email || trim($user->email) == '') { $this->msg('User ' . $user->username . ' does not have an email address, bypassing due date reminders'); continue; } // Initialize settings and interface $userInstitution = reset(explode(':', $user->username, 2)); if (!$institution || $institution != $userInstitution) { $institution = $userInstitution; if (!isset($datasourceConfig[$institution])) { foreach ($datasourceConfig as $code => $values) { if (isset($values['institution']) && strcasecmp($values['institution'], $institution) == 0) { $institution = $code; break; } } } if (!($configArray = $this->readInstitutionConfig($institution))) { continue; } // Start Interface $interface = new UInterface($siteLocal); $validLanguages = array_keys($configArray['Languages']); $dateFormat = new VuFindDate(); } $language = $user->language; if (!in_array($user->language, $validLanguages)) { $language = $configArray['Site']['language']; } $translator = new I18N_Translator(array($configArray['Site']['local'] . '/lang', $configArray['Site']['local'] . '/lang_local'), $language, $configArray['System']['debug']); $interface->setLanguage($language); // Go through accounts and check loans $account = new User_account(); $account->user_id = $user->id; if (!$account->find(false)) { continue; } $remindLoans = array(); while ($account->fetch()) { $patron = $catalog->patronLogin($account->cat_username, $account->cat_password); if ($patron === null || PEAR::isError($patron)) { $this->msg('Catalog login failed for user ' . $user->id . ', account ' . $account->id . ' (' . $account->cat_username . '): ' . ($patron ? $patron->getMessage() : 'patron not found')); continue; } $loans = $catalog->getMyTransactions($patron); if (PEAR::isError($loans)) { $this->msg('Could not fetch loans for user ' . $user->id . ', account ' . $account->id . ' (' . $account->cat_username . ')'); continue; } foreach ($loans as $loan) { $dueDate = new DateTime($loan['duedate']); if ($todayTime >= $dueDate || $dueDate->diff($todayTime)->days <= $user->due_date_reminder) { // Check that a reminder hasn't been sent already $reminder = new Due_date_reminder(); $reminder->user_id = $user->id; $reminder->loan_id = $loan['item_id']; $reminder->due_date = $dueDate->format($iso8601); if ($reminder->find(false)) { // Reminder already sent continue; } // Store also title for display in email $title = isset($loan['title']) ? $loan['title'] : translate('Title not available'); if (isset($loan['id'])) { $record = $db->getRecord($loan['id']); if ($record && isset($record['title'])) { $title = $record['title']; } } $remindLoans[] = array('loanId' => $loan['item_id'], 'dueDate' => $loan['duedate'], 'dueDateFormatted' => $dueDate->format(isset($configArray['Site']['displayDateFormat']) ? $configArray['Site']['displayDateFormat'] : "m-d-Y"), 'title' => $title); } } } if ($remindLoans) { $this->msg(count($remindLoans) . ' new loans to remind for user ' . $user->id); $interface->assign('date', $dateFormat->convertToDisplayDate("U", floor(time()))); $interface->assign('loans', $remindLoans); $key = $this->getSecret($user, $user->id); $params = array('id' => $user->id, 'type' => 'reminder', 'key' => $key); $unsubscribeUrl = $configArray['Site']['url'] . '/MyResearch/Unsubscribe?' . http_build_query($params); $interface->assign(compact('unsubscribeUrl')); // Load template $message = $interface->fetch('MyResearch/due-date-email.tpl'); if (strstr($message, 'Warning: Smarty error:')) { $this->msg("Message template processing failed: {$message}"); continue; } $result = $mailer->send($user->email, $configArray['Site']['email'], translate('due_date_email_subject'), $message); if (PEAR::isError($result)) { $this->msg("Failed to send message to {$user->email}: " . $result->getMessage()); continue; } // Mark reminders sent foreach ($remindLoans as $loan) { $reminder = new Due_date_reminder(); $reminder->user_id = $user->id; $reminder->loan_id = $loan['loanId']; $reminder->delete(); $dueDate = new DateTime($loan['dueDate']); $reminder->due_date = $dueDate->format($iso8601); $reminder->notification_date = gmdate($iso8601, time()); $reminder->insert(); } } else { $this->msg('No loans to remind for user ' . $user->id); } } $this->reportErrors(); $this->msg('Due date reminders execution completed'); }
*/ /** CORE APPLICATION CONTROLLER **/ require_once 'bootstrap.php'; //Do additional tasks that are only needed when running the full website loadModuleActionId(); spl_autoload_register('vufind_autoloader'); initializeSession(); if (isset($_REQUEST['test_role'])) { if ($_REQUEST['test_role'] == '') { setcookie('test_role', $_REQUEST['test_role'], time() - 1000, '/'); } else { setcookie('test_role', $_REQUEST['test_role'], 0, '/'); } } // Start Interface $interface = new UInterface(); global $timer; $timer->logTime('Create interface'); if (isset($configArray['Site']['smallLogo'])) { $interface->assign('smallLogo', $configArray['Site']['smallLogo']); } if (isset($configArray['Site']['largeLogo'])) { $interface->assign('largeLogo', $configArray['Site']['largeLogo']); } //Set focus to the search box by default. $interface->assign('focusElementId', 'lookfor'); //Set footer information /** @var Location $locationSingleton */ global $locationSingleton; $location = $locationSingleton->getActiveLocation(); $interface->assign('footerTemplate', 'footer.tpl');