Skip to content

Instantly share code, notes, and snippets.

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

  • Save masakielastic/7d9d3d6641079e1af3021e01bee30505 to your computer and use it in GitHub Desktop.

Select an option

Save masakielastic/7d9d3d6641079e1af3021e01bee30505 to your computer and use it in GitHub Desktop.
filter_var_array() の第2引数に渡す descriptor 配列を生成するための小さな helper 関数です。 filter_validation_descriptors() は標準の validation filter 用 descriptor を生成します。 filter_callback_descriptors() は FILTER_CALLBACK 用 descriptor を生成します。 アプリケーション側では FILTER_VALIDATE_* や FILTER_CALLBACK を直接書かず、検証ルール名と callback の対応だけを書けるようにします。 小規模サイトのフォームでは、生成した descriptor 配列を array_replace…
<?php
$input = [
'email' => 'taro@example.com',
'age' => '17',
'message' => '',
];
$descriptors = array_replace(
filter_validation_descriptors([
'email' => 'email',
'age' => [
'rule' => 'int',
'options' => [
'min_range' => 18,
'max_range' => 120,
],
],
]),
filter_callback_descriptors([
'message' => 'validate_message',
]),
);
$result = filter_var_array($input, $descriptors);
var_dump($descriptors);
var_dump($result);
function validate_message(string $value): string|false
{
if ($value === '') {
return false;
}
if (mb_strlen($value, 'UTF-8') > 1000) {
return false;
}
return $value;
}
<?php
declare(strict_types=1);
/**
* Build descriptors for validation filters.
*
* Input:
*
* [
* 'email' => 'email',
* 'age' => [
* 'rule' => 'int',
* 'options' => [
* 'min_range' => 18,
* 'max_range' => 120,
* ],
* ],
* ]
*
* Output:
*
* [
* 'email' => [
* 'filter' => FILTER_VALIDATE_EMAIL,
* ],
* 'age' => [
* 'filter' => FILTER_VALIDATE_INT,
* 'options' => [
* 'min_range' => 18,
* 'max_range' => 120,
* ],
* ],
* ]
*/
function filter_validation_descriptors(array $rules): array
{
$descriptors = [];
foreach ($rules as $field => $spec) {
if (!is_string($field)) {
throw new InvalidArgumentException('Field name must be a string.');
}
$descriptors[$field] = filter_validation_descriptor($field, $spec);
}
return $descriptors;
}
/**
* Build descriptors for FILTER_CALLBACK.
*
* Input:
*
* [
* 'message' => 'validate_message',
* ]
*
* Output:
*
* [
* 'message' => [
* 'filter' => FILTER_CALLBACK,
* 'options' => 'validate_message',
* ],
* ]
*/
function filter_callback_descriptors(array $callbacks): array
{
$descriptors = [];
foreach ($callbacks as $field => $callback) {
if (!is_string($field)) {
throw new InvalidArgumentException('Field name must be a string.');
}
if (!is_callable($callback)) {
throw new InvalidArgumentException("Callback is not callable: {$field}");
}
$descriptors[$field] = [
'filter' => FILTER_CALLBACK,
'options' => $callback,
];
}
return $descriptors;
}
function filter_validation_descriptor(string $field, mixed $spec): array
{
if (is_string($spec)) {
return [
'filter' => validation_filter_id($spec),
];
}
if (!is_array($spec)) {
throw new InvalidArgumentException(
"Validation rule spec must be a string or an array: {$field}"
);
}
$rule = $spec['rule'] ?? null;
if (!is_string($rule) || $rule === '') {
throw new InvalidArgumentException(
"Validation rule name must be a non-empty string: {$field}"
);
}
$options = $spec['options'] ?? [];
$flags = $spec['flags'] ?? 0;
if (!is_array($options)) {
throw new InvalidArgumentException("options must be an array: {$field}");
}
if (!is_int($flags)) {
throw new InvalidArgumentException("flags must be an int: {$field}");
}
$descriptor = [
'filter' => filter_validation_id($rule),
];
if ($options !== []) {
$descriptor['options'] = $options;
}
if ($flags !== 0) {
$descriptor['flags'] = $flags;
}
return $descriptor;
}
function filter_validation_id(string $name): int
{
return match ($name) {
'email' => FILTER_VALIDATE_EMAIL,
'int' => FILTER_VALIDATE_INT,
'float' => FILTER_VALIDATE_FLOAT,
'boolean', 'bool' => FILTER_VALIDATE_BOOL,
'url' => FILTER_VALIDATE_URL,
'ip' => FILTER_VALIDATE_IP,
'domain' => FILTER_VALIDATE_DOMAIN,
'mac' => FILTER_VALIDATE_MAC,
'regexp', 'regex' => FILTER_VALIDATE_REGEXP,
default => throw new InvalidArgumentException(
"Unknown validation rule: {$name}"
),
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment