У меня есть MacOS-сервер с небольшим сайтом, который преобразует текстовые фрагменты в аудио, используя say
команда.
С обновлением до Сьерры все прошло гладко, кроме одного: 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 применяется, верно?
Я хотел бы подчеркнуть, что изменения в PHP или команде say были относительно недавними, с новой ОС. Да, я посмотрел и попробовал другой вывод и перенаправление stderr, но скрипт просто зависает.
Видя say
команда в Activity Viewer (графический интерфейс для 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()); }
?>
ОБНОВЛЕНИЕ: Высокая Сьерра — то же самое.
ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ: после установки Mojave, которая удаляет большинство функций Server.app, я добавил MAMP для решения этой задачи. Услышьте это для себя, если вы хотите — это в macspeaks.com.
Я тоже испытал эту же проблему.
Вот обходной путь, который я только что придумал, но, честно говоря, я думаю, что это БОЛЬШОЙ СООБЩЕНИЕ, чтобы иметь возможность проигрывать аудио из php-скрипта на основе apache. У меня есть некоторые идеи о том, почему это может происходить, но после многих испытаний я, кажется, разрушаю свои собственные теории. Я думал, что это может быть связано с отсутствием активного TTY. Я не смог воспроизвести звук, запустив оболочку с sudo -i
и МНОГИЕ МНОГИЕ другие attmepts из php, но я смог воспроизвести аудио, используя все те же команды с локального терминала, и, как оказалось, также через SSH в компьютер, так что это привело к моему последнему обходному пути , Еще раз, я думаю, что это WAY излишнее, но пока это единственный способ, которым я смог вернуть аудио в мои скрипты, основанные на 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 работает как демон на macOS Sierra.
В моем случае я решил эту проблему следующим образом:
jenkins
пользователь и сгенерируйте ключ ssh с ssh-keygen
,присоединять ~/.ssh/id_rsa.pub
в .ssh/authorized-keys
так что пароль не будет запрошен.
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized-keys
Измени мою работу Дженкинс, которая использует 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(); }
?>