setName('lock:wait')
->setDescription('Lock wait command')
->setHelp('Lock wait command. Wait for lock a file. The lock can be either exclusive or shared')
->addArgument(
'filename',
InputOption::VALUE_REQUIRED,
'Filename'
)
->addOption(
'dir',
null,
InputOption::VALUE_REQUIRED,
'Directory path file',
'/tmp'
)
->addOption(
'timeout',
null,
InputOption::VALUE_REQUIRED,
'Timeout execution (ms)',
600
)
->addOption(
'no-exclusive',
'no-e',
InputOption::VALUE_NONE,
'No exclusive lock'
)
;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$filename = $input->getArgument('filename');
$dir = $input->getOption('dir');
$timeout = $input->getOption('timeout');
$no_exclusive = $input->getOption('no-exclusive');
if ($filename) {
$handle = $this->fopen($filename, $dir);
if ($this->flock($handle, $timeout, $no_exclusive)) {
$output->writeln('OK');
}
} else {
$output->writeln('Enter a valid filename');
}
}
/**
* @param string $filename
* @param string $dir
*
* @return resource
*/
protected function fopen($filename, $dir)
{
// limpio el filename completo
$invalid_chars = array(" ", '"', "'", "&", "\\", "?", "#", "$", "//");
$delimiter = DIRECTORY_SEPARATOR;
$dir_pieces = explode($delimiter, str_replace($invalid_chars, '', $dir));
$filename_pieces = explode($delimiter, str_replace($invalid_chars, '', $filename));
$last_filename_piece = array_pop($filename_pieces);
$dir = $delimiter . implode($delimiter, array_filter(array_merge($dir_pieces, $filename_pieces)));
$filename = $dir . $delimiter . $last_filename_piece;
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
}
return fopen($filename, "w+");
}
/**
* @param resource $handle
* @param int $timeout
* @param boolean $no_exclusive
*
* @throws \Exception
*/
protected function flock($handle, $timeout = 600, $no_exclusive = false)
{
pcntl_signal(SIGALRM, function() {
exit(1);
});
pcntl_alarm($timeout);
try {
$operation = LOCK_EX;
if ($no_exclusive) {
$operation = LOCK_SH;
}
if (!flock($handle, $operation)) {
throw new \Exception("Timeout");
}
} finally {
pcntl_alarm(0);
pcntl_signal_dispatch();
pcntl_signal(SIGALRM, SIG_DFL);
}
flock($handle, LOCK_UN);
fclose($handle);
return true;
}
}