I am using the Amazon S3 API to upload files and I am changing the name of the file each time I upload.
So for example:
Dog.png > 3Sf5f.png
Now I got
It appears what's actually going on is rather than fully producing the filename right now, you're in effect passing a very small 'program' through the interface so it can then produce the filename later (when the variable $filename exists and is in scope). The other side of the interface eventually executes that 'program' you pass in, which produces the modified filename. (Of course passing a 'program' to something else to execute later doesn't tend to make debugging real easy:-)
(It's of course up to you whether you want to "make this work" or "do it a different way". "Different ways" typically involve renaming or copying the file yourself before you even try to invoke the upload interface, and are described in other answers.)
If you decide you want to "make it work", then the entire filename parameter needs to be a program, rather than just part of it. This somewhat uncommon functionality typically involves enclosing the entire string in single quotes. (You also need to do something about existing single quote marks inside the string so they don't terminate the quoted string too soon. One way is to quote each of them with a backslash. Another way that may look cleaner and usually works is to replace them with double quotes.) In other words, I believe the code below will work for you (I haven't got the right environment to test it, so I'm not sure).
$file_extension = 'substr(strrchr(${filename}, "."), 1)';
$params->key = rand_string(5).$file_extension;
(Once you get it working, you might want to revisit your naming scheme. Perhaps the name needs to be a little longer. Or perhaps it should include some identifiable information {like today's date, or the original name of the file}. You may hit on something like $file_base.rand_string(7).$file_extension.