Disabling the Codeigniter’s cache for logged in users - php

I'm using codeigniter cache on my personal CMS. The problem is, i don't want to show cached pages if the user it's logged on administration.
Saw this tutorial on google:
http://www.badpenguin.org/codeigniter-cache-disable
class MY_Output extends CI_Output {
function _display_cache(&$CFG, &$URI)
{
/* Simple Test for Ip Address */
if ($_SERVER['REMOTE_ADDR'] == NOCACHE_IP )
{
return FALSE;
}
/* Simple Test for a cookie value */
if ( (isset($_COOKIE['nocache'])) && ( $_COOKIE['nocache'] > 0 ) )
{
return FALSE;
}
/* Call the parent function */
return parent::_display_cache($CFG,$URI);
}
}
The problem it's that the session it's on database (ci_sessions), and i can't access it inside MY_Output.
using:
$CI =& get_instance();
$CI->session->userdata('userID')
give me:
Class 'CI_Controller' not found in
As output runs before controller, and session Needs CIcontroller, the only Thing i can think of its disable session storage on database and the encription, and i don't want do that rs.
Someone can give me some light on this? i still can't find the solution to this!
Thanks!

Try this:
#$SESS = & load_class('Session', 'libraries/Session');
The # is there to prevent it from whining about "session already started". Do note: this is for CI3. The code for the original Output class states (lines 407-409):
// Note: We use load_class() because we can't use $CI =& get_instance()
// since this function is sometimes called by the caching mechanism,
// which happens before the CI super object is available.

Related

CakePHP 3: Session was already started with Hybridauth 3

I have a LoginController where I do my usual login operation with combination of an email address and a password associated with the account.
I have separated my Hybridauth related code into a separate controller named OauthController where I have all my Hybridauth magic and where my callback / endpoint resides.
In the OauthController I check if user's email from the specified provider is already registered, and in either case I try to login that user with $this->Auth->setUser(object).
Whenever, or whatever from the $this->Auth is called, I get a response stating:
Session was already started
I have browser through CakePHP 3 code and found the following statement in:
vendor/cakephp/cakephp/src/Network/Session.php (335)
public function start()
{
if ($this->_started) {
return true;
}
if ($this->_isCLI) {
$_SESSION = [];
$this->id('cli');
return $this->_started = true;
}
if (session_status() === \PHP_SESSION_ACTIVE) {
throw new RuntimeException('Session was already started');
}
...
And that's the point in code where that message is thrown at me.
Now, as I browsed through the Hybridauth code itself, I have found following in:
vendor/hybridauth/hybridauth/src/Storage/Session.php (46)
public function __construct()
{
if (session_id()) {
return;
}
if (headers_sent()) {
throw new RuntimeException('HTTP headers already sent to browser and Hybridauth won\'t be able to start/resume PHP session. To resolve this, session_start() must be called before outputing any data.');
}
if (! session_start()) {
throw new RuntimeException('PHP session failed to start.');
}
}
And both of them call session_start, one before the other, although CakePHP's part is blocking me.
I have tried removing !session_start() check from Hybridauth, but then Hybridauth doesn't know where to read out it's thingies it needs to read.
So, as a demonstrator, I am trying to achieve this in OauthController:
<?php
namespace App\Controller;
use Hybridauth\Hybridauth;
class OauthController extends AppController
{
public function callback($provider)
{
try {
$hybridauth = new Hybridauth($config);
// additional mystery code
$hybridauth->authenticate();
if($everything_okay) {
$this->Auth->setUser($userObject); // and this is the point of failure
return $this->redirect('/account'); // and this never happends... :(
}
}
}
}
Any help, ideas, insights on how to deal with this are all welcome!
Simply start the CakePHP session manually before using the Hybridauth library, so that it bails out at the session_id() check and picks up the existing session.
For example in your controller:
$this->getRequest()->getSession()->start();
// in CakePHP versions before 3.6/3.5
// $this->request->session()->start();

PHPUnit Selenium 2 extension setting cookies

I'm trying to set cookies before test but for some reason they are not set.
Here is my example code:
class WebTest extends PHPUnit_Extensions_Selenium2TestCase
{
protected function setUp()
{
$this->setBrowser('firefox');
$this->setBrowserUrl('http://dev.local/');
}
public function testTitle()
{
$session = $this->prepareSession();
$session->cookie()->remove('language_version');
$session->cookie()->add('language_version', 'en')->set();
$this->url('/');
$this->assertEquals('Title in English', $this->title());
}
}
Does anyone know how to do it? Any help greatly appreciated.
I have found an answer to my question in Selenium documentation:
If you are trying to preset cookies before you start interacting with a site and your homepage is large / takes a while to load an alternative is to find a smaller page on the site, typically the 404 page is small (http://example.com/some404page)
Now my tests look something like this:
$this->url('/unit_tests.php');
$this->cookie()->remove('language_version');
$this->cookie()->add('language_version', 'en')->set();
$this->url('/');
$this->assertEquals('Title in English', $this->title());
The /unit_tests.php is an empty PHP file that lets me initially set the cookie for the page.
The cookie shouldn't exist so the remove will fail. Selenium runs the browser with a new empty profile on each run of a test suite.
.

How do I run a PHPUnit Selenium test without having a new browser window run for each function?

I am trying to run a selenium test case using PHPUnit. And the first thing I do is trying the login function, this works perfect but then I want to run a function to check information on the page following the login but it opens a new browser instead of continuing in the current browser window. The reason this is a problem is because the page is setup to remove login authentication when the window is closed so if you use $this->url() to go to the page it gives the error that I need to login. This is my code right now, It starts the browser and runs the function to test the login form, then it closes the browser, open a new one and run the link check. This of course results in an error due to the authentication error because the window was closed. I could run all the tests in one function but that is really sloppy coding and I want to avoid this. Anyone know how to solve this?
<?php
class TestMyTest extends PHPUnit_Extensions_Selenium2TestCase {
public function setUp()
{
$this->setBrowser("firefox");
$this->setBrowserUrl("https://**************************");
}
public function testLoginForm()
{
$this->url("login.php");
$this->byLinkText('Forgot your password?');
$form = $this->byCssSelector('form');
$this->byName('username')->value('test');
$this->byName('password')->value('1234');
$form->submit();
}
public function testCheckForMainMenueLinks ()
{
$this->url("index.php");
$this->byLinkText('Home');
$this->byLinkText('Products');
$this->byLinkText('About us');
$this->byLinkText('Contact');
}
}
?>
To share browser sessions in Selenium2TestCase, you must set sessionStrategy => 'shared' in your initial browser setup:
public static $browsers = array(
array(
'...
'browserName' => 'iexplorer',
'sessionStrategy' => 'shared',
...
)
);
The alternative (default) is 'isolated'.
Okej so I guess you can just call the function directly from another function like so:
public function testOne
{
#code
$this->Two();
}
public function Two()
{
#code
$this->Three();
}
public function Three()
{
#code
}
and so on, this will just run the next function without a new browser, however, if it fails anywhere in any test the whole test is stoped so the feedback wont bee as good as individual tests.
make assetrions in one function because this is functional test.
i am new to phpunit and selenium too, but I successfully test all in one like this:
public function testAuth(){
$this->open('register.php&XDEBUG_SESSION_START=PHPSTORM');
$this->assertTextPresent('Register');
$this->type('name=email', "...");
$this->type('name=firstname', "...");
$this->type('name=lastname', "...");
$this->type('name=password', "...");
$this->type('name=verifyPassword', "...");
$this->click("reg-butt");
$this->waitForPageToLoad("5000");
$this->assertTextPresent('Profile');
$this->open('logout.php');
$this->assertTextPresent('text from redirect page');
$this->open('login.php');
.....
}
An elegant way to set the session shared is to use PHPUnit's setUpBeforeClass() method:
public static function setUpBeforeClass()
{
self::shareSession(true);
}
You can call PHPUnit_Extensions_SeleniumTestCase::shareSession(true) to enable browser window reuse.
In the manual it says:
From Selenium 1.1.1, an experimental feature is included allowing the user to share the session between tests. The only supported case is to share the session between all tests when a single browser is used. Call PHPUnit_Extensions_SeleniumTestCase::shareSession(true) in your bootstrap file to enable session sharing. The session will be reset in the case of not successul tests (failed or incomplete); it is up to the user to avoid interactions between tests by resetting cookies or logging out from the application under test (with a tearDown() method).

getUser() always return 0 in Codeigniter

I started to create a small application using codeigniter framework
and i have dowloaded Facebook connect from github after creating my application inside facebook, at this moment all work alright my only problem is getUser() always return 0
i have create a facebook.php inside application/config/
alse i have extracting facebook.php & base_facebook.php inside application/libraries/
this is my code
class Welcome extends CI_Controller {
private $data = array();
public function index() {
$this->data['loginUrl'] = $this->facebook->getLoginUrl();
$this->data['userId'] = $this->facebook->getUser();
$this->load->view('welcome_message', $this->data);
}
}
in autoload
i have :
$autoload['libraries'] = array('database','session','facebook');
so why getUser() return 0 and how can i fix this problem
thx
on base_facebook.php, find the makeRequest() method, and, inside the function, find this line:
$opts = self::$CURL_OPTS;
Immediately following it, add:
$opts[CURLOPT_SSL_VERIFYPEER] = false;
or read from here
It does this, sometimes. I've never worked out why, but there is a simple solution that I now always follow.
As opposed to asking for getUser, ask for api(/me) wrapped in a try catch block. If this fails, user is not logged in/token is invalid. If it works the user is logged in, and you get the user id from the resultant array.
You're probably saving a call, as you'll ask for /me anyway. Just remember the try catch for error trapping!

Preventing error pages caching when using Zend_Cache_Backend_Static

We're currently running an app that caches pages to static html files using Zend_Cache_Backend_Static. This works really well, except that our cache is getting filled with hundreds of empty files and folders when incorrect urls are requested. Is there any way to prevent a page being cached if an Exception is being thrown? I was surprised to discover that this wasn't standard behaviour.
I've done a little digging and the ZF code that actually deals with saving out the static html pages is as follows in Zend_Cache_Frontend_Capture:
public function _flush($data) {
$id = array_pop($this->_idStack);
if ($id === null) {
Zend_Cache::throwException('use of _flush() without a start()');
}
if ($this->_extension) {
$this->save(serialize(array($data, $this->_extension)), $id, $this->_tags);
} else {
$this->save($data, $id, $this->_tags);
}
return $data;
}
This function is the output_callback for ob_start. I've tried getting hold of the response object to test for status but it doesn't seem to work inside _flush.
$response = Zend_Controller_Front::getInstance()->getResponse();
if($response->getStatus() == '200') {
// do the save as normal
}
else {
// do nothing
return false;
}
My only other thought was to test the length of $data, only caching if strlen($data) > 0 seems to work but it doesn't feel robust enough.
Update:
Unfortunately by the time we hit the ErrorController the static page has already been written to the cache, so disabling the cache at that point won't work. However it is possible to remove the page based on $_SERVER['REQUEST_URI'], which is what is used as an id when the page is first written. This line can be added to the start of errorAction in the ErrorController:
$this->_helper->cache->removePage($_SERVER['REQUEST_URI'], true);
It works nicely, but I'd prefer not to write the page in the first place!
From further experimentation the problem is not down to standard Zend Framework exceptions that cause 404s (ie. Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE, Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER, Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION) but to my custom exceptions. This is now really obvious now that I think about it, as Zend_Cache_Backend_Static needs to be initialised in the init method of an action controller. Any situation where there is no route, controller or action it won't ever be initialised anyway.
I'm throwing exceptions in existing actions where a user may be querying for a non-existent article. Therefore caching has been enabled in init and the page has been written by the time we hit postDispatch in a Front Controller Plugin (still not sure why this is the case it just is) so I can't cancel at that point. One solution then is to cancel the cache at the point of throwing the exception. The standard method of managing static page caching is using the Zend_Controller_Action_Helper_Cache action helper. I've extended this to add a cancel method like so:
<?php
class Zend_Controller_Action_Helper_PageCache extends Zend_Controller_Action_Helper_Cache {
public function cancel() {
$cache = $this->getCache(Zend_Cache_Manager::PAGECACHE);
$cache->setOption('caching', false);
$cache->getBackend('disable_caching', true);
}
}
My action controller now looks like this:
<?php
class IndexController extends Zend_Controller_Action {
private $_model;
public function init() {
$this->_model = new Model();
// using extended pageCache rather than $this->_helper->cache:
$this->_helper->pageCache(array('index'), array('indexaction'));
}
public function indexAction() {
$alias = $this->_request->getParam('article');
$article = $this->_model->getArticleByAlias($alias);
if(!$article) {
// new cancel method will disable caching
$this->_helper->pageCache->cancel();
throw new Zend_Controller_Action_Exception('Invalid article alias', 404);
}
$this->view->article = $article;
}
}
You should alter your .htaccess file RewriteRules to check for filesizes with option -s
This way if an error should occur when a page is being cached (thus producing a 0 byte file) it won't permanently be stored in the cache.
If you are using the standard ErrorController to handle 404, 500, and unhandled exceptions, and you can get a reference to your cache object from there, you could disable caching from the error handler.
In your error controller (or wherever you would like to cancel caching from), try:
$cache->setOption('caching', false);
When the save() metod of Zend_Cache_Core is called by Zend_Cache_Frontend_Capture::_flush(), it will see the caching option is set to false and it will not actually save the data to the cache and return true.

Categories