PHP

#10
TIOBE#15
PYPL#7
GitHub#14
RedMonk#4
IEEESpectrum#13
JetBrains#12
プログラミング言語Web開発サーバーサイドCMSWordPress

プログラミング言語

PHP(PHP: Hypertext Preprocessor)

概要

PHPは、Web開発に特化したサーバーサイドスクリプト言語です。HTMLに埋め込んで使用でき、動的なWebページやWebアプリケーションの開発に広く使用されています。WordPress、Drupal、LaravelなどのCMSやフレームワークでも採用され、Web開発の基盤技術として重要な地位を占めています。

詳細

PHPは1995年にRasmus Lerdorfによって開発され、当初は「Personal Home Page」の略でした。現在は「PHP: Hypertext Preprocessor」という再帰的な略語として知られています。

オープンソースで無料で利用でき、学習コストが比較的低いことから、多くの開発者に採用されています。PHP 7以降では大幅な性能向上が図られ、PHP 8では型システムの強化、JITコンパイラの導入など、モダンな言語機能が追加されています。

書き方の例

Hello World

<?php
echo "Hello, World!";
?>

<!-- HTMLと組み合わせ -->
<!DOCTYPE html>
<html>
<head>
    <title>PHP サンプル</title>
</head>
<body>
    <h1><?php echo "Hello, World!"; ?></h1>
    <p>現在時刻: <?php echo date('Y-m-d H:i:s'); ?></p>
</body>
</html>

変数とデータ型

<?php
// 変数の定義($マークで始まる)
$name = "太郎";
$age = 25;
$height = 175.5;
$is_student = true;

// 配列
$fruits = ["りんご", "バナナ", "オレンジ"];
$person = [
    "name" => "花子",
    "age" => 23,
    "city" => "東京"
];

// 変数の表示
echo "名前: $name\n";
echo "年齢: {$age}歳\n";
echo "身長: " . $height . "cm\n";

// 配列の表示
echo "好きな果物: " . $fruits[0] . "\n";
echo "人物情報: " . $person["name"] . "さん(" . $person["age"] . "歳)\n";

// 型の確認
var_dump($name);    // string
var_dump($age);     // int
var_dump($height);  // float
var_dump($is_student); // bool

// 文字列連結
$greeting = "こんにちは、" . $name . "さん!";
echo $greeting . "\n";
?>

関数とクラス

<?php
// 関数の定義
function greet($name, $time = "こんにちは") {
    return $time . "、" . $name . "さん!";
}

// 型指定を使った関数(PHP 7+)
function add(int $a, int $b): int {
    return $a + $b;
}

// 可変長引数
function sum(...$numbers) {
    return array_sum($numbers);
}

// クラスの定義
class Person {
    private string $name;
    private int $age;
    private array $skills;
    
    public function __construct(string $name, int $age) {
        $this->name = $name;
        $this->age = $age;
        $this->skills = [];
    }
    
    public function getName(): string {
        return $this->name;
    }
    
    public function getAge(): int {
        return $this->age;
    }
    
    public function addSkill(string $skill): void {
        $this->skills[] = $skill;
    }
    
    public function getSkills(): array {
        return $this->skills;
    }
    
    public function introduce(): string {
        $skillList = empty($this->skills) 
            ? "特になし" 
            : implode(", ", $this->skills);
        
        return "私は{$this->name}です。{$this->age}歳です。スキル: {$skillList}";
    }
}

// 使用例
echo greet("太郎") . "\n";
echo greet("花子", "おはよう") . "\n";
echo "計算結果: " . add(5, 3) . "\n";
echo "合計: " . sum(1, 2, 3, 4, 5) . "\n";

$person = new Person("山田太郎", 30);
$person->addSkill("PHP");
$person->addSkill("JavaScript");
echo $person->introduce() . "\n";
?>

データベース接続(PDO)

<?php
try {
    // データベース接続
    $pdo = new PDO(
        'mysql:host=localhost;dbname=testdb;charset=utf8',
        'username',
        'password',
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]
    );
    
    // テーブル作成
    $pdo->exec("
        CREATE TABLE IF NOT EXISTS users (
            id INT AUTO_INCREMENT PRIMARY KEY,
            name VARCHAR(100) NOT NULL,
            email VARCHAR(100) UNIQUE NOT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    ");
    
    // データ挿入(プリペアドステートメント)
    $stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
    $stmt->execute(["山田太郎", "[email protected]"]);
    $stmt->execute(["佐藤花子", "[email protected]"]);
    
    // データ取得
    $stmt = $pdo->query("SELECT * FROM users ORDER BY created_at DESC");
    $users = $stmt->fetchAll();
    
    echo "登録されているユーザー:\n";
    foreach ($users as $user) {
        echo "ID: {$user['id']}, 名前: {$user['name']}, Email: {$user['email']}\n";
    }
    
    // 特定ユーザーの検索
    $stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
    $stmt->execute(["[email protected]"]);
    $user = $stmt->fetch();
    
    if ($user) {
        echo "検索結果: {$user['name']} ({$user['email']})\n";
    }
    
    // ユーザー数の取得
    $stmt = $pdo->query("SELECT COUNT(*) as count FROM users");
    $count = $stmt->fetch()['count'];
    echo "総ユーザー数: {$count}\n";
    
} catch (PDOException $e) {
    echo "データベースエラー: " . $e->getMessage() . "\n";
}
?>

Webフォーム処理

<?php
session_start();

// CSRF トークン生成
if (!isset($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// エラーメッセージ配列
$errors = [];

// フォームが送信された場合の処理
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // CSRF トークンの確認
    if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
        die('CSRF token mismatch');
    }
    
    // バリデーション
    $name = trim($_POST['name'] ?? '');
    $email = trim($_POST['email'] ?? '');
    $message = trim($_POST['message'] ?? '');
    
    if (empty($name)) {
        $errors['name'] = '名前は必須です';
    } elseif (strlen($name) > 50) {
        $errors['name'] = '名前は50文字以内で入力してください';
    }
    
    if (empty($email)) {
        $errors['email'] = 'メールアドレスは必須です';
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errors['email'] = '有効なメールアドレスを入力してください';
    }
    
    if (empty($message)) {
        $errors['message'] = 'メッセージは必須です';
    } elseif (strlen($message) > 1000) {
        $errors['message'] = 'メッセージは1000文字以内で入力してください';
    }
    
    // エラーがない場合の処理
    if (empty($errors)) {
        // データベース保存やメール送信などの処理
        // ...
        
        $_SESSION['success'] = 'お問い合わせを受け付けました';
        header('Location: ' . $_SERVER['PHP_SELF']);
        exit;
    }
}

// サクセスメッセージの取得と削除
$success = $_SESSION['success'] ?? null;
unset($_SESSION['success']);
?>

<!DOCTYPE html>
<html>
<head>
    <title>お問い合わせフォーム</title>
    <style>
        .error { color: red; }
        .success { color: green; }
        .form-group { margin-bottom: 1rem; }
    </style>
</head>
<body>
    <h1>お問い合わせフォーム</h1>
    
    <?php if ($success): ?>
        <p class="success"><?php echo htmlspecialchars($success); ?></p>
    <?php endif; ?>
    
    <form method="post">
        <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
        
        <div class="form-group">
            <label for="name">名前:</label><br>
            <input type="text" id="name" name="name" value="<?php echo htmlspecialchars($name ?? ''); ?>">
            <?php if (isset($errors['name'])): ?>
                <div class="error"><?php echo htmlspecialchars($errors['name']); ?></div>
            <?php endif; ?>
        </div>
        
        <div class="form-group">
            <label for="email">メールアドレス:</label><br>
            <input type="email" id="email" name="email" value="<?php echo htmlspecialchars($email ?? ''); ?>">
            <?php if (isset($errors['email'])): ?>
                <div class="error"><?php echo htmlspecialchars($errors['email']); ?></div>
            <?php endif; ?>
        </div>
        
        <div class="form-group">
            <label for="message">メッセージ:</label><br>
            <textarea id="message" name="message" rows="5" cols="50"><?php echo htmlspecialchars($message ?? ''); ?></textarea>
            <?php if (isset($errors['message'])): ?>
                <div class="error"><?php echo htmlspecialchars($errors['message']); ?></div>
            <?php endif; ?>
        </div>
        
        <button type="submit">送信</button>
    </form>
</body>
</html>

JSON API の作成

<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type');

// エラーハンドリング関数
function sendError($message, $code = 400) {
    http_response_code($code);
    echo json_encode(['error' => $message]);
    exit;
}

// 成功レスポンス関数
function sendResponse($data, $code = 200) {
    http_response_code($code);
    echo json_encode($data);
    exit;
}

// リクエストメソッドの取得
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

// 仮のデータ配列(通常はデータベースから取得)
$users = [
    ['id' => 1, 'name' => '山田太郎', 'email' => '[email protected]'],
    ['id' => 2, 'name' => '佐藤花子', 'email' => '[email protected]'],
    ['id' => 3, 'name' => '田中次郎', 'email' => '[email protected]'],
];

// ルーティング
switch ($method) {
    case 'GET':
        if (preg_match('/\/api\/users\/(\d+)$/', $path, $matches)) {
            // 特定ユーザーの取得
            $userId = (int)$matches[1];
            $user = array_filter($users, function($u) use ($userId) {
                return $u['id'] === $userId;
            });
            
            if (empty($user)) {
                sendError('User not found', 404);
            }
            
            sendResponse(array_values($user)[0]);
            
        } elseif ($path === '/api/users') {
            // 全ユーザーの取得
            $page = $_GET['page'] ?? 1;
            $limit = $_GET['limit'] ?? 10;
            $search = $_GET['search'] ?? '';
            
            // 検索フィルタ
            if ($search) {
                $users = array_filter($users, function($user) use ($search) {
                    return stripos($user['name'], $search) !== false ||
                           stripos($user['email'], $search) !== false;
                });
            }
            
            // ページネーション
            $total = count($users);
            $offset = ($page - 1) * $limit;
            $users = array_slice($users, $offset, $limit);
            
            sendResponse([
                'data' => array_values($users),
                'pagination' => [
                    'page' => (int)$page,
                    'limit' => (int)$limit,
                    'total' => $total,
                    'pages' => ceil($total / $limit)
                ]
            ]);
        } else {
            sendError('Endpoint not found', 404);
        }
        break;
        
    case 'POST':
        if ($path === '/api/users') {
            // ユーザー作成
            $input = json_decode(file_get_contents('php://input'), true);
            
            if (!$input || !isset($input['name']) || !isset($input['email'])) {
                sendError('Name and email are required');
            }
            
            // バリデーション
            if (!filter_var($input['email'], FILTER_VALIDATE_EMAIL)) {
                sendError('Invalid email format');
            }
            
            // 新しいユーザーの作成(通常はデータベースに保存)
            $newUser = [
                'id' => count($users) + 1,
                'name' => $input['name'],
                'email' => $input['email']
            ];
            
            sendResponse($newUser, 201);
        } else {
            sendError('Endpoint not found', 404);
        }
        break;
        
    default:
        sendError('Method not allowed', 405);
}
?>

ファイルアップロード処理

<?php
// アップロード設定
$uploadDir = 'uploads/';
$maxFileSize = 5 * 1024 * 1024; // 5MB
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];

// アップロードディレクトリの作成
if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0755, true);
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['upload'])) {
    $file = $_FILES['upload'];
    $errors = [];
    
    // エラーチェック
    if ($file['error'] !== UPLOAD_ERR_OK) {
        $errors[] = 'ファイルのアップロードに失敗しました';
    }
    
    // ファイルサイズチェック
    if ($file['size'] > $maxFileSize) {
        $errors[] = 'ファイルサイズが大きすぎます(最大5MB)';
    }
    
    // ファイル形式チェック
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeType = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);
    
    if (!in_array($mimeType, $allowedTypes)) {
        $errors[] = '対応していないファイル形式です(JPEG、PNG、GIFのみ)';
    }
    
    // エラーがない場合はファイルを保存
    if (empty($errors)) {
        $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
        $filename = uniqid() . '.' . $extension;
        $destination = $uploadDir . $filename;
        
        if (move_uploaded_file($file['tmp_name'], $destination)) {
            echo "ファイルがアップロードされました: " . htmlspecialchars($filename);
            
            // 画像の場合はサムネイル作成
            if (strpos($mimeType, 'image/') === 0) {
                createThumbnail($destination, $uploadDir . 'thumb_' . $filename);
            }
        } else {
            $errors[] = 'ファイルの保存に失敗しました';
        }
    }
    
    // エラー表示
    if (!empty($errors)) {
        foreach ($errors as $error) {
            echo "<p style='color: red;'>" . htmlspecialchars($error) . "</p>";
        }
    }
}

// サムネイル作成関数
function createThumbnail($source, $destination, $maxWidth = 200, $maxHeight = 200) {
    $imageInfo = getimagesize($source);
    if (!$imageInfo) return false;
    
    $originalWidth = $imageInfo[0];
    $originalHeight = $imageInfo[1];
    $mimeType = $imageInfo['mime'];
    
    // 元画像の読み込み
    switch ($mimeType) {
        case 'image/jpeg':
            $originalImage = imagecreatefromjpeg($source);
            break;
        case 'image/png':
            $originalImage = imagecreatefrompng($source);
            break;
        case 'image/gif':
            $originalImage = imagecreatefromgif($source);
            break;
        default:
            return false;
    }
    
    // サムネイルサイズの計算
    $ratio = min($maxWidth / $originalWidth, $maxHeight / $originalHeight);
    $newWidth = intval($originalWidth * $ratio);
    $newHeight = intval($originalHeight * $ratio);
    
    // サムネイル画像の作成
    $thumbnail = imagecreatetruecolor($newWidth, $newHeight);
    imagecopyresampled(
        $thumbnail, $originalImage,
        0, 0, 0, 0,
        $newWidth, $newHeight,
        $originalWidth, $originalHeight
    );
    
    // 保存
    $result = imagejpeg($thumbnail, $destination, 80);
    
    // メモリ解放
    imagedestroy($originalImage);
    imagedestroy($thumbnail);
    
    return $result;
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>ファイルアップロード</title>
</head>
<body>
    <h1>ファイルアップロード</h1>
    <form method="post" enctype="multipart/form-data">
        <label for="upload">画像ファイル(JPEG、PNG、GIF、最大5MB):</label><br>
        <input type="file" id="upload" name="upload" accept="image/*" required><br><br>
        <button type="submit">アップロード</button>
    </form>
    
    <?php
    // アップロード済みファイルの一覧表示
    if (is_dir($uploadDir)) {
        $files = glob($uploadDir . '*');
        if (!empty($files)) {
            echo "<h2>アップロード済みファイル</h2>";
            foreach ($files as $file) {
                if (is_file($file) && strpos(basename($file), 'thumb_') !== 0) {
                    $filename = basename($file);
                    $thumbFile = $uploadDir . 'thumb_' . $filename;
                    
                    echo "<div style='margin: 10px; display: inline-block;'>";
                    if (file_exists($thumbFile)) {
                        echo "<img src='$thumbFile' alt='$filename' style='max-width: 200px; max-height: 200px;'><br>";
                    }
                    echo "<a href='$file' target='_blank'>" . htmlspecialchars($filename) . "</a>";
                    echo "</div>";
                }
            }
        }
    }
    ?>
</body>
</html>

メリット・デメリット

メリット

  • 学習コストが低い: 比較的簡単に習得できる構文
  • Web開発特化: HTMLとの親和性が高く、Web開発に最適化
  • 豊富な資料: 長年の蓄積による学習リソースとコミュニティ
  • ホスティング対応: 多くのレンタルサーバーで標準サポート
  • CMSエコシステム: WordPress、Drupalなどの巨大な生態系
  • フレームワーク: Laravel、Symfony、CodeIgniterなどの選択肢

デメリット

  • 言語設計の一貫性: 歴史的経緯による関数名や仕様の不統一
  • パフォーマンス: 他の言語と比較して実行速度が劣る場合がある
  • 型安全性: 動的型付けによる実行時エラーのリスク
  • セキュリティ: 適切な対策なしでは脆弱性を作り込みやすい
  • 企業利用: 大規模システムでの採用が限定的

主要リンク

ランキング情報

  • 総合ランキング: 10位
  • TIOBE Index: 15位
  • PYPL PopularitY: 7位
  • GitHub使用率: 14位
  • RedMonk言語ランキング: 4位
  • IEEE Spectrum: 13位
  • JetBrains開発者調査: 12位

PHPは、Web開発において長年の実績を持つサーバーサイド言語として、CMS開発やWebアプリケーション構築で重要な役割を果たしています。