Lock library to provide serialized execution of PHP code.

Overview

Requirements | Installation | Usage | License and authors | Donations

php-lock/lock

Latest Stable Version Total Downloads Latest Unstable Version Build Status License

This library helps executing critical code in concurrent situations.

php-lock/lock follows semantic versioning. Read more on semver.org.


Requirements

  • PHP 7.1 or above
  • Optionally nrk/predis to use the Predis locks.
  • Optionally the php-pcntl extension to enable locking with flock() without busy waiting in CLI scripts.
  • Optionally flock(), ext-redis, ext-pdo_mysql, ext-pdo_sqlite, ext-pdo_pgsql or ext-memcached can be used as a backend for locks. See examples below.
  • If ext-redis is used for locking and is configured to use igbinary for serialization or lzf for compression, additionally ext-igbinary and/or ext-lzf have to be installed.

Installation

Composer

To use this library through composer, run the following terminal command inside your repository's root folder.

composer require "malkusch/lock"

Usage

This library uses the namespace malkusch\lock.

Mutex

The malkusch\lock\mutex\Mutex class is an abstract class and provides the base API for this library.

Mutex::synchronized()

malkusch\lock\mutex\Mutex::synchronized() executes code exclusively. This method guarantees that the code is only executed by one process at once. Other processes have to wait until the mutex is available. The critical code may throw an exception, which would release the lock as well.

This method returns whatever is returned to the given callable. The return value is not checked, thus it is up to the user to decide if for example the return value false or null should be seen as a failed action.

Example:

$newBalance = $mutex->synchronized(function () use (
    $bankAccount,
    $amount
): int {
    $balance = $bankAccount->getBalance();
    $balance -= $amount;
    if ($balance < 0) {
        throw new \DomainException('You have no credit.');
    }
    $bankAccount->setBalance($balance);

    return $balance;
});

Mutex::check()

malkusch\lock\mutex\Mutex::check() sets a callable, which will be executed when malkusch\lock\util\DoubleCheckedLocking::then() is called, and performs a double-checked locking pattern, where it's return value decides if the lock needs to be acquired and the synchronized code to be executed.

See https://en.wikipedia.org/wiki/Double-checked_locking for a more detailed explanation of that feature.

If the check's callable returns false, no lock will be acquired and the synchronized code will not be executed. In this case the malkusch\lock\util\DoubleCheckedLocking::then() method, will also return false to indicate that the check did not pass either before or after acquiring the lock.

In the case where the check's callable returns a value other than false, the malkusch\lock\util\DoubleCheckedLocking::then() method, will try to acquire the lock and on success will perform the check again. Only when the check returns something other than false a second time, the synchronized code callable, which has been passed to then() will be executed. In this case the return value of then() will be what ever the given callable returns and thus up to the user to return false or null to indicate a failed action as this return value will not be checked by the library.

Example:

$newBalance = $mutex->check(function () use ($bankAccount, $amount): bool {
    return $bankAccount->getBalance() >= $amount;
})->then(function () use ($bankAccount, $amount): int {
    $balance = $bankAccount->getBalance();
    $balance -= $amount;
    $bankAccount->setBalance($balance);

    return $balance;
});

if (false === $newBalance) {
    if ($balance < 0) {
        throw new \DomainException('You have no credit.');
    }
}

Extracting code result after lock release exception

Mutex implementations based on malkush\lock\mutex\LockMutex will throw malkusch\lock\exception\LockReleaseException in case of lock release problem, but the synchronized code block will be already executed at this point. In order to read the code result (or an exception thrown there), LockReleaseException provides methods to extract it.

Example:

try {
    // or $mutex->check(...)
    $result = $mutex->synchronized(function () {
        if (someCondition()) {
            throw new \DomainException();
        }

        return "result";
    });
} catch (LockReleaseException $unlockException) {
    if ($unlockException->getCodeException() !== null) {
        $codeException = $unlockException->getCodeException()
        // do something with the code exception
    } else {
        $code_result = $unlockException->getCodeResult();
        // do something with the code result
    }

    // deal with LockReleaseException or propagate it
    throw $unlockException;
}

Implementations

Because the malkusch\lock\mutex\Mutex class is an abstract class, you can choose from one of the provided implementations or create/extend your own implementation.

CASMutex

The CASMutex has to be used with a Compare-and-swap operation. This mutex is lock free. It will repeat executing the code until the CAS operation was successful. The code should therefore notify the mutex by calling malkusch\lock\mutex\CASMutex::notify().

As the mutex keeps executing the critical code, it must not have any side effects as long as the CAS operation was not successful.

Example:

$mutex = new CASMutex();
$mutex->synchronized(function () use ($memcached, $mutex, $amount): void {
    $balance = $memcached->get("balance", null, $casToken);
    $balance -= $amount;
    if (!$memcached->cas($casToken, "balance", $balance)) {
        return;
    }
    $mutex->notify();
});

FlockMutex

The FlockMutex is a lock implementation based on flock().

Example:

$mutex = new FlockMutex(fopen(__FILE__, "r"));
$mutex->synchronized(function () use ($bankAccount, $amount) {
    $balance = $bankAccount->getBalance();
    $balance -= $amount;
    if ($balance < 0) {
        throw new \DomainException("You have no credit.");
    }
    $bankAccount->setBalance($balance);
});

Timeouts are supported as an optional second argument. This uses the ext-pcntl extension if possible or busy waiting if not.

MemcachedMutex

The MemcachedMutex is a spinlock implementation which uses the Memcached API.

Example:

$memcache = new \Memcached();
$memcache->addServer("localhost", 11211);

$mutex = new MemcachedMutex("balance", $memcache);
$mutex->synchronized(function () use ($bankAccount, $amount) {
    $balance = $bankAccount->getBalance();
    $balance -= $amount;
    if ($balance < 0) {
        throw new \DomainException("You have no credit.");
    }
    $bankAccount->setBalance($balance);
});

PHPRedisMutex

The PHPRedisMutex is the distributed lock implementation of RedLock which uses the phpredis extension.

This implementation requires at least phpredis-2.2.4.

If used with a cluster of Redis servers, acquiring and releasing locks will continue to function as long as a majority of the servers still works.

Example:

$redis = new Redis();
$redis->connect("localhost");

$mutex = new PHPRedisMutex([$redis], "balance");
$mutex->synchronized(function () use ($bankAccount, $amount) {
    $balance = $bankAccount->getBalance();
    $balance -= $amount;
    if ($balance < 0) {
        throw new \DomainException("You have no credit.");
    }
    $bankAccount->setBalance($balance);
});

PredisMutex

The PredisMutex is the distributed lock implementation of RedLock which uses the Predis API.

Example:

$redis = new Client("redis://localhost");

$mutex = new PredisMutex([$redis], "balance");
$mutex->synchronized(function () use ($bankAccount, $amount) {
    $balance = $bankAccount->getBalance();
    $balance -= $amount;
    if ($balance < 0) {
        throw new \DomainException("You have no credit.");
    }
    $bankAccount->setBalance($balance);
});

SemaphoreMutex

The SemaphoreMutex is a lock implementation based on Semaphore.

Example:

$semaphore = sem_get(ftok(__FILE__, "a"));
$mutex = new SemaphoreMutex($semaphore);
$mutex->synchronized(function () use ($bankAccount, $amount) {
    $balance = $bankAccount->getBalance();
    $balance -= $amount;
    if ($balance < 0) {
        throw new \DomainException("You have no credit.");
    }
    $bankAccount->setBalance($balance);
});

TransactionalMutex

The TransactionalMutex delegates the serialization to the DBS. The exclusive code is executed within a transaction. It's up to you to set the correct transaction isolation level. However if the transaction fails (i.e. a PDOException was thrown), the code will be executed again in a new transaction. Therefore the code must not have any side effects besides SQL statements. Also the isolation level should be conserved for the repeated transaction. If the code throws an exception, the transaction is rolled back and not replayed again.

Example:

$mutex = new TransactionalMutex($pdo);
$mutex->synchronized(function () use ($pdo, $accountId, $amount) {
    $select = $pdo->prepare(
        "SELECT balance FROM account WHERE id = ? FOR UPDATE"
    );
    $select->execute([$accountId]);
    $balance = $select->fetchColumn();

    $balance -= $amount;
    if ($balance < 0) {
        throw new \DomainException("You have no credit.");
    }
    $pdo->prepare("UPDATE account SET balance = ? WHERE id = ?")
        ->execute([$balance, $accountId]);
});

MySQLMutex

The MySQLMutex uses MySQL's GET_LOCK function.

It supports time outs. If the connection to the database server is lost or interrupted, the lock is automatically released.

Note that before MySQL 5.7.5 you cannot use nested locks, any new lock will silently release already held locks. You should probably refrain from using this mutex on MySQL versions < 5.7.5.

$pdo = new PDO("mysql:host=localhost;dbname=test", "username");

$mutex = new MySQLMutex($pdo, "balance", 15);
$mutex->synchronized(function () use ($bankAccount, $amount) {
    $balance = $bankAccount->getBalance();
    $balance -= $amount;
    if ($balance < 0) {
        throw new \DomainException("You have no credit.");
    }
    $bankAccount->setBalance($balance);
});

PgAdvisoryLockMutex

The PgAdvisoryLockMutex uses PostgreSQL's advisory locking functions.

Named locks are offered. PostgreSQL locking functions require integers but the conversion is handled automatically.

No time outs are supported. If the connection to the database server is lost or interrupted, the lock is automatically released.

$pdo = new PDO("pgsql:host=localhost;dbname=test;", "username");

$mutex = new PgAdvisoryLockMutex($pdo, "balance");
$mutex->synchronized(function () use ($bankAccount, $amount) {
    $balance = $bankAccount->getBalance();
    $balance -= $amount;
    if ($balance < 0) {
        throw new \DomainException("You have no credit.");
    }
    $bankAccount->setBalance($balance);
});

License and authors

This project is free and under the WTFPL. Responsible for this project is Willem Stuursma-Ruwen [email protected].

Donations

If you like this project and feel generous donate a few Bitcoins here: 1P5FAZ4QhXCuwYPnLZdk3PJsqePbu1UDDA

Comments
  • flock with timeout support

    flock with timeout support

    I like FlockMutex because it work on kernel level and is reliable.

    however there's the problem that acquiring the lock makes program wait forever. I wish to get error "unable to obtain lock withing timeout"

    for flock there's LOCK_NB flag which can be used.

    ps: SemaphoreMutex has similar issue

    enhancement 
    opened by glensc 17
  • SpinlockMutex unlock method

    SpinlockMutex unlock method

    Shouldn't the unlock method of SpinlockMutex throw a TimeoutException if the executed time lasted longer than the set timeout instead of an LockReleaseException?

    Related code from SpinlockMutex:

    protected function unlock()
        {
            $elapsed = microtime(true) - $this->acquired;
            if ($elapsed >= $this->timeout) {
                $message = sprintf(
                    "The code executed for %d seconds. But the timeout is %d seconds.",
                    $elapsed,
                    $this->timeout
                );
                throw new LockReleaseException($message);
            }
            /*
             * Worst case would still be one second before the key expires.
             * This guarantees that we don't delete a wrong key.
             */
            if (!$this->release($this->key)) {
                throw new LockReleaseException("Failed to release the lock.");
            }
        }
    

    If not, can you explain why?

    opened by TheLevti 7
  • No access to code return value in case of ExecutionOutsideLockException or LockReleaseException

    No access to code return value in case of ExecutionOutsideLockException or LockReleaseException

    When LockReleaseException or ExecutionOutsideLockException is thrown there is no way to access the return value of the code block (it was executed).

    Following change to LockMutex::synchronized() comes to mind:

        public function synchronized(callable $code)
        {
            $this->lock();
    
            $result = null;
            try {
                $result = $code();
            } finally {
    	        try {
    		        $this->unlock();
    	        } catch (ExecutionOutsideLockException|LockReleaseException $e) {
    		        $e->setCodeResult($result);
    		        throw $e;
    	        }
            }
    
            return $result;
        }
    

    Also setCodeResult and getCodeResult should be added to both exception classes.

    Of course a library user can always extend specific LockMutex subclass (ex. PredisMutex) and override the synchronized() method to deal with this problem, but maybe it's worth incorporating directly into the library.

    opened by Furgas 6
  • php-lock/lock#19: Added a new exception

    php-lock/lock#19: Added a new exception

    • Added ExecutionOutsideLockException which can be thrown when the lock is released or times out before the synchronized code finished execution.
    • Changed SpinlockMutex to use the new ExecutionOutsideLockException when the synchronized code executes longer than the set timeout.

    Resolves php-lock/lock#19

    opened by TheLevti 6
  • Code clean up

    Code clean up

    • Added php-cs-fixer with a configurable ruleset for code format. Run vendor/bin/php-cs-fixer fix to run php-cs-fixer against the .phpcs_dist or .phpcs config. Current configuration is based on PSR-12 plus a few extras.
    • Added declare(strict_types=1); to all files to enable strict type checking.
    • Fixed a missing log placeholder 2ca1e30.
    • Added many missing docblock comments.
    • Improved documentation in many classes.
    • Improved exception inheritance. All exceptions extend one common project specific interface.
    • Fixed package case to support composer 2.0 921622c.
    opened by TheLevti 5
  • Add ability to retrieve executed code result or exception on unlock error

    Add ability to retrieve executed code result or exception on unlock error

    Add ability to do this:

    try {
        $mutex->synchronized(function () {
            if (someCondition()) {
                throw new \DomainException();
            }
    
            return "result";
        });
    } catch (LockReleaseException $e) {
        if ($e->getCodeException() !== null) {
            // do something with the code exception
        } else {
            $result = $e->getCodeResult();
            // do something with the code result
        }
        
        // deal with or propagate the LockReleaseException
        throw $e;
    }
    
    opened by Furgas 5
  • php-lock/lock#25: Drop support for php 5.6 and 7.0

    php-lock/lock#25: Drop support for php 5.6 and 7.0

    php-lock/lock#25: Drop support for php 5.6 and 7.0

    • Updated all packages.
    • Updated all tests to use phpunit 7.x.x
    • Updated project files.

    What else needs to be done?

    opened by TheLevti 5
  • PHPRedisMutex not working

    PHPRedisMutex not working

    I have a simple piece of code:

    $mutex = new \malkusch\lock\mutex\PHPRedisMutex([$app['redis']], "lock.".$guid, 8);
                $mutex->synchronized(function () use ($object) {
                    echo 'test';
                    sleep(3);
                });
    

    but it throws the following exception: LockReleaseException in SpinlockMutex.php line 94: Failed to release the lock.

    I am running PHP Version 7.0.15 with Redis extension 3.0.0

    Seems that the problem is with the file PHPRedisMutex.php, at line 63: return $redis->eval($script, $arguments, $numkeys);

    At https://github.com/phpredis/phpredis#eval we can read:

    Return value

    Mixed. What is returned depends on what the LUA script itself returns, which could be a scalar value (int/string), or an array.

    So, I have replaced the code at line 63 with:

    $redis->eval($script, $arguments, $numkeys);
                return $redis->getlasterror() == 0;
    

    In that way it seems to work properly. I think that with the new php redis extension the return of the eval function has changed, and becouse of that it returns an unexpected value. So I have changed the code in a way that it returns a boolean, checking if redis encountered an error. I'm not sure if that's the best way to fix that trouble, but with my tests it seems working.

    opened by cattivik66 5
  • Loop::execute throws TimeoutException even though lock was acquired

    Loop::execute throws TimeoutException even though lock was acquired

    (We are using php 7.3.22 on Linux together with php-lock v2.1, but it seems this issue persists in v2.2 as well)

    I'm not quite sure if this is desired behavior, but I want to talk about Loop::execute():

    Let's suppose the call $result = $code(); was successful, meaning $code() called Loop::end() and had side effects, but its successful execution took longer than $this->timeout.

    In that case

    if (microtime(true) >= $deadline) {
            throw TimeoutException::create($this->timeout);
    }
    

    which appears after the for loop, would still throw a TimeoutException, which seems counterintuitive to me.

    A possible fix could be to only throw if additionally $this->looping is true:

    if (microtime(true) >= $deadline && $this->looping) {
            throw TimeoutException::create($this->timeout);
    }
    

    See LongLockTest.txt for a quick unit test

    opened by felixkempf 4
  • Limit max. sleep duration per loop iteration

    Limit max. sleep duration per loop iteration

    max. sleep duration should be based on timeout, as for shorter timeouts, we should loop more often (like for web/API) vs. some long timeouts (for CLI/crons)

    opened by mvorisek 4
  • Fix PHPRedisMutex tests

    Fix PHPRedisMutex tests

    In PHP Redis extension, closing the connection won't trigger RedisException on further function calls, as it will reconnect and continue to work. This fix makes sure the exception is thrown on closed connection.

    opened by Furgas 4
  • MySQLMutex doesn't work correctly together with Sentry

    MySQLMutex doesn't work correctly together with Sentry

    After upgrading Symfony and Sentry ("sentry/sentry-symfony": "^4.3.0") I got the message that I needed to also upgrade doctrine/dbal ("doctrine/dbal": "^2.13.9",) , which then subsequently broke my use of MySQLMutex.

    <b>Fatal error</b>:  Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Type error: Argument 1 
    passed to malkusch\lock\mutex\MySQLMutex::__construct() must be an instance of PDO, instance of 
    Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingServerInfoAwareDriverConnection given, called in 
    /var/www/html/src/ApiBundle/Controller/Invoicing/InvoiceController.php on line 533 in 
    /var/www/html/vendor/malkusch/lock/classes/mutex/MySQLMutex.php:27
    

    The MySQLMutex class only expects an instance of PDO to be provided, and in my case this is actually an instance of the Doctrine\DBAL\Connection interface with the updated Sentry package.

    $em = $this->getContainer()->get('doctrine.orm.entity_manager');
    $pdo = $em->getConnection()->getWrappedConnection();
    $mutex = new MySQLMutex($pdo, 'Some lock');
    

    A solution would be to adapt the package so that the MySQLMutex class accepts both an instance of PDO and Doctrine\DBAL\Connection.

    Might make a PR for this in the coming week.

    opened by eddokloosterman 1
  • Unit Test fails if I try to use parallel threads

    Unit Test fails if I try to use parallel threads

    The following PHPUnit test fails if I try to use parallel threads

    I'm using php-lock version 2.1 on windows with php version 7.4.6

    If I deactivate the $this->mutex->synchronized function by commenting out the function the test is executed without an error. Does anyone have an idea whats wrong with my test case?

    <?php
    namespace Squeeze;
    
    use Exception;
    use malkusch\lock\mutex\FlockMutex;
    use PHPUnit\Framework\TestCase;
    
    class ThreadLockTest extends TestCase
    {
    
        /**
         * @var FlockMutex
         */
        private $mutex;
    
        /**
         * @var resource
         */
        private $file;
    
        protected function setUp(): void
        {
            parent::setUp();
    
            $this->file = __DIR__ . DIRECTORY_SEPARATOR . 'flock';
            $this->mutex = new FlockMutex(fopen($this->file, 'w'), 1);
        }
    
        protected function tearDown(): void
        {
            unlink($this->file);
    
            parent::tearDown();
        }
    
        public function testThreadLock(): void
        {
            $syncFunction = function ($i) {
                try {
                    require_once __DIR__ . '/../../../bootstrap/app.php';
                    echo $i .' Running ' . PHP_EOL;
                    return $this->mutex->synchronized(function () use ($i) : string {
                        sleep(1);
                        return $i .' Finished.' . PHP_EOL;
                    });
                } catch (Exception $e) {
                    return $e->getMessage() . PHP_EOL;
                }
            };
    
            $results = array();
            for ($i = 1; $i < 6; $i++) {
                $results[] = \parallel\run($syncFunction, array($i));
            }
    
            foreach ($results as $item) {
                echo $item->value();
            }
        }
    }
    
    opened by reeperbahnause 1
  • Locked timeout

    Locked timeout

    Spinlock with a twist (pun intended 😉)

    Problem: I needed to throw an exception if the lock is already taken, but only after a given timeout.

    Proposed solution The spinlock already has its own timeout (eg: 5 seconds). With this new option: lockedTimeout you can now specify a timeout while lock is already taken. (eg: 3 seconds). The process will try to acquire the lock for 3 seconds then throw an exception if it doesn't succeed.

    If we specify a lockedTimeout of 0, the exception will be thrown immediately after the first lock acquire attempt.

    This (with a lockedTimeout of zero) also addresses: https://github.com/php-lock/lock/issues/21#issuecomment-394963109

    opened by bstanescu 3
  • Rework redis locking

    Rework redis locking

    Some improvements that can be made:

    • If the lock fails to be acquired on a majority of servers, immediately abort the lock.
    • Only release locks on servers where we tried to set the lock
    • Further investigate multiplexing (does not seem possible with current approaches)
    • Acquire locks in random order of servers
    opened by willemstuursma 0
  • half of redis server are not available!

    half of redis server are not available!

    What is this this error?

    It's not possible to acquire a lock because at least half of the Redis serv er are not available.

    This is my code:

            $redis = new Client;
            $redis->auth(REDIS-PASSWORD,null);
            $redis->connect();
            $my_range = range(1,100);
    
            foreach ($my_range as $each_range){
                $mutex = new PredisMutex([$redis], "balance");
                $mutex->synchronized(function () use($each_range) {
                    $this->use_this_range($each_range);
                });
            }
    
    opened by nimaamiri92 6
Releases(v2.2.1)
  • v2.2.1(Apr 26, 2022)

  • v2.2(Mar 7, 2021)

    • Support LZF compression on Redis connections (#32)
    • Redlock token is now in hexadecimal for easier debugging (#41)
    • Various changes such as adding phpstan, upgrading to a more recent version of PHPUnit, adding PHPCS etc.
    • Add PHP 8.0 support (#45)

    Thanks everyone who contributed: @mvorisek and @TheLevti.

    Source code(tar.gz)
    Source code(zip)
  • v2.1(Dec 12, 2018)

  • v2.0(Nov 8, 2018)

    • PHP >= 7.1 only release. Thanks @TheLevti for assisting.
    • This version adds type hints to arguments and return types to methods. If you have your own implementations of the Mutex class, you might need to update it slightly.
    • The Memcache Mutex has been removed. You should use the Memcached mutex instead.
    • The Predis and PHPRedis mutexes have been updated to better follow the distlock from the Redis documentation.
    • A bug has been fixed in the Predis mutex where failing to release a lock could cause a fatal error if sentinel replication was used.
    • The return value of the callable passed to then() is now returned (#23). Thanks @TheLevti.
    • Various testing and CI improvements.
    Source code(tar.gz)
    Source code(zip)
  • v1.4(Jul 7, 2018)

  • v1.3(May 26, 2018)

    • Adds a new lock backend based on PostgreSQL's advisory locks. Thanks to @korotovsky for suggesting this feature.
    • Spinlocks now use a back off factor of 1.5 instead of 2. This means that released locks will be detected earlier at the cost of performing more checks. This affects the various Redis and Memcached based lock backends.
    • Various testing and CI improvements.
    Source code(tar.gz)
    Source code(zip)
  • v1.2(May 22, 2018)

  • v1.1(Apr 15, 2018)

    • Library no longer uses rand() but instead uses random_int(). Now depends on paragonie/random_compat for PHP 5.6 compatibility (#7, #9, #10).
    • Fixed issue where locks could not be released if ext-redis was used with SERIALIZER_PHP or SERIALIZER_IGBINARY serialization option (#8, #14, provided by @maestroprog).
    • Spin locks will now time out at the exact time out time, instead of waiting beyond the timeout.
    • Distribution no longer ships with tests or tooling files.
    • composer.json was updated to require all development extensions too.
    • Now tested against PHP 7.2 and PHP 7.3 too.
    • HHVM support dropped.

    BC breaks

    • The method seedRandom() has been removed from the RedisMutex class.
    Source code(tar.gz)
    Source code(zip)
Owner
null
Simple library that abstracts different metrics collectors. I find this necessary to have a consistent and simple metrics (functional) API that doesn't cause vendor lock-in.

Metrics Simple library that abstracts different metrics collectors. I find this necessary to have a consistent and simple metrics API that doesn't cau

Benjamin Eberlei 311 Nov 20, 2022
Mutex lock implementation

Yii Mutex This package provides mutex implementation and allows mutual execution of concurrent processes in order to prevent "race conditions". This i

Yii Software 30 Dec 28, 2022
Detection of execution by command (Terminal) or web environment.

WEB-CLI-Detector Detection of execution by command (Terminal) or web environment. Acronym: [WEB-CLI-Detector]. Name: WEB-CLI-Detector. Dependencies: S

Walter Nuñez 4 Jul 13, 2022
The FileLocator library was created to provide file locating capabilities to a larger project

File Locator A simple file locator library. Summary The FileLocator library was created to provide file locating capabilities to a larger project. It

KHerGe - Archived Projects 20 Dec 22, 2021
Signaler library that provide stack for signal listeners.

Stack Signaler. Contents Installation Usage Testing License Installation composer require kafkiansky/signaler Usage Simple example with \SIGINT signal

kafkiansky 1 Mar 25, 2022
This package was created to provide simple way to manipulate arrays in PHP

PHP Collections This package was created to provide simple way to manipulate arrays in PHP. The package was inspired by the Laravel Collections.

Wojciech Mleczek 13 Jul 26, 2021
Medical Master or "Medic-M" was built to reduce the hassle of buying medicine, provide medicine to the sick in a short time. It is an HTML, CSS, JAVASCRIPT and PHP based system.

Medical Master (Medic-M) | WELCOME TO Medic-M(MEDICAL MASTER) | | Introduction | Medical Master or "Medic-M" was built to reduce the hassle of buying

NILOY KANTI PAUL 5 Oct 8, 2022
Provide blocks which allow positioning content within them in layouts.

Mini layouts Provide blocks which allow positioning content within them in layouts. Backdrop Installation Install and enable the module as usual. Go t

Backdrop CMS contributed projects 5 Dec 17, 2021
Uses internet-connectable temperature sensors to provide cooling/heating assist for small buildings, as well as weather data

ambient-hvac Uses internet-connectable temperature sensors to provide cooling/heating assist for houses and other small buildings, as well as weather

null 3 Nov 25, 2021
Secure package for WP CLI, built to provide an easier way of securing your WordPress installation

wp-cli/secure-command Official website: Hackthewp.com Manages common security aspects of WordPress. Supports nginx and Apache. Basic Usage This packag

Igor Hrcek 68 Dec 27, 2022
Strings Package provide a fluent, object-oriented interface for working with multibyte string

Strings Package provide a fluent, object-oriented interface for working with multibyte string, allowing you to chain multiple string operations together using a more readable syntax compared to traditional PHP strings functions.

Glowy PHP 14 Mar 12, 2022
Provide CSV, JSON, XML and YAML files as an Import Source for the Icinga Director and optionally ship hand-crafted additional Icinga2 config files

Icinga Web 2 Fileshipper module The main purpose of this module is to extend Icinga Director using some of it's exported hooks. Based on them it offer

Icinga 25 Sep 18, 2022
Result of our code-along meetup writing PHP 8.1 code

PHP 8.1 Demo Code This code demonstrates various PHP 8.0 and 8.1 features in a realistic, functional (but incomplete) codebase. The code is part of so

azPHP 2 Nov 14, 2021
Dead Code Detector (DCD) for PHP code.

This project is no longer maintained and its repository is only kept for archival purposes. PHP Dead Code Detector (PHPDCD) phpdcd is a Dead Code Dete

Sebastian Bergmann 406 Dec 30, 2022
⚗️ Adds code analysis to Laravel improving developer productivity and code quality.

⚗️ About Larastan Larastan was created by Can Vural and Nuno Maduro, got artwork designed by @Caneco, is maintained by Can Vural, Nuno Maduro, and Vik

Nuno Maduro 4.4k Jan 4, 2023
Free ZIP Code API - Free Access to Worldwide Postal Code Data

About Zipcodebase - Free Zip Code API Zipcodebase is a zip code API that was founded in 2019 to solve common issues with postal code data. As we have

SaaS Industries 2 Nov 26, 2022
Preload your sweet sweet code to opcache with a composer command, making your code faster to run.

Composer Preload Preload your sweet sweet code to opcache with a composer command, making your code run faster. Composer Preload is a composer plugin

Ayesh Karunaratne 197 Dec 6, 2022
The SensioLabs DeprecationDetector runs a static code analysis against your project's source code to find usages of deprecated methods, classes and interfaces

SensioLabs DeprecationDetector CAUTION: This package is abandoned and will no longer receive any updates. The SensioLabs DeprecationDetector runs a st

QOSSMIC GmbH 389 Nov 24, 2022