ExiftoolServer.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <?php
  2. /**
  3. * This file is part of the PHPExiftool package.
  4. *
  5. * (c) Alchemy <support@alchemy.fr>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace PHPExiftool;
  11. use PHPExiftool\Exception\RuntimeException;
  12. use Symfony\Component\Process\Process;
  13. class ExiftoolServer extends Exiftool
  14. {
  15. private $pipefile;
  16. private $server;
  17. private $offset = 0;
  18. public function __construct()
  19. {
  20. $this->setUp();
  21. }
  22. public function __destruct()
  23. {
  24. $this->cleanup();
  25. }
  26. public function reset()
  27. {
  28. $this->cleanup();
  29. $this->setUp();
  30. }
  31. public function start()
  32. {
  33. $this->server->start();
  34. }
  35. public function stop()
  36. {
  37. if ($this->isRunning()) {
  38. file_put_contents($this->pipefile, "-stay_open False\n", FILE_APPEND);
  39. }
  40. $this->server->stop();
  41. }
  42. public function isRunning()
  43. {
  44. return null !== $this->server && $this->server->isRunning();
  45. }
  46. public function executeCommand($commands, $timeout = 4)
  47. {
  48. $optwithargs = array('-i', '-charset', '-if', '-w', '-common_args');
  49. if (true !== $this->isRunning()) {
  50. throw new RuntimeException('Server is not running');
  51. }
  52. $prev = null;
  53. // // first split execute (sub queries)
  54. //
  55. // if (false !== $pos = strpos($commands, '-common_args')) {
  56. // $common_args = substr($commands, $pos + 12);
  57. //
  58. // $recomposed = array();
  59. //
  60. // foreach (explode(' -execute ', substr($commands, 0, $pos)) as $subcommand) {
  61. // $recomposed[] = $subcommand . ' ' . $common_args;
  62. // }
  63. // $commands = implode(' -execute ', $recomposed);
  64. // }
  65. foreach (explode(' ', $commands) as $command) {
  66. if ($command == '-q') {
  67. continue;
  68. }
  69. if (substr($command, 0, 1) === "'" && substr($command, -1) === "'") {
  70. $command = substr($command, 1, -1);
  71. }
  72. if (substr($command, 0, 1) === '"' && substr($command, -1) === '"') {
  73. $command = substr($command, 1, -1);
  74. }
  75. $end = "\n";
  76. file_put_contents($this->pipefile, $command . $end, FILE_APPEND);
  77. }
  78. file_put_contents($this->pipefile, "\n-execute\n", FILE_APPEND);
  79. // here we send sigcont
  80. //$this->server->signal(SIGCONT);
  81. $start = microtime(true);
  82. while ((strlen($this->server->getOutput()) <= $this->offset || substr(substr($this->server->getOutput(), $this->offset), -8) !== "{ready}\n") && (microtime(true) - $start) < $timeout) {
  83. usleep(25000);
  84. }
  85. // var_dump(microtime(true) - $start);
  86. // server output should be cached here because streams are polled
  87. // everytime I request the output
  88. $outputIsValid = substr($this->server->getOutput(), -8) === "{ready}\n";
  89. $output = $outputIsValid ? substr($this->server->getOutput(), $this->offset, -8) : '';
  90. $this->offset = strlen($this->server->getOutput());
  91. if (trim($output) === '' && $outputIsValid === false && $this->server->getErrorOutput()) {
  92. throw new RuntimeException('Command failed');
  93. }
  94. return $output;
  95. }
  96. private function setUp()
  97. {
  98. $this->pipefile = tempnam(sys_get_temp_dir(), 'exiftool-pipe');
  99. $this->server = new Process(self::getBinary() . ' -stay_open True -@ ' . $this->pipefile);
  100. }
  101. private function cleanup()
  102. {
  103. $this->stop();
  104. if (file_exists($this->pipefile) && is_writable($this->pipefile)) {
  105. unlink($this->pipefile);
  106. $this->pipefile = null;
  107. }
  108. $this->server = null;
  109. }
  110. }