Merge pull request #1078

This commit is contained in:
Ingo Schommer 2013-01-29 18:04:15 +01:00
commit 6cb1570282
20 changed files with 237 additions and 67 deletions

View File

@ -41,6 +41,7 @@
*
* Email:
* - SS_SEND_ALL_EMAILS_TO: If you set this define, all emails will be redirected to this address.
* - SS_SEND_ALL_EMAILS_FROM: If you set this define, all emails will be send from this address.
*
* @package framework
* @subpackage core
@ -105,7 +106,10 @@ if(defined('SS_DATABASE_USERNAME') && defined('SS_DATABASE_PASSWORD')) {
}
if(defined('SS_SEND_ALL_EMAILS_TO')) {
Email::send_all_emails_to(SS_SEND_ALL_EMAILS_TO);
Config::inst()->update("Email","send_all_emails_to", SS_SEND_ALL_EMAILS_TO);
}
if(defined('SS_SEND_ALL_EMAILS_FROM')) {
Config::inst()->update("Email","send_all_emails_from", SS_SEND_ALL_EMAILS_FROM);
}
if(defined('SS_DEFAULT_ADMIN_USERNAME')) {

View File

@ -454,7 +454,7 @@ class Controller extends RequestHandler implements TemplateGlobalProvider {
public function redirect($url, $code=302) {
if(!$this->response) $this->response = new SS_HTTPResponse();
if($this->response->getHeader('Location')) {
if($this->response->getHeader('Location') && $this->response->getHeader('Location') != $url) {
user_error("Already directed to " . $this->response->getHeader('Location')
. "; now trying to direct to $url", E_USER_WARNING);
return;

View File

@ -725,6 +725,9 @@ class Director implements TemplateGlobalProvider {
$matched = false;
if($patterns) {
// Calling from the command-line?
if(!isset($_SERVER['REQUEST_URI'])) return;
// protect portions of the site based on the pattern
$relativeURL = self::makeRelative(Director::absoluteURL($_SERVER['REQUEST_URI']));
foreach($patterns as $pattern) {

View File

@ -220,11 +220,17 @@ class SS_HTTPResponse {
<meta http-equiv=\"refresh\" content=\"1; url=$url\" />
<script type=\"text/javascript\">setTimeout('window.location.href = \"$url\"', 50);</script>";
} else {
if(!headers_sent()) {
$line = $file = null;
if(!headers_sent($file, $line)) {
header($_SERVER['SERVER_PROTOCOL'] . " $this->statusCode " . $this->getStatusDescription());
foreach($this->headers as $header => $value) {
header("$header: $value", true, $this->statusCode);
}
} else {
// It's critical that these status codes are sent; we need to report a failure if not.
if($this->statusCode >= 300) {
user_error("Couldn't set response type to $this->statusCode because of output on line $line of $file", E_USER_WARNING);
}
}
// Only show error pages or generic "friendly" errors if the status code signifies

View File

@ -415,7 +415,7 @@ class Session {
protected function recursivelyApply($data, &$dest) {
foreach($data as $k => $v) {
if(is_array($v)) {
if(!isset($dest[$k])) $dest[$k] = array();
if(!isset($dest[$k]) || !is_array($dest[$k])) $dest[$k] = array();
$this->recursivelyApply($v, $dest[$k]);
} else {
$dest[$k] = $v;

View File

@ -213,6 +213,7 @@ class Debug {
public static function noticeHandler($errno, $errstr, $errfile, $errline, $errcontext) {
if(error_reporting() == 0) return;
ini_set('display_errors', 0);
// Send out the error details to the logger for writing
SS_Log::log(
@ -227,7 +228,9 @@ class Debug {
);
if(Director::isDev()) {
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Notice");
return self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Notice");
} else {
return false;
}
}
@ -242,8 +245,10 @@ class Debug {
*/
public static function warningHandler($errno, $errstr, $errfile, $errline, $errcontext) {
if(error_reporting() == 0) return;
ini_set('display_errors', 0);
if(self::$send_warnings_to) {
self::emailError(self::$send_warnings_to, $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
return self::emailError(self::$send_warnings_to, $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
}
// Send out the error details to the logger for writing
@ -263,8 +268,10 @@ class Debug {
}
if(Director::isDev()) {
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Warning");
}
return self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Warning");
} else {
return false;
}
}
/**
@ -279,6 +286,8 @@ class Debug {
* @param unknown_type $errcontext
*/
public static function fatalHandler($errno, $errstr, $errfile, $errline, $errcontext) {
ini_set('display_errors', 0);
if(self::$send_errors_to) {
self::emailError(self::$send_errors_to, $errno, $errstr, $errfile, $errline, $errcontext, "Error");
}
@ -300,11 +309,10 @@ class Debug {
}
if(Director::isDev() || Director::is_cli()) {
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Error");
return self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Error");
} else {
self::friendlyError();
return self::friendlyError();
}
exit(1);
}
/**
@ -363,6 +371,7 @@ class Debug {
$renderer->writeFooter();
}
}
return false;
}
/**
@ -652,7 +661,7 @@ class Debug {
$_SESSION['Security']['Message']['type'] = 'warning';
$_SESSION['BackURL'] = $_SERVER['REQUEST_URI'];
header($_SERVER['SERVER_PROTOCOL'] . " 302 Found");
header("Location: " . Director::baseURL() . "Security/login");
header("Location: " . Director::baseURL() . Security::login_url());
die();
}
}
@ -679,7 +688,7 @@ function exceptionHandler($exception) {
$file = $exception->getFile();
$line = $exception->getLine();
$context = $exception->getTrace();
Debug::fatalHandler($errno, $message, $file, $line, $context);
return Debug::fatalHandler($errno, $message, $file, $line, $context);
}
/**
@ -698,21 +707,18 @@ function errorHandler($errno, $errstr, $errfile, $errline) {
case E_ERROR:
case E_CORE_ERROR:
case E_USER_ERROR:
Debug::fatalHandler($errno, $errstr, $errfile, $errline, debug_backtrace());
break;
return Debug::fatalHandler($errno, $errstr, $errfile, $errline, debug_backtrace());
case E_WARNING:
case E_CORE_WARNING:
case E_USER_WARNING:
Debug::warningHandler($errno, $errstr, $errfile, $errline, debug_backtrace());
break;
return Debug::warningHandler($errno, $errstr, $errfile, $errline, debug_backtrace());
case E_NOTICE:
case E_USER_NOTICE:
case E_DEPRECATED:
case E_USER_DEPRECATED:
case E_STRICT:
Debug::noticeHandler($errno, $errstr, $errfile, $errline, debug_backtrace());
break;
return Debug::noticeHandler($errno, $errstr, $errfile, $errline, debug_backtrace());
}
}

View File

@ -205,7 +205,15 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
$className = get_class($this);
$fixtureFile = eval("return {$className}::\$fixture_file;");
$prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_';
// Set up email
$this->originalMailer = Email::mailer();
$this->mailer = new TestMailer();
Email::set_mailer($this->mailer);
Config::inst()->remove('Email', 'send_all_emails_to');
Email::send_all_emails_to(null);
// Todo: this could be a special test model
$this->model = DataModel::inst();
@ -259,12 +267,6 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
$this->logInWithPermission("ADMIN");
}
// Set up email
$this->originalMailer = Email::mailer();
$this->mailer = new TestMailer();
Email::set_mailer($this->mailer);
Email::send_all_emails_to(null);
// Preserve memory settings
$this->originalMemoryLimit = ini_get('memory_limit');

View File

@ -96,8 +96,12 @@ class TestSession {
$form->setField(new SimpleByName($k), $v);
}
if($button) $submission = $form->submitButton(new SimpleByName($button));
else $submission = $form->submit();
if($button) {
$submission = $form->submitButton(new SimpleByName($button));
if(!$submission) throw new Exception("Can't find button '$button' to submit as part of test.");
} else {
$submission = $form->submit();
}
$url = Director::makeRelative($form->getAction()->asString());
@ -137,6 +141,15 @@ class TestSession {
return $this->lastResponse;
}
/**
* Return the fake HTTP_REFERER; set each time get() or post() is called.
*
* @return string
*/
public function lastUrl() {
return $this->lastUrl;
}
/**
* Get the most recent response's content
*/

View File

@ -125,16 +125,54 @@ class Email extends ViewableData {
static $admin_email_address = '';
/**
* Send every email generated by the Email class to the given address.
*
* It will also add " [addressed to (email), cc to (email), bcc to (email)]" to the end of the subject line
*
* To set this, set Email.send_all_emails_to in your yml config file.
* It can also be set in _ss_environment.php with SS_SEND_ALL_EMAILS_TO.
*
* @param string $send_all_emails_to Email-Address
*/
protected static $send_all_emails_to = null;
/**
* Send every email generated by the Email class *from* the given address.
* It will also add " [, from to (email)]" to the end of the subject line
*
* To set this, set Email.send_all_emails_from in your yml config file.
* It can also be set in _ss_environment.php with SS_SEND_ALL_EMAILS_FROM.
*
* @param string $send_all_emails_from Email-Address
*/
protected static $send_all_emails_from = null;
/**
* BCC every email generated by the Email class to the given address.
* It won't affect the original delivery in the same way that send_all_emails_to does. It just adds a BCC header
* with the given email address. Note that you can only call this once - subsequent calls will overwrite the
* configuration variable.
*
* This can be used when you have a system that relies heavily on email and you want someone to be checking all
* correspondence.
*
* To set this, set Email.bcc_all_emails_to in your yml config file.
*
* @param string $bcc_all_emails_to Email-Address
*/
protected static $bcc_all_emails_to = null;
/**
* CC every email generated by the Email class to the given address.
* It won't affect the original delivery in the same way that send_all_emails_to does. It just adds a CC header
* with the given email address. Note that you can only call this once - subsequent calls will overwrite the
* configuration variable.
*
* This can be used when you have a system that relies heavily on email and you want someone to be checking all
* correspondence.
*
* To set this, set Email.cc_all_emails_to in your yml config file.
*
* @param string $cc_all_emails_to Email-Address
*/
protected static $cc_all_emails_to = null;
@ -399,37 +437,45 @@ class Email extends ViewableData {
if(project()) $headers['X-SilverStripeSite'] = project();
$to = $this->to;
$from = $this->from;
$subject = $this->subject;
if(self::$send_all_emails_to) {
if($sendAllTo = $this->config()->send_all_emails_to) {
$subject .= " [addressed to $to";
$to = self::$send_all_emails_to;
$to = $sendAllTo;
if($this->cc) $subject .= ", cc to $this->cc";
if($this->bcc) $subject .= ", bcc to $this->bcc";
$subject .= ']';
unset($headers['Cc']);
unset($headers['Bcc']);
} else {
if($this->cc) $headers['Cc'] = $this->cc;
if($this->bcc) $headers['Bcc'] = $this->bcc;
}
if(self::$cc_all_emails_to) {
if($ccAllTo = $this->config()->cc_all_emails_to) {
if(!empty($headers['Cc']) && trim($headers['Cc'])) {
$headers['Cc'] .= ', ' . self::$cc_all_emails_to;
$headers['Cc'] .= ', ' . $ccAllTo;
} else {
$headers['Cc'] = self::$cc_all_emails_to;
$headers['Cc'] = $ccAllTo;
}
}
if(self::$bcc_all_emails_to) {
if($bccAllTo = $this->config()->bcc_all_emails_to) {
if(!empty($headers['Bcc']) && trim($headers['Bcc'])) {
$headers['Bcc'] .= ', ' . self::$bcc_all_emails_to;
$headers['Bcc'] .= ', ' . $bccAllTo;
} else {
$headers['Bcc'] = self::$bcc_all_emails_to;
$headers['Bcc'] = $bccAllTo;
}
}
if($sendAllfrom = $this->config()->send_all_emails_from) {
if($from) $subject .= " [from $from]";
$from = $sendAllfrom;
}
Requirements::restore();
return self::mailer()->sendPlain($to, $this->from, $subject, $this->body, $this->attachments, $headers);
return self::mailer()->sendPlain($to, $from, $subject, $this->body, $this->attachments, $headers);
}
/**
@ -459,40 +505,49 @@ class Email extends ViewableData {
if(project()) $headers['X-SilverStripeSite'] = project();
$to = $this->to;
$from = $this->from;
$subject = $this->subject;
if(self::$send_all_emails_to) {
if($sendAllTo = $this->config()->send_all_emails_to) {
$subject .= " [addressed to $to";
$to = self::$send_all_emails_to;
$to = $sendAllTo;
if($this->cc) $subject .= ", cc to $this->cc";
if($this->bcc) $subject .= ", bcc to $this->bcc";
$subject .= ']';
unset($headers['Cc']);
unset($headers['Bcc']);
} else {
if($this->cc) $headers['Cc'] = $this->cc;
if($this->bcc) $headers['Bcc'] = $this->bcc;
}
if(self::$cc_all_emails_to) {
if($ccAllTo = $this->config()->cc_all_emails_to) {
if(!empty($headers['Cc']) && trim($headers['Cc'])) {
$headers['Cc'] .= ', ' . self::$cc_all_emails_to;
$headers['Cc'] .= ', ' . $ccAllTo;
} else {
$headers['Cc'] = self::$cc_all_emails_to;
$headers['Cc'] = $ccAllTo;
}
}
if(self::$bcc_all_emails_to) {
if($bccAllTo = $this->config()->bcc_all_emails_to) {
if(!empty($headers['Bcc']) && trim($headers['Bcc'])) {
$headers['Bcc'] .= ', ' . self::$bcc_all_emails_to;
$headers['Bcc'] .= ', ' . $bccAllTo;
} else {
$headers['Bcc'] = self::$bcc_all_emails_to;
$headers['Bcc'] = $bccAllTo;
}
}
if($sendAllfrom = $this->config()->send_all_emails_from) {
if($from) $subject .= " [from $from]";
$from = $sendAllfrom;
}
Requirements::restore();
return self::mailer()->sendHTML($to, $this->from, $subject, $this->body, $this->attachments, $headers,
return self::mailer()->sendHTML($to, $from, $subject, $this->body, $this->attachments, $headers,
$this->plaintext_body);
}
@ -526,7 +581,7 @@ class Email extends ViewableData {
public static function send_all_emails_to($emailAddress) {
self::$send_all_emails_to = $emailAddress;
}
/**
* CC every email generated by the Email class to the given address.
* It won't affect the original delivery in the same way that send_all_emails_to does. It just adds a CC header

View File

@ -291,7 +291,7 @@ function encodeMultipart($parts, $contentType, $headers = false) {
*/
function wrapImagesInline($htmlContent) {
global $_INLINED_IMAGES;
$_INLINED_IMAGES = null;
$_INLINED_IMAGES = array();
$replacedContent = imageRewriter($htmlContent, 'wrapImagesInline_rewriter($URL)');
@ -303,8 +303,8 @@ function wrapImagesInline($htmlContent) {
// Make all the image parts
global $_INLINED_IMAGES;
foreach($_INLINED_IMAGES as $url => $cid) {
$multiparts[] = encodeFileForEmail($url, false, "inline", "Content-ID: <$cid>\n");
if($_INLINED_IMAGES) foreach($_INLINED_IMAGES as $url => $cid) {
$multiparts[] = encodeFileForEmail(BASE_PATH . '/' . $url, false, "inline", "Content-ID: <$cid>\n");
}
// Merge together in a multipart
@ -312,10 +312,10 @@ function wrapImagesInline($htmlContent) {
return processHeaders($headers, $body);
}
function wrapImagesInline_rewriter($url) {
$url = relativiseURL($url);
$url = Director::makeRelative($url);
global $_INLINED_IMAGES;
if(!$_INLINED_IMAGES[$url]) {
if(!isset($_INLINED_IMAGES[$url])) {
$identifier = "automatedmessage." . rand(1000,1000000000) . "@silverstripe.com";
$_INLINED_IMAGES[$url] = $identifier;
}
@ -384,6 +384,7 @@ function encodeFileForEmail($file, $destFileName = false, $disposition = NULL, $
$file = array('filename' => $file);
$fh = fopen($file['filename'], "rb");
if ($fh) {
$file['contents'] = "";
while(!feof($fh)) $file['contents'] .= fread($fh, 10000);
fclose($fh);
}
@ -393,12 +394,12 @@ function encodeFileForEmail($file, $destFileName = false, $disposition = NULL, $
if(!$destFileName) $base = basename($file['filename']);
else $base = $destFileName;
$mimeType = $file['mimetype'] ? $file['mimetype'] : HTTP::get_mime_type($file['filename']);
$mimeType = !empty($file['mimetype']) ? $file['mimetype'] : HTTP::get_mime_type($file['filename']);
if(!$mimeType) $mimeType = "application/unknown";
if (empty($disposition)) $disposition = isset($file['contentLocation']) ? 'inline' : 'attachment';
// Encode for emailing
if (substr($file['mimetype'], 0, 4) != 'text') {
if (substr($mimeType, 0, 4) != 'text') {
$encoding = "base64";
$file['contents'] = chunk_split(base64_encode($file['contents']));
} else {

View File

@ -250,7 +250,9 @@ class Form extends RequestHandler {
// Protection against CSRF attacks
$token = $this->getSecurityToken();
if(!$token->checkRequest($request)) {
$this->httpError(400, "Sorry, your session has timed out.");
$this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE",
"There seems to have been a technical problem. Please click the back button,"
. " refresh your browser, and try again."));
}
// Determine the action button clicked

View File

@ -35,7 +35,7 @@ class RequiredFields extends Validator {
* Clears all the validation from this object.
*/
public function removeValidation(){
$this->required = null;
$this->required = array();
}
/**

View File

@ -55,6 +55,9 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
* @return ArrayIterator
*/
public function getIterator() {
foreach($this->items as $i => $item) {
if(is_array($item)) $this->items[$i] = new ArrayData($item);
}
return new ArrayIterator($this->items);
}

View File

@ -302,7 +302,7 @@ class Date extends DBField {
* @return boolean
*/
public function InPast() {
return strtotime($this->value) < time();
return strtotime($this->value) < SS_Datetime::now()->Format('U');
}
/**
@ -310,7 +310,7 @@ class Date extends DBField {
* @return boolean
*/
public function InFuture() {
return strtotime($this->value) > time();
return strtotime($this->value) > SS_Datetime::now()->Format('U');
}
/**
@ -318,7 +318,7 @@ class Date extends DBField {
* @return boolean
*/
public function IsToday() {
return (date('Y-m-d', strtotime($this->value)) == date('Y-m-d', time()));
return (date('Y-m-d', strtotime($this->value)) == SS_Datetime::now()->Format('Y-m-d'));
}
/**

View File

@ -136,8 +136,21 @@ class HTMLText extends Text {
return ShortcodeParser::get_active()->parse($this->value);
}
/**
* Returns true if the field has meaningful content.
* Excludes null content like <h1></h1>, <p></p> ,etc
*
* @return boolean
*/
public function exists() {
return parent::exists() && $this->value != '<p></p>';
// If it's blank, it's blank
if(!parent::exists()) return false;
// If it's got a content tag
if(preg_match('/<(img|embed|object|iframe)[^>]*>/i', $this->value)) return true;
// If it's just one or two tags on its own (and not the above) it's empty. This might be <p></p> or <h1></h1> or whatever.
if(preg_match('/^[\\s]*(<[^>]+>[\\s]*){1,2}$/', $this->value)) return false;
// Otherwise its content is genuine content
return true;
}
public function scaffoldFormField($title = null, $params = null) {

View File

@ -242,7 +242,10 @@ class Security extends Controller {
// Audit logging hook
$controller->extend('permissionDenied', $member);
$controller->redirect("Security/login?BackURL=" . urlencode($_SERVER['REQUEST_URI']));
$controller->redirect(
Config::inst()->get('Security', 'login_url')
. "?BackURL=" . urlencode($_SERVER['REQUEST_URI'])
);
}
return;
}
@ -927,8 +930,25 @@ class Security extends Controller {
public static function set_ignore_disallowed_actions($flag) {
self::$ignore_disallowed_actions = $flag;
}
public static function ignore_disallowed_actions() {
return self::$ignore_disallowed_actions;
}
protected static $login_url = "Security/login";
/**
* Set a custom log-in URL if you have built your own log-in page.
*/
public static function set_login_url($loginUrl) {
self::$login_url = $loginUrl;
}
/**
* Get the URL of the log-in page.
* Defaults to Security/login but can be re-set with {@link set_login_url()}
*/
public static function login_url() {
return self::$login_url;
}
}

View File

@ -1,4 +1,9 @@
<form $FormAttributes>
<% if Message %>
<p id="{$FormName}_error" class="message $MessageType">$Message</p>
<% else %>
<p id="{$FormName}_error" class="message $MessageType" style="display: none"></p>
<% end_if %>
<fieldset>
<% loop Fields %>
$FieldHolder

View File

@ -252,7 +252,7 @@ class DirectorTest extends SapphireTest {
}
public function testForceSSLOnSubPagesPattern() {
$_SERVER['REQUEST_URI'] = Director::baseURL() . 'Security/login';
$_SERVER['REQUEST_URI'] = Director::baseURL() . Config::inst()->get('Security', 'login_url');
$output = Director::forceSSL(array('/^Security/'));
$this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
}

View File

@ -139,4 +139,38 @@ class HTMLTextTest extends SapphireTest {
$data = DBField::create_field('HTMLText', '"this is a test"');
$this->assertEquals($data->ATT(), '&quot;this is a test&quot;');
}
function testExists() {
$h = new HTMLText;
$h->setValue("");
$this->assertFalse($h->exists());
$h->setValue("<p></p>");
$this->assertFalse($h->exists());
$h->setValue("<p> </p>");
$this->assertFalse($h->exists());
$h->setValue("<h2/>");
$this->assertFalse($h->exists());
$h->setValue("<h2></h2>");
$this->assertFalse($h->exists());
$h->setValue("something");
$this->assertTrue($h->exists());
$h->setValue("<img src=\"dummy.png\">");
$this->assertTrue($h->exists());
$h->setValue("<img src=\"dummy.png\"><img src=\"dummy.png\">");
$this->assertTrue($h->exists());
$h->setValue("<p><img src=\"dummy.png\"></p>");
$this->assertTrue($h->exists());
$h->setValue("<iframe src=\"http://www.google.com\"></iframe>");
$this->assertTrue($h->exists());
$h->setValue("<embed src=\"test.swf\">");
$this->assertTrue($h->exists());
$h->setValue("<object width=\"400\" height=\"400\" data=\"test.swf\"></object>");
$this->assertTrue($h->exists());
$h->setValue("<p>test</p>");
$this->assertTrue($h->exists());
}
}

View File

@ -57,7 +57,10 @@ class SecurityTest extends FunctionalTest {
$response = $this->get('SecurityTest_SecuredController');
$this->assertEquals(302, $response->getStatusCode());
$this->assertContains('Security/login', $response->getHeader('Location'));
$this->assertContains(
Config::inst()->get('Security', 'login_url'),
$response->getHeader('Location')
);
$this->logInWithPermission('ADMIN');
$response = $this->get('SecurityTest_SecuredController');
@ -74,7 +77,7 @@ class SecurityTest extends FunctionalTest {
$this->session()->inst_set('loggedInAs', $member->ID);
/* View the Security/login page */
$response = $this->get('Security/login');
$response = $this->get(Config::inst()->get('Security', 'login_url'));
$items = $this->cssParser()->getBySelector('#MemberLoginForm_LoginForm input.action');
@ -108,7 +111,7 @@ class SecurityTest extends FunctionalTest {
$this->autoFollowRedirection = true;
/* Attempt to get into the admin section */
$response = $this->get('Security/login/');
$response = $this->get(Config::inst()->get('Security', 'login_url'));
$items = $this->cssParser()->getBySelector('#MemberLoginForm_LoginForm input.text');
@ -396,7 +399,7 @@ class SecurityTest extends FunctionalTest {
public function doTestLoginForm($email, $password, $backURL = 'test/link') {
$this->get('Security/logout');
$this->session()->inst_set('BackURL', $backURL);
$this->get('Security/login');
$this->get(Config::inst()->get('Security', 'login_url'));
return $this->submitForm(
"MemberLoginForm_LoginForm",