Karl_T

SessionHandlerDBRedis

Recommended Posts

Greetings. I am here to share my first module. I make this module because I cannot find one to suit my need. I like SessionHandlerDB but I do not want to use mysql database to store session for performance. So, Redis seems to be the best choice. I have tried to use netcarver's SessionHandlerRedis but it lacks something I need, those are the active session checking and the easy module configuration while I do borrow some code from it (thanks to netcarver). So I take this chance to merge them together to form a new module. I am new to use github and I don't know if it is appropriate to publish another similar project, or fork from them. 

You may grab this from Github: SessionHandlerDBRedis

I hope this could give somebody a help.

 

Updated to v0.4

changelog: 

v0.3 - added ability to get forwarded IP instead of normal remote IP. 

v0.4 - added session lock

  • Like 6

Share this post


Link to post
Share on other sites

Thanks for posting Karl.

I think it would be best to fork the project and commit your changes. This way there will be only one Redis session handler database but with two developers. @netcarver is a really nice guy, so I think you guys can work this out :)

Share this post


Link to post
Share on other sites

@arjen Thanks for your suggestion. Hopefully my publish does not cause much issue here. Sorry if I have violated something. I wondered if it is appropriate to fork a project with 90% code changed or instead fork to SessionHandlerDB with more similarity. I will try to fork SessionHandlerRedis later. Hope that netcarver is still interested in this module. ^_^

  • Like 1

Share this post


Link to post
Share on other sites

No issues here :)

But since the amount of modules is (luckily) pretty small in ProcessWire I guess it would be wise to join forces instead of creating several modules with overlap. If 90% of the code is changed, I'm not really sure if a fork is appropriate, but it might be. I guess we have to wait until @netcarver joins the discussion.

  • Like 2

Share this post


Link to post
Share on other sites
8 hours ago, netcarver said:

My module was very experimental. Very happy for it to have a successor ^-^

Thanks netcarver, I will try to make a pr on it. ^_^

I do think using Redis as the session handler has many advantages such as reduce work load for mysql(if you are using it to store sessions) and performance boot(fastest way at the moment?). I experienced a faster page load after using it, no thorough experiment anyway lol. So, I am surprised that no much dev is interested in this(no reply in the SessionHandlerRedis post last two years!?). I wonder if I missed some drawbacks or this tech is already outdated.:undecided:

  • Like 1

Share this post


Link to post
Share on other sites

Redis is often not available in shared hosting environments and we have lots of users, where this kind of tech / performance gain doesn't make a real difference. It's certainly a really nice to have module, but it always depends on the use-case.

Share this post


Link to post
Share on other sites
7 minutes ago, LostKobrakai said:

Redis is often not available in shared hosting environments and we have lots of users, where this kind of tech / performance gain doesn't make a real difference. It's certainly a really nice to have module, but it always depends on the use-case.

Thanks for your points. It indeed makes less difference for low traffic site where shared hosting is the common choice. I always use cheap VPS plan in DigitalOcean or Linode to gain the largest control for less money so I forgot about shared hosting for long.:P.

  • Like 3

Share this post


Link to post
Share on other sites

@Karl_T It's great of what you have done. I can feel your excitement about using Redis. 

Haven't had the chance to dig deeper into your code but of what I saw, you are not using session lock. Forgive me if I am wrong.

I was using phpredis (the php extension) as a global session handler replacement in php.ini , but it lacks support for session lock. I was having trouble because of this and I wrote my own solution attached here. I just prepend it.

When using session with files - the files system have lock on write. When using SessionDB - the database has a row or table lock depending on the table engine. Memcache have lock implemented and it's suitable for replacement in php.ini. Of what I saw in the phpredis code, there is no lock and have to be implemented externally. 

  • My issue because of this here.
  • This guy here explained more about the session lock and session fixation.
  • Here is the related issue/feature request at GitHub/phpredis. 
  • Magento's dev opinion here .

Also many recommend igbinary as a php serializer of the session data before to be stored in Redis. Of course, it is not installed by default on a shared hosting. Just as a reminder, there were many ways to decrease the memory usage. Some prefer using "strings" instead of "hashes" as a datatype if not using millions of sessions and shortened keys for memory optimization. 

Also, just saw a cron job deleting the expired keys. Redis have native key removal for the expired keys and there is no reason for garbage collector or a cron job to delete the old keys. Sorry if I am wrong about your code. I am keen to test it in the morning. 

Hope this helps. Peace!

session_handler_redis.php

test_serializers.php

  • Like 5

Share this post


Link to post
Share on other sites

@seddass Thanks for your great lesson. I have really learnt a lot! I lack the knowledge and sense to find out the potential threats. And, I should have made it clear about the existence of any open issues affecting the usage before using a library. I will dig deeper and try to resolve the issue. Your attached code would be a great help for this.:lol:

11 hours ago, seddass said:

Some prefer using "strings" instead of "hashes" as a datatype if not using millions of sessions and shortened keys for memory optimization. 

I was using string as datatype originally. Hash is used because it is the only way I found that can let me to do calculation like finding recent active session using timestamp by ZADD.

11 hours ago, seddass said:

Also, just saw a cron job deleting the expired keys. Redis have native key removal for the expired keys and there is no reason for garbage collector or a cron job to delete the old keys.

Thanks for poitning this out. I overlooked this one.

 

  • Like 3

Share this post


Link to post
Share on other sites

@Karl_T Glad to save your time. If we join forces we can create a great Redis Sess Handler for PW. Hope @netcarver will help too. 

Quote

Hash is used because it is the only way I found that can let me to do calculation like finding recent active session using timestamp by ZADD.

If it's just occasionally, I would try with strings using TTL (or PTTL) to get their expire time and to sort all the keys in php array. BTW never played with TTL till now. It has to be tested with a lot of sessions. 

The next feature will be to provide connection support for local socket and to multiple Redis servers with priority and auth.

My experience with Redis started when I find out session_id() took 12 seconds because of many sess files. 

  • Like 2

Share this post


Link to post
Share on other sites

@seddass, @Karl_T

I'm a little out of the loop regarding Redis, at the moment, but I like the idea of collaborating on this. As I have the original repo on github, how about I add you both as collaborators, and we can make this a more community oriented effort?

  • Like 7

Share this post


Link to post
Share on other sites

Hmm in the meanwhile I was able to download it, but I'm unsure how it works. 

PS: Karl_T, can't you implement the locks in your module with this example?

Share this post


Link to post
Share on other sites

Hi @Hosted Power. Currently session lock is missing in the module. I am currently busy on my own project. I will make a pull request to netcarver's repo with the session lock implemented some time later, maybe a month later as I want to use this on my project too. I will post it here after that.

Share this post


Link to post
Share on other sites
3 minutes ago, Hosted Power said:

Hmm in the meanwhile I was able to download it, but I'm unsure how it works. 

 

@Hosted Power The 'session_handler_redis.php' will change your session handler. By changing the default session handler you may store your session data in files, in database, redis, memcache, etc. You can use it in any PHP project, with any CMS or framework. Include it at the beginning of your index.php or header.php, before your session_start(); Of course, you may have to tweak the port and/or socket path. Make sure you have "php_redis" extension installed for greater performance. You may need to edit the file if you don't have igbinary_serializer extension installed. 

I am busy too and hopefully, one rainy weekend I will focus on converting it as PW module with Karl_T.  Meanwhile, you have a working solution and despite it's not as a module yet, it is reliable and you can use it with ProcessWire. Enjoy!

  • Like 1

Share this post


Link to post
Share on other sites

Hi All,

Sorry for my own late reply, but you guys here are really fast and to the point, wow! I bet this is one of the reasons our customers with ProcessWire like it so much :)

In any case we're looking forward to the redis module improvements! 

Share this post


Link to post
Share on other sites

Session lock is added finally. ;) I also make a pull request to netcarver's SessionHandlerRedis. Once it is done I will close this one and move to that one probably.

FYI: phpredis is undergoing a pull request to add their session lock.

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By dragan
      If I have two PW sites that sit in separate folders, I can't be logged-in in both sites.
      e.g.
      site.com/project-a/pw-admin-slug/
      site.com/project-b/pw-admin-slug/
      If I login to project-a, then also login to project-b, get back to the first site, I have to login again.
      Is the cookie / session mechanism storing my domain? If it does, and it's meant to be some sort of security enhancement, it should not check my domain, but root-URL of the PW-installation. (strangely, this doesn't happen on localhost)
      Is it possible to prevent that behavior? Often I have two sites open (e.g. check to see if I have the same CKEditor setup and quickly copy and paste it, or copy a user-role)
    • By Jarden Black
      Hi everyone,
      [edit: do not loose your time reading this post, I solved it by disabling cache in the Pages2Pdf module... sorry 😓]
       
      I do not know if I should post on the Pages2Pdf thread or here. Mods, feel free to move the post.
       
      Since three days I am scratching my head  to understand a weird thing happening with $session and $config->debug used in conjunction with Pages2Pdf module. For information, I tested it on a fresh install of ProcessWire 3.0.96 with PHP-7.0.28 and Pages2Pdf-1.1.7 (domain: http://session.sites.sek/). I will try to explain what is going on.
       
      What I am trying to achieve :
      In a template, I need to set some sessions variables which are then echo'd in the PDF document.
      (on the test installation, the basic-page template (page /about/?pages2pdf) serve the PDF, the home and sitemap template set the session variable.)
       
      The problem :
      From the template sitemap, I set a variable: $session->setFor('pdf', 'myvar', 'Session set from Sitemap template');
      From the template home, I set a variable: $session->setFor('pdf', 'myvar', 'Session set from Home template');
      Then in the PDF default template, I echo the session variable: <p>Session: <?= $session->getFor('pdf', 'myvar'); ?></p>
       
      Now I turn ON debug mode ($config->debug = true) :
      Then I navigate to  "http://session.sites.sek/home/" and the session variable "myvar" is set to "Session set from Home template". Then I navigate to  "http://session.sites.sek/sitemap/" and the session variable "myvar" is set to "Session set from Sitemap template". Now I want my PDF document, so I navigate to "http://session.sites.sek/about/?pages2pdf=1" and I get my PDF document with the right session var : "Session set from Sitemap template" For the moment, nothing special happen. Everything work great. We are in debug mode.
       
      Now I turn OFF debug mode ($config->debug = false) :
      Then I navigate to  "http://session.sites.sek/home/" and the session variable "myvar" is set to "Session set from Home template". Then I navigate to  "http://session.sites.sek/sitemap/" and the session variable "myvar" is set to "Session set from Sitemap template". Then I navigate back to "http://session.sites.sek/home/" and the session variable "myvar" is set back to "Session set from Home template". Now I want my PDF document - as expected, the "myvar" should be set to "Session set from Home template" - so I navigate to "http://session.sites.sek/about/?pages2pdf=1" and here the problem happen. Instead of echoing  "Session set from Home template" in the PDF document, the phrase "Session set from sitemap" is echo'd (the last value recorded before switching from debug ON).  
       
      I made two small screencasts to show the issue :
      DEBUG ON (Everything is OK)
       
      DEBUG OFF
       
       
      I am missing something ? EDIT: YES, you are dumb!
       
       
    • By flydev
      Hi everyone,
      [edit: do not loose your time reading this post, I solved it by disabling cache in the Pages2Pdf module... sorry 😓]
       
      I do not know if I should post on the Pages2Pdf thread or here. Mods, feel free to move the post.
       
      Since three days I am scratching my head to understand a weird thing happening with $session and $config->debug used in conjunction with Pages2Pdf module. For information, I tested it on a fresh install of ProcessWire 3.0.96 with PHP-7.0.28 and Pages2Pdf-1.1.7 (domain: http://session.sites.sek/). I will try to explain what is going on.
       
      What I am trying to achieve :
      In a template, I need to set some sessions variables which are then echo'd in the PDF document.
      (on the test installation, the basic-page template (page /about/?pages2pdf) serve the PDF, the home and sitemap template set the session variable.)
       
      The problem :
      From the template sitemap, I set a variable: $session->setFor('pdf', 'myvar', 'Session set from Sitemap template');
      From the template home, I set a variable: $session->setFor('pdf', 'myvar', 'Session set from Home template');
      Then in the PDF default template, I echo the session variable: <p>Session: <?= $session->getFor('pdf', 'myvar'); ?></p>
       
      Now I turn ON debug mode ($config->debug = true) :
      Then I navigate to  "http://session.sites.sek/home/" and the session variable "myvar" is set to "Session set from Home template". Then I navigate to  "http://session.sites.sek/sitemap/" and the session variable "myvar" is set to "Session set from Sitemap template". Now I want my PDF document, so I navigate to "http://session.sites.sek/about/?pages2pdf=1" and I get my PDF document with the right session var : "Session set from Sitemap template" For the moment, nothing special happen. Everything work great. We are in debug mode.
       
      Now I turn OFF debug mode ($config->debug = false) :
      Then I navigate to  "http://session.sites.sek/home/" and the session variable "myvar" is set to "Session set from Home template". Then I navigate to  "http://session.sites.sek/sitemap/" and the session variable "myvar" is set to "Session set from Sitemap template". Then I navigate back to "http://session.sites.sek/home/" and the session variable "myvar" is set back to "Session set from Home template". Now I want my PDF document - as expected, the "myvar" should be set to "Session set from Home template" - so I navigate to "http://session.sites.sek/about/?pages2pdf=1" and here the problem happen. Instead of echoing  "Session set from Home template" in the PDF document, the phrase "Session set from sitemap" is echo'd (the last value recorded before switching from debug ON).  
       
      I made two small screencasts to show the issue :
      DEBUG ON (Everything is OK)
       
      DEBUG OFF
       
       
      I am missing something ? EDIT: YES, you are dumb!
      Why it is working with debug mode ON and not vice-versa ?
      Is there someone who already spotted this strange behavior ?
      Is there a PHP settings which should be modified ?
       
      ====================================================
      Edit:
      I needed to post just to figure myself that Pages2Pdf cache the document when $config->debug is false.
      😬😬😬
       
    • By psy
      I've used this code on another site (same web host) and it all works fine.
      When a visitor lands on a page and they're not logged, the page name/path/url/httpUrl (tried them all) is saved to a session var. Code in _init.php is:
      $loginPage = pages( 1085); if(!$user->isLoggedin() && $page->id != $loginPage->id) { // not for login page $session->set('returnPage', $page->path); // results in /http404/ stored in session var // $session->set('returnPage', '/rants/'); // works fine $session->redirect($loginPage->url); } Code in the LoginRegister template:
      if($user->isLoggedin() && !$input->get('profile') && !$input->get('logout')) { // login and go back to the previous page or go to the home page $goToUrl = $session->get('returnPage') ? $session->get('returnPage') : '/'; var_dump($session->getAll()); die; $session->redirect($goToUrl); } else { // let the LoginRegister module have control $content = $modules->get('LoginRegister')->execute(); } This var_dump shows that the returnPage session variable is stored as the path to the 404 error page
      ["returnPage"]=> string(9) "/http404/" I also tried $page->id with the resulting var (int) 27 which is the 404 Page id.
      Also tried namespace in the session var...
      It all worked fine when I manually typed in a valid page path, ie only weirdness when I used the $page var.
      Any help to explain why this is happening and how to fix greatly appreciated.
      tia
    • By eutervogel
      Hi,
      On my website the user is able to choose between to styles of a gallery. A gridview and a stripe view.
      I want to store the choice during the whole session. 
      So if the user chooses a style I do it like so:
      $query = $_GET['view'];     if($query){         $session->set('view', $query);     } So that's working pretty fine, but after a random number of menuclicks or reloads its gone. Sometimes it is stored for 10 -15 pageloads and sometimes it's gone after 2 loads,
      Lifetime is set to 3600 in php.ini
      session.gc_maxlifetime = 3600  
      This is how I look if it exists:   
       if($session->view == 'grid'){         include('album-grid-title.php');         $session->set('view', $query);     }     elseif($session->view == 'stripes'){         include('album-stripes.php');         $session->set('view', $query);     }     else{         include('album-stripes.php');            }  
      Can anyone point me in the right direction and tell me what I'm doing wrong or why $session gets lost?
       
      Thanks in advance