Well, sorry, I guess I misspoke.
In this particular case there's no query string because Apache does not recognize '?', there's only a %3F. So (.*) gets what is after file.php and send it as a query string (qs) It is working fine now as a partial solution.
WRONG! Apache knows that %3F is the ? character and will treat everything after it as a query string. Because the query string is NOT available to the regex in a RewriteRule (only available in a RewriteCond statement and only when specified), your (.*) will NEVER match anything (unless you've enabled MultiViews which, IMHO, is a dumb thing to do). Test it and look at the value (null every time) that $1 returns.
These are the facts:
If I FF to www.domain.com/dir/file.php%3Fi%3Dbob
I get a 404 error.
In .htaccess I add
RewriteRule ^dir/file\.php(.*) index.php?qs=$1
Retry www.domain.com/dir/file.php%3Fi%3Dbob from web browser
index.php is displayed.
FF URI: www.domain.com/index.php?qs=%3fid=bob (yes, %3f and '=')
I add these lines into index.php to handle qs
That acts like asking for www.domain.com/dir/file.php?id=bob
$qs = urldecode(str_replace("qs=%3f",NULL,$_SERVER['QUERY_STRING']));