はじめに
Webアプリケーション開発において、適切なHTTPステータスコードの設定は、SEO対策、ユーザーエクスペリエンス、API設計の観点から非常に重要です。PHPのhttp_response_code
関数は、レスポンスのHTTPステータスコードを簡単に制御できる便利な関数です。
この記事では、http_response_code
関数の基本的な使い方から実践的な活用方法まで、具体的なコード例を交えて詳しく解説します。
http_response_code関数とは?
http_response_code
関数は、PHPでHTTPレスポンスのステータスコードを設定または取得するための関数です。PHP 5.4.0以降で使用可能で、従来のheader()
関数よりもシンプルで直感的にステータスコードを操作できます。
基本構文
http_response_code(int $response_code = 0): int|bool
- パラメータなし:現在のステータスコードを取得
- パラメータあり:指定したステータスコードを設定
基本的な使用例
現在のステータスコードを取得
<?php
// 現在のHTTPステータスコードを取得
$current_code = http_response_code();
echo "現在のステータスコード: " . $current_code;
// 出力: 現在のステータスコード: 200(デフォルト)
?>
ステータスコードの設定
<?php
// 404 Not Foundを設定
http_response_code(404);
echo "ページが見つかりません";
// 設定されたコードを確認
echo "設定されたコード: " . http_response_code();
// 出力: 設定されたコード: 404
?>
主要なHTTPステータスコード
Webアプリケーションでよく使用されるステータスコードとその用途を整理しました:
2xx 成功
<?php
// 200 OK - 正常なレスポンス
http_response_code(200);
// 201 Created - リソースの作成成功
http_response_code(201);
echo json_encode(['message' => 'ユーザーが作成されました']);
// 204 No Content - 成功だがコンテンツなし
http_response_code(204);
exit; // 204の場合は通常コンテンツを返さない
?>
3xx リダイレクト
<?php
// 301 Moved Permanently - 永続的なリダイレクト
http_response_code(301);
header('Location: https://example.com/new-page');
exit;
// 302 Found - 一時的なリダイレクト
http_response_code(302);
header('Location: https://example.com/temporary-page');
exit;
// 304 Not Modified - キャッシュ有効
http_response_code(304);
exit;
?>
4xx クライアントエラー
<?php
// 400 Bad Request - 不正なリクエスト
if (empty($_POST['required_field'])) {
http_response_code(400);
echo json_encode(['error' => '必須フィールドが未入力です']);
exit;
}
// 401 Unauthorized - 認証が必要
if (!isAuthenticated()) {
http_response_code(401);
echo json_encode(['error' => '認証が必要です']);
exit;
}
// 403 Forbidden - アクセス禁止
if (!hasPermission()) {
http_response_code(403);
echo json_encode(['error' => 'アクセス権限がありません']);
exit;
}
// 404 Not Found - リソースが見つからない
if (!pageExists()) {
http_response_code(404);
include '404.php';
exit;
}
?>
5xx サーバーエラー
<?php
// 500 Internal Server Error - サーバー内部エラー
try {
// 何らかの処理
processData();
} catch (Exception $e) {
http_response_code(500);
error_log('Server Error: ' . $e->getMessage());
echo json_encode(['error' => 'サーバーエラーが発生しました']);
exit;
}
// 503 Service Unavailable - サービス利用不可
if (isMaintenanceMode()) {
http_response_code(503);
header('Retry-After: 3600'); // 1時間後に再試行
echo 'メンテナンス中です';
exit;
}
?>
実践的な活用例
1. REST API の実装
<?php
class UserAPI {
public function handleRequest() {
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
switch ($method) {
case 'GET':
$this->getUser($path);
break;
case 'POST':
$this->createUser();
break;
case 'PUT':
$this->updateUser($path);
break;
case 'DELETE':
$this->deleteUser($path);
break;
default:
http_response_code(405); // Method Not Allowed
echo json_encode(['error' => '許可されていないメソッドです']);
}
}
private function getUser($path) {
$userId = $this->extractUserId($path);
if (!$userId) {
http_response_code(400);
echo json_encode(['error' => '無効なユーザーIDです']);
return;
}
$user = $this->findUser($userId);
if (!$user) {
http_response_code(404);
echo json_encode(['error' => 'ユーザーが見つかりません']);
return;
}
http_response_code(200);
echo json_encode($user);
}
private function createUser() {
$input = json_decode(file_get_contents('php://input'), true);
if (!$this->validateUserData($input)) {
http_response_code(400);
echo json_encode(['error' => '入力データが無効です']);
return;
}
if ($this->userExists($input['email'])) {
http_response_code(409); // Conflict
echo json_encode(['error' => 'ユーザーは既に存在します']);
return;
}
$userId = $this->saveUser($input);
http_response_code(201);
header('Location: /api/users/' . $userId);
echo json_encode(['id' => $userId, 'message' => 'ユーザーが作成されました']);
}
private function updateUser($path) {
$userId = $this->extractUserId($path);
$input = json_decode(file_get_contents('php://input'), true);
if (!$this->findUser($userId)) {
http_response_code(404);
echo json_encode(['error' => 'ユーザーが見つかりません']);
return;
}
$this->updateUserData($userId, $input);
http_response_code(200);
echo json_encode(['message' => 'ユーザーが更新されました']);
}
private function deleteUser($path) {
$userId = $this->extractUserId($path);
if (!$this->findUser($userId)) {
http_response_code(404);
echo json_encode(['error' => 'ユーザーが見つかりません']);
return;
}
$this->removeUser($userId);
http_response_code(204); // No Content
// 204の場合はレスポンスボディを返さない
}
}
$api = new UserAPI();
$api->handleRequest();
?>
2. ファイルダウンロード機能
<?php
class FileDownloader {
public function download($filename) {
$filepath = $this->getSecureFilePath($filename);
// ファイルの存在確認
if (!file_exists($filepath)) {
http_response_code(404);
echo 'ファイルが見つかりません';
return;
}
// アクセス権限の確認
if (!$this->hasDownloadPermission($filename)) {
http_response_code(403);
echo 'ダウンロード権限がありません';
return;
}
// ファイルサイズの確認
$filesize = filesize($filepath);
if ($filesize === false || $filesize > 100 * 1024 * 1024) { // 100MB制限
http_response_code(413); // Payload Too Large
echo 'ファイルサイズが大きすぎます';
return;
}
// 成功時のレスポンス
http_response_code(200);
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Content-Length: ' . $filesize);
header('Cache-Control: no-cache');
readfile($filepath);
}
private function getSecureFilePath($filename) {
// セキュリティ: パストラバーサル攻撃を防ぐ
$safe_filename = basename($filename);
return '/secure/downloads/' . $safe_filename;
}
private function hasDownloadPermission($filename) {
// 権限チェックのロジック
return isset($_SESSION['user_id']) && $this->userCanDownload($_SESSION['user_id'], $filename);
}
}
$downloader = new FileDownloader();
$downloader->download($_GET['file'] ?? '');
?>
3. 認証システムの実装
<?php
class AuthSystem {
public function login($email, $password) {
// 入力値の検証
if (empty($email) || empty($password)) {
http_response_code(400);
return ['error' => 'メールアドレスとパスワードが必要です'];
}
// レート制限のチェック
if ($this->isRateLimited($email)) {
http_response_code(429); // Too Many Requests
return ['error' => 'ログイン試行回数が上限に達しました。しばらく待ってからお試しください'];
}
// ユーザーの認証
$user = $this->authenticateUser($email, $password);
if (!$user) {
$this->recordFailedAttempt($email);
http_response_code(401);
return ['error' => 'メールアドレスまたはパスワードが正しくありません'];
}
// アカウントの状態確認
if (!$user['is_active']) {
http_response_code(403);
return ['error' => 'アカウントが無効化されています'];
}
// セッションの開始
$this->startUserSession($user);
http_response_code(200);
return ['message' => 'ログインに成功しました', 'user' => $user];
}
public function logout() {
if (!isset($_SESSION['user_id'])) {
http_response_code(400);
return ['error' => 'ログインしていません'];
}
$this->endUserSession();
http_response_code(200);
return ['message' => 'ログアウトしました'];
}
public function requireAuth() {
if (!isset($_SESSION['user_id'])) {
http_response_code(401);
header('WWW-Authenticate: Bearer');
echo json_encode(['error' => '認証が必要です']);
exit;
}
}
private function isRateLimited($email) {
// レート制限のロジック(Redis等を使用)
return false; // 実装例では省略
}
private function recordFailedAttempt($email) {
// 失敗試行の記録
}
}
// 使用例
session_start();
$auth = new AuthSystem();
if ($_POST['action'] === 'login') {
$result = $auth->login($_POST['email'], $_POST['password']);
echo json_encode($result);
} elseif ($_POST['action'] === 'logout') {
$result = $auth->logout();
echo json_encode($result);
}
?>
4. エラーハンドリングシステム
<?php
class ErrorHandler {
public function handleError($error_type, $message = '') {
switch ($error_type) {
case 'validation':
http_response_code(400);
$this->sendErrorResponse('入力データが無効です', $message);
break;
case 'authentication':
http_response_code(401);
$this->sendErrorResponse('認証が必要です', $message);
break;
case 'permission':
http_response_code(403);
$this->sendErrorResponse('アクセス権限がありません', $message);
break;
case 'not_found':
http_response_code(404);
$this->sendErrorResponse('リソースが見つかりません', $message);
break;
case 'conflict':
http_response_code(409);
$this->sendErrorResponse('競合が発生しました', $message);
break;
case 'rate_limit':
http_response_code(429);
header('Retry-After: 60');
$this->sendErrorResponse('リクエスト制限に達しました', $message);
break;
case 'server_error':
default:
http_response_code(500);
error_log('Server Error: ' . $message);
$this->sendErrorResponse('サーバーエラーが発生しました');
break;
}
}
private function sendErrorResponse($default_message, $custom_message = '') {
$response = [
'error' => true,
'message' => $custom_message ?: $default_message,
'timestamp' => date('c'),
'status_code' => http_response_code()
];
header('Content-Type: application/json');
echo json_encode($response);
exit;
}
}
// グローバルエラーハンドラーの設定
set_exception_handler(function($exception) {
$handler = new ErrorHandler();
$handler->handleError('server_error', $exception->getMessage());
});
// 使用例
try {
$user = findUser($user_id);
if (!$user) {
$handler = new ErrorHandler();
$handler->handleError('not_found', 'ユーザーID: ' . $user_id);
}
} catch (Exception $e) {
throw $e; // グローバルハンドラーで処理される
}
?>
SEO対策での活用
1. 適切なリダイレクト処理
<?php
class SEORedirector {
public function permanentRedirect($old_url, $new_url) {
if ($_SERVER['REQUEST_URI'] === $old_url) {
http_response_code(301); // SEOの評価を引き継ぐ
header('Location: ' . $new_url);
exit;
}
}
public function temporaryRedirect($url) {
http_response_code(302); // 一時的なリダイレクト
header('Location: ' . $url);
exit;
}
public function handleCanonicalURL() {
$canonical_url = $this->getCanonicalURL();
$current_url = $this->getCurrentURL();
if ($canonical_url !== $current_url) {
http_response_code(301);
header('Location: ' . $canonical_url);
exit;
}
}
}
$redirector = new SEORedirector();
$redirector->permanentRedirect('/old-page', '/new-page');
?>
2. カスタム404ページ
<?php
function handle404() {
http_response_code(404);
// SEOに配慮したカスタム404ページ
include 'templates/404.php';
// 404エラーをログに記録
error_log('404 Error: ' . $_SERVER['REQUEST_URI'] . ' from ' . $_SERVER['HTTP_REFERER']);
exit;
}
// ページの存在確認
if (!pageExists($_SERVER['REQUEST_URI'])) {
handle404();
}
?>
header()関数との比較
<?php
// 従来のheader()関数
header("HTTP/1.1 404 Not Found");
// http_response_code()関数(推奨)
http_response_code(404);
// 組み合わせて使用
http_response_code(404);
header('Content-Type: application/json');
echo json_encode(['error' => 'Not Found']);
?>
メリット
- シンプルな構文:ステータスコードの設定が直感的
- 型安全:整数値のみ受け付ける
- 取得機能:現在のステータスコードを簡単に取得可能
- 保守性:コードの意図が明確
パフォーマンスとベストプラクティス
1. 早期終了パターン
<?php
// 認証チェックを早期に実行
if (!isAuthenticated()) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit; // 早期終了でパフォーマンス向上
}
// 以降の処理は認証済みユーザーのみ実行される
?>
2. キャッシュ制御
<?php
function setCacheHeaders($max_age = 3600) {
http_response_code(200);
header('Cache-Control: public, max-age=' . $max_age);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $max_age) . ' GMT');
}
function setNoCacheHeaders() {
http_response_code(200);
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
}
// 静的コンテンツ
setCacheHeaders(86400); // 24時間
// 動的コンテンツ
setNoCacheHeaders();
?>
まとめ
http_response_code
関数は、PHPでHTTPステータスコードを効率的に管理するための重要なツールです。適切なステータスコードの設定により、以下の効果が期待できます:
主な利点:
- SEO効果の向上:検索エンジンへの正確な情報伝達
- ユーザーエクスペリエンスの改善:明確なエラーメッセージと適切な処理
- API設計の品質向上:RESTful APIの標準に準拠
- デバッグの効率化:問題の特定と解決の迅速化
- セキュリティの強化:適切なアクセス制御とエラーハンドリング
ベストプラクティス:
- ステータスコードの意味を正しく理解して使用する
- エラー時は適切なメッセージと共にコードを設定する
- SEO対策を考慮したリダイレクト処理を実装する
- パフォーマンスを意識した早期終了パターンを活用する
- ログ記録と組み合わせて問題の追跡を行う
適切なHTTPステータスコードの使用は、プロフェッショナルなWebアプリケーション開発の基本です。http_response_code
関数を効果的に活用して、ユーザーにとって使いやすく、検索エンジンにとって理解しやすいWebサイトを構築しましょう。
この記事がお役に立ちましたら、ぜひ開発チームと共有してください。HTTPステータスコードやWeb開発について、他にもご質問がございましたらお気軽にお尋ねください。