PHP のスニペット集

このページは、PHP のスニペットとユーティリティ関数などをまとめる予定のページです。

目次

注意

スニペット

HTTP

filter_input()

$_GET['x'] を string で取得
$x = filter_input(INPUT_GET, 'x');
$_GET['x'] を int で取得
$x = filter_input(INPUT_GET, 'x', FILTER_VALIDATE_INT);
$_GET['x'] を float で取得
$x = filter_input(INPUT_GET, 'x', FILTER_VALIDATE_FLOAT);
$_GET['x'] を array で取得
$x = filter_input(INPUT_GET, 'x', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
$_POST['x'] を string で取得
$x = filter_input(INPUT_POST, 'x');
$_POST['x'] を int で取得
$x = filter_input(INPUT_POST, 'x', FILTER_VALIDATE_INT);
$_POST['x'] を float で取得
$x = filter_input(INPUT_POST, 'x', FILTER_VALIDATE_FLOAT);
$_POST['x'] を array で取得
$x = filter_input(INPUT_POST, 'x', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
404
header('HTTP/1.1 404 Not Found');
403
header('HTTP/1.1 403 Forbidden');
503
header('HTTP/1.1 503 Service Unavailable');
リダイレクト
header('Location: http://example.com/');
テキスト
header('Content-Type: text/plain');
HTML
header('Content-Type: text/html; charset=UTF-8');
JSON
header('Content-Type: application/json');
CORS
header('Access-Control-Allow-Origin: *');

文字列

置換

str_replace()
$s = '\\a\\b\\c';
$s2 = str_replace('\\', '/', $s); // /a/b/c

かな変換

半角カタカナ→全角カタカナ
$s = 'アイウ';
$s = mb_convert_kana($s, "KV"); // アイウ

preg_match()

// $s: 検査文字列, $m: マッチ結果
if (preg_match('#正規表現#', $s, $m)) {
}
YYYYMMDD から年月日を分割して取得
$s = '20190101';
if (preg_match('#\A([0-9]{4})([0-9]{2})([0-9]{2})\z#', $s, $m)) {
    $yyyy = $m[1];
    $mm = $m[2];
    $dd = $m[3];
}

preg_replace()

YYYYMMDD → YYYY/MM/DD
$s = '20190101';
$s2 = preg_replace('#\A([0-9]{4})([0-9]{2})([0-9]{2})\z#', '$1/$2/$3', $s);

cURL

GET リクエスト

$url = 'https://example.com'; // リクエスト先のURL
$query = array( // パラメータ
    'key' => 'value',
);

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url . '?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986)); // URL
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // リクエスト先が https の場合、証明書検証をしない (環境によって動作しない場合があるため)
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // curl_exec() 経由で応答データを直接取得できるようにする
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); // 接続タイムアウトの秒数
// curl_setopt($curl, CURLOPT_REFERER, 'https://example.com'); // リファラセット (必要な場合)
// curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // リダイレクトをたどる (必要な場合)
// curl_setopt($curl, CURLOPT_HTTPHEADER, array('Cookie: key=value')); // リクエストヘッダーをセット (必要な場合)
$responseString = curl_exec($curl); // 応答データ取得(失敗した場合false)
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE); // 応答コード
curl_close($curl);

//$json = ($responseString !== false) ? json_decode($responseString, true) : false; // 連想配列で応答データ取得(応答データがJSONのときに使用します)

POST リクエスト

$url = 'https://example.com'; // リクエスト先のURL
$query = array( // パラメータ
    'key' => 'value',
);

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url ); // URL
curl_setopt($curl, CURLOPT_POST, true); // POST送信
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($query, '', '&', PHP_QUERY_RFC3986)); // 送信データをセット
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // リクエスト先が https の場合、証明書検証をしない (環境によって動作しない場合があるため)
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // curl_exec() 経由で応答データを直接取得できるようにする
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); // 接続タイムアウトの秒数
// curl_setopt($curl, CURLOPT_REFERER, 'https://example.com'); // リファラセット (必要な場合)
$responseString = curl_exec($curl); // 応答データ取得(失敗した場合false)
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE); // 応答コード
curl_close($curl);

メール

送信テスト

$from = 'from@example.com';
$to = 'to@example.com';
$subject = 'test subject';
$message = 'test message';
$sent = mail($to, $subject, $message, 'From: ' . $from);

ob_start()

ob_start();
// echo や var_dump() などを実行
$c = ob_get_clean();

セッションの設定と開始

<?php

// 設定 (別途定数などを定義しておいて取得)
$sessionLifetime = 14*24*60*60; // セッション有効期限 (秒)。例: 14*24*60*60 = 14日
$sessionUrlPath = '/'; // セッション範囲のURLパス
$sessionSavePath = dirname(__FILE__) . '/tmp'; // セッション保存場所 (レンタルサーバーの場合はGC設定が他ユーザーと競合して意図しない動作になるため特に変更が必要)

// ガベージコレクション(GC)の設定
ini_set('session.gc_maxlifetime', max(ini_get('session.gc_maxlifetime'), $sessionLifetime)); // セッション有効期限より長くします

// セッションクッキーの設定
$cookieParams = session_get_cookie_params();
$lifetime = $sessionLifetime;
$path = $sessionUrlPath;
$domain = $cookieParams['domain'];
$secure = isset($_SERVER['HTTPS']) /*&& $_SERVER['HTTPS'] == 'on'*/; // https の時は true
$httponly = true; // 常に true
session_set_cookie_params($lifetime, $path, $domain, $secure, $httponly);

// セッション保存場所変更
if (!is_dir($sessionSavePath)) @mkdir($sessionSavePath, 0700, true);
session_save_path($sessionSavePath);

// セッション開始
@session_start();

暗号化

$method = 'AES-256-CBC'; // 暗号化の種類 (http://php.net/manual/ja/function.openssl-get-cipher-methods.php にあるもの)
$key = 'password'; // 任意のキー(パスフレーズ)
$iv = '1234567890123456'; // 任意の初期化ベクトル。AESの場合16桁。openssl_cipher_iv_length($method) で取得した桁をもとに文字をランダム生成してもよいです

$data = 'テスト'; // 暗号化したい文字列
$encrypted = openssl_encrypt($data, $method, $key, 0, $iv); // 暗号化 (バイナリが必要な場合、 0 の部分を OPENSSL_RAW_DATA にします)
$decrypted = openssl_decrypt($encrypted, $method, $key, 0, $iv); // 復号 ($sと同じ文字列になります。バイナリの復号は 0 の部分を OPENSSL_RAW_DATA にします)
$method = 'AES-256-CBC'; // 暗号化の種類 (http://php.net/manual/ja/function.openssl-get-cipher-methods.php にあるもの)
$key = 'password'; // 任意のキー(パスフレーズ)
$iv = '1234567890123456'; // 任意の初期化ベクトル。AESの場合16桁。openssl_cipher_iv_length($method) で取得した桁をもとに文字をランダム生成してもよいです

$src = 'test.pdf'; // 元ファイル
$enPath = 'test-e.pdf'; // 暗号化ファイル
$dePath = 'test-d.pdf'; // 複合ファイル

// 暗号化
$data = file_get_contents($src);
file_put_contents($enPath, openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv));

// 復号
$enData = file_get_contents($enPath);
file_put_contents($dePath, openssl_decrypt($enData, $method, $key, OPENSSL_RAW_DATA, $iv));

簡易的なBasic認証

.htaccess で Basic 認証ができない場合(サーバーで制限されている場合等)でBasic認証したいときに使用します。

<?php
// IDとパスワード(平文)を「:」で区切ってセットして下さい。複数IDで認証したい場合は「,」で区切って下さい。
// 例: define('BASIC_AUTH_PASSWORD', 'test:testpw,test2:test2pw');
define('BASIC_AUTH_PASSWORD', 'test:test,test2:test2');
 
function basic_auth() {
    // http://stackoverflow.com/questions/3663520/php-auth-user-not-set
    // CGIモードの場合、.htaccessに下記を記述して下さい (CGIだとPHP_AUTH_**がセットされない)
    //     RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    if (substr(php_sapi_name(), 0, 3) == 'cgi' && isset($_SERVER['HTTP_AUTHORIZATION'])) {
        list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
            explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
    }
 
    $user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
    $pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
 
    $auth = false;
    $pairs = preg_split('/\s*,\s*/', BASIC_AUTH_PASSWORD);
    foreach ($pairs as $pair) {
        list($u, $p) = preg_split('/\s*:\s*/', $pair);
        if ($user == $u && $pass == $p) {
            $auth = true;
            break;
        }
    }
 
    if (!$auth) {
        header('WWW-Authenticate: Basic realm=\'INPUT USER/PW\'');
        header('HTTP/1.0 401 Unauthorized');
        echo '認証に失敗しました。';
        exit;
    }
}
basic_auth();
?>
以下にBASIC認証後のHTMLなどを記載します。非公開領域に置いたファイルを readfile() してきてもよいです。

QRコード生成

Google Chart API を利用して QR コードを生成します。

$size = 300; // QRコードのサイズ(px)
$text = 'https://knooto.info/'; // QRコードに埋め込みたいテキスト
$url = "https://chart.googleapis.com/chart?chs={$size}x{$size}&cht=qr&chl=" . rawurlencode($text); // QRコードのURL

// ファイル保存する場合
// file_put_contents('qr.png', file_get_contents($url));
?>
<img src="<?php echo htmlspecialchars($url, ENT_QUOTES) ?>">

CLI

標準入力からの取得
$input = trim(fgets(STDIN));

ユーティリティ関数

(主にフレームワークなどを使う必要が無い小さなプログラム用の関数です)

htmlspecialchars の簡易版

htmlspecialchars(), echo htmlspecialchars() と打つのが長いため、h(), eh() で呼び出せるようにします。

/**
 * 値をHTMLエスケープします。
 * @param mixed $value 対象文字列
 * @return mixed 変換された文字列
 */
function h($value, $encoding = 'UTF-8') { return htmlspecialchars($value, ENT_QUOTES, $encoding); }
/**
 * 値をHTMLエスケープして出力します。
 * @param mixed $value 対象文字列
 * @return mixed 変換された文字列
 */
function eh($value, $encoding = 'UTF-8') { echo h($value, $encoding); }

リダイレクト

header('Location: ...'); を書く煩わしさを軽減するためのものです。

/**
 * 指定されたパスにリダイレクトします。
 * @param string $url URL
 * @param mixed $args 追加引数 
 */
function redirect($url, $args = null) {
	if (!is_null($args)) {
		$query = http_build_query($args, '', '&', PHP_QUERY_RFC3986); // 追加の引数がある場合、クエリとして追加します。
		$url = $url . '?' . $query;
	}
	header('Location: ' . $url);
	exit;
}

// 例:
// redirect('http://example.com/');
// redirect('http://example.com/', array('param' => 'value'));

GET リクエスト判定

/**
 * リクエストが GET リクエストか確認します。
 * @return boolean GET の場合 true
 */
function is_get() { return (strtoupper($_SERVER['REQUEST_METHOD']) == 'GET'); }

POST リクエスト判定

/**
 * リクエストが POST か確認します。
 * @return boolean POST の場合 true
 */
function is_post() { return (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST'); }

Ajax リクエスト判定

/**
 * リクエストがAjaxのものか確認します。
 * @return boolean Ajaxリクエストの場合 (HTTP_X_REQUESTED_WITHが 'XMLHttpRequest' ※case-insentive) true
 */
function is_ajax(){ return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'; }

HTTPS 判定

/**
 * 現在の通信が https かどうかを確認します。
 * @return boolean 現在の通信が https (SSL/TLS) の場合 true
 */
function is_https() {
    if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') $https = true;
    else if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https') $https = true;
    else $https = false;
    return $https;
}

現在のページの URL

/**
 * 現在のページの URL を取得します。
 * @return string URL文字列
 */
function current_url() {
    return 'http' . (is_https() ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; // is_https() を使います
}

var_dump() の文字列化

/**
 * var_dump() を文字列で返します。
 * @return string var_dump() の結果
 */
function var_dump_str(/* ... */) {
    ob_start();
    call_user_func_array('var_dump', func_get_args());
    $c = ob_get_clean();
    return $c;
}

文字エンコーディングの変換

SJIS

/**
 * 文字列を SJIS に変換します。
 *
 * @param string $s 文字列
 * @param string $fromEncoding 文字列のエンコーディング
 * @return mixed 変換後の文字列。失敗した場合は false
 */
function sjis($s, $fromEncoding = 'UTF-8') { return mb_convert_encoding($s, 'SJIS-win', $fromEncoding); }

base64 (URL形式) のエンコード・デコード

/**
 * 指定した data を base64 でエンコードします。URLに含められるよう、"+", "/" は "-", "_" に変換し、不要なパディング("=")は除去します。
 *
 * @param string $data エンコードするデータ。
 * @return string エンコードされたデータを文字列で返します。失敗した場合に FALSE を返します。
 */
function base64url_encode($data) {
	$encoded = base64_encode($data);
	if ($encoded === false) return false;

	return rtrim(strtr($encoded, '+/', '-_'), '='); 
}
/**
 * base64 でエンコードされた data をデコードします。base64url_encode() でエンコードされたデータをデコードするための関数です。
 *
 * @param string $data デコードされるデータ
 * @return string デコードしたデータを返します。失敗した場合に FALSE を返します。
 */
function base64url_decode($data) { 
	return base64_decode(strtr($data, '-_', '+/')); // base64_decode() はパディング("=")を埋めなくてもデコード可能です。
}

ファイルコピー (フォルダが無ければ生成)

/**
 * ファイルをコピーします。(コピー先のフォルダが無い場合はフォルダを作成します)
 *
 * @param string $src コピー元
 * @param string $dest コピー先
 * @return bool
 */
function file_copy($src, $dest) {
    if (!is_dir(dirname($dest))) @mkdir(dirname($dest), 0777, true);
    return copy($src, $dest);
}

ユニークID (UUID v4)

/**
 * ユニークID (UUID v4) を生成します。
 * 
 * @return string RRRRRRRR-RRRR-4RRR-rRRR-RRRRRRRRRRRR 形式の文字列 (R = ランダム、4 = 固定数字 4、r = 0b10RR に相当する16進数文字列)
 */
function uuid_v4() {
    return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
        mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff),
        mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
        mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
    );
}

バイト数のフォーマット

/**
 * バイト数のフォーマットした値を取得します。(例: 2048 → 2 KB, 1234567 → 1.17737484 MB → 1.18 MB)
 *
 * @param integer $bytes バイト数
 * @param integer $precision 小数点の桁数
 * @return string 結果文字列
 */
function byte_format($bytes, $precision = 2) {
    $units = array('B', 'KB', 'MB', 'GB', 'TB'); // 単位
    $sign = '';
    if ($bytes < 0) { // 負数の場合正にして計算したのち最後に符号を追加します
        $bytes = $bytes * -1;
        $sign = '-';
    }
    $exp = min(floor(log($bytes, 1024)), count($units) - 1); // 指数を取得
    if ($bytes != 0) $bytes = $bytes / pow(1024, $exp); // 除算 (KB  bytes / 1024, MB  bytes / 1024^2, GB  bytes / 1024^3, ...)
    return $sign . number_format($bytes, $precision) . ' ' . $units[$exp]; // フォーマット
}

簡易ログ

<?php
/** ログの出力先ディレクトリパス */
define('DEBUG_LOG_DIR', './log');
/** ログの保持日数 */
define('DEBUG_LOG_DAYS', 7);
/*
 * 簡易ログを出力します。(例: '[2018-01-01 00:00:00] テスト')
 * @param string $message ログメッセージ
 */
function debug_log($message) {
    $dir = defined('DEBUG_LOG_DIR') ? DEBUG_LOG_DIR : null; // 出力先ディレクトリパスを定数から取得
    if (is_null($dir) || (!is_dir($dir) && !@mkdir($dir))) return false; // 出力先ディレクトリパスが無い・生成できない場合中断

    $days = (defined('DEBUG_LOG_DAYS')) ? DEBUG_LOG_DAYS : 7; // 保持日数を定数から取得
    $logPath = $dir . DIRECTORY_SEPARATOR . date('Ymd') . '.log'; // 例: 20180101.log

    // ログファイルを取得して古いログを削除
    $files = glob($dir . DIRECTORY_SEPARATOR . '*.log');
    $oldLogName = date('Ymd', strtotime("-{$days} day")) . '.log'; // $days = 7 の場合7日前のログ
    foreach ($files as $path) {
        $name = basename($path);
        if (preg_match('#\A[0-9]{8}.log\z#', $name) && $name <= $oldLogName) @unlink($path);
    }
    // ログ出力
    $log = '[' . date('Y-m-d H:i:s') . '] ' . $message . PHP_EOL;
    error_log($log, 3, $logPath);
}

// debug_log('テスト');

エラー制御

/**
 * エラーを独自制御してメッセージやログを出力します。(h()関数が必要です)
 * @param string $errno
 * @param string $errstr
 * @param string $ettfile
 * @param int $errline
 */
function error_handler($errno, $errstr, $errfile, $errline) {
    // @ 付きで呼び出された場合 (0) や error_reporting 外のエラーは制御しない
    if (!(error_reporting() & $errno)) {
        return;
    }
    // エラーのラベル
    $labels = array(
        E_WARNING => 'E_WARNING', E_NOTICE => 'E_NOTICE', E_USER_ERROR => 'E_USER_ERROR',
        E_USER_WARNING => 'E_USER_WARNING', E_USER_NOTICE => 'E_USER_NOTICE',
        E_STRICT => 'E_STRICT', E_DEPRECATED => 'E_DEPRECATED',
    );
    if (defined('E_RECOVERABLE_ERROR')) $labels[E_RECOVERABLE_ERROR] = 'E_RECOVERABLE_ERROR';
    if (defined('E_DEPRECATED')) $labels[E_DEPRECATED] = 'E_DEPRECATED';
    if (defined('E_USER_DEPRECATED')) $labels[E_USER_DEPRECATED] = 'E_USER_DEPRECATED';

    $label = isset($labels[$errno]) ? $labels[$errno] : 'ERROR';

    // 画面表示
    if (ini_get('display_errors')) {
        header('Content-Type: text/html;charset=UTF-8');
        echo '<strong>' . h($label) . '</strong> (' . h($errno) . ') ' . h($errstr) . ' - ';
        echo '<strong>' . h($errfile) . '</strong><strong>' . h($errline) . '</strong> 行目でエラーが発生しました。' . '<br>';
        if (function_exists('debug_backtrace')) { // 4.3.0 未満は debug_backtrace() が無い
            $backtrace = debug_backtrace();
            array_shift($backtrace);
            foreach($backtrace as $i=>$l){
                echo '&nbsp;&nbsp;[' . h($i) . '] in function <strong>';
                echo (isset($l['class']) ? (h($l['class'])) : '');
                echo (isset($l['type']) ? (h($l['type'])) : '');
                echo (isset($l['function']) ? (h($l['function'])) : '');
                echo '</strong>';
                if(isset($l['file'])) echo ' in <strong>' . h($l['file']) . '</strong>';
                if(isset($l['line'])) echo ' on line <strong>' . h($l['line']) . '</strong>';
                echo '<br>';
            }
        }
    }

    // ログ
    $message = '';
    $message .= $label . ' (' . $errno . ') ' . $errstr . ' - ';
    $message .= $errfile . ' の ' . $errline . ' 行目でエラーが発生しました。' . PHP_EOL;
    if (function_exists('debug_backtrace')) { // 4.3.0 未満に debug_backtrace() が無い
        $backtrace = debug_backtrace();
        array_shift($backtrace);
        foreach($backtrace as $i=>$l){
            $message .= '  [' . $i . '] in function ';
            $message .= (isset($l['class']) ? ($l['class']) : '');
            $message .= (isset($l['type']) ? ($l['type']) : '');
            $message .= (isset($l['function']) ? ($l['function']) : '');
            if(isset($l['file'])) $message .= ' in ' . $l['file'];
            if(isset($l['line'])) $message .= ' on line ' . $l['line'];
            $message .= PHP_EOL;
        }
    }
    //@debug_log($message); // 必要なログ関数を実行

    // 内部エラーハンドラを実行しない
    return true;
}

WordPress にある checked() の超簡易版

ラジオボタンやチェックボックスの checked (checked="checked") を書く煩わしさを軽減するためのものです。

/**
 * 真になる値の場合、checkedを出力します(ラジオボタン、チェックボックス用)。
 * @param mixed $v
 */
function checked($v) { if ($v) echo ' checked="checked" '; }

// 例: $x の値によってラジオボタンのチェックを変える
// <input type="radio" name="x" value="1" <?php checked($x == 1) ?>>
// <input type="radio" name="x" value="2" <?php checked($x == 2) ?>>
// <input type="radio" name="x" value="3" <?php checked($x == 3) ?>>
  • WordPressの場合、例と同じ形で出力するには checked($x, 1, true)checked($x == 1, true, true) とする必要があります。

WordPress にある selected() の超簡易版

プルダウンの selected (selected="selected") を書く煩わしさを軽減するためのものです。

/**
 * 真になる値の場合、selectedを出力します(select用)。
 * @param mixed $v
 */
function selected($v) { if ($v) echo ' selected="selected" '; }

// 例: $x の値によって<select>のチェックを変える
// <select name="x">
//     <option value="1" <?php selected($x === '1') ?>>1</option>
//     <option value="2" <?php selected($x === '2') ?>>2</option>
//     <option value="3" <?php selected($x === '3') ?>>3</option>
// </select>
  • WordPressの場合、例と同じ形で出力するには selected($x, 1, true)selected($x == 1, true, true) とする必要があります。

HTMLの生成関数

<?php
/**
 * HTMLのタグを生成します。
 * ※ 内部で h() を使用します。
 *
 * @param string $tagName タグ名 (例: 'a')
 * @param mixed $attrs 属性 (例; array('href' => 'http://example.com'), 'href="http://example.com"')
 * @param mixed $content タグの内容 (例; 'test', array( html_tag('strong', null, '強調'), '通常' ))
 * @return string HTMLタグ文字列
 */
function html_tag($tagName, $attrs = null, $content = null) {
    $empty = array('area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'); // https://developer.mozilla.org/en-US/docs/Glossary/Empty_element

    $attrString = '';
    if (is_array($attrs)) foreach ($attrs as $n => $v) $attrString .= ' ' . $n . ($v === true ? '' : '="' . h($v) . '"');
    else $attrString = strlen((string)$attrs) > 0 ? ' ' . (string)$attrs : '';

    if (in_array($tagName, $empty, true)) return '<' . $tagName . $attrString . '>';
    return '<' . $tagName . $attrString . '>' . (is_array($content) ? implode('', $content) : $content) . '</' . $tagName . '>';
}

/**
 * 選択肢の中からユーザーに選択させる部品(プルダウン、チェックボックスリスト、ラジオボタンリスト)を生成するための共通処理です。
 * ※ 内部で html_tag() を使用します。
 *
 * @param string $type 選択肢の種類 ('select', 'checkbox', 'radio')
 * @param mixed $attrs 属性
 * @param array $items 選択肢 (例: array('a', 'b', 'c'), array(1 => '北海道', ...)。配列キーが値、配列値がテキストになります。キーがない場合は値、テキストとも配列値を使用します)
 * @param mixed $selectedItem 選択された項目 (例: 1, array(1, 2))
 * @return string HTMLタグ文字列
 */
function html_select_base($type, $attrs, array $items = null, $selectedItem = null) {
    $selectedItems = array();
    if (is_array($selectedItem)) {
        foreach ($selectedItem as $item) $selectedItems[] = (string)$item;
    }
    else if (strlen((string)$selectedItem) > 0) {
        $selectedItems[] = (string)$selectedItem;
    }

    $itemTags = array();
    $i = 0;
    if (is_array($items)) foreach ($items as $k => $v) {
        $value = ($i !== $k) ? $k : $v;
        $text = $v;

        if ($type == 'select') {
            $itemAttrs = array('value' => $value);
            if (in_array((string)$value, $selectedItems, true)) $itemAttrs['selected'] = 'selected';
            $itemTags[] = html_tag('option', $itemAttrs, $text);
        }
        else {
            if (is_array($attrs)) $itemAttrs = array_merge(array('type' => $type, 'value' => $value), $attrs);
            else if (strlen((string)$attrs) > 0) $itemAttrs = 'type="' . h($type) . '" value="' . h($value) . '" ' . $attrs;

            if (in_array((string)$value, $selectedItems, true)) {
                if (is_array($itemAttrs)) $itemAttrs['checked'] = true;
                else $itemAttrs .= ' checked';
            }
            $itemTags[] = ' ' . html_tag('label', null, array( html_tag('input', $itemAttrs), $text ));
        }
        $i++;
    }

    if ($type == 'select') return html_tag('select', $attrs, $itemTags);
    else return implode('', $itemTags);
}
// <select>
function html_select($attrs, $items = null, $selectedItem = null) {
    return html_select_base('select', $attrs, $items, $selectedItem);
}
// <input type="checkbox">
function html_checkbox_list($attrs, $items = null, $checkedItem = null) {
    return html_select_base('checkbox', $attrs, $items, $checkedItem);
}
// <input type="radio">
function html_radio_list($attrs, $items = null, $checkedItem = null) {
    return html_select_base('radio', $attrs, $items, $checkedItem);
}
// 使用例
$items = array(1 => '北海道', 2 => '青森県', 3 => '岩手県');

echo html_tag('html', null, array(
    html_tag('head', null, array(
        html_tag('meta', 'charset="UTF-8"'),
        html_tag('link', 'rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"'),
        html_tag('title', null, 'テスト用HTML'),
    )),
    html_tag('body', null, array(
        html_tag('div', 'class="container"', array(
            html_tag('div', 'class="card"', array(
                html_tag('div', 'class="card-header"', 'テスト'),
                html_tag('div', 'class="card-body"', array(
                    html_select('name="select1" class="form-control"', $items, 1),
                    html_tag('br'),
                    html_checkbox_list('name="check1[]"', $items, array(2, 3)),
                    html_tag('br'),
                    html_radio_list('name="radio1"', $items, 3),
                    html_tag('script', 'src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js')
                ))
            ))
        ))
    ))
));

入力チェックの簡易関数

1つの値の入力チェックをするための簡易関数です。

/**
 * 入力ルールに従って1つの値の入力チェックを行います。
 * @param string $var 入力値
 * @param array $rule 入力ルール
 * @param array $errors 標準エラーメッセージを上書きするための連想配列
 * @return array 'success' (true, false), 'error' (エラーメッセージ) をキーに持つ連想配列
 */
function validate_var($var, array $rule, array $errors = null) {
    $success = true; // 成功したか
    $error = ''; // エラーメッセージ
    // エラーメッセージ一覧
    $defaultErrors = array(
        'required' => '{displayName}を入力してください。',
        'minValue' => '{displayName}は{minValue}以上で入力してください。',
        'maxValue' => '{displayName}は{maxValue}以下で入力してください。',
        'minLength' => '{displayName}は{minLength}文字以上で入力してください。',
        'maxLength' => '{displayName}は{maxLength}文字以下で入力してください。',
        'format' => array(
            'number' => '{displayName}は数値の形式で入力してください。',
            'email' => '{displayName}はメールアドレスの形式で入力してください。'
        ),
        'items' => '{displayName}の値が規定値と異なります。',
        'pattern' => '{displayName}の形式が異なります。'
    );
    // エラーメッセージ一覧 (マージ)
    $e = ($errors) ? array_merge($defaultErrors, $errors) : $defaultErrors;
    // エラーメッセージの書式化関数
    $str_format = function($text, $params) {
        return preg_replace_callback('#\{([^}]+)\}#', function($m) use($params) {
            return $params[$m[1]];
        }, $text);
    };
    // フォーマット
    $formatPatterns = array(
        'number' => '#\A-?(?:[0-9]|[1-9][0-9]+)(?:\.[0-9]+)?\z#',
        'email' => '#\A.+?@.+?\..+\z#'
    );

    if (is_array($var) || is_object($var)) $v = '';
    else $v = (string)$var;

    if (!isset($rule['displayName'])) $rule['displayName'] = '項目';

    $ruleKeys = array_keys($e);
    $format = '';
    if ($v === '') {
        $success = (!isset($rule['required']) || !$rule['required']);
    }
    else {
        foreach ($ruleKeys as $k) {
            if (!isset($rule[$k])) continue;

            $format = '';
            switch ($k) {
                // 最小値
                case 'minValue':
                    if ($v < $rule[$k]) $success = false;
                    break;
                // 最大値
                case 'maxValue':
                    if ($v > $rule[$k]) $success = false;
                    break;
                // 最小桁数
                case 'minLength':
                    if (mb_strlen($v) < $rule[$k]) $success = false;
                    break;
                // 最大桁数
                case 'maxLength':
                    if (mb_strlen($v) > $rule[$k]) $success = false;
                    break;
                // 形式
                case 'format':
                    $format = $rule[$k];
                    if (isset($formatPatterns[$format])) {
                        $formatPattern = $formatPatterns[$format];
                        if (!preg_match($formatPattern, $v)) {
                            $success = false;
                        }
                    }
                    break;
                // 規定値
                case 'items':
                    if (!in_array($v, $rule[$k])) $success = false;
                    break;
                // パターン
                case 'pattern':
                    if (!preg_match($rule[$k], $v)) $success = false;
                    break;
            }

            if (!$success) {
                if (!$error) {
                    $ve = $e[$k];
                    if ($k == 'format' && isset($ve[$format])) {
                        $ve = $ve[$format];
                    }
                    // ルールにエラーメッセージがある場合はルールのエラーを優先
                    if (isset($rule['error'])) {
                        // 連想配列
                        if (is_array($rule['error'])) {
                            // チェック名と同じキーがある
                            if (isset($rule['error'][$k])) {
                                // 形式の場合さらに連想配列になっているので、あればその値を使用
                                if ($k == 'format' && isset($rule['error'][$k][$format])) {
                                    $ve = $rule['error'][$k][$format];
                                }
                                else {
                                    $ve = $rule['error'][$k];
                                }
                            }
                        }
                        // 文字列
                        else {
                            $ve = $rule['error'];
                        }
                    }
                    $error = $str_format($ve, $rule);
                }
                return compact('success', 'error');
            }
        }
    }
    return compact('success', 'error');
}
使用例 ($_POST データのチェック)
// 入力チェックルールの例
$rules = array(
    'title' => array('required' => true, 'maxLength' => 20, 'displayName' => 'タイトル'),
    'content' => array('required' => true, 'maxLength' => 100, 'displayName' => '内容'),
    'item1' => array('required' => true, 'format' => 'number', 'minValue' => 5, 'displayName' => '最小値'),
    'item2' => array('required' => true, 'format' => 'number', 'maxValue' => 5, 'displayName' => '最大値'),
    'item3' => array('required' => true, 'format' => 'number', 'minLength' => 5, 'displayName' => '最小桁'),
    'item4' => array('required' => true, 'format' => 'number', 'maxLength' => 5, 'displayName' => '最大桁'),
    'item5' => array('required' => true, 'items' => array('A', 'B', 'C'), 'displayName' => '規定値',
        'error' => array('items' => '{displayName}はA, B, Cのいずれかを入力してください。')),
    'item6' => array('required' => true, 'format' => 'email', 'displayName' => '形式'),
    'item7' => array('required' => true, 'pattern' => '#\AA+\z#', 'displayName' => 'パターン',
        'error' => array('pattern' => '{displayName}はAの連続を入力してください。')),
);
// 入力データ ($_POST など)
$data = array(
    'title' => 'タイトル',
    'content' => '内容',
    'item1' => '5',
    'item2' => '5',
    'item3' => '12345',
    'item4' => '5',
    'item5' => 'A',
    'item6' => 'a@a.com',
    'item7' => 'AAA',
);

$success = true;
$error = '';
$filterData = array();
foreach ($rules as $k => $rule) {
    $v = (isset($data[$k]) && !is_array($data[$k])) ? $data[$k] : '';
    $result = validate_var($v, $rule); // 入力チェック

    // エラーがあった場合終了
    if (!$result['success']) {
        $success = false;
        $error = $result['error'];
        break;
    }

    $filterData[$k] = $v;
}

var_dump($success, $error);