← Debugging Guides

阅读中文版本

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.

intermediatedebuggingphphttpcurl

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.