PHP JSON Functions
Introduction to PHP JSON Functions
PHP provides built-in functions for working with JSON (JavaScript Object Notation), a lightweight data interchange format commonly used in web APIs and modern applications.
Basic JSON Operations
Encoding PHP Data to JSON
<?php
// json_encode() - Convert PHP data to JSON string
// Arrays
$array = ['apple', 'banana', 'cherry'];
echo json_encode($array); // ["apple","banana","cherry"]
// Associative arrays become JSON objects
$assoc = ['name' => 'John', 'age' => 30, 'city' => 'New York'];
echo json_encode($assoc); // {"name":"John","age":30,"city":"New York"}
// Nested structures
$data = [
'user' => [
'name' => 'John Doe',
'email' => '[email protected]',
'preferences' => [
'theme' => 'dark',
'notifications' => true
]
],
'posts' => [
['title' => 'First Post', 'likes' => 10],
['title' => 'Second Post', 'likes' => 5]
]
];
echo json_encode($data);
?>
Decoding JSON to PHP Data
<?php
// json_decode() - Convert JSON string to PHP data
$json = '{"name":"John","age":30,"city":"New York"}';
// Decode to associative array (default)
$array = json_decode($json, true);
print_r($array);
// Array ( [name] => John [age] => 30 [city] => New York )
// Decode to object
$object = json_decode($json);
echo $object->name; // John
echo $object->age; // 30
// Complex JSON
$complexJson = '{
"users": [
{"id": 1, "name": "John", "active": true},
{"id": 2, "name": "Jane", "active": false}
],
"total": 2
}';
$data = json_decode($complexJson, true);
foreach ($data['users'] as $user) {
echo "User: " . $user['name'] . " (ID: " . $user['id'] . ")\n";
}
?>
JSON Encoding Options
Common Encoding Flags
<?php
$data = [
'name' => 'John Doe',
'age' => 30,
'scores' => [85, 90, 78],
'address' => [
'street' => '123 Main St',
'city' => 'New York'
]
];
// Pretty print JSON (formatted)
echo json_encode($data, JSON_PRETTY_PRINT);
/*
{
"name": "John Doe",
"age": 30,
"scores": [
85,
90,
78
],
"address": {
"street": "123 Main St",
"city": "New York"
}
}
*/
// Unescaped Unicode
$unicode = ['message' => 'Hello 世界'];
echo json_encode($unicode, JSON_UNESCAPED_UNICODE);
// {"message":"Hello 世界"}
// Unescaped slashes
$url = ['website' => 'https://example.com/path'];
echo json_encode($url, JSON_UNESCAPED_SLASHES);
// {"website":"https://example.com/path"}
// Force object output for empty arrays
$empty = [];
echo json_encode($empty, JSON_FORCE_OBJECT);
// {}
// Combine multiple flags
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
?>
Handling Special Values
<?php
// Numeric strings
$data = ['id' => '123', 'score' => '95.5'];
echo json_encode($data, JSON_NUMERIC_CHECK);
// {"id":123,"score":95.5}
// HTML entities
$html = ['content' => '<script>alert("hello")</script>'];
echo json_encode($html, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
// Preserve zero fraction
$numbers = ['price' => 10.00, 'tax' => 1.50];
echo json_encode($numbers, JSON_PRESERVE_ZERO_FRACTION);
// {"price":10.0,"tax":1.5}
// Invalid UTF-8 handling
$invalid = ['text' => "Invalid UTF-8: \x80\x81"];
echo json_encode($invalid, JSON_INVALID_UTF8_SUBSTITUTE);
?>
JSON Decoding Options
Decoding Configuration
<?php
$json = '{"name":"John","age":30,"height":5.8,"active":true,"address":null}';
// Maximum depth (default is 512)
$data = json_decode($json, true, 10);
// Decode as objects with specific class
class User {
public $name;
public $age;
public $height;
public $active;
public $address;
}
// Decode large integers as strings
$bigNumber = '{"bigint": 9223372036854775808}';
$result = json_decode($bigNumber, true, 512, JSON_BIGINT_AS_STRING);
echo $result['bigint']; // "9223372036854775808"
// Throw exceptions on error (PHP 7.3+)
try {
$invalid = '{"invalid": json}';
$result = json_decode($invalid, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
echo "JSON Error: " . $e->getMessage();
}
?>
Error Handling
Traditional Error Handling
<?php
function safeJsonDecode($json, $assoc = true) {
$data = json_decode($json, $assoc);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new InvalidArgumentException('JSON decode error: ' . json_last_error_msg());
}
return $data;
}
function safeJsonEncode($data, $options = 0) {
$json = json_encode($data, $options);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('JSON encode error: ' . json_last_error_msg());
}
return $json;
}
// Usage
try {
$invalid = '{"name": "John", "age":}'; // Invalid JSON
$data = safeJsonDecode($invalid);
} catch (InvalidArgumentException $e) {
echo "Error: " . $e->getMessage();
}
// Check specific error types
$json = '{"name": "John"}';
$data = json_decode($json);
switch (json_last_error()) {
case JSON_ERROR_NONE:
echo 'No errors';
break;
case JSON_ERROR_DEPTH:
echo 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
echo 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
echo 'Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
echo 'Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
echo 'Malformed UTF-8 characters';
break;
default:
echo 'Unknown error';
break;
}
?>
Modern Error Handling (PHP 7.3+)
<?php
// Using JSON_THROW_ON_ERROR flag
function modernJsonDecode($json, $assoc = true) {
try {
return json_decode($json, $assoc, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new InvalidArgumentException("Failed to decode JSON: " . $e->getMessage(), 0, $e);
}
}
function modernJsonEncode($data, $options = 0) {
try {
return json_encode($data, $options | JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new RuntimeException("Failed to encode JSON: " . $e->getMessage(), 0, $e);
}
}
// Usage
try {
$data = modernJsonDecode('{"invalid": json}');
} catch (InvalidArgumentException $e) {
echo "Decode error: " . $e->getMessage();
}
try {
$invalid = "\xB1\x31"; // Invalid UTF-8
$json = modernJsonEncode(['text' => $invalid]);
} catch (RuntimeException $e) {
echo "Encode error: " . $e->getMessage();
}
?>
Working with JSON APIs
HTTP API Requests
<?php
class JsonApiClient {
private $baseUrl;
private $headers;
public function __construct($baseUrl) {
$this->baseUrl = rtrim($baseUrl, '/');
$this->headers = [
'Content-Type: application/json',
'Accept: application/json'
];
}
public function get($endpoint) {
$url = $this->baseUrl . '/' . ltrim($endpoint, '/');
$context = stream_context_create([
'http' => [
'method' => 'GET',
'header' => implode("\r\n", $this->headers)
]
]);
$response = file_get_contents($url, false, $context);
if ($response === false) {
throw new RuntimeException('Failed to fetch data from API');
}
return $this->parseResponse($response);
}
public function post($endpoint, $data) {
$url = $this->baseUrl . '/' . ltrim($endpoint, '/');
$jsonData = json_encode($data, JSON_THROW_ON_ERROR);
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => implode("\r\n", $this->headers),
'content' => $jsonData
]
]);
$response = file_get_contents($url, false, $context);
if ($response === false) {
throw new RuntimeException('Failed to send data to API');
}
return $this->parseResponse($response);
}
private function parseResponse($response) {
try {
return json_decode($response, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new RuntimeException('Invalid JSON response: ' . $e->getMessage());
}
}
}
// Usage
$client = new JsonApiClient('https://api.example.com');
try {
$users = $client->get('/users');
foreach ($users as $user) {
echo "User: " . $user['name'] . "\n";
}
$newUser = $client->post('/users', [
'name' => 'John Doe',
'email' => '[email protected]'
]);
echo "Created user with ID: " . $newUser['id'];
} catch (Exception $e) {
echo "API Error: " . $e->getMessage();
}
?>
Response Formatting
<?php
class JsonResponse {
public static function success($data = null, $message = 'Success', $statusCode = 200) {
http_response_code($statusCode);
header('Content-Type: application/json');
$response = [
'success' => true,
'message' => $message
];
if ($data !== null) {
$response['data'] = $data;
}
echo json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
exit;
}
public static function error($message, $statusCode = 400, $errors = null) {
http_response_code($statusCode);
header('Content-Type: application/json');
$response = [
'success' => false,
'message' => $message
];
if ($errors !== null) {
$response['errors'] = $errors;
}
echo json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
exit;
}
public static function paginated($data, $page, $perPage, $total) {
$totalPages = ceil($total / $perPage);
self::success([
'items' => $data,
'pagination' => [
'current_page' => $page,
'per_page' => $perPage,
'total' => $total,
'total_pages' => $totalPages,
'has_next' => $page < $totalPages,
'has_prev' => $page > 1
]
]);
}
}
// Usage in API endpoints
try {
$users = getUsersFromDatabase();
JsonResponse::success($users, 'Users retrieved successfully');
} catch (Exception $e) {
JsonResponse::error('Failed to retrieve users', 500);
}
?>
Advanced JSON Operations
JSON Schema Validation
<?php
class JsonValidator {
public static function validateUser($data) {
$errors = [];
// Required fields
$required = ['name', 'email'];
foreach ($required as $field) {
if (!isset($data[$field]) || empty($data[$field])) {
$errors[] = "Field '{$field}' is required";
}
}
// Email validation
if (isset($data['email']) && !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
$errors[] = "Invalid email format";
}
// Age validation
if (isset($data['age']) && (!is_numeric($data['age']) || $data['age'] < 0 || $data['age'] > 150)) {
$errors[] = "Age must be a number between 0 and 150";
}
return $errors;
}
public static function validateApiRequest($json) {
try {
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
return ['Invalid JSON format: ' . $e->getMessage()];
}
return self::validateUser($data);
}
}
// Usage
$requestBody = file_get_contents('php://input');
$errors = JsonValidator::validateApiRequest($requestBody);
if (!empty($errors)) {
JsonResponse::error('Validation failed', 400, $errors);
}
?>
JSON Streaming for Large Data
<?php
class JsonStreamer {
private $handle;
public function __construct($filename) {
$this->handle = fopen($filename, 'w');
if (!$this->handle) {
throw new RuntimeException("Cannot open file for writing: {$filename}");
}
}
public function startArray() {
fwrite($this->handle, '[');
}
public function writeItem($data, $isFirst = false) {
if (!$isFirst) {
fwrite($this->handle, ',');
}
fwrite($this->handle, json_encode($data));
}
public function endArray() {
fwrite($this->handle, ']');
}
public function close() {
if ($this->handle) {
fclose($this->handle);
$this->handle = null;
}
}
public function __destruct() {
$this->close();
}
}
// Stream large dataset to JSON file
$streamer = new JsonStreamer('large_dataset.json');
$streamer->startArray();
$users = getUsersFromDatabase(); // Large dataset
foreach ($users as $index => $user) {
$streamer->writeItem($user, $index === 0);
}
$streamer->endArray();
$streamer->close();
// Read large JSON file in chunks
function readJsonStream($filename, $callback) {
$handle = fopen($filename, 'r');
if (!$handle) {
throw new RuntimeException("Cannot open file: {$filename}");
}
$buffer = '';
$depth = 0;
$inString = false;
$escaped = false;
while (!feof($handle)) {
$chunk = fread($handle, 8192);
$buffer .= $chunk;
// Simple JSON parsing (for demonstration)
// In production, use a proper streaming JSON parser
$objects = explode('},{', $buffer);
foreach ($objects as $index => $object) {
if ($index === count($objects) - 1 && !feof($handle)) {
$buffer = $object;
break;
}
$object = '{' . trim($object, '[]{}') . '}';
try {
$data = json_decode($object, true, 512, JSON_THROW_ON_ERROR);
$callback($data);
} catch (JsonException $e) {
// Handle parsing errors
}
}
}
fclose($handle);
}
?>
Performance Considerations
Optimizing JSON Operations
<?php
class JsonPerformance {
public static function benchmarkEncoding($data, $iterations = 1000) {
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
json_encode($data);
}
$end = microtime(true);
return ($end - $start) * 1000; // Return milliseconds
}
public static function optimizeForSpeed($data) {
// Use minimal flags for maximum speed
return json_encode($data, JSON_UNESCAPED_SLASHES);
}
public static function optimizeForSize($data) {
// Remove unnecessary whitespace
return json_encode($data);
}
public static function optimizeForReadability($data) {
// Use pretty print for debugging
return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
public static function memoryEfficientEncode($largeArray) {
// For very large arrays, consider streaming
$tempFile = tempnam(sys_get_temp_dir(), 'json_');
$handle = fopen($tempFile, 'w');
fwrite($handle, '[');
foreach ($largeArray as $index => $item) {
if ($index > 0) {
fwrite($handle, ',');
}
fwrite($handle, json_encode($item));
}
fwrite($handle, ']');
fclose($handle);
$result = file_get_contents($tempFile);
unlink($tempFile);
return $result;
}
}
// Example usage
$data = ['user' => 'John', 'scores' => range(1, 100)];
echo "Speed optimized: " . JsonPerformance::optimizeForSpeed($data) . "\n";
echo "Size optimized: " . JsonPerformance::optimizeForSize($data) . "\n";
echo "Readable: " . JsonPerformance::optimizeForReadability($data) . "\n";
$time = JsonPerformance::benchmarkEncoding($data);
echo "Encoding time: {$time} ms\n";
?>
Best Practices
Security Considerations
<?php
class SecureJsonHandler {
private $maxDepth;
private $maxSize;
public function __construct($maxDepth = 512, $maxSize = 1048576) { // 1MB default
$this->maxDepth = $maxDepth;
$this->maxSize = $maxSize;
}
public function safeDecode($json) {
// Check size limit
if (strlen($json) > $this->maxSize) {
throw new InvalidArgumentException('JSON string too large');
}
// Validate JSON structure
if (!$this->isValidJsonStructure($json)) {
throw new InvalidArgumentException('Invalid JSON structure');
}
try {
return json_decode($json, true, $this->maxDepth, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new InvalidArgumentException('JSON decode error: ' . $e->getMessage());
}
}
public function safeEncode($data) {
try {
$json = json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
// Check resulting size
if (strlen($json) > $this->maxSize) {
throw new RuntimeException('Encoded JSON too large');
}
return $json;
} catch (JsonException $e) {
throw new RuntimeException('JSON encode error: ' . $e->getMessage());
}
}
private function isValidJsonStructure($json) {
// Basic structure validation
$trimmed = trim($json);
return (
(str_starts_with($trimmed, '{') && str_ends_with($trimmed, '}')) ||
(str_starts_with($trimmed, '[') && str_ends_with($trimmed, ']'))
);
}
public function sanitizeInput($data) {
if (is_array($data)) {
return array_map([$this, 'sanitizeInput'], $data);
}
if (is_string($data)) {
// Remove potential XSS characters
return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
}
return $data;
}
}
// Usage
$handler = new SecureJsonHandler();
try {
$data = $handler->safeDecode($userInput);
$sanitized = $handler->sanitizeInput($data);
$response = $handler->safeEncode($sanitized);
} catch (Exception $e) {
error_log('JSON processing error: ' . $e->getMessage());
JsonResponse::error('Invalid data format');
}
?>
PHP's JSON functions provide robust tools for handling JSON data in modern web applications, with proper error handling and security considerations being essential for production use.