レンタルサーバで活用しているPHPモジュールのメモ

普段AWSを利用する事が多いのですが、コストの都合や検証用の環境としてレンタルサーバも契約しています。
レンタルサーバでは普段利用している言語で開発をするのが難しいためPHPで開発していますが、フレームワークは利用していません。
(フレームワークのアップデートなどを追うほど利用しないため)
上記の様な背景もあり、複雑な処理を書くこともありませんし、負荷を気にするほどのコンテンツでもないので、他の言語を使っていればなんとなく分かるようにしています。

common.php

DB接続以外のよく利用するAPIで必要な処理やメール送信、Slack通知などをまとめています。

<?php

function allowOrigin($origin, $methods = "GET, POST, OPTIONS, PUT, DELETE")
{
  header("Access-Control-Allow-Origin: " . $origin);
  header("Access-Control-Allow-Methods: " . $methods);
  header("Access-Control-Allow-Headers: Content-Disposition, Content-Type, Content-Length, Accept-Encoding");
  header("Content-Type: application/json; charset=utf-8");
}

function noCache()
{
  header("Cache-Control: private, no-cache, no-store, must-revalidate");
  header("Cache-Control: post-check=0, pre-check=0", false);
  header("Pragma:no-cache");
}

function ok($data)
{
  header("HTTP/1.1 200 OK");
  echo json_encode($data, JSON_UNESCAPED_UNICODE);
  exit;
}

function badRequest($data)
{
  header("HTTP/1.1 400 Bad Request");
  echo json_encode($data, JSON_UNESCAPED_UNICODE);
  exit;
}

function serverInternalError($data)
{
  header("HTTP/1.1 500 Internal Server Error");
  echo json_encode($data, JSON_UNESCAPED_UNICODE);
  exit;
}

function sendMail($toEmail, $subject, $mailBody, $fromEmail)
{
  $mailFrom = "From: " . $fromEmail;
  return mb_send_mail($toEmail, $subject, $mailBody, $mailFrom);
}

function slackPost($url, $message)
{
  $params = ["text" => $message];

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-type: application/json"]);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
  $result = curl_exec($ch);
  curl_close($ch);
  return $result;
}

database_connection.php

DB接続の管理用のクラスです。

<?php
// Example:
//   $conn = new DatabaseConnection();
//   $conn->insert("products", ["name" => "Sample", "price" => 10]);
//   $rows = $conn->select("select * from products");
//   $row = $rows[0];
//   $row["price"] = 100;
//   $conn->update("products", $row);
//   $conn->delete("products", $row);
//   $conn->close();
class DatabaseConnection
{
  public mixed $db; // DBインスタンス
  public ?string $err; // エラーメッセージ

  private string $host = "localhost"; // DBサーバ
  private string $dbname = "DATABASE_NAME"; // DB名
  private string $charset = "utf8";
  private string $user = "DATABASE_USER"; // DBユーザ
  private string $password = "DATABASE_PASSWORD"; // DB接続パスワード
  private string $primaryKey = "id"; // プライマリキー

  function __construct($database = null)
  {
    $this->err = null;

    if ($database) {
      $this->db = $database;
    } else {
      $dsn = "mysql:host=" . $this->host . ";dbname=" . $this->dbname . ";charset=" . $this->charset;
      try {
        $this->db = new PDO($dsn, $this->user, $this->password);
      } catch (PDOException $e) {
        $this->err = $e->getMessage();
      }
    }
  }

  function select($sql): bool|array
  {
    $stmt = $this->db->query($sql);
    return $stmt->fetchAll();
  }

  function insert($table, $data): bool
  {
    $columns = array_keys($data);
    $columnsStr = implode(", ", $columns);
    $valuesStr = implode(", ", array_map(fn($col) => ":" . $col, $columns));
    $sql = "INSERT INTO " . $table . " (" . $columnsStr .") VALUES (" . $valuesStr . ")";
    $stmt = $this->db->prepare($sql);
    return $stmt->execute($data);
  }

  function update($table, $data): bool
  {
    if (array_key_exists($this->primaryKey, $data) && $data[$this->primaryKey]) {
      $setValues = [];
      foreach (array_keys($data) as $key) {
        if ($key == $this->primaryKey) {
          continue;
        }
        $setValues[] = $key . " = :" . $key;
      }
      $setValuesStr = implode(", ", $setValues);
      $sql = "UPDATE " . $table . " SET " . $setValuesStr . " WHERE " . $this->primaryKey . " = :" . $this->primaryKey;
      $stmt = $this->db->prepare($sql);
      return $stmt->execute($data);
    }

    return false;
  }

  function delete($table, $data): bool
  {
    if (array_key_exists($this->primaryKey, $data) && $data[$this->primaryKey]) {
      $sql = "DELETE FROM " . $table . " WHERE " . $this->primaryKey . " = :" . $this->primaryKey;
      $stmt = $this->db->prepare($sql);
      return $stmt->execute([$this->primaryKey => $data[$this->primaryKey]]);
    }

    return false;
  }

  function close(): void
  {
    $this->db = null;
  }
}

使用例

<?php
require "../lib/common.php";
require "../lib/database_connection.php";

// CORS設定
allowOrigin("https://app.example.com");

// キャッシュしない
noCache();

// DBからデータを取得
$conn = new DatabaseConnection();
$products = $conn->select("select * from products");
$conn->close();

// JSONでレスポンスを返す
ok($products);