Three ways to call HTTP in PHP — with Harbour/FiveWin analogies
Pick the level of abstraction that matches your needs. The closer you go to the wire, the more you must implement yourself.
curl_* (libcurl)file_get_contents + stream_contextfsockopen + manual HTTP/1.1hb_socket* + HBSSL, everything by hand.Drop‑in replacement: from cURL to stream_context
Swap the cURL block for this minimal version when you post JSON to a local microservice. It keeps your code tiny and readable.
$ctx = stream_context_create([
'http' => [
'method' => 'POST',
'header' => ['Content-Type: application/json; charset=utf-8', 'Connection: close'],
'content' => json_encode($payload, JSON_UNESCAPED_UNICODE),
'timeout' => 5,
'ignore_errors' => true
]
]);
$resp = @file_get_contents('http://127.0.0.1:9090/booklock_status', false, $ctx);
if ($resp === false) {
http_response_code(502);
echo json_encode(['success'=>false,'message'=>'proxy_error','error'=>'MS unreachable']);
exit;
}
$statusLine = $http_response_header[0] ?? 'HTTP/1.1 200';
$parts = explode(' ', $statusLine);
$status = (int)($parts[1] ?? 200);
http_response_code($status);
echo $resp;
Tip: ignore_errors => true lets you read 4xx/5xx bodies for richer error JSON.
What stream_context_create() actually does
The real work happens in file_get_contents('http://…', false, $ctx): PHP’s built‑in HTTP wrapper opens the socket, builds the request, reads the response, and returns the body. The received headers go into $http_response_header.
Low‑level socket (HTTP/1.1) — why it’s not for production
Great to understand what happens on the wire; painful to maintain in real projects.
$socket = @fsockopen('127.0.0.1', 9090, $errno, $errstr, 5);
$body = json_encode($payload, JSON_UNESCAPED_UNICODE);
$req = "POST /booklock_status HTTP/1.1\r\n";
$req .= "Host: 127.0.0.1:9090\r\n";
$req .= "Content-Type: application/json; charset=utf-8\r\n";
$req .= "Content-Length: ".strlen($body)."\r\n";
$req .= "Connection: close\r\n\r\n";
$req .= $body;
fwrite($socket, $req);
$response = stream_get_contents($socket);
fclose($socket);
// Then split headers/body, parse status line, handle chunking…
Harbour/FiveWin parallels
- PHP cURL ≈ Harbour high‑level HTTP client (WinInet/WinHTTP wrapper). Minimal code, maximum robustness.
- PHP stream_context ≈ Harbour “system HTTP wrapper” — covers the common 80% with tiny code.
- PHP fsockopen ≈ Harbour hb_socket* + HBSSL — total control, total responsibility.
Where does the HTTP status code come from?
- cURL: libcurl reads the first line (HTTP/1.1 200 OK) and stores the number; you read it via curl_getinfo(..., CURLINFO_RESPONSE_CODE).
- stream wrapper: headers are exposed via $http_response_header. The first line contains the status; parse it and mirror it with http_response_code($status).
Debug & CLI testing with curl
Even if your PHP uses file_get_contents, keep the curl CLI for smoke tests, CI checks, and documentation.
curl -v -X POST http://127.0.0.1:9090/booklock_status \
-H "Content-Type: application/json" \
-d '{"dbname":"BELEGUNG","buchung_id":"12345","user":"TEST","intent":"edit"}'
Practical recommendations
Migration checklist: cURL → stream_context
- Set Content‑Type to application/json; charset=utf‑8
- Enable ignore_errors to read 4xx/5xx bodies
- Apply a sensible timeout (e.g. 5s)
- Adopt the microservice status code from $http_response_header
- Return the raw MS JSON body unchanged
Abbreviations legend
- HTTP
- Protocol for web requests and responses between clients and servers.
- TCP
- Connection‑oriented transport protocol used under HTTP.
- TLS
- Encryption layer that makes HTTP secure (HTTPS).
- cURL
- Library and CLI tool for HTTP(S) requests; PHP exposes it via curl_*.
- DLL
- Dynamic‑link library on Windows, loaded by processes at runtime.
- CLI
- Command‑line interface; here, the curl terminal tool.
- JSON
- Text format for structured data (key‑value pairs).
- PoC
- Proof of Concept; minimal demo to show feasibility.
- CI/CD
- Continuous Integration/Continuous Deployment automation pipelines.
- Proxy
- A mediator that forwards requests to an upstream service.
Max. 10 entries • Collected on first occurrence • Plain‑language explanations