AJAX is a browser-to-server request followed by a page update. Despite its historic name, modern examples often use JSON rather than XML. JavaScript runs in the browser and calls fetch(); PHP runs on the server and produces a response. Understanding that boundary prevents the common mistake of expecting a browser to execute PHP source. This reference builds a small same-origin endpoint and client, explains request methods and JSON bodies, and handles errors explicitly. You will also learn why a successful network request is different from a successful HTTP status and why safe DOM updates matter.
Separate the browser and PHP responsibilities
The browser can collect form values, show progress, send a request, and render results. The PHP endpoint checks the method, validates the data, applies authorization, and returns an agreed response format. Keeping these jobs separate makes the API testable with a command-line HTTP client as well as a browser. A URL is a route to a server handler, not a direct function call into PHP. The response may be JSON, HTML, text, or an error document, so the client needs a clear contract. For a JSON API, send Content-Type: application/json and make sure notices, whitespace, and debugging echoes do not corrupt the body. Use a server-side log for diagnostics rather than adding them to the JSON response.
Choose methods by behavior
GET suits reading data and should not create or delete records. Query parameters are visible in URLs and logs, so do not put secrets into them. POST suits a state-changing operation or a body that does not fit a read URL, while other methods can express updates and deletion in an API. A form-encoded body populates $_POST; a JSON body usually needs file_get_contents('php://input') followed by json_decode(). Limit body size and use JSON_THROW_ON_ERROR to identify malformed JSON. Validate the decoded shape before reading keys, because a valid JSON array or scalar may not match your expected object. Method checks and response status codes help clients distinguish unsupported operations from invalid data.
Handle fetch responses correctly
fetch() normally rejects for network failures, not merely because a server returns 404 or 500. Check response.ok or the status before treating the operation as successful. Decide whether error responses use the same JSON envelope so the client can show a meaningful message. JSON parsing can also fail when a proxy or PHP fatal error returns HTML, so keep that failure visible in development. Disable duplicate submissions while a state-changing request is pending and restore controls in finally. For a read-only widget, show loading, empty, success, and failure states distinctly. A spinner without a clear error state leaves users unsure whether retrying will repeat an operation.
Protect authenticated state changes
AJAX does not remove ordinary web security requirements. Session cookies identify a browser, but a state-changing request still needs authorization and, for cookie-based authentication, CSRF protection. A same-origin endpoint is the simplest starting point. Cross-origin requests introduce CORS rules, credentials settings, and explicit allowed origins; a wildcard is not a universal solution. CORS is a browser access mechanism, not authentication, and it does not stop non-browser clients from making requests. Validate every submitted ID against the current user's permissions. Keep database values in prepared statements and avoid returning private fields merely because JavaScript did not request them. Return the minimum data needed by the interface.
Render data as text unless markup is trusted
A name returned by the API is still data. Setting textContent or creating text nodes prevents it from becoming executable markup. Inserting an untrusted API field into innerHTML can introduce cross-site scripting even when the SQL query was prepared safely. If the server deliberately returns HTML, it needs a reviewed rendering and escaping policy rather than a casual string assembly. Build lists with document.createElement() and set their text content. Keep the result region accessible, for example by using an appropriate live-status region for changes. Preserve normal form submission as a fallback when practical. A page that can read data only through JavaScript may need explicit handling for disabled scripts and connection failures.
Avoid stale results and accidental duplicates
Several requests can be in flight at once, and the oldest can finish last. For read widgets, cancel obsolete requests with AbortController or use a sequence number so only the latest response is rendered. Cancellation does not guarantee the server stopped its work. For payments or other important writes, prevent duplicate business operations with server-side idempotency keys and constraints rather than relying only on a disabled button. Set reasonable timeouts and present retry choices suited to the operation. Cache read responses only under a policy compatible with private data. Log server request identifiers so a reported failure can be traced without exposing stack traces to the client.
Practice task and worked solution
Build a newsletter signup interface with a JSON POST body. The solution parses the body, requires an object containing a scalar email, validates the email, checks the endpoint's abuse policy, and returns a structured success or validation error with an appropriate status. The client disables its submit button while pending, checks response.ok, and restores the button in finally. Render messages with textContent. If the feature uses authenticated sessions, include the application's CSRF token and authorization rules. Test malformed JSON, an array instead of an object, invalid email, a network failure, and a duplicate submission. Connect the validated request to your configured mailing service.
Continue learning
Review JSON, REST APIs, and forms to understand the complete request contract.
The PHP JSON manual documents server encoding and decoding APIs.
AJAX with PHP Examples
Each example shows the code, the output it produces and what each part does.
A same-origin JSON greeting endpoint
Place greeting.php behind a PHP-enabled server. Its companion JavaScript runs on a page at the same origin; the PHP source is never executed by JavaScript.
Requesting greeting.php?name=Ada returns JSON equivalent to {"message":"Hello, Ada"}. On the browser page, use const r = await fetch('/greeting.php?name=Ada'); if (!r.ok) throw new Error('Request failed'); const data = await r.json(); output.textContent = data.message;. The exact server URL depends on your routing configuration.
<?php
// greeting.php
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
header('Allow: GET');
exit;
}
header('Content-Type: application/json; charset=UTF-8');
$name = $_GET['name'] ?? 'visitor';
if (!is_string($name) || strlen($name) > 60) {
http_response_code(422);
echo json_encode(['error' => 'Choose a name up to 60 bytes.']);
exit;
}
echo json_encode(['message' => 'Hello, ' . $name], JSON_THROW_ON_ERROR);{"message":"Hello, Ada"}AJAX with PHP FAQ
Does fetch run PHP?
No. fetch() runs in the browser and sends an HTTP request. It requests a server route that runs PHP, exactly like loading a page, and PHP's response, usually JSON, comes back to the JavaScript that made the request.
Why did fetch accept a 500?
fetch() only rejects its promise for network failures, such as no connection. HTTP error statuses like 404 and 500 still produce a normal response, so they normally require an explicit response.ok check before you read the body as successful data.
Can I use innerHTML for API values?
Avoid it for untrusted text. Inserting API data with innerHTML lets any HTML or script in that data run in the page, which is cross-site scripting. Prefer textContent for untrusted text, and build elements with DOM methods when you need structure.
Does AJAX eliminate CSRF?
No. A request sent with fetch() carries the user's cookies just like a form, so authenticated state changes still need protection. Send a CSRF token in a header or the request body, and use SameSite cookies as an additional defence.
AJAX with PHP Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
An API returns a visitor-provided display name. How should it enter a list item?
AJAX with PHP Quiz
2 questions to check what you learned.
Where does PHP execute in an AJAX flow?
- Inside fetch in the browser
- On the server handling the requested route
- In the browser after the JSON response arrives
- In the browser when the page has a .php URL
Which check detects an HTTP 500 after fetch resolves?
- Only catch without checking status
- Whether response.json() returns a parseable object
- response.ok or response.status
- Whether the response includes a Content-Type header