|
@@ -0,0 +1,125 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace WorkflowBundle\Command;
|
|
|
+
|
|
|
+use Symfony\Component\Console\Command\Command;
|
|
|
+use Symfony\Component\Console\Input\InputInterface;
|
|
|
+use Symfony\Component\Console\Input\InputOption;
|
|
|
+use Symfony\Component\Console\Output\OutputInterface;
|
|
|
+
|
|
|
+class LockWaitCommand extends Command
|
|
|
+{
|
|
|
+
|
|
|
+ protected function configure()
|
|
|
+ {
|
|
|
+ $this
|
|
|
+ ->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('<info>OK</info>');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $output->writeln('<error>Enter a valid filename</error>');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @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;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|