So how did I found out about this? Thanks to Steve Kamerman, who took the time to comment to the PHP documentation. It turns out this issue is caused by the way libcurl behaves on linux and unix systems, where a SIGALRM is raised during the name resolution that is being caught by libcurl as a timeout alarm. Because of this, the request times out immediately instead of after the actual timeout.
The solution is to tell curl to ignore signals alltogether. This is not a perfect solution of course, because you're now suppressing something that can be useful in other situations, but in this case we decided the timeouts to be too important for the software to not use timeouts. So now it looks like this:
$curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_TIMEOUT_MS, 250); curl_setopt($curl, CURLOPT_NOSIGNAL, 1);
It now works like a charm!