session_regenerate_id() - headers already sent in unit testing Yii controller - session

I'm trying to unit-test my controller (Yii framework).
/**
* #dataProvider provider
*/
public function testActionEdit_view_login($controller){
$user = new CWebUser;
$user->id = 978;
$identity = new UserIdentity('me#test.com', '123456');
$user->login($identity);
$controller->actionEdit();
$output = ob_get_contents();
assertContains('Add/Change Profile Picture:', $output);
assertContains('bio', $output);
assertContains('specialties', $output);
assertContains('change login', $output);
assertContains('New Password', $output);
}
When I do
$user->login($identity);
in order to login, I get the following error:
session_regenerate_id(): Cannot regenerate session id - headers already sent
I've already tried buffering the output by putting this at the beginning of the class:
public static function setUpBeforeClass(){
ob_start();
}
I also put ob_clean() in setUp() and ob_end_clean() in tearDownAfterClass().
Still I get the message that headers have already been sent. There are no spaces or newlines in the file, when I comment out the specific test method, it works perfectly. The login() seems to cause the problem.
Anyone got ideas how to prevent this / maybe unit-test the controller differently?
Thanks,
MrB

Before your call to $user->login, add the following code:
$mockSession = $this->getMock('CHttpSession', array('regenerateID'));
Yii::app()->setComponent('session', $mockSession);
This overwrites the regenerateID method with a method that does nothing.
Adding ob_start() to the bootstrap also works, but there is no output from PHPUnit until everything has completed.
With this method, you can still see the progress as it is happening.
I upgraded from Yii 1.1.7 to 1.1.10 and the regenerateID method was added in 1.1.8 so I got this error today.

Got it. I had included some Yii files before the ob_start(), which seem to have printed the headers. Now I buffer that, too.

Related

Laravel flash message and redirection not working properly

I'm using laravel 5.8 and "laracasts/flash": "^3.0"
Within my application all redirections and flash messages are working well except for this very specific piece of code.
/* Controller */
public function show( Test $test) {
$test->checkPermission();
...
}
/* Model */
public function checkPermission()
{
flash()->warning('You can not have access to this.');
return redirect( route('home' ) )->send(); //Notice the send()
}
If i'm using this code with the ->send()(that I never used before) I'm well redirected to the homepage but without flash message.
If I remove the ->send(), I have got the flash message but I'm not redirected.
I also tried to remove the flash() and using redirect()->with(). Then the session is containing the message and I'm redirected. But I want to use flash() or atleast undertand why it's not working for this specific use-case.
The controller should return the redirect, not the check permission. Try to return what check permission is returning in the controller.
Try adding the web middleware on your routes. or ensure the web middleware group contains the StartSession middleware.
via https://laracasts.com/discuss/channels/laravel/auth-session-killed-after-redirect-laravel-52/replies/124991

Problems with destroy() Method in Laravel Backpack

I'm having problems overriding the destroy() method in Laravel Backpack. When I try to do more, like calling an external method using cURL to an API inside the destroy() method of my entityCRUD, it stops working (and there are no errors returned).
<?php
public function destroy($id)
{
$this->crud->hasAccessOrFail('delete');
$customer = Customer::find($id);
$array_api_user_options = AdminUserJsonRepositoryData::deleteArrayData();
$array_api_user_options['mail'] = $customer->email;
$array_api_user_options['ke'] = $customer->api_group_key;
$array_api_user_options['uid'] = $customer->api_user_id;
// Instancia o Shinobi com token e group key
$apiShinobi = New ShinobiAPIRepositoryAPI($customer->api_auth_token, $customer->group_key, $customer->user_id);
$apiShinobi->deleteAdminUser(json_encode($array_api_user_options));
return $this->crud->delete($id);
}
When I remove the line: $apiShinobi->deleteAdminUser() it works again and deletes my record. Can someone help me out, please?
If it work without that line, the problem is definitely with that line :-)
In Chrome Developer Tools, the Network tab, you should be able to see the result of your AJAX request - and the error you're getting:

Joomla bugging out with status 200 but blank screen no errors

When I set:
error_reporting(E_ALL);
ini_set('display_errors', '1');
Hundreds of warnings and strict messages but no errors, locally it works but not on site. When I make a GET request it works but same url sending a POST request doesn't work.
I think it's some plugin causing this but hard to track down when Joomla happily gives me a blank page with 200 response.
In firebug I can't see the response, it only gives me:
Reload the page to get source for: the_url
This is in the /components/com_doctrine/doctrine.php
$route=JRequest::getVar('router', 'Tournament');
$controllerName = 'doctrineController'.$route;
include_once(dirname(__FILE__) . '/controllers/'.$route.".php");
$controller = new $controllerName(JRequest::getVar('task', ''));
$controller->setEntityManager(bootstrapDoctrine());
//echo "something";die(0); will show here but not after the next line
// and only when I post values not on a get request
$controller->execute(JRequest::getVar('task', ''));
$controller->redirect();
In the controller I have:
//JoomlaDoctrineBootstrapper extends JController
class doctrineControllerTournament extends JoomlaDoctrineBootstrapper{
function __construct()
{
parent::__construct();
$this->registerTask( 'show','show' );
$this->registerTask( 'save','save' );
}
function show(){
echo "works only on get requests, not on post";
$model=$this->getModel('tournament');
$view = $this->getView('show','text');
$view->setLayout('default');
$model->em=$this->getEntityManager();
$view->data = $model->getTournamentAsJson();
$view->display();
}
Looks like a plugin messing with my post requests but don't know where to look for it. Client doesn't have a test environment set up and tried copying all 200+ thousand php files through ssh with a sql dump from the database but can't get it going locally.

symfony2 crud & http cache

I'm using Symfony2 and I have a ReaderBundle that has an Rss entity.
I'm created CRUD for this entity.
php app/console generate:doctrine:crud --entity=RSSReaderBundle:Rss --format=annotation --with-write
All was well, before I connected Cache.
$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
require_once __DIR__.'/../app/AppCache.php';
require_once __DIR__.'/../app/AppKernel.php';
Debug::enable();
$kernel = new AppKernel('dev' , true);
$kernel->loadClassCache();
$kernel = new AppCache($kernel); // THAT STRING IS MAIN PROBLEM
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
And then when i'm trying to delete some record, i take this error:
No route found for "POST /rss/delete/30": Method Not Allowed (Allow: DELETE)
405 Method Not Allowed
I created a form that clearly indicates the method:
private function createDeleteForm($id)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('rss_delete', array('id' => $id)))
->setMethod("DELETE")
->add('submit', 'submit', array('label' => 'Delete'))
->getForm()
;
}
I have not found the problem. Help please
This problem occurred since symfony2.2, see https://github.com/symfony/symfony-standard/commit/1970b831f8843a5cf551e9d88404cb62f21b90f9
You need to modify the Symfony\Component\HttpFoundation\Request::$httpMethodParameterOverride boolean manually in your app.php file:
// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
Request::enableHttpMethodParameterOverride();
There is no method="DELETE" in html forms ... at least not supported in almost all browsers - only in ajax requests.
Work around this by allowing DELETE and POST requests to the route.
we must remove the string with comment "THAT STRING IS MAIN PROBLEM". Cache is working all the same. And CRUD working right
I have the same problem that you had (with PUT and DELETE HTTP method) but I don't understand your solution.
Did you:
a) just get rid of // THAT STRING IS MAIN PROBLEM
or
b) get rid of $kernel = new AppCache($kernel); // THAT STRING IS MAIN PROBLEM
The solution b) is the same as not using cache so in my case, it's not helping as the page take a very long time to load.
#Nifr:
I thought there were method PUT and DELETE. I use them in my forms following the instructions on this link: http://symfony.com/fr/doc/current/cookbook/routing/method_parameters.html
So in fact, Symfony2 is able to tell whether a method is PUT, DELETE, POST or GET. But somehow, the cache can't...
Any help on that?
Edit:
I found a solution that doesn't involve changing anything in the app.php file.
Basically, the problem comes from the fact that the getMethod method of the request object of symfony2 doesn't know about PUT or DELETE method. The point is to change that in the AppCache.php file.
We just have to override the method invalidate of the AppCache.php file:
protected function invalidate(Request $request, $catch = false)
{
$request->setMethod($request->request->get('_method'));
return parent::invalidate($request, $catch);
}
Here, I just change the method of the request by the method posted from the form.

Symfony2 : Echo in kernel.response event breaks cookies?

I had a weird problem with one of my Services, an event listener on kernel.response.
I wanted to set some cookies (I need cookies instead of session for compatibility with Symfony1) in it, and couldn't find how..
Until finally I understood that the code I wrote works except if I debug something in it (like a var_dump of the cookies).
public function onKernelResponse(FilterResponseEvent $event)
{
if (HttpKernel::MASTER_REQUEST == $event->getRequestType()):
$request = $event->getRequest();
$response = $event->getResponse();
var_dump($request->cookies->all());
$response->headers->setCookie(new Cookie('foo', 'bar'));
endif;
}
So that wasn't working, my cookie was never in $request->cookies->all().
But if I comment the var_dump line, refresh, and uncomment it, the cookie has been set !
Is it normal ? Why ? Does printing in an event like that break the headers ?!
Inject the logger service and use it
$this->logger->debug(print_r($request->cookies->all(), true));
This is because doing the var_dump(), you "force" php to send the headers and so, when trying to set headers directly in your response, it doesn't work as they already have been populated.
Try doing the var_dump() after setting the cookie in the header.

Resources