Setting a fe_users session from extbase - typo3

As I have to verify the login-data in a way, normal login extensions can not handle, I have to develop a custom login-form. This login box is part of an ext. written in extbase.
But I stuck with a basic question: How can i handle fe_users sessions in extbase?

I wrote this function, maybe it helps:
/** #var $fe_user tslib_feUserAuth */
$fe_user = $GLOBALS['TSFE']->fe_user;
$fe_user->createUserSession(array('uid' => $uid));
$fe_user->user = $fe_user->getRawUserByUid($uid);
$fe_user->fetchGroupData();
$GLOBALS['TSFE']->loginUser = 1;
It's inspired by Tx_Phpunit_Framework::loginFrontEndUser($userId) :
// Instead of passing the actual user data to createUserSession, we
// pass an empty array to improve performance (e.g. no session record
// will be written to the database).
$GLOBALS['TSFE']->fe_user->createUserSession(array());
$GLOBALS['TSFE']->fe_user->user = $GLOBALS['TSFE']->fe_user->getRawUserByUid($userId);
$GLOBALS['TSFE']->fe_user->fetchGroupData();
$GLOBALS['TSFE']->loginUser = 1;

None of the answers provided seemed to work for me in TYPO3 6.2. The fix is described in a Bugreport in the Forge, https://forge.typo3.org/issues/62194 . Basically, the SessionCookie isn't placed automatically anymore, you need to do that on your own now, adding
$reflection = new \ReflectionClass($GLOBALS['TSFE']->fe_user);
$setSessionCookieMethod = $reflection->getMethod('setSessionCookie');
$setSessionCookieMethod->setAccessible(TRUE);
$setSessionCookieMethod->invoke($GLOBALS['TSFE']->fe_user);
after calling the createUserSession().

I finally made it, by combining lots of snippets. Thats how it worked out for me:
$loginData = array(
'uname' => $loginData['user'],
'uident' => $loginData['passw'],
'status' => 'login'
);
$GLOBALS['TSFE']->fe_user->checkPid = 0;
$info = $GLOBALS['TSFE']->fe_user->getAuthInfoArray();
$user = $GLOBALS['TSFE']->fe_user->fetchUserRecord( $info['db_user'], $loginData['uname'] );
if ( $GLOBALS['TSFE']->fe_user->compareUident($user,$loginData) )
{
$GLOBALS["TSFE"]->fe_user->user = $GLOBALS["TSFE"]->fe_user->fetchUserSession();
$GLOBALS['TSFE']->loginUser = 1;
$GLOBALS['TSFE']->fe_user->fetchGroupData();
$GLOBALS['TSFE']->fe_user->start();
$GLOBALS["TSFE"]->fe_user->createUserSession($user);
$GLOBALS["TSFE"]->fe_user->loginSessionStarted = TRUE;
}

Related

Typo3: How to upload a file and create a file reference?

i'll try to upload a file (or later multiple files) in FE. This works, like my current code. But how can i get a file reference of this file now?
/**
*
* #var array $fileData
* #var integer $feUserId
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference
*/
private function uploadFile($fileData, $feUserId) {
$storageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\StorageRepository');
$storage = $storageRepository->findByUid(1); # Fileadmin = 1
$saveFolder = $storage->getFolder($this->settings['uploadFolder']);
// Datei speichern
$fileObject = $storage->addFile($fileData['tmp_name'], $saveFolder, $feUserId.'_'.$fileData['name']);
// Dateiobjekt
$repositoryFileObject = $storage->getFile($fileObject->getIdentifier());
die(\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($repositoryFileObject));
#$newFileReference = $this->objectManager->get('TYPO3\CMS\Extbase\Domain\Model\FileReference');
#$newFileReference->setOriginalResource($repositoryFileObject);
return $newFileReference;
}
There should be something like »setFileReference« by now, but I can not find the like in the API http://typo3.org/api/typo3cms/class_t_y_p_o3_1_1_c_m_s_1_1_core_1_1_resource_1_1_file_reference.html
Well, you may wanna use the following script as temporary solution, which uses the datamap process to create file references.
$sys_file_uid = $file->getUid();
$tt_content_uid = 42;
$tt_content_pid = 1337;
// Do not directly insert a record into sys_file_reference, as this bypasses all sanity checks and automatic updates done!
$data = array();
$data['sys_file_reference']['NEW' . $sys_file_uid] = array(
'uid_local' => $sys_file_uid,
'table_local' => 'sys_file',
'uid_foreign' => $tt_content_uid,
'tablenames' => 'tt_content',
'fieldname' => 'image',
'pid' => $tt_content_pid,
);
$data['tt_content'][$tt_content_uid] = array('image' => 'NEW' . $sys_file_uid);
$tce = t3lib_div::makeInstance('t3lib_TCEmain'); // create TCE instance
$tce->start($data, array());
$tce->process_datamap();
if ($tce->errorLog) {
// Error - Reference not created
// t3lib_utility_Debug::viewArray($tce->errorLog);
}
else {
// Success - Reference created
}
after hitting google for a while i figured out a article that sounded quite well to me.. gonna examine it tomorrow:
http://insight.helhum.io/post/85015526410/file-upload-using-extbase-and-fal-in-typo3-6-2
(just in case somebody else needs this before i could test it)

TYPO3 6.1 - how can I login a fe_user via code?

I am using TYPO3 6.1 and try to login a FE user via Code (included via PHP and USER_INT).
This code does not work for me. :( Any ideas why?
// try to login the user now
$loginData = array(
'uname' => trim($postData['username']), //usernmae
'uident' => trim($postData['password']), //password
'status' => 'login'
);
// $GLOBALS['TSFE']->fe_user-checkPid=0; //do not use a particular pid
$GLOBALS['TSFE']->fe_user->checkPid = $this->feUserPid; // ''; //do not use a particular pid
$info = $GLOBALS['TSFE']->fe_user->getAuthInfoArray();
//
$user = $GLOBALS['TSFE']->fe_user->fetchUserRecord(
$info['db_user'], $loginData['uname']
);
$ok = $GLOBALS['TSFE']->fe_user->compareUident($user, $loginData);
//
if($ok)
{
// login successfull
$GLOBALS['TSFE']->fe_user->createUserSession($user);
//
$content = '<h3 class="green">LOGIN OK!</h3>';
$content .= '<p>Sie sind eingeloggt als ' . $feUsername . ' und wurden nun weitergeleitet...</p>';
}
else
{
// login failed
$content = '<h3 class="red">LOGIN FAILED!</h3>';
}
Thanks for any hint!
Starting with TYPO3 4.7, you must use $loginData['uident_text'] instead of $loginData['uident'] for the password.
If the problem persists, please give more information what exactly is going wrong, what your log says etc.
Does compareUident() return TRUE for you?
I, fx have a case, where I automatically log in user that has just created themselves. And compareUident() didn't work for me for some reason, but as I know this same website visitor just created the user, I skip that function and continue on initiating all the session variables. The following is a working code on TYPO3 6.1:
$loginData = array(
'uname' => $postdata['username'],
'uident' => $postdata['password'],
'status' => 'login',
);
$GLOBALS['TSFE']->fe_user->checkPid = 0;
$info = $GLOBALS['TSFE']->fe_user->getAuthInfoArray();
$user = $GLOBALS['TSFE']->fe_user->fetchUserRecord($info['db_user'], $loginData['uname']);
//if($GLOBALS['TSFE']->fe_user->compareUident($user, $loginData)) {
$GLOBALS['TSFE']->fe_user->user = $GLOBALS['TSFE']->fe_user->fetchUserSession();
$GLOBALS['TSFE']->loginUser = 1;
$GLOBALS['TSFE']->fe_user->fetchGroupData();
$GLOBALS['TSFE']->fe_user->start();
$GLOBALS['TSFE']->fe_user->createUserSession($user);
$GLOBALS['TSFE']->fe_user->loginSessionStarted = TRUE;
//}
Inspired by:
https://stackoverflow.com/a/7738383/445364
https://typo3.org/extensions/repository/view/dix_easylogin

Zend Framework Router Hostname and Multi-Language support

Last two days I was fighting with Zend Framework Router and still didn't find solution.
Existing project has 2 different modules which work with the same domain e.g. www.domain1.com:
default - Contains public information, can be accessed via www.domain1.com
admin - Administrator interface, can be accessed via www.domain1.com/admin
Project is multi-langual and to keep language code it is transmitted as first parameter of every URL, e.g. www.domain1.com/en/ www.domain1.com/en/admin
Part of code which takes care is next plugin:
class Foo_Plugin_Language extends Zend_Controller_Plugin_Abstract
{
const LANGUAGE_KEY = 'lang';
public function routeStartup(Zend_Controller_Request_Abstract $request)
{
$languagesRegexp = implode('|', array_map('preg_quote', $this->_bootstrap->getLanguages()));
$routeLang = new Zend_Controller_Router_Route(
':' . self::LANGUAGE_KEY,
array(self::LANGUAGE_KEY => $this->_bootstrap->getLanguage()->toString()),
array(self::LANGUAGE_KEY => $languagesRegexp)
);
$router = $this->getFrontController()->getRouter();
$router->addDefaultRoutes();
$chainSeparator = '/';
foreach ($router->getRoutes() as $name => $route) {
$chain = new Zend_Controller_Router_Route_Chain();
$chain
->chain($routeLang, $chainSeparator)
->chain($route, $chainSeparator);
$new_name = $this->_formatLanguageRoute($name);
$router->addRoute($new_name, $chain);
}
protected function _formatLanguageRoute($name)
{
$suffix = '_' . self::LANGUAGE_KEY;
if (substr($name, -strlen($suffix)) == $suffix) return $name;
return $name . '_' . self::LANGUAGE_KEY;
}
public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
$lang = $request->getParam(self::LANGUAGE_KEY, null);
$this->_bootstrap->setLanguage($lang);
$actual_lang = $this->_bootstrap->getLanguage()->toString();
$router = $this->getFrontController()->getRouter();
$router->setGlobalParam(self::LANGUAGE_KEY, $lang);
// Do not redirect image resize requests OR get js, css files
if (preg_match('/.*\.(jpg|jpeg|gif|png|bmp|js|css)$/i', $request->getPathInfo())) {
return true;
}
// redirect to appropriate language
if ($lang != $actual_lang) {
$redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
$params = array(self::LANGUAGE_KEY => $actual_lang);
$route = $this->_formatLanguageRoute($router->getCurrentRouteName());
return $redirector->gotoRouteAndExit($params, $route, false);
}
}
}
One of the first question is what do you think about such way to provide multi-lang support. What I've noticed is that all this chains dramatically decrease operation speed of the server, response time from the server is about 4 seconds...
Main question is: Currently I have to implement such feature: I have domain www.domain2.com that should work just with single module e.g. "foobar"... and it should be available via second url... or, of course, it should work like www.domain1.com/en/foobar by default...
To provide this functionality in Bootstrap class I'be implemented such part of code
// Instantiate default module route
$routeDefault = new Zend_Controller_Router_Route_Module(
array(),
$front->getDispatcher(),
$front->getRequest()
);
$foobarHostname = new Zend_Controller_Router_Route_Hostname(
'www.domain2.com',
array(
'module' => 'foobar'
)
);
$router->addRoute("foobarHostname", $foobarHostname->chain($routeDefault));
And that is not working and as I've found routeDefault always rewrite found correct model name "foobar" with value "default"
Then I've implemented default router like this:
new Zend_Controller_Router_Route(
':controller/:action/*',
array(
'controller' => 'index',
'action' => 'index'
);
);
But that still didn't work, and started work without language only when I comment "routeStartup" method in Foo_Plugin_Language BUT I need language support, I've played a lot with all possible combinations of code and in the end made this to provide language support by default:
class Project_Controller_Router_Route extends Zend_Controller_Router_Route_Module
{
/**
* #param string $path
* #param bool $partial
* #return array
*/
public function match($path, $partial = false)
{
$result = array();
$languageRegexp = '%^\/([a-z]{2})(/.*)%i';
if (preg_match($languageRegexp, $path, $matches)) {
$result['lang'] = $matches[1];
$path = $matches[2];
}
$parentMatch = parent::match($path);
if (is_array($parentMatch)) {
$result = array_merge($result, $parentMatch);
}
return $result;
}
}
So language parameter was carefully extracted from path and regular processed left part as usual...
But when I did next code I was not able to get access to the foobar module via www.domain2.com url, because of module name in request was always "default"
$front = Zend_Controller_Front::getInstance();
/** #var Zend_Controller_Router_Rewrite $router */
$router = $front->getRouter();
$dispatcher = $front->getDispatcher();
$request = $front->getRequest();
$routerDefault = new Project_Controller_Router_Route(array(), $dispatcher, $request);
$router->removeDefaultRoutes();
$router->addRoute('default', $routerDefault);
$foobarHostname = new Zend_Controller_Router_Route_Hostname(
'www.domain2.com',
array(
'module' => 'foobar'
)
);
$router->addRoute("foobar", $foobarHostname->chain($routerDefault));
Instead of summary:
Problem is that I should implement feature that will provide access for the secondary domain to the specific module of ZendFramework, and I should save multi-language support. And I cannot find a way, how to manage all of this...
Secondary question is about performance of chain router, it makes site work very-very slow...
The way I have solved problem with multilanguage page is in this thread:
Working with multilanguage routers in Zend (last post).
Ofcourse my sollution need some caching to do, but I think it will solve your problem.
Cheers.

silverstripe dataobject searchable

I´m trying to have certain DataObjects (News) displayed in the default SearchResult Page. So the result should display normal Pages and News.
Is there an easy way to accomplish that in Silverstripe 3?
Or is it recommended to code it completely custom - I mean a custom controller/action which handles the search request and creates a result list, which I display then in a custom template?
I found this, but obviously search is disabled right now:
https://github.com/arambalakjian/DataObjects-as-Pages
Thx and regards,
Florian
I usually but together a custom search function after enabling FulltextSearchable. So in _config.php I would have
FulltextSearchable::enable();
Object::add_extension('NewsStory', "FulltextSearchable('Name,Content')");
replacing Name and Content with whatever DBField you want to be searchable. And each searchable DataObject have this in their class to enable search indexes (pretty sure this needs to be added and run dev/build before enabling the extension, and only works on MySQL DB).
static $create_table_options = array(
'MySQLDatabase' => 'ENGINE=MyISAM'
);
then in my PageController I have my custom searchForm and results functions.
Here is the search function that returns the search form, called with $search in the template:
public function search()
{
if($this->request && $this->request->requestVar('Search')) {
$searchText = $this->request->requestVar('Search');
}else{
$searchText = 'Search';
}
$f = new TextField('Search', false, $searchText);
$fields = new FieldList(
$f
);
$actions = new FieldList(
new FormAction('results', 'Go')
);
$form = new Form(
$this,
'search',
$fields,
$actions
);
//$form->disableSecurityToken();
$form->setFormMethod('GET');
$form->setTemplate('SearchForm');
return $form;
}
and here the custom results function to handle the queries...
function results($data, $form, $request)
{
$keyword = trim($request->requestVar('Search'));
$keyword = Convert::raw2sql($keyword);
$keywordHTML = htmlentities($keyword, ENT_NOQUOTES, 'UTF-8');
$pages = new ArrayList();
$news = new ArrayList();
$mode = ' IN BOOLEAN MODE';
//$mode = ' WITH QUERY EXPANSION';
//$mode = '';
$siteTreeClasses = array('Page');
$siteTreeMatch = "MATCH( Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords ) AGAINST ('$keyword'$mode)
+ MATCH( Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords ) AGAINST ('$keywordHTML'$mode)";
$newsItemMatch = "MATCH( Name, Content ) AGAINST ('$keyword'$mode)
+ MATCH( Name, Content ) AGAINST ('$keywordHTML'$mode)";
//Standard pages
foreach ( $siteTreeClasses as $c )
{
$query = DataList::create($c)
->where($siteTreeMatch);
$query = $query->dataQuery()->query();
$query->addSelect(array('Relevance' => $siteTreeMatch));
$records = DB::query($query->sql());
$objects = array();
foreach( $records as $record )
{
if ( in_array($record['ClassName'], $siteTreeClasses) )
$objects[] = new $record['ClassName']($record);
}
$pages->merge($objects);
}
//news
$query = DataList::create('NewsStory')->where($newsItemMatch);
$query = $query->dataQuery()->query();
$query->addSelect(array('Relevance' => $newsItemMatch));
$records = DB::query($query->sql());
$objects = array();
foreach( $records as $record ) $objects[] = new $record['ClassName']($record);
$news->merge($objects);
//sorting results
$pages->sort(array(
'Relevance' => 'DESC',
'Title' => 'ASC'
));
$news->sort(array(
'Relevance' => 'DESC',
'Date' => 'DESC'
));
//output
$data = array(
'Pages' => $pages,
'News' => $news,
'Query' => $keyword
);
return $this->customise($data)->renderWith(array('Search','Page'));
}
I add all the Page classes I want to be searched and that extend SiteTree in the $siteTreeClasses array, and the News parts can be pretty much copied for any other DataObjectI need searchable.
I am not saying this is the best solution and this can definitely be improved on, but it works for me and this might be a good stating point.
I have adapted #colymba's solution into a silverstripe module: https://github.com/burnbright/silverstripe-pagesearch
It allows setting the pagetype in the url.
You'll need to substantially overwrite SearchForm->getResults().
It uses Database->searchEngine(), but those are tailored towards SiteTree and Page classes.
The "proper" solution is to feed the data into a search engine like Solr or Sphinx.
We have the SS3-compatible "fulltextsearch" module for this purpose:
https://github.com/silverstripe-labs/silverstripe-fulltextsearch
It's going to take some upfront setup, and is only feasible if you can either host Solr yourself, or are prepared to pay for a SaaS provider. Once you've got it running though, the possibilities are endless, its a great tool!

is it different 'default ' and 'Default' in zend default session namespace?

I am using sessions in zend framework.
the question is i need to know is there a difference between
new Zend_Session_Namespace("default");
and
new Zend_Session_Namespace("Default");
in my application, I have used both, it seems the code is not working correctly,
if there is a difference, what is the correct one to use.
here is my code
<?php
class Admin_DashboardController extends Zend_Controller_Action
{
function init()
{
//
}
/**
* Add hotelId to default session
* redirect to admin/hotels if hotelId is not avialble
*/
public function indexAction()
{
$params = $this->getRequest()->getParams();
$hotelid = NULL;
$config_session = new Zend_Session_Namespace("default");
$config_session->hotelid = $params['id'];
if(isset($params['id']) && !empty($params['id'])){
}else{
//redirect user to select hotels page
$redirector = new Zend_Controller_Action_Helper_Redirector();
$url = array(
'action' => 'admin/hotels/index'
);
$redirector->gotoRouteAndExit($url);
}
}
}
All Zend_Session_Namespace does internally is create a named array inside the $_SESSION superglobal. As array keys in PHP are case sensitive, "Default" and "default" will be treated as separate namespaces.
You can use whichever one you want, just be consistent if you expect to use the same data.