Created
December 8, 2011 12:54
-
-
Save koyhoge/1446922 to your computer and use it in GitHub Desktop.
single_exection patched by koyhoge
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ | |
// created by bto | |
// via http://blog.bz2.jp/archives/2008/05/1php.html | |
// http://blog.bz2.jp/archives/2008/05/singleexecution.html | |
class singleExecution | |
{ | |
var $key = null; | |
var $options = array( | |
'begin' => true, | |
'lock_directory' => null, | |
'checks_process_existence' => true, | |
'do_unlock' => true, | |
); | |
function singleExecution($options = array()) | |
{ | |
$this->options['lock_directory'] = $this->createPath( | |
$this->temporaryDirectory(), $this->underscore(__CLASS__)); | |
$this->options = array_merge($this->options, $options); | |
if ($this->options['begin']) { | |
$this->lock(); | |
} | |
} | |
function setDoUnlock($val = true) { | |
$this->options['do_unlock'] = $val; | |
} | |
function createKey() | |
{ | |
foreach (debug_backtrace() as $stack) { | |
if ($stack['file'] !== __FILE__) { | |
return $stack['file'] . ':' . $stack['line']; | |
} | |
} | |
return __FILE__ . ':' . __LINE__; | |
} | |
function createPath() | |
{ | |
return join(func_get_args(), DIRECTORY_SEPARATOR); | |
} | |
function failed() | |
{ | |
exit(); | |
} | |
function isInvalidLock($directory) | |
{ | |
if (!file_exists($directory)) { | |
return true; | |
} | |
if (!is_dir($directory)) { | |
return false; | |
} | |
$pid_file = $this->createPath($directory, 'pid'); | |
if (!is_file($pid_file)) { | |
return false; | |
} | |
if (!$this->options['checks_process_existence']) { | |
return true; | |
} | |
return $this->processExists(intval(file_get_contents($pid_file))); | |
} | |
function lock($key = null) | |
{ | |
if (!$key) { | |
$key = $this->createKey(); | |
} | |
$this->unlockIfInvalid($key); | |
$lock_directory = $this->lockDirectory($key); | |
if (!$this->mkdir($lock_directory)) { | |
return $this->failed(); | |
} | |
if (singleExecution::loadExtension('pcntl')) { | |
$this->key = $key; | |
pcntl_signal(SIGTERM, array($this, 'unlockExit')); | |
pcntl_signal(SIGHUP, array($this, 'unlockExit')); | |
} | |
register_shutdown_function(array($this, 'unlock'), $key); | |
$this->registerPid($lock_directory); | |
return $this->succeeded(); | |
} | |
function lockDirectory($key) | |
{ | |
return $this->createPath( | |
$this->options['lock_directory'], urlencode($key)); | |
} | |
function mkdir($directory) | |
{ | |
$parent = dirname($directory); | |
if ($parent === $directory) { | |
return true; | |
} | |
$this->mkdir(dirname($directory)); | |
return @mkdir($directory); | |
} | |
function processExists($pid) | |
{ | |
if ($this->loadExtension('posix')) { | |
return posix_kill($pid, 0); | |
} else if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { | |
return intval(exec(sprintf( | |
'tasklist /nh /fi "PID eq %s" 2>nul | find /C "%s"', | |
$pid, $pid))); | |
} else { | |
return intval(exec("ps -e|grep '^ *{$pid} '")); | |
} | |
} | |
function registerPid($directory) | |
{ | |
$fp = fopen($this->createPath($directory, 'pid'), 'a'); | |
if (!$fp) { | |
return false; | |
} | |
fwrite($fp, getmypid()); | |
fclose($fp); | |
return true; | |
} | |
function succeeded() | |
{ | |
return true; | |
} | |
function temporaryDirectory() | |
{ | |
if (function_exists('sys_get_temp_dir')) { | |
return sys_get_temp_dir(); | |
} else if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { | |
return $this->createPath('c:', 'temp'); | |
} else { | |
return $this->createPath('', 'tmp'); | |
} | |
} | |
function underscore($string) | |
{ | |
return strtolower(preg_replace('/([A-Z])/', '_\1', $string)); | |
} | |
function unlinkAll($file) | |
{ | |
if (!is_dir($file)) { | |
return unlink($file); | |
} | |
$d = dir($file); | |
while ($entry = $d->read()) { | |
if ($entry === '.' || $entry === '..') { | |
continue; | |
} | |
$this->unlinkAll($this->createPath($d->path, $entry)); | |
} | |
$d->close(); | |
return rmdir($file); | |
} | |
function unlock($key) | |
{ | |
if ($this->options['do_unlock']) { | |
return $this->unlinkAll($this->lockDirectory($key)); | |
} | |
} | |
function unlockExit($signo) | |
{ | |
$this->unlock($this->key); | |
exit; | |
} | |
function unlockIfInvalid($key) | |
{ | |
$common_key = 'common'; | |
// spin lock - failed if cannot locked in 2 sec | |
$common_lock = $this->lockDirectory($common_key); | |
for ($i = 0; $i < 200; ++$i) { | |
if ($this->mkdir($common_lock)) { | |
break; | |
} | |
usleep(10000); | |
} | |
if (!is_dir($common_lock)) { | |
$this->failed(); | |
} | |
// critical section | |
if (!$this->isInvalidLock($this->lockDirectory($key))) { | |
$this->unlock($key); | |
} | |
// unlock | |
$this->unlock($common_key); | |
} | |
/* | |
* static methods | |
*/ | |
function loadExtension($extension) | |
{ | |
if (extension_loaded($extension)) { | |
return true; | |
} | |
if (defined('PHP_SHLIB_SUFFIX')) { | |
$suffix = PHP_SHLIB_SUFFIX; | |
} else if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { | |
$suffix = 'dll'; | |
} else { | |
$suffix = 'so'; | |
} | |
$prefix = $suffix === 'dll' ? 'php_' : ''; | |
$libraries = array("{$prefix}{$extension}.{$suffix}"); | |
$libraries[] = "{$extension}.so"; | |
$libraries[] = "php_{$extension}.dll"; | |
$libraries = array_unique($libraries); | |
foreach ($libraries as $library) { | |
if (@dl($library)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment