AsyncConsole.php 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. <?php
  2. namespace common\components;
  3. use Yii;
  4. class AsyncConsole
  5. {
  6. /**
  7. * Start a detached Yii console command.
  8. *
  9. * @param array $arguments Command route followed by positional arguments.
  10. * @param string $logName
  11. * @return bool
  12. */
  13. public static function run(array $arguments, $logName = 'async-console.log')
  14. {
  15. if (empty($arguments)) {
  16. Yii::warning('Unable to start async console command: command arguments are empty');
  17. return false;
  18. }
  19. if (!self::canExec()) {
  20. Yii::warning('Unable to start async console command: exec is disabled');
  21. return false;
  22. }
  23. $phpBinary = getenv('PHP_CLI_BINARY') ?: '/usr/local/bin/php';
  24. $yii = dirname(Yii::getAlias('@console')) . '/yii';
  25. if (!is_file($phpBinary) || !is_executable($phpBinary)) {
  26. Yii::warning('Unable to start async console command: invalid PHP_CLI_BINARY ' . $phpBinary);
  27. return false;
  28. }
  29. if (!is_file($yii) || !is_executable($yii)) {
  30. Yii::warning('Unable to start async console command: yii entrypoint is not executable ' . $yii);
  31. return false;
  32. }
  33. $logName = basename($logName);
  34. $logFile = Yii::getAlias('@console/runtime/logs') . '/' . $logName;
  35. $escapedArguments = array_map(function ($argument) {
  36. return escapeshellarg((string)$argument);
  37. }, $arguments);
  38. $command = 'nohup '
  39. . escapeshellarg($phpBinary) . ' '
  40. . escapeshellarg($yii) . ' '
  41. . implode(' ', $escapedArguments)
  42. . ' >> ' . escapeshellarg($logFile)
  43. . ' 2>&1 < /dev/null &';
  44. $output = [];
  45. $exitCode = 0;
  46. exec($command, $output, $exitCode);
  47. if ($exitCode !== 0) {
  48. Yii::warning('Unable to start async console command, exit code: ' . $exitCode);
  49. return false;
  50. }
  51. return true;
  52. }
  53. private static function canExec()
  54. {
  55. if (!is_callable('exec')) {
  56. return false;
  57. }
  58. $disabled = array_filter(array_map('trim', explode(',', (string)ini_get('disable_functions'))));
  59. return !in_array('exec', $disabled, true);
  60. }
  61. }