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