Overlapping g1 just to show how very, very slowly I type RewriteCond %{QUERY_STRING} ^$
= If there is no query string.
The reason it seems to make no difference is that you've only tested the rewrite with requests that are supposed to work. You also need to test it with requests that are supposed to
not work-- including garbage requests.
RewriteRule ^work/([^/]+)/([0-9]+)/$ /work/$1/$2 [R,L]
RewriteRule ^work/([^/]+)/([0-9]+)$ /work/files.php?project_number=$1&key=$2 [L]
Didn't you start out saying that the htaccess is located in the /work/ directory? Seems like the Rewrites would then only work --haha-- if the request is for
/work/work/blahblah
Even if you never expect anyone-- or any search engine-- to see the result, say [R=301] just to get in the habit. The default unfortunately is 302 (same as with mod_alias redirects).
RewriteRule ^work/([^/]+)/([0-9]+)/$ /work/$1/$2 [R,L]
= a request for /work/directoryname/number(s)/ with trailing slash is externally redirected to /work/directoryname/number(s) without trailing slash.
Can I assume that the string of numbers is not an actual directory? Otherwise you will run afoul of mod_dir, whose job is to put back the slash.
Incidentally, you don't need to break the capture-and-reuse into two pieces just because there's a directory slash.
work/([^/]+/[0-9]+)/$ /work/$1
will do the same job in a nanosecond less time. But separating them will do no harm if it's easier for you to keep track of the rules that way.
RewriteRule ^work/([^/]+)/([0-9]+)$ /work/files.php?project_number=$1&key=$2 [L]
= request for /work/directoryname/number(s) without trailing slash is internally rewritten to serve content from /work/files.php with query string project_number=directoryname and key=number(s)
You should probably spend a little time looking at all the things that can possibly happen to a query string. The default behavior is that the pattern side of the Rule doesn't "see" the query string, just like it doesn't "see" the domain name; the target side of the Rule reappends the query string
unless you've replaced it with a new one.
In your first Rule, the redirect, you probably want to play it safe by attaching ? to the target, meaning "throw out the query string if there was one". Your second rule as written will replace any existing query; this is probably what you want.
It looks as if you are doing the redirect-plus-rewrite two-step. It has three parts; you've got two of them. The third part may be what you were trying to do with your original Condition: make sure you're only redirecting brand-new requests that came in from "outside", not your newly rewritten requests. One ridiculously easy approach is
RewriteCond %{THE_REQUEST} \?
meaning: only apply this rule if the original request contained a question mark (i.e a query string).
Leave a blank line after every RewriteRule, and include a #comment line explaining what the rule does. This will make sense when you look at your htaccess in 2027-- or possibly next week-- and can't remember what the Rule was supposed to do.