Recommended Free Tools
To create an API in PHP that can return JSON, XML, or HTML, keep the application logic in one service layer and let an HTTP controller handle routes, validation, status codes, headers, and serialization. Choose a supported representation explicitly—through a format parameter or the request’s Accept header—and send a matching Content-Type with every response. The examples below show the key pieces and the decisions needed to make them safe and predictable.
What makes a PHP endpoint an API?
An API is an HTTP contract, not just a PHP script that prints data. Clients need to know which routes and methods to use, what inputs are accepted, which response formats are available, what status codes mean, and how errors are shaped. Define those rules before adding serializers.
A useful request flow is:
- Match the route and HTTP method.
- Authenticate the caller and authorize access to the requested resource or action.
- Check the request media type and body size, then parse and validate the input.
- Call application or domain logic that returns data independently of HTTP format.
- Select an allowed response representation and serialize it.
- Set the status and headers, then emit the body.
For example, the same user lookup can return a JSON object to an application, XML to an established integration, or an HTML page to a person. Keep the lookup and permission checks shared; give each representation its own serializer.
Choose how clients select JSON, XML, or HTML
There are two common designs. A format parameter is simple to understand and explicit; /users/42?format=json and /users/42?format=xml select a representation. Allowlist the values and reject unknown formats rather than using user input as a header value. Alternatively, negotiate using Accept, selecting among media types such as application/json, application/xml, and text/html.
#1 Best Overall
If you use Accept, document what happens when the header is absent and how quality values and conflicts are handled. If none of the requested media types is supported, return 406 Not Acceptable. If you support both a format parameter and Accept, specify which takes precedence and test that rule. Add Vary: Accept when a cache may store different representations of the same URL. For sensitive responses, use an appropriate cache policy such as Cache-Control: no-store.
Do not copy an arbitrary Accept value into Content-Type. OWASP’s REST guidance states that the request or response body should match the intended content type in its header. A request with an unsupported body media type commonly receives 415 Unsupported Media Type.
Return JSON safely with PHP
PHP’s json_encode() returns a string containing the JSON representation of a value. Strings supplied to it must be UTF-8. Use JSON_THROW_ON_ERROR so encoding failures are handled deliberately instead of silently producing an unusable response.
<?php
$data = [
'id' => $user['id'],
'name' => $user['name'],
];
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
Choose a stable shape for collections and errors. For example, a collection can use {"data":[...],"meta":{...}}, while an error can use {"error":{"code":"invalid_request","message":"..."}}. Keep the schema consistent across routes, and do not send database exceptions, file paths, or stack traces to clients. Log diagnostic detail on the server instead.
Rank #2
In a real controller, catch JsonException or other serialization failures at the HTTP boundary, log them with a request or correlation ID, and return a generic server error if a response has not already been sent. Do not let partial output precede a JSON error response.
Build XML with a document API
Use DOMDocument to create XML rather than concatenating markup around values. Text nodes let the XML library handle characters such as ampersands and angle brackets. PHP’s DOM extension uses UTF-8 encoding.
<?php
$doc = new DOMDocument('1.0', 'UTF-8');
$root = $doc->createElement('user');
$id = $doc->createElement('id');
$id->appendChild($doc->createTextNode((string) $user['id']));
$root->appendChild($id);
$name = $doc->createElement('name');
$name->appendChild($doc->createTextNode((string) $user['name']));
$root->appendChild($name);
$doc->appendChild($root);
header('Content-Type: application/xml; charset=utf-8');
echo $doc->saveXML();
For incoming XML, require an accepted XML media type, cap the request size, and validate the resulting fields and business rules. Configure parsing defensively: unsafe external-entity processing can expose local files or cause network requests. Do not assume that well-formed XML is safe or valid for your application.
Render HTML without turning data into code
Use a server-side template or a deliberately escaped view when HTML is a supported representation. HTML text, attributes, URLs, JavaScript, and CSS are different output contexts; escaping for one context does not automatically make a value safe in another. For ordinary text and quoted attribute values, PHP’s htmlspecialchars() with quotes and UTF-8 handling is a common starting point:
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware match<?php
$nameForHtml = htmlspecialchars(
(string) $user['name'],
ENT_QUOTES | ENT_SUBSTITUTE,
'UTF-8'
);
header('Content-Type: text/html; charset=utf-8');
echo '<!doctype html><html lang="en"><body>';
echo '<h1>' . $nameForHtml . '</h1>';
echo '</body></html>';
That example escapes a value for an HTML text context; it is not a universal encoder for JavaScript, CSS, or URLs. Validate URL schemes and use context-specific handling if values appear in those locations.
If browser code fetches JSON and displays a value, insert it as text rather than interpreting it as markup. For example, assign to textContent or append a text node. Do not put untrusted API data into innerHTML: attacker-controlled markup can execute in the page.
Send Content-Type: text/html; charset=utf-8 for HTML and consider X-Content-Type-Options: nosniff. Explicit MIME types reduce the risk of browsers treating a response as a different kind of content.
Parse and validate JSON requests
For a JSON request, first require Content-Type: application/json (allowing parameters such as a charset if your contract permits them). Read the raw body from php://input, decode it, confirm its expected top-level shape, and validate each field before using it. Parsing only proves that the syntax is valid; it does not prove that the request is authorized or that its values make sense.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #4
<?php
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
if (stripos($contentType, 'application/json') !== 0) {
http_response_code(415);
header('Content-Type: application/json; charset=utf-8');
echo json_encode([
'error' => ['code' => 'unsupported_media_type', 'message' => 'Send application/json.'],
], JSON_THROW_ON_ERROR);
exit;
}
$rawBody = file_get_contents('php://input');
try {
$input = json_decode($rawBody, false, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
http_response_code(400);
header('Content-Type: application/json; charset=utf-8');
echo json_encode([
'error' => ['code' => 'invalid_json', 'message' => 'The request body is not valid JSON.'],
], JSON_THROW_ON_ERROR);
exit;
}
if (!is_object($input)) {
http_response_code(400);
// Return the same documented JSON error envelope here.
exit;
}
// Validate allowed fields, types, lengths, ranges, and business rules before use.
The example demonstrates the parsing boundary, not a complete endpoint. Enforce a body-size limit before accepting input, define whether unknown fields are rejected, and return a documented 400 for malformed syntax or 422 Unprocessable Content (often called a 422-style validation error) for syntactically valid but invalid values. Keep error messages useful to the client without revealing internals.
Use status codes and headers as part of the contract
Every response body needs the media type that describes the representation actually sent. Set the status before writing output, and avoid emitting warnings or whitespace before headers. A practical contract should explain success, client errors, and server errors rather than returning 200 for every outcome.
200for a successful read or operation with a response body;201when a resource is created.400for malformed requests,401when authentication is required or invalid, and403when the authenticated caller lacks permission.404when the route or resource is not available to the caller, and405when the route does not allow the method. A405response should identify allowed methods where applicable.406when no requested response representation is supported,415for an unsupported request body media type, and422for validly parsed input that fails application validation.429when rate limits are exceeded and500for an unexpected server failure.
Choose exact status and error behavior consistently and document it. Set X-Content-Type-Options: nosniff, a deliberate cache policy, and any other headers required by your deployment. For browser clients, configure CORS only for known origins and make credential handling explicit; CORS is not a substitute for authentication or authorization.
Keep outbound HTTP calls bounded and checked
When PHP calls another API, encode JSON and declare the request media type instead of sending an unlabelled body. PHP’s cURL supports setting the method, body, headers, and response handling:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →<?php
$payload = ['name' => $name];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 15,
]);
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
// Log transport details; return a safe application-level error.
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$responseType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
Choose timeouts appropriate to the operation and also cap how much response data your application will accept. Check transport failures, HTTP status, response size, and response media type before decoding an upstream body. Treat non-2xx responses and malformed data as explicit cases, not successful results. Avoid putting credentials or tokens in query strings, where they can leak into logs and other records.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Secure the API at every layer
Serialization does not secure an endpoint. Apply controls to the route, caller, input, database, and deployment:
- Use HTTPS in production and keep credentials and tokens out of logs.
- Authenticate callers and authorize every resource and action. Knowing a valid user ID is not permission to access that user’s record.
- Validate methods, media types, body size, field types, lengths, ranges, and business rules.
- Use prepared database statements and a database account with only the privileges the API needs.
- Return generic client-facing errors; log server-side details with a correlation ID that helps connect a response to an operational record.
- Apply rate limits to expensive or authenticated operations and cap pagination limits.
For XML specifically, harden the parser against external entities and resource abuse. For HTML, escape values for their output context. For negotiated responses, ensure cache keys distinguish representations or disable storage when the content is sensitive.
Compare the representations before supporting all three
Supporting more formats adds serializers, tests, and compatibility decisions. Offer a representation because a client needs it, not simply because the endpoint can emit it.
| Representation | Best fit | Design concern |
|---|---|---|
| JSON | Most programmatic clients and web applications | Define stable field names and error envelopes; handle UTF-8 and encoding failures. |
| XML | Existing integrations that require XML structure, schemas, or namespaces | Use a document API, define the schema and compatibility rules, and harden input parsing. |
| HTML | A human-facing page served by the same route or application | Escape according to context and account for browser caching and rendering behavior. |
JSON is often a sensible default for programmatic consumers. XML can be necessary for established integrations, especially when their contract depends on namespaces or a defined document structure. HTML makes sense when a route is also intended to serve a person. Choose one canonical application data model and test each serializer against the contract clients consume.
Test and document the behavior clients depend on
Test each route, method, and supported representation—not only the happy-path JSON response. Include:
- Successful reads and creations with the intended status and exact media type.
- Malformed JSON, invalid UTF-8, oversized bodies, wrong top-level shapes, unknown fields, and invalid business values.
- Authorization checks across users or tenants, including attempts to access another caller’s object.
- Unsupported methods and media types, unknown formats, unsupported
Acceptvalues, and cache behavior for negotiated responses. - XML parser attack cases and HTML rendering with hostile strings.
- Rate-limit responses, upstream timeouts, malformed upstream responses, and non-success upstream statuses.
Document routes and methods, authentication, parameters, request and response schemas, error codes, pagination, rate limits, and supported media types. An API description such as OpenAPI can make the contract easier for clients and tests to use. The OWASP API testing guidance treats CRUD behavior, content types, and API descriptions as core concerns, not optional polish.
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.

