Keep SSL certificate and hostname verification enabled. An SSL error usually means the PHP process making the request cannot build a trusted chain for the hostname it contacted. Identify the actual client and transport, then give that process a valid CA source or fix the server certificate chain. The setting is not universal: native PHP streams use SSL context options, Guzzle uses verify, and Symfony HttpClient relies on the system certificate store.
What an SSL verification error means
During an HTTPS request, the client checks two related properties:
- Peer verification: the certificate chain leads to a certificate authority (CA) trusted by the client.
- Hostname verification: the certificate is valid for the hostname in the request.
A browser succeeding does not prove that PHP can validate the same endpoint. Symfony documents that its client uses the operating system’s certificate store, while browsers use their own stores. CLI PHP, a web server, and a container can also load different PHP configuration and trust stores. Diagnose the process that actually failed, not a different browser or shell.
A safe diagnostic sequence
- Save the complete error. Record the exception text, requested URL, hostname, HTTP client, handler or transport, PHP SAPI (CLI, FPM, Apache module), and runtime environment.
- Confirm the hostname. Follow redirects and check that the URL uses the intended name. A certificate issued for
api.example.comwill not validate a request to an unrelated alias. Keep hostname verification enabled; PHP exposesverify_peer_nameandpeer_namefor stream contexts. - Find the trust source. Determine whether the client is using a system CA store, a bundled CA file, a custom file, or a hashed CA directory. Verify that the failing PHP process can read it.
- Check the complete chain. The server should send the intermediate certificates needed to reach a trusted root. A missing intermediate can fail in PHP even when another client has cached or independently discovered it.
- Apply the fix in the client you actually use. Native streams, Guzzle, and Symfony HttpClient have different configuration names and defaults.
- Retest with both checks active. If the request still fails, inspect the exact certificate chain and selected transport instead of suppressing verification.
Native PHP streams: configure an SSL context
PHP’s SSL context defaults verify_peer and verify_peer_name to true. The cafile option names a local CA bundle; capath points to a directory whose certificates are correctly hashed. allow_self_signed defaults to false and does not replace the need for peer verification.
Recommended Free Tools
#1 Best Overall
<?php
$url = 'https://api.example.com/data';
$context = stream_context_create([
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
'cafile' => '/path/to/ca-bundle.pem',
// Use capath instead when your deployment maintains a
// correctly hashed certificate directory.
// 'capath' => '/path/to/ca-directory',
],
]);
$body = file_get_contents($url, false, $context);
if ($body === false) {
throw new RuntimeException('HTTPS request failed');
}
echo $body;
The path above is an example, not a universal location. Use a CA bundle appropriate for the operating system and deployment, and ensure the user running PHP has read access. Do not add a self-signed leaf certificate indiscriminately; trust the intended development CA instead.
When using a stream wrapper, pass the context to the operation that opens the URL. A context created but not supplied to file_get_contents has no effect. If a framework wraps streams, configure the framework’s documented option rather than assuming this context is used.
Guzzle: use the verify request option
Guzzle enables certificate verification by default. Its verify option accepts true for the default CA bundle or a string path to a specific CA bundle. Setting it to false disables verification and is explicitly insecure. Guzzle’s FAQ recommends specifying the CA bundle path when an SSL verification error occurs.
<?php
require 'vendor/autoload.php';
use GuzzleHttpClient;
$client = new Client([
'base_uri' => 'https://api.example.com',
'verify' => '/path/to/ca-bundle.pem',
'timeout' => 30,
]);
$response = $client->request('GET', '/data');
echo $response->getBody();
For a normal public service, first try 'verify' => true and repair the system or bundled CA configuration if it is missing or stale. A custom path must exist, contain a usable PEM bundle, and be readable by the PHP worker. The installed Guzzle version, operating system, handler, and PHP configuration determine which default bundle is available.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Do not confuse Guzzle’s request option with PHP stream settings. A Guzzle installation can use different handlers, so changing an unrelated php.ini value may not change the trust source used by the request.
Symfony HttpClient: repair the system trust store
Symfony HttpClient validates certificates against the system certificate store. That store is separate from a browser’s store, so a successful browser test is not conclusive. Symfony supports both PHP streams and cURL; identify the active transport when behavior differs between environments.
Rank #3
<?php
require 'vendor/autoload.php';
use SymfonyComponentHttpClientHttpClient;
$client = HttpClient::create();
$response = $client->request('GET', 'https://api.example.com/data');
if ($response->getStatusCode() !== 200) {
throw new RuntimeException('Unexpected HTTP status');
}
echo $response->getContent();
For a private or self-signed development service, Symfony recommends creating a development CA and adding that CA to the system store. Add the CA to the store used by the PHP process and restart long-running workers if their environment is loaded only at startup. Disabling verify_host or verify_peer is not recommended in production.
Development certificates and private services
A self-signed certificate is not automatically trustworthy. The safer pattern is to create or obtain a private development CA, issue the service certificate from it with the correct hostname, and trust that CA only in the development environment. Then configure the relevant system store, cafile/capath, or Guzzle verify path.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →- Use the hostname present in the certificate’s subject alternative names.
- Install the CA, not every leaf certificate, when several development services share it.
- Keep production trust stores separate from development ones.
- Retest after rotating certificates or changing a container image; trust files may not survive an image rebuild.
Common symptoms, causes, and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| “Certificate verify failed” in one PHP environment | The SAPI or container has no usable CA source, or cannot read it. | Inspect that process’s configuration and permissions; provide a valid bundle or system-store entry. |
| Browser works, PHP fails | Different trust stores or transports. | Configure the store used by PHP; do not infer trust from the browser result. |
| Hostname mismatch | URL host is not covered by the certificate. | Use the certificate’s hostname or obtain a certificate containing the requested name. |
| Works with a custom CA file but not the default | The default bundle is absent, stale, or not selected by the runtime. | Install/update the platform CA source or configure the explicit path in the client. |
| Private service fails everywhere except a developer laptop | The private CA is trusted locally but not in the server, worker, or container. | Install the intended development or private CA in the failing environment. |
Changing php.ini has no effect |
The request uses another SAPI, handler, or client configuration. | Confirm the active runtime and transport, then change the option that client consumes. |
| Disabling verification makes it work | The endpoint is no longer authenticated; the certificate problem remains. | Restore verification immediately and repair the CA chain, hostname, or trust source. |
What not to do
Do not ship verify => false, verify_peer => false, or verify_host => false as a production fix. Those settings allow an attacker who can intercept traffic to present an untrusted certificate. A request that succeeds only after disabling checks has stopped authenticating the remote endpoint. If you temporarily disable a check for isolated local diagnosis, keep it out of production, limit the test, and restore the secure setting immediately.
Rank #4
- 2-part carbonless unit set
- Consecutive numbering
- Includes Gift Certificates Available sign
- 25 certificates with envelopes per package
- White/canary form sequence
Reliability and operational notes
- Pin configuration to the deployment: use an explicit CA path when a reproducible container or appliance must not depend on an image’s implicit defaults.
- Keep the CA source current: certificate authorities and intermediates change; stale bundles eventually reject otherwise valid endpoints.
- Check permissions and secrets handling: a CA bundle is normally public trust material, but its path must still be readable by the worker account and present in every replica.
- Separate failures: certificate validation happens before an HTTP response. A 4xx or 5xx is an application response; a TLS verification exception is a transport/trust failure.
- Retest each execution mode: scheduled jobs, queue workers, FPM, CLI scripts, and containers can select different PHP binaries, environment variables, and trust stores.
Or skip the browser setup: ScreenshotNeo
If your goal is to obtain a clean image or PDF of an HTTPS page rather than build a PHP HTTP client, ScreenshotNeo provides a single screenshot API request. It accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
Use the documented endpoint and parameters at ScreenshotNeo docs:
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://stripe.com
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', data));
The free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to get an API key.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsFAQ
Should I set verify_peer_name to false for an IP address?
No. Use a hostname covered by the certificate, or obtain a certificate that includes the intended name. Disabling hostname verification removes an essential identity check.
Best Value
Is a CA file the same as the server certificate?
Usually not. A CA bundle contains trusted issuer certificates used to validate the server chain. Supplying an arbitrary server leaf certificate does not establish a sound trust policy.
Why does a failed TLS request have no HTTP status code?
TLS validation occurs before HTTP headers and status codes are exchanged, so the client raises a transport exception instead of returning a 4xx or 5xx response.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




