An alternative Redis session handler for PHP featuring per-session locking and session fixation protection

Overview

RedisSessionHandler

Build Status Scrutinizer Code Quality Latest Stable Version Monthly Downloads

An alternative Redis session handler featuring session locking and session fixation protection.

News

  • phpredis v4.1.0 (released on 2018-07-10) added support for session locking, but it is disabled by default. To enable it you must set the new redis.session.locking_enabled INI directive to true. This version is the first to pass the test in ConcurrentTest that stresses the locking mechanism.

Installation

RedisSessionHandler requires PHP >=5.6 with the phpredis extension enabled and a Redis >=2.6 endpoint. Add uma/redis-session-handler to the composer.json file:

$ composer require uma/redis-session-handler

Overwrite the default session handler with UMA\RedisSessionHandler before your application calls any session_ function. If you are using a framework and unsure when or where that happens, a good rule of thumb is "as early as possible". A safe bet might be the frontend controller in the public directory of the project or an equivalent initialization script.

// top of my-project/web/app.php

require_once __DIR__ . '/../vendor/autoload.php';

session_set_save_handler(new \UMA\RedisSessionHandler(), true);

Note that calling session_set_save_handler overwrites any value you might have set in the session.save_handler option of the php.ini file, so you don't need to change that. However, RedisSessionHandler still uses session.save_path to find the Redis server, just like the vanilla phpredis session handler:

; examples
session.save_path = "localhost"
session.save_path = "localhost?timeout=2.5"
session.save_path = "tcp://1.2.3.4:5678?prefix=APP_SESSIONS:&database=2"
session.save_path = "unix:///var/run/redis.sock"
session.save_path = "/var/run/redis.sock?database=2"

Available query params:

  • timeout (float), default 0.0, which means unlimited timeout
  • prefix (string), default 'PHPREDIS_SESSION:'
  • auth (string), default null
  • database (int), default 0

Currently only a single host definition is supported.

Note than when connecting through a Unix socket the timeout is ignored.

Known Caveats

Using RedisSessionHandler with the max_execution_time directive set to 0 is not recommended

Whenever it can, the handler uses the max_execution_time directive as a hard timeout for the session lock. This is a last resort mechanism to release the session lock even if the PHP process crashes and the handler fails to do it itself.

When max_execution_time is set to 0 (meaning there is no maximum execution time) this kind of hard timeout cannot be used, as the lock must be kept for as long as it takes to run the script, which is an unknown amount of time. This means that if for some unexpected reason the PHP process crashes and the handler fails to release the lock there would be no safety net and you'd end up with a dangling lock that you'd have to detect and purge by other means.

So when using RedisSessionHandler it is advised not to disable max_execution_time.

RedisSessionHandler does not support session.use_trans_sid=1 nor session.use_cookies=0

When these directives are set this way PHP switches from using cookies to passing the session ID around as a query param.

RedisSessionHandler cannot work in this mode. This is by design.

RedisSessionHandler ignores the session.use_strict_mode directive

Because running PHP with strict mode disabled (which is the default!) does not make any sense whatsoever. RedisSessionHandler only works in strict mode. The Session fixation section of this README explains what that means.

Motivation

The Redis session handler bundled with phpredis has had a couple of rather serious bugs for years, namely the lack of per-session locking and the impossibility to protect against session fixation attacks.

This package provides a compatible session handler built on top of the Redis extension that is not affected by these issues.

Session Locking explained

In the context of PHP, "session locking" means that when multiple requests with the same session ID hit the server roughly at the same time, only one gets to run while the others get stuck waiting inside session_start(). Only when that first request finishes or explicitly runs session_write_close(), one of the others can move on.

When a session handler does not implement session locking concurrency bugs might start to surface under heavy traffic. I'll demonstrate the problem using the default phpredis handler and this simple script:

<?php

// a script that returns the total number of
// requests made during a given session's lifecycle.

session_start();

if (!isset($_SESSION['visits'])) {
  $_SESSION['visits'] = 0;
}

$_SESSION['visits']++;

echo $_SESSION['visits'];

First, we send a single request that will setup a new session. Then we use the session ID returned in the Set-Cookie header to send a burst of 200 concurrent, authenticated requests.

$ http localhost/visit-counter.php
HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate
Connection: keep-alive
Content-Type: text/html; charset=UTF-8
Date: Mon, 23 Jan 2017 12:30:17 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Pragma: no-cache
Server: nginx/1.11.8
Set-Cookie: PHPSESSID=9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21; path=/; HttpOnly
Transfer-Encoding: chunked

1

$ hey -n 200 -H "Cookie: PHPSESSID=9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21;" http://localhost/visit-counter.php
All requests done.

Summary:
  Total:	0.4033 secs
  Slowest:	0.1737 secs
  Fastest:	0.0086 secs
  Average:	0.0805 secs
  Requests/sec:	495.8509

Status code distribution:
  [200]	200 responses

Everything looks fine from the outside, we got the expected two hundred OK responses, but if we peek inside the Redis database we see that the counter is way off. Instead of 201 visits we see a random number that is way lower than that:

127.0.0.1:6379> KEYS *
1) "PHPREDIS_SESSION:9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21"

127.0.0.1:6379> GET PHPREDIS_SESSION:9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21
"visits|i:134;"

Looking at Redis' MONITOR output we can see that under heavy load, Redis often executes two or more GET commands one after the other, thus returning the same number of visits to two or more different requests. When that happens, all those unlucky requests pass the same number of visits back to Redis, so some of them are ultimately lost. For instance, in this excerpt of the log you can see how the 130th request is not accounted for.

1485174643.241711 [0 172.21.0.2:49780] "GET" "PHPREDIS_SESSION:9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21"
1485174643.241891 [0 172.21.0.2:49782] "GET" "PHPREDIS_SESSION:9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21"
1485174643.242444 [0 172.21.0.2:49782] "SETEX" "PHPREDIS_SESSION:9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21" "900" "visits|i:129;"
1485174643.242878 [0 172.21.0.2:49780] "SETEX" "PHPREDIS_SESSION:9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21" "900" "visits|i:129;"
1485174643.244780 [0 172.21.0.2:49784] "GET" "PHPREDIS_SESSION:9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21"
1485174643.245385 [0 172.21.0.2:49784] "SETEX" "PHPREDIS_SESSION:9mcjmlsh9gp0conq7i5rci7is8gfn6s0gh8r3eub3qpac09gnh21" "900" "visits|i:130;"

RedisSessionHandler solves this problem with a "lock" entry for every session that only one thread of execution can create at a time.

Session fixation explained

Session fixation is the ability to choose your own session ID as an HTTP client. When clients are allowed to choose their session IDs, a malicious attacker might be able to trick other clients into using an ID already known to him, then wait for them log in and hijack their session.

Starting from PHP 5.5.2, there's an INI directive called session.use_strict_mode to protect PHP applications against such attacks. When "strict mode" is enabled and a unknown session ID is received, PHP should ignore it and generate a new one, just as if it was not received at all. Unfortunately the phpredis handler ignores that directive and always trust whatever session ID is received from the HTTP request.

$ http -v http://localhost/visit-counter.php Cookie:PHPSESSID=madeupkey
GET / HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: PHPSESSID=madeupkey     <----
Host: 127.0.0.1
User-Agent: HTTPie/0.9.6

HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate
Connection: close
Content-type: text/html; charset=UTF-8
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Host: 127.0.0.1
Pragma: no-cache

1

$ redis-cli

127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION:madeupkey"

127.0.0.1:6379> GET PHPREDIS_SESSION:madeupkey
"visits|i:1;"

Hence RedisSessionHandler only works in strict mode. It only accepts external session IDs that are already inside the Redis store.

Testing

Running the tests

To do that you'll need Docker >=1.10 and docker-compose >=1.8.

In order to run the integration test suite just type composer test and it will take care of installing the dev dependencies, setting up the testing containers and running the tests.

$ composer test
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Nothing to install or update
Generating autoload files
> docker-compose -f tests/docker-compose.yml up -d
tests_redis_1 is up-to-date
tests_fpm56_1 is up-to-date
tests_fpm71_1 is up-to-date
tests_fpm70_1 is up-to-date
tests_redis_monitor_1 is up-to-date
tests_nginx_1 is up-to-date
tests_runner_1 is up-to-date
> docker exec -t tests_runner_1 sh -c "TARGET=php56 vendor/bin/phpunit"
stty: standard input
PHPUnit 6.2.3 by Sebastian Bergmann and contributors.

................           16 / 16 (100%)

Time: 1.39 seconds, Memory: 4.00MB

OK (16 tests, 54 assertions)
> docker exec -t tests_runner_1 sh -c "TARGET=php70 vendor/bin/phpunit"
stty: standard input
PHPUnit 6.2.3 by Sebastian Bergmann and contributors.

................           16 / 16 (100%)

Time: 1.29 seconds, Memory: 4.00MB

OK (16 tests, 54 assertions)
> docker exec -t tests_runner_1 sh -c "TARGET=php71 vendor/bin/phpunit"
stty: standard input
PHPUnit 6.2.3 by Sebastian Bergmann and contributors.

................           16 / 16 (100%)

Time: 1.08 seconds, Memory: 4.00MB

OK (16 tests, 54 assertions)

Running the tests against the native phpredis handler

You can easily run the same test suite against the native phpredis handler.

To do so, comment out the line in tests/webroot/visit-counter.php where RedisSessionHandler is enabled and the FPM container will automatically choose the phpredis save handler (version 3.1.2 at the time of writing).

// session_set_save_handler(new \UMA\RedisSessionHandler(), true);
$ composer test
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Nothing to install or update
Generating autoload files
> docker-compose -f tests/docker-compose.yml up -d
tests_redis_1 is up-to-date
tests_fpm56_1 is up-to-date
tests_fpm71_1 is up-to-date
tests_fpm70_1 is up-to-date
tests_redis_monitor_1 is up-to-date
tests_nginx_1 is up-to-date
tests_runner_1 is up-to-date
> docker exec -t tests_runner_1 sh -c "TARGET=php56 vendor/bin/phpunit"
stty: standard input
PHPUnit 6.2.3 by Sebastian Bergmann and contributors.

...FFF..FF......           16 / 16 (100%)

Time: 1.15 seconds, Memory: 4.00MB

There were 5 failures:

~~snip~~

Manual testing

The docker-compose.yml file is configured to expose a random TCP port linked to the nginx container port 80. After running composer env-up or composer test you can see which one was assigned with docker ps. With that knowledge you can poke the testing webserver directly from your local machine using either a regular browser, cURL, wrk or similar tools.

Depending on your Docker setup you might need to replace localhost with the IP of the virtual machine that actually runs the Docker daemon:

$ curl -i localhost:32768/visit-counter.php?with_custom_cookie_params
HTTP/1.1 200 OK
Server: nginx/1.13.1
Date: Sat, 15 Jul 2017 09:40:25 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: PHPSESSID=tqm3akv0t5gdf25lf1gcspn479aa989jp0mltc3nuun2b47c7g10; expires=Sun, 16-Jul-2017 09:40:25 GMT; Max-Age=86400; path=/; secure; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache

1
Comments
  • Use cookie parameters as set in the session

    Use cookie parameters as set in the session

    Hi Marcel,

    I've got another fix, this one is for regeneration cookies with non-default parameters such as long expiry, path, secure or HTTP only flags. Without this patch I end up with two distinct cookies in my browser when I use a non-existent session ID and browsers only replace cookies with matching parameters.

    Thanks

    Scott

    opened by scottlucas 20
  • handler does not work on PHP7+

    handler does not work on PHP7+

    Error #2 session_regenerate_id(): Session object destruction failed. ID: user (path: tcp://127.0.0.1:6379?database=2&timeout=2)

    Steps to reproduce: enter website flush redis: redis-cli> SELECT 2 redis-cli> FLUSHDB reload website

    opened by marcing 14
  • Errors while connecting to redis

    Errors while connecting to redis

    Get such errors while testing (not always, but very often): Warning: Redis::connect(): php_network_getaddresses: getaddrinfo failed: Name or service not known in /mnt/www/example.com/includes/RedisSessionHandler/uma/redis-session-handler/src/RedisSessionHandler.php on line 105

    Warning: Redis::connect(): connect() failed: php_network_getaddresses: getaddrinfo failed: Name or service not known in /mnt/www/example.com/includes/RedisSessionHandler/uma/redis-session-handler/src/RedisSessionHandler.php on line 105

    Fatal error: Uncaught exception 'RedisException' with message 'Redis server went away' in /mnt/www/example.com/includes/RedisSessionHandler/uma/redis-session-handler/src/RedisSessionHandler.php:242 Stack trace: #0 /mnt/www/example.com/includes/RedisSessionHandler/uma/redis-session-handler/src/RedisSessionHandler.php(242): Redis->exists('aninlrkd8dijko6...') #1 /mnt/www/example.com/includes/RedisSessionHandler/uma/redis-session-handler/src/RedisSessionHandler.php(139): UMA\RedisSessionHandler->mustRegenerate('aninlrkd8dijko6...') #2 [internal function]: UMA\RedisSessionHandler->read('aninlrkd8dijko6...') #3 /mnt/www/example.com/1askjdha.php(18): session_start() #4 {main} thrown in /mnt/www/example.com/includes/RedisSessionHandler/uma/redis-session-handler/src/RedisSessionHandler.php on line 242

    Fatal error: Uncaught exception 'RedisException' with message 'Redis server went away' in /mnt/www/example.com/includes/RedisSessionHandler/uma/redis-session-handler/src/RedisSessionHandler.php:159 Stack trace: #0 /mnt/www/example.com/includes/RedisSessionHandler/uma/redis-session-handler/src/RedisSessionHandler.php(159): Redis->setex('aninlrkd8dijko6...', 1440, '') #1 [internal function]: UMA\RedisSessionHandler->write('aninlrkd8dijko6...', '') #2 [internal function]: session_write_close() #3 {main} thrown in /mnt/www/example.com/includes/RedisSessionHandler/uma/redis-session-handler/src/RedisSessionHandler.php on line 159

    opened by macktab 13
  • Session handler broke on PHP 7.3.0

    Session handler broke on PHP 7.3.0

    Apparently the problem lies in RedisSessionHandler.php:L143

    if ($this->mustRegenerate($session_id)) {
        session_id($session_id = $this->create_sid());
        // ...
    }
    

    Up until PHP 7.2 calling session_id($session_id) inside RedisSessionHandler::read() updates the ID in PHP's internals, so that when the session is closed later on and PHP calls RedisSessionHandler::write(), $session_id is the new ID. On PHP 7.3.0 the $session_id received in RedisSessionHandler::write() is still the old value (the one that has to change), so the handler generates a new ID, puts it in the Cookie header and sends it back to the client, but in Redis the stored key is the stale one. In other words, session_id($session_id) no longer does anything.

    Example

    $ curl -i -H "Cookie: PHPSESSID=madeupkey;" php73:32768/visit-counter.php
    HTTP/1.1 200 OK
    Server: nginx/1.13.12
    Date: Thu, 20 Dec 2018 20:03:59 GMT
    Content-Type: text/html; charset=UTF-8
    Transfer-Encoding: chunked
    Connection: keep-alive
    X-Powered-By: PHP/7.3.0
    Set-Cookie: PHPSESSID=3m5qrhtk9upe63069ilf2h3ogr; path=/      <------ new (but lost) ID
    Expires: Thu, 19 Nov 1981 08:52:00 GMT
    Cache-Control: no-store, no-cache, must-revalidate
    Pragma: no-cache
    
    1
    

    Redis MONITOR log:

    1545336238.057942 [0 172.18.0.6:57078] "EXISTS" "PHPREDIS_SESSION:madeupkey"
    1545336238.587852 [0 172.18.0.6:57078] "SET" "PHPREDIS_SESSION:3m5qrhtk9upe63069ilf2h3ogr_lock" "" "nx"
    1545336239.123639 [0 172.18.0.6:57078] "SETEX" "PHPREDIS_SESSION:madeupkey" "1440" "visits|i:1;"
    1545336239.595592 [0 172.18.0.6:57078] "DEL" "PHPREDIS_SESSION:3m5qrhtk9upe63069ilf2h3ogr_lock"
    

    Keys in Redis:

    127.0.0.1:6379> KEYS *
    1) "PHPREDIS_SESSION:madeupkey"           <---- successful session fixation attack
    
    127.0.0.1:6379> GET PHPREDIS_SESSION:madeupkey
    "visits|i:1;"
    

    Test suite results on PHP 7.3.0:

    290ed5384ec4:/var/www/redis-sessions.test# TARGET=php73 vendor/bin/phpunit 
    PHPUnit 7.2.6 by Sebastian Bergmann and contributors.
    
    ...FF....F......                                                  16 / 16 (100%)
    
    Time: 604 ms, Memory: 6.00MB
    
    There were 3 failures:
    
    1) UMA\RedisSessions\Tests\E2E\BasicTest::testMaliciousRequest
    Failed asserting that 'visits|i:1;' is false.
    
    /var/www/redis-sessions.test/tests/e2e/BasicTest.php:113
    
    2) UMA\RedisSessions\Tests\E2E\BasicTest::testMaliciousRequestWithCustomCookieParams
    Failed asserting that 'visits|i:1;' is false.
    
    /var/www/redis-sessions.test/tests/e2e/BasicTest.php:136
    
    3) UMA\RedisSessions\Tests\E2E\ConcurrentTest::testMaliciousRequests
    Failed asserting that 1 is identical to 200.
    
    /var/www/redis-sessions.test/tests/e2e/ConcurrentTest.php:69
    
    FAILURES!
    Tests: 16, Assertions: 55, Failures: 3.
    
    opened by 1ma 6
  • Spinlock should usleep

    Spinlock should usleep

    Great initiative! I think your spinlock should use a usleep of 150 ms.

    https://github.com/1ma/RedisSessionHandler/blob/master/RedisSessionHandler.php#L164

    In order not to stress the CPU too much. See also:

    https://github.com/php-memcached-dev/php-memcached/blob/master/php_memcached_session.c#L162

    and

    https://github.com/snc/SncRedisBundle/blob/master/Session/Storage/Handler/RedisSessionHandler.php#L146

    I hope this helps.

    opened by mevdschee 6
  • Fix hang when max_execution_time is zero

    Fix hang when max_execution_time is zero

    Hi Marcel,

    I know the phpredis team have nearly added locking into the module but I am still using your code as a workaround at the moment. I noticed an issue whereby a script will hang if the execution time is not limited.

    Please see attached pull request. I wasn't able to run the tests in Docker (it's nearby impossible to get PECL working in the php-cli image) so please check everything is working.

    Kind Regards

    Scott

    opened by scottlucas 5
  • [Proposal] Sessions without cookie

    [Proposal] Sessions without cookie

    I was thinking about the issue https://github.com/1ma/RedisSessionHandler/issues/3.

    The sessions are stored in a cookie in the client for authentication propose. But I use to work with JWT instead and I wanna be able to use a JWT for the session authentication.

    Example:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXNzaW9uSWQiOiJramhiazIzajFodmhvbW9tYXJjZWwxMjMxMmluMTMiLCJuYW1lIjoiVmljdG9yIFJpb3MiLCJyb2xlcyI6WyJsZWdhY3kiXX0.M6vwdTwaXMFrYphDbytCzRwk2ONIYcXaV960oxBDyUs

    You can use the JWT token as sessionId or like in this token add a a sessionId inside. This mechanism can give me the possibility of expire a valid JWT token, for example.

    The handler will require some modifications to allow custom SessionAware objects and a default CookieSessionAware.

    That do you think? Make sense to you?

    opened by jorge07 3
  • does not support save_path parameters

    does not support save_path parameters

    Hi,

    The handler only works with save_path which does not contain any parameters like timeout, database, auth.

    Open method should be something like:

    public function open($save_path, $name) { $save_path = parse_url($save_path); $timeout = 0; $database = 0; $auth = null;

        if(isset($save_path['query']))
        {
            parse_str($save_path['query']);
            $timeout = floatval($timeout);
            $database = intval($database);
        }
    
        $result = $this->redis->connect($save_path['host'], $save_path['port'], $timeout);
        if(!$result)
        {
            return false;
        }
    
        if($auth !== null)
        {
            $result = $this->redis->auth($auth);
            if(!$result)
            {
                return false;
            }
        }
    
        if($database > 0)
        {
            $result = $this->redis->select($database);
            if(!$result)
            {
                return false;
            }
        }
    
        return true;
    }
    
    opened by marcing 3
  • Fixes #11

    Fixes #11

    Solution based on the recommendation from @waverage, but maintaining compatibility with php>=5.6 while maintaining an enforced security against session fixation

    opened by wgirhad 2
  • Breaking change in phpredis 4.0

    Breaking change in phpredis 4.0

    According to https://github.com/phpredis/phpredis/issues/1323 Redis::exists() is now returning integer instead of bool, which breaks

    https://github.com/1ma/RedisSessionHandler/blob/061dce59eeadfdc4b15cf29f1e83026196fcc9df/src/RedisSessionHandler.php#L253

    Any plans of supporting the newer extension? And perhaps add this info to the known caveats section.

    Thanks.

    opened by ud-klee 2
  • Correct type return from read() method in SessionHandlerInterface implementation

    Correct type return from read() method in SessionHandlerInterface implementation

    As it said at https://www.php.net/manual/en/class.sessionhandlerinterface.php , any custom session handler must return a string from the read() method.

    This ensures the returning value is a string, not a random boolean.

    opened by therosco 1
  • PHP session storage Unable to specify Redis database

    PHP session storage Unable to specify Redis database

    session.save_path = " tcp://127.0.0.1:6379?database=2 " Useless, the session cannot be stored in the specified reids database,What is the problem and how to solve it?

    PHP 版本 7.3.8-1+ubuntu16.04.1+deb.sury.org+1 PHPRedis 版本 4.3.0 Redis 服务器 v=6.0.11

    opened by tangzhiqiangh 1
Releases(v0.9.9)
Owner
Marcel Hernandez
Marcel Hernandez
Redis-based session handler for Magento with optimistic locking

Cm_RedisSession A Redis-based session handler for Magento with optimistic locking. Features: Falls back to mysql handler if it can't connect to Redis.

Colin Mollenhour 216 Jan 5, 2023
A Redis-based session handler for Magento with optimistic locking.

Cm_RedisSession A Redis-based session handler for Magento with optimistic locking. Features: Falls back to mysql handler if it can't connect to Redis.

Colin Mollenhour 215 Jan 28, 2022
Implementazione generica di Sender per l'invio di Fatture Elettroniche ad intermediari per lo SDI

Implementazione generica di Sender per l'invio di Fatture Elettroniche ad intermediari per lo SDI Implementazione generica di Sender per l'invio di Fa

Fattura Elettronica - PHP 4 Nov 8, 2022
A super simple, clean and pretty error handler that replace the default error handler of PHP. You need only include this file!

php-custom-error-handler A super simple, clean and pretty error handler that replace the default error handler of PHP. You need just include only this

null 6 Nov 7, 2022
AWS DynamoDB session handler for Magento (experimental!)

Magento Session Handler for AWS DynamoDB Author: Fabrizio Branca TODO: disable automatic gc create cron that does gc how does it keep track of lifetim

AOE 5 Apr 6, 2017
PHP Class Encoding featuring popular Encoding::toUTF8() function --formerly known as forceUTF8()-- that fixes mixed encoded strings.

forceutf8 PHP Class Encoding featuring popular \ForceUTF8\Encoding::toUTF8() function --formerly known as forceUTF8()-- that fixes mixed encoded strin

Sebastián Grignoli 1.6k Dec 22, 2022
A simple but scalable FFA Practice Core featuring one Game Mode & Vasar PvP aspects.

A simple but scalable FFA Practice Core featuring one Game Mode & Vasar PvP aspects. An example of this Plugin can be found in-game at ganja.bet:19132!

null 6 Dec 7, 2022
This is a plugin for pocketmine-mp, when locking a player's items helps players not to lose items or throw things around causing server lag.

[] LockedItem| v1.0.0 Player's item lock Features Player's item lock Players aren't afraid of losing items For Devolopers You can access to LockedItem

JeroGamingYT 3 Jan 4, 2022
Plot and protection plugin for PocketMine-MP

MyPlot Create, manage, and build in protected plots. Keep your builds safe from griefers! Official MyPlot precompiled builds can be found on Poggit at

Jason 101 Oct 28, 2022
Block malicious scripts using botscout.com protection for your laravel app

Laravel BotScout Protect your website against automated scripts using the botscout.com API. Installation You can install the package via composer: com

Nicolas Beauvais 64 Jul 30, 2022
Recoded, added features, removed useless stuff, more efficent code, PER PLAYER TEXT

WFT - 1.2.0 (BETA) Hello, and welcome to WFT. NOW IN API 4.0 This is the official recode of my old plugin WFT, witch had some issues. Overall I was no

null 9 Jul 4, 2022
ReintegrApp è una Web Application gestionale sviluppata senza fini di lucro da Riccardo Riggi per organizzazioni di volontariato che operano nel campo dell'emergenza/urgenza

ReintegrApp ReintegrApp è una Web Application gestionale sviluppata senza fini di lucro da Riccardo Riggi per organizzazioni di volontariato che opera

Riccardo Riggi 3 Nov 27, 2021
Laragon MultiPHP per App + PECL Module + Extension manager + Ini Manager

LMPA Laragon MultiPHP per App This tools allow you to run multiple PHP version per app with Laragon, so you can have multiple site running different p

Gilbert Paquin 8 Oct 10, 2022
Modello base con tutto il docker configurato per php7.4, mariadb, vue3, apache...con esempi di component e chiamate rest interne

Applicazione base per utilizzare laravel con docker, php7.4, apache, mariadb10, vue3 Semplice installazione corredate di rotte web e api di base, 3 co

null 0 Jul 14, 2022
A Magento 2 module that allows for creating discrete PDP (Product Detail Pages) page layouts for customers landing on the site from a PPC (Pay Per Click) link/ad by allowing routing to the same pages using a `/ppc/` prefix in the URL path.

A Magento 2 module that allows for creating discrete PDP (Product Detail Pages) page layouts for customers landing on the site from a PPC (Pay Per Click) link/ad by allowing routing to the same pages using a `/ppc/` prefix in the URL path.

null 16 Nov 11, 2022
Adds a "spam protection" field to SilverStripe userforms using Cloudflare's Turnstile service.

Turnstile for Silverstripe Adds a "spam protection" field to SilverStripe userforms using Cloudflare's Turnstile service. Maintainer Contact Ed Chipma

Webbuilders Group 3 Dec 15, 2022
Calibre OPDS (and HTML) PHP Server : web-based light alternative to Calibre content server / Calibre2OPDS to serve ebooks (epub, mobi, pdf, ...)

COPS COPS stands for Calibre OPDS (and HTML) Php Server. See : COPS's home for more details. Don't forget to check the Wiki. Why ? In my opinion Calib

Sébastien Lucas 1.3k Jan 1, 2023
Personal PHP MySQL query handler based on Eloquent using PDO.

?? Equivoluent Welcome to "Equivoluent" my personal PHP MySQL query handler using PDO. Equivoluent is based on Laravel's Eloquent. The goal of "Equivo

Wob Jelsma 2 Sep 7, 2022
Highly customizable alternative to var_export for PHP code generation

PHP Variable Exporter PHPEncoder is a PHP library for exporting variables and generating PHP code representations for said variables similar to the bu

Riikka Kalliomäki 71 Dec 30, 2022