У меня есть сервер macOS с небольшим сайтом, который преобразует фрагменты текста в аудио, используя команду say
.
С обновлением до Sierra все прошло гладко, за исключением одного: команда say
больше не работает при завершении в exec()
в моем PHP-скрипте.
Страница просто разрывается. Ошибка не обнаружена.
<?php try { exec('/usr/bin/say "hello"'); } catch (Exception $e) { echo $e->getMessage(); } ?>
Обычно я хотел бы сохранить звуковые фрагменты с say -o filename
но я попробовал все варианты, а также другие команды оболочки, которые отлично работали, включая создание файлов в моей выходной папке.
Интересно, что если я запускаю его из командной строки, он работает – либо громко говорит, либо создает выходной файл.
macOS Sierra имеет PHP 5.6.24, поэтому я не думаю, что safe_mode применяется, righht?
Я хотел бы подчеркнуть, что изменение в команде PHP или say было довольно недавним, с новой ОС. Да, я просмотрел и попробовал разные выходные данные и перенаправление stderr, но скрипт просто зависает.
Увидев команду say
в Activity Viewer (GUI для top
эквивалента), я попытался ее пробовать, не уверен, что это помогает:
2695 Thread_1742595 DispatchQueue_1: com.apple.main-thread (serial) + 2695 start (in libdyld.dylib) + 1 [0x7fffb0f58255] + 2695 ??? (in say) load address 0x10907d000 + 0x1fac [0x10907efac] + 2695 NewSpeechChannel (in SpeechSynthesis) + 52 [0x7fff9acd3f19] + 2695 SpeechChannelHandle::SpeechChannelHandle() (in SpeechSynthesis) + 265 [0x7fff9acd797f] + 2695 dispatch_once_f (in libdispatch.dylib) + 38 [0x7fffb0f220e5] + 2695 _dispatch_client_callout (in libdispatch.dylib) + 8 [0x7fffb0f22128] + 2695 ___ZN13SpeechGlobals8InstanceEv_block_invoke (in SpeechSynthesis) + 28 [0x7fff9acd54da] + 2695 SpeechGlobals::SpeechGlobals() (in SpeechSynthesis) + 471 [0x7fff9acd56db] + 2695 xpc_connection_send_message_with_reply_sync (in libxpc.dylib) + 154 [0x7fffb11b65a8] + 2695 dispatch_mach_send_with_result_and_wait_for_reply (in libdispatch.dylib) + 45 [0x7fffb0f3cf39] + 2695 _dispatch_mach_send_and_wait_for_reply (in libdispatch.dylib) + 591 [0x7fffb0f3cad4] + 2695 mach_msg (in libsystem_kernel.dylib) + 55 [0x7fffb107e867] + 2695 mach_msg_trap (in libsystem_kernel.dylib) + 10 [0x7fffb107f41a] 2695 Thread_1742600 2695 start_wqthread (in libsystem_pthread.dylib) + 13 [0x7fffb116f211] 2695 _pthread_wqthread (in libsystem_pthread.dylib) + 1426 [0x7fffb116f7b5] 2695 __workq_kernreturn (in libsystem_kernel.dylib) + 10 [0x7fffb10874e6]
Это статистика:
И из открытых файлов и портов я мог видеть, что я устанавливаю как stdout
и stderr
в /private/var/log/apache2/error_log
но пока ничего не отображается.
Кроме того, попытался захватить результаты с более сложным прогоном, но без радости, просто тайм-аут (папка сценария также доступна для записи):
<?php try { $pipes = array(); proc_close(proc_open("say hi", array(0 => array("pipe", "r"), 1 => array("pipe", "r"), 2 => array("pipe", "r")), $pipes, dirname(__FILE__), null)); } catch (Exception $e) { error_log($e->getMessage()); } ?>
ОБНОВЛЕНИЕ: Высокая Сьерра – то же самое.
Я тоже испытал эту же проблему.
Вот обход, который я только что придумал, но, честно говоря, я думаю, что это БОЛЬШАЯ МССА, чтобы иметь возможность воспроизводить аудио с php-скрипта на основе apache. У меня есть некоторые идеи о том, почему это может произойти, но при МНОГИХ тестах я, кажется, уничтожаю свои собственные теории. Я думал, что это могло быть связано с отсутствием активного TTY. Я не смог воспроизвести звук, запустив оболочку с помощью sudo -i
и MANY MANY других attmepts от php, но я смог воспроизводить звук, используя все те же команды из локального терминала, и, как выясняется, также SSH «в компьютер, так что это привело к моей последней работе. Еще раз, я думаю, что это WAY overkill, но до сих пор это единственный способ, которым я смог вернуть аудио в свои веб-скрипты, основанные на php (в основном связанные с географом).
Итак, здесь мы идем, и да, я понимаю, что риски и глупость связаны с этим:
В моем php-скрипте я создаю аудиофайл в каталоге / tmp с помощью команды, подобной этой:
exec "sudo -u <username> /usr/bin/say -o /tmp/outputfile.aiff --voice=Ava \"<What to Say>\"";
Затем, после того как звуковой файл сгенерирован, единственный способ, который я нашел, чтобы воспроизвести его (и фактически услышать вывод) из apache / php, – это использовать сценарий ожидания для ssh локально и воспроизвести его. Итак, моя следующая строка:
exec "sudo -u <username> -i ~<username>/expectscript";
Мой сценарий ожидания выглядит следующим образом:
#!/usr/bin/expect -f spawn /usr/bin/ssh localhost expect "Password" send "<PASSWORD>\r" expect "<username>" send "/usr/bin/afplay /tmp/outputfile.aiff\r" expect "<username>" send "/usr/bin/touch /tmp/touchthis\r" expect "<username>" send "exit\r"
Убедитесь, что вы заменили все <username>
выше на ваше имя пользователя (без <>, очевидно,) и <PASSWORD>
с вашим паролем. Возможно, вам придется настроить сценарий ожидания, если ваши подсказки bash не содержат ваше имя пользователя, так как это то, что я использовал в сценарии ожидания, чтобы найти возвращаемое приглашение. Прикосновение – это просто определить, что сценарий ожидания работал, и у вас есть ссылка на последний раз, когда был затронут файл.
Надеюсь, это откроет дискуссию о том, что на самом деле вызывает это, и мы можем определить более разумное решение. Я спустил много кроличьих отверстий, пытаясь найти разные способы заставить это работать, я создал приложения Automator и вызвал их из PHP (не работал). Я запустил оболочки в оболочках как мой пользователь, все выполнение команд всегда завершено успешно, просто нет аудиовыхода. Все решения, которые я пробовал, отлично работают с терминалом (и даже с php с терминала), а не с Apache / PHP.
У меня возникла такая же проблема, когда я использовал команду say
на моей работе Jenkins. Мой сервер Jenkins работает как демон на macOS Sierra.
В моем случае я решил эту проблему следующим образом:
jenkins
и сгенерируйте ключ ssh-keygen
с помощью ssh-keygen
. Добавить ~/.ssh/id_rsa.pub
в .ssh/authorized-keys
чтобы пароль не запрашивался.
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized-keys
Измените мою работу Jenkins, которая использует команду say
следующим образом:
ssh localhost say -v Alex "Test"
Извините, я не тестировал Apache / PHP, но почему бы вам не попробовать так:
<?php try { exec('/usr/bin/ssh localhost /usr/bin/say "hello"'); } catch (Exception $e) { echo $e->getMessage(); } ?>