PHP failed to open stream — allow_url_fopen Disabled
Fix "failed to open stream: HTTP request failed" by enabling allow_url_fopen or switching to cURL with proper error reporting.
Symptoms
- Warning: file_get_contents(): Failed to open stream: HTTP request failed
- Reading a URL works on one server but not another
- The failure appeared after a hosting or PHP upgrade
Possible causes
- allow_url_fopen is Off, so file_get_contents cannot read http(s) URLs
- An outbound firewall or proxy blocks the request
- TLS verification fails because the CA bundle is missing or outdated
Diagnosis steps
Check the setting and the wrapper error
php -r "var_dump(ini_get('allow_url_fopen')); var_dump(file_get_contents('https://example.com'));"Interpretation
If allow_url_fopen is empty/Off, the URL wrapper is disabled; a TLS error points elsewhere.
Switch to cURL with explicit error capture
php -r '$c=curl_init("https://example.com"); curl_setopt($c,CURLOPT_RETURNTRANSFER,true); $r=curl_exec($c); if($r===false) var_dump(curl_error($c));' Interpretation
cURL reports the real failure (DNS, TLS, timeout) and is not gated by allow_url_fopen.
Root cause
file_get_contents can only read remote URLs when allow_url_fopen is enabled and the required stream wrapper plus TLS trust are available. Any of these missing yields a failed-to-open-stream warning.
Fix
Prefer cURL or a HTTP client library with explicit options and error handling; if URL wrappers are required, enable allow_url_fopen and ensure a current CA bundle is configured.
Risk note
Enabling allow_url_fopen widens SSRF exposure when URLs come from user input; validate allowlists.
Verify the fix
Run the request again and confirm a 200 and body; assert curl_getinfo reports HTTP 200 and no curl_error.
Symptoms
When you hit “PHP failed to open stream — allow_url_fopen Disabled”, guessing wastes time. The guide below follows evidence: reproduce the symptom, run targeted diagnostics, identify the root cause, apply the fix, and verify it with concrete checks.
Observed symptoms include:
- Warning: file_get_contents(): Failed to open stream: HTTP request failed
- Reading a URL works on one server but not another
- The failure appeared after a hosting or PHP upgrade
Reproduce and Diagnose
Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.
Step 1: Check the setting and the wrapper error
php -r "var_dump(ini_get('allow_url_fopen')); var_dump(file_get_contents('https://example.com'));"
If allow_url_fopen is empty/Off, the URL wrapper is disabled; a TLS error points elsewhere.
Step 2: Switch to cURL with explicit error capture
php -r '$c=curl_init("https://example.com"); curl_setopt($c,CURLOPT_RETURNTRANSFER,true); $r=curl_exec($c); if($r===false) var_dump(curl_error($c));'
cURL reports the real failure (DNS, TLS, timeout) and is not gated by allow_url_fopen.
Likely contributors, in order of frequency:
- allow_url_fopen is Off, so file_get_contents cannot read http(s) URLs
- An outbound firewall or proxy blocks the request
- TLS verification fails because the CA bundle is missing or outdated
Root Cause
file_get_contents can only read remote URLs when allow_url_fopen is enabled and the required stream wrapper plus TLS trust are available. Any of these missing yields a failed-to-open-stream warning.
The Fix
Prefer cURL or a HTTP client library with explicit options and error handling; if URL wrappers are required, enable allow_url_fopen and ensure a current CA bundle is configured.
Watch out: Enabling allow_url_fopen widens SSRF exposure when URLs come from user input; validate allowlists.
function fetch(string $url): string {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_CAINFO => '/etc/ssl/certs/ca-certificates.crt',
]);
$body = curl_exec($ch);
if ($body === false) {
throw new RuntimeException('curl error: ' . curl_error($ch));
}
curl_close($ch);
return $body;
}
Verify and Prevent
Run the request again and confirm a 200 and body; assert curl_getinfo reports HTTP 200 and no curl_error.
Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.
This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.