LockWaitCommand.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. namespace WorkflowBundle\Command;
  3. use Symfony\Component\Console\Command\Command;
  4. use Symfony\Component\Console\Input\InputInterface;
  5. use Symfony\Component\Console\Input\InputOption;
  6. use Symfony\Component\Console\Output\OutputInterface;
  7. class LockWaitCommand extends Command
  8. {
  9. protected function configure()
  10. {
  11. $this
  12. ->setName('lock:wait')
  13. ->setDescription('Lock wait command')
  14. ->setHelp('Lock wait command. Wait for lock a file. The lock can be either exclusive or shared')
  15. ->addArgument(
  16. 'filename',
  17. InputOption::VALUE_REQUIRED,
  18. 'Filename'
  19. )
  20. ->addOption(
  21. 'dir',
  22. null,
  23. InputOption::VALUE_REQUIRED,
  24. 'Directory path file',
  25. '/tmp'
  26. )
  27. ->addOption(
  28. 'timeout',
  29. null,
  30. InputOption::VALUE_REQUIRED,
  31. 'Timeout execution (ms)',
  32. 600
  33. )
  34. ->addOption(
  35. 'no-exclusive',
  36. 'no-e',
  37. InputOption::VALUE_NONE,
  38. 'No exclusive lock'
  39. )
  40. ;
  41. }
  42. /**
  43. * @param InputInterface $input
  44. * @param OutputInterface $output
  45. */
  46. protected function execute(InputInterface $input, OutputInterface $output)
  47. {
  48. $filename = $input->getArgument('filename');
  49. $dir = $input->getOption('dir');
  50. $timeout = $input->getOption('timeout');
  51. $no_exclusive = $input->getOption('no-exclusive');
  52. if ($filename) {
  53. $handle = $this->fopen($filename, $dir);
  54. if ($this->flock($handle, $timeout, $no_exclusive)) {
  55. $output->writeln('<info>OK</info>');
  56. }
  57. } else {
  58. $output->writeln('<error>Enter a valid filename</error>');
  59. }
  60. }
  61. /**
  62. * @param string $filename
  63. * @param string $dir
  64. *
  65. * @return resource
  66. */
  67. protected function fopen($filename, $dir)
  68. {
  69. // limpio el filename completo
  70. $invalid_chars = array(" ", '"', "'", "&", "\\", "?", "#", "$", "//");
  71. $delimiter = DIRECTORY_SEPARATOR;
  72. $dir_pieces = explode($delimiter, str_replace($invalid_chars, '', $dir));
  73. $filename_pieces = explode($delimiter, str_replace($invalid_chars, '', $filename));
  74. $last_filename_piece = array_pop($filename_pieces);
  75. $dir = $delimiter . implode($delimiter, array_filter(array_merge($dir_pieces, $filename_pieces)));
  76. $filename = $dir . $delimiter . $last_filename_piece;
  77. if (!file_exists($dir)) {
  78. mkdir($dir, 0777, true);
  79. }
  80. return fopen($filename, "w+");
  81. }
  82. /**
  83. * @param resource $handle
  84. * @param int $timeout
  85. * @param boolean $no_exclusive
  86. *
  87. * @throws \Exception
  88. */
  89. protected function flock($handle, $timeout = 600, $no_exclusive = false)
  90. {
  91. pcntl_signal(SIGALRM, function() {
  92. exit(1);
  93. });
  94. pcntl_alarm($timeout);
  95. try {
  96. $operation = LOCK_EX;
  97. if ($no_exclusive) {
  98. $operation = LOCK_SH;
  99. }
  100. if (!flock($handle, $operation)) {
  101. throw new \Exception("Timeout");
  102. }
  103. } finally {
  104. pcntl_alarm(0);
  105. pcntl_signal_dispatch();
  106. pcntl_signal(SIGALRM, SIG_DFL);
  107. }
  108. flock($handle, LOCK_UN);
  109. fclose($handle);
  110. return true;
  111. }
  112. }