Amarok can be controlled using DCOP, but in order to do this an Apache server running locally (as www-data) has to be able to connect to the current desktop user's DCOP server.
I tried a number of ways to get around this:
Connecting to the user's DCOP session: dcop --list-sessions --user alf
exec('dcop --session .DCOPserver_mycomputer__0 --user alf amarok player volumeDown');
but this doesn't work because www-data seems to never be able to connect to the right session.
Connecting to the user's X server and launching Amarok directly: xhost + allows anyone to connect to your X server amarok --display=:0 --load filename.m3u --play
but this launches Amarok as www-data, which doesn't help as the preferences are all user-specific. This wouldn't really have achieved what was needed anyway.
Using suPHP, which uses php_cgi instead of mod_php5 and runs scripts as the file's owner, rather than as www-data. It's easy to install in Ubuntu, but this didn't work because exec, system and shell_exec PHP commands are still run as root; tried using exec("su alf -c 'amarok'"), but su has to be run in a terminal.
The XUL Remote script for Amarok sets up a separate Python HTTP server, running as the current user. This can't be called directly using XMLHttpRequest as it runs on a different port (so counts as cross-domain), but can be called indirectly using a PHP script as a proxy.
So, finally, I have a local web page (Apache) which responds to clicks with XMLHttpRequest to a local PHP script (Apache), which then POSTs that information to my Python HTTP server, which sends the information to Amarok using DCOP.