问题
I have a macOS server with a little site which converts text snippets to audio using say
command.
With upgrade to Sierra, everything went smooth except one thing: the say
command doesn't work any more when wrapped in exec()
in my PHP script.
The page just times out. No error is caught either.
<?php
try {
exec('/usr/bin/say "hello"');
}
catch (Exception $e) { echo $e->getMessage(); }
?>
Typically I would save the audio snippets with say -o filename
but I tried all the variants and also other shell commands which worked fine including creating files in my output folder.
Interesting is that if I run it from a command line, it works - either says it loud or creates an output file.
macOS Sierra has PHP 5.6.24 so I don't think safe_mode applies, righht?
I would like to emphasise that the change in either PHP or say command was quite recent, with the new OS. Yes I did look into and tried different output and stderr redirection but the script just hangs.
Seeing the say
command in Activity Viewer (GUI for top
equivalent), I tried to sample it, not sure if it helps:
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]
These are statistics:
And from open files and ports, I could see that I set both stdout
and stderr
to /private/var/log/apache2/error_log
yet nothing shows there at all.
Also, tried to capture outputs with more elaborate run, but no joy, just timeout (the script folder is also writable):
<?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()); }
?>
UPDATE: High Sierra is the same.
FINAL UPDATE: after installing Mojave, which removes most of the Server.app features, I added MAMP to handle this task. Hear it for yourselves if you wish - it's at macspeaks.com.
THE STORY CONTINUES: somehow during the install of Catalina, or was it MAMP update? (now on 5.5), I killed it again. Sigh...
回答1:
I too have experienced this same problem.
Here is a work-around that I just came up with, but honestly I think it's a BIG MESS just to be able to play audio from an apache based php script. I have some ideas on why this might be happening, but upon MANY tests I seem to destroy my own theories. I thought it might have been related to not having an active TTY. I was not able to play audio by launching a shell with sudo -i
, and MANY MANY other attmepts from php, but I was able to play audio using all the same commands from the local terminal, and as it turns out, also by SSH'ing into the computer, so that led to my latest work-around. Once again, I think this is WAY overkill, but so far is the only way I've been able to get the audio back in my web based php-driven scripts (mostly geo-fencing related.)
So, here we go, and yes I understand the risks and stupidity involved in this:
In my php script I generate an audio file in the /tmp directory with a command similar to this:
exec "sudo -u <username> /usr/bin/say -o /tmp/outputfile.aiff --voice=Ava \"<What to Say>\"";
Then after the audio file is generated, the only way I've found to play it (and actually hear the output) from apache/php is by using an expect script to ssh in locally and play it. So my next line is:
exec "sudo -u <username> -i ~<username>/expectscript";
My expect script is as follows:
#!/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"
Make sure you replace all the <username>
above with your username (without the <> obviously,) and <PASSWORD>
with your password. You may need to tweak the expect script if your bash prompts don't contain your username, as that is what I used in my expect script to find the returned prompt. The touch is just to determine that the expect script worked, and you have reference of the last time the file was touched.
I hope this opens up the discussion on what is actually causing this and we can determine a more reasonable solution. I went down a lot of rabbit holes trying to find different ways of getting this to work, I created Automator applications and called those from PHP (didn't work.) I launched shells within shells as my user, all the execution of commands always completed successfully, just no audio output. All of the solutions I tried would work fine from the terminal (and even php from the terminal), just not from Apache/PHP.
回答2:
I have experienced same problem while using say
command on my Jenkins job. My Jenkins server is working as daemon on macOS Sierra.
In my case I solved this problem like this:
- Login as
jenkins
user and generate ssh key withssh-keygen
. Append
~/.ssh/id_rsa.pub
to.ssh/authorized-keys
so that password will not be requested.cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized-keys
Change my Jenkins job which use
say
command like this:ssh localhost say -v Alex "Test"
I’m sorry, I have not tested with Apache/PHP, but why don't you try this way like this:
<?php
try {
exec('/usr/bin/ssh localhost /usr/bin/say "hello"');
}
catch (Exception $e) { echo $e->getMessage(); }
?>
来源:https://stackoverflow.com/questions/40233677/a-change-in-macos-sierra-prevents-say-to-be-execd-in-a-php-script