Browse Source

lock:wait command

Guillermo Espinoza 8 years ago
parent
commit
0fbd8ea918
1 changed files with 125 additions and 0 deletions
  1. 125 0
      Command/LockWaitCommand.php

+ 125 - 0
Command/LockWaitCommand.php

@@ -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;
+    }
+
+}