Skip to content

Instantly share code, notes, and snippets.

@masakielastic
Last active July 9, 2026 06:17
Show Gist options
  • Select an option

  • Save masakielastic/84463f530fd6bd220d514383fe12020d to your computer and use it in GitHub Desktop.

Select an option

Save masakielastic/84463f530fd6bd220d514383fe12020d to your computer and use it in GitHub Desktop.
Small userland helper functions for PHP filter extension. filter_validate_var() is a shortcut for filter_var() with built-in validation filters. It accepts validation filter names such as "email", "int", "float", "url", and "ip", and hides FILTER_VALIDATE_* constants from application code. filter_callback_var() is a shortcut for FILTER_CALLBACK.…
<?php
declare(strict_types=1);
require __DIR__ . '/filter_helpers.php';
$age = filter_validate_var('20', 'int', [
'options' => [
'min_range' => 18,
'max_range' => 120,
],
]);
var_dump($age); // int(20)
$email = filter_validate_var('taro@example.com', 'email');
var_dump($email); // string(16) "taro@example.com"
function validate_message(string $value): string|false
{
if ($value === '') {
return false;
}
if (mb_strlen($value) > 1000) {
return false;
}
return $value;
}
$message = filter_callback_var('お問い合わせ内容です。', 'validate_message');
var_dump($message);
<?php
declare(strict_types=1);
/**
* Returns the FILTER_VALIDATE_* constant for a validation filter name.
*
* This helper intentionally accepts only validation filter names.
* It does not accept sanitize filters or FILTER_CALLBACK.
*/
if (!function_exists('filter_validation_id')) {
function filter_validation_id(string $filter): int
{
return match ($filter) {
'email' => FILTER_VALIDATE_EMAIL,
'int' => FILTER_VALIDATE_INT,
'float' => FILTER_VALIDATE_FLOAT,
'bool', 'boolean' => FILTER_VALIDATE_BOOL,
'url' => FILTER_VALIDATE_URL,
'domain' => FILTER_VALIDATE_DOMAIN,
'ip' => FILTER_VALIDATE_IP,
'mac' => FILTER_VALIDATE_MAC,
'regexp', 'regex' => FILTER_VALIDATE_REGEXP,
default => throw new InvalidArgumentException(
"Unknown validation filter: {$filter}"
),
};
}
}
/**
* Validates a value using a named built-in validation filter.
*
* This is a small shortcut for:
*
* filter_var($value, FILTER_VALIDATE_*, $options)
*
* The second argument is a validation filter name such as:
*
* 'email', 'int', 'float', 'bool', 'url', 'ip'
*
* It intentionally does not accept FILTER_VALIDATE_* constants.
*/
if (!function_exists('filter_validate_var')) {
function filter_validate_var(
mixed $value,
string $filter,
array|int $options = 0,
): mixed {
return filter_var(
$value,
filter_validation_id($filter),
$options
);
}
}
/**
* Applies a custom callback filter to a value.
*
* This is a small shortcut for:
*
* filter_var($value, FILTER_CALLBACK, ['options' => $callback])
*
* This function is not validation-specific. The callback contract is the same
* as FILTER_CALLBACK: the callback return value becomes the filter result.
*/
if (!function_exists('filter_callback_var')) {
function filter_callback_var(
mixed $value,
callable $callback,
): mixed {
return filter_var($value, FILTER_CALLBACK, [
'options' => $callback,
]);
}
}
<?php
$input = [
'email' => 'taro@example.com', // valid
'age' => '17', // invalid: less than 18
'message' => '', // invalid: empty string
];
$app_spec = [
'email' => 'email',
'age' => [
'rule' => 'int',
'options' => [
'min_range' => 18,
'max_range' => 120,
],
],
'message' => 'message',
];
$custom_rule_registry = [
'message' => 'validate_message',
];
$result = validate_input(
input: $input,
app_spec: $app_spec,
custom_rule_registry: $custom_rule_registry,
);
var_dump($result);
/**
* アプリ仕様をもとに入力値を検証する。
*
* 標準の validation filter は filter_validate_var() に渡す。
* 独自ルールは $custom_rule_registry から callback を解決して filter_callback_var() に渡す。
*/
function validate_input(
array $input,
array $app_spec,
array $custom_rule_registry = [],
): array {
$result = [];
foreach ($app_spec as $field => $field_spec) {
$rule = rule_from_field_spec($field_spec);
$options = options_from_field_spec($field_spec);
$value = $input[$field] ?? null;
if (isset($custom_rule_registry[$rule])) {
$result[$field] = filter_callback_var(
value: $value,
callback: $custom_rule_registry[$rule],
);
continue;
}
$result[$field] = filter_validate_var(
value: $value,
filter: $rule,
options: $options,
);
}
return $result;
}
/**
* フィールド仕様からルール名を取り出す。
*/
function rule_from_field_spec(string|array $field_spec): string
{
if (is_string($field_spec)) {
return $field_spec;
}
if (!isset($field_spec['rule']) || !is_string($field_spec['rule'])) {
throw new InvalidArgumentException('Field spec must have a string rule.');
}
return $field_spec['rule'];
}
/**
* フィールド仕様から filter_var() 用の options を取り出す。
*/
function options_from_field_spec(string|array $field_spec): array|int
{
if (is_string($field_spec)) {
return 0;
}
return $field_spec['options'] ?? 0;
}
/**
* 独自バリデーションルール。
*
* FILTER_CALLBACK と同じく、戻り値がそのまま検証結果になる。
*/
function validate_message(mixed $value): string|false
{
if (!is_string($value)) {
return false;
}
if ($value === '') {
return false;
}
return $value;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment