diff options
Diffstat (limited to 'phpBB/phpbb/lock')
| -rw-r--r-- | phpBB/phpbb/lock/db.php | 146 | ||||
| -rw-r--r-- | phpBB/phpbb/lock/flock.php | 141 | 
2 files changed, 287 insertions, 0 deletions
| diff --git a/phpBB/phpbb/lock/db.php b/phpBB/phpbb/lock/db.php new file mode 100644 index 0000000000..85ba9a7aa3 --- /dev/null +++ b/phpBB/phpbb/lock/db.php @@ -0,0 +1,146 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\lock; + +/** +* Database locking class +*/ +class db +{ +	/** +	* Name of the config variable this lock uses +	* @var string +	*/ +	private $config_name; + +	/** +	* Unique identifier for this lock. +	* +	* @var string +	*/ +	private $unique_id; + +	/** +	* Stores the state of this lock +	* @var bool +	*/ +	private $locked; + +	/** +	* The phpBB configuration +	* @var \phpbb\config\config +	*/ +	private $config; + +	/** +	* A database connection +	* @var \phpbb\db\driver\driver_interface +	*/ +	private $db; + +	/** +	* Creates a named released instance of the lock. +	* +	* You have to call acquire() to actually create the lock. +	* +	* @param	string								$config_name	A config variable to be used for locking +	* @param	\phpbb\config\config				$config			The phpBB configuration +	* @param	\phpbb\db\driver\driver_interface	$db				A database connection +	*/ +	public function __construct($config_name, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db) +	{ +		$this->config_name = $config_name; +		$this->config = $config; +		$this->db = $db; +	} + +	/** +	* Tries to acquire the lock by updating +	* the configuration variable in the database. +	* +	* As a lock may only be held by one process at a time, lock +	* acquisition may fail if another process is holding the lock +	* or if another process obtained the lock but never released it. +	* Locks are forcibly released after a timeout of 1 hour. +	* +	* @return	bool			true if lock was acquired +	*							false otherwise +	*/ +	public function acquire() +	{ +		if ($this->locked) +		{ +			return false; +		} + +		if (!isset($this->config[$this->config_name])) +		{ +			$this->config->set($this->config_name, '0', false); +		} +		$lock_value = $this->config[$this->config_name]; + +		// make sure lock cannot be acquired by multiple processes +		if ($lock_value) +		{ +			// if the other process is running more than an hour already we have to assume it +			// aborted without cleaning the lock +			$time = explode(' ', $lock_value); +			$time = $time[0]; + +			if ($time + 3600 >= time()) +			{ +				return false; +			} +		} + +		$this->unique_id = time() . ' ' . unique_id(); + +		// try to update the config value, if it was already modified by another +		// process we failed to acquire the lock. +		$this->locked = $this->config->set_atomic($this->config_name, $lock_value, $this->unique_id, false); + +		return $this->locked; +	} + +	/** +	* Does this process own the lock? +	* +	* @return	bool			true if lock is owned +	*							false otherwise +	*/ +	public function owns_lock() +	{ +		return (bool) $this->locked; +	} + +	/** +	* Releases the lock. +	* +	* The lock must have been previously obtained, that is, acquire() call +	* was issued and returned true. +	* +	* Note: Attempting to release a lock that is already released, +	* that is, calling release() multiple times, is harmless. +	* +	* @return null +	*/ +	public function release() +	{ +		if ($this->locked) +		{ +			$this->config->set_atomic($this->config_name, $this->unique_id, '0', false); +			$this->locked = false; +		} +	} +} diff --git a/phpBB/phpbb/lock/flock.php b/phpBB/phpbb/lock/flock.php new file mode 100644 index 0000000000..df88e1490a --- /dev/null +++ b/phpBB/phpbb/lock/flock.php @@ -0,0 +1,141 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\lock; + +/** +* File locking class +*/ +class flock +{ +	/** +	* Path to the file to which access is controlled +	* +	* @var string +	*/ +	private $path; + +	/** +	* File pointer for the lock file +	* @var string +	*/ +	private $lock_fp; + +	/** +	* Constructor. +	* +	* You have to call acquire() to actually acquire the lock. +	* +	* @param	string	$path	Path to the file to which access is controlled +	*/ +	public function __construct($path) +	{ +		$this->path = $path; +		$this->lock_fp = null; +	} + +	/** +	* Tries to acquire the lock. +	* +	* If the lock is already held by another process, this call will block +	* until the other process releases the lock. If a lock is acquired and +	* is not released before script finishes but the process continues to +	* live (apache/fastcgi) then subsequent processes trying to acquire +	* the same lock will be blocked forever. +	* +	* If the lock is already held by the same process via another instance +	* of this class, this call will block forever. +	* +	* If flock function is disabled in php or fails to work, lock +	* acquisition will fail and false will be returned. +	* +	* @return	bool			true if lock was acquired +	*							false otherwise +	*/ +	public function acquire() +	{ +		if ($this->lock_fp) +		{ +			return false; +		} + +		// For systems that can't have two processes opening +		// one file for writing simultaneously +		if (file_exists($this->path . '.lock')) +		{ +			$mode = 'rb'; +		} +		else +		{ +			$mode = 'wb'; +		} + +		$this->lock_fp = @fopen($this->path . '.lock', $mode); + +		if ($mode == 'wb') +		{ +			if (!$this->lock_fp) +			{ +				// Two processes may attempt to create lock file at the same time. +				// Have the losing process try opening the lock file again for reading +				// on the assumption that the winning process created it +				$mode = 'rb'; +				$this->lock_fp = @fopen($this->path . '.lock', $mode); +			} +			else +			{ +				// Only need to set mode when the lock file is written +				@chmod($this->path . '.lock', 0666); +			} +		} + +		if ($this->lock_fp) +		{ +			@flock($this->lock_fp, LOCK_EX); +		} + +		return (bool) $this->lock_fp; +	} + +	/** +	* Does this process own the lock? +	* +	* @return	bool			true if lock is owned +	*							false otherwise +	*/ +	public function owns_lock() +	{ +		return (bool) $this->lock_fp; +	} + +	/** +	* Releases the lock. +	* +	* The lock must have been previously obtained, that is, acquire() call +	* was issued and returned true. +	* +	* Note: Attempting to release a lock that is already released, +	* that is, calling release() multiple times, is harmless. +	* +	* @return null +	*/ +	public function release() +	{ +		if ($this->lock_fp) +		{ +			@flock($this->lock_fp, LOCK_UN); +			fclose($this->lock_fp); +			$this->lock_fp = null; +		} +	} +} | 
