Validasi dalam PHP. Kecantikan atau mie?

Memilih validator PHP terbaik dari sepuluh yang populer, saya menghadapi dilema. Apa yang lebih penting bagi saya? Kepatuhan pada semua kanon SOLID / OOP atau kegunaan dan kejelasan kode? Apa yang lebih disukai oleh pengguna kerangka Comet ? Jika Anda berpikir bahwa pertanyaannya jauh dari sederhana - selamat datang di jalan pintas dalam perjalanan panjang melalui cuplikan kode :)





Selain kekhawatiran tentang kinerja untuk REST API dan layanan mikro, saya sangat khawatir dengan keterbacaan kode yang kami ketik setiap hari untuk menyelesaikan masalah pekerjaan, termasuk validasi data.



Saya ingin menunjukkan potongan kode dari tolok ukur saya sendiri sehingga Anda dapat menghargai luasnya pendekatan untuk memecahkan masalah yang sama. Mari kita bayangkan bahwa kumpulan data berikut telah sampai kepada kita:



$form = [
    'name'           => 'Elon Mask', 
    'name_wrong'     => 'Mask',
    'login'          => 'mask', 
    'login_wrong'    => 'm@sk', 
    'email'          => 'elon@tesla.com', 
    'email_wrong'    => 'elon@tesla_com', 
    'password'       => '1q!~|w2o<z', 
    'password_wrong' => '123456',
    'date'           => '2020-06-05 15:52:00',
    'date_wrong'     => '2020:06:05 15-52-00',
    'ipv4'           => '192.168.1.1',
    'ipv4_wrong'     => '402.28.6.12',
    'uuid'           => '70fcf623-6c4e-453b-826d-072c4862d133',
    'uuid_wrong'     => 'abcd-xyz-6c4e-453b-826d-072c4862d133',
    'extra'          => 'that field out of scope of validation',
    'empty'          => ''
];


Tujuan kami adalah menjalankan larik ini melalui sekumpulan aturan validasi, menghasilkan daftar semua bidang dengan kesalahan dan pesan standar untuk demonstrasi kepada pengguna.



Standar industri dan ikon OOP murni - tentu saja Symfony





use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Translation\MessageSelector;

$validator = Validation::createValidator();

$constraint = new Assert\Collection([    
    'name' => new Assert\Regex('/^[A-Za-z]+\s[A-Za-z]+$/u'),   	
    'login' => new Assert\Regex('/^[a-zA-Z0-9]-_+$/'),
    'email' => new Assert\Email(),
    'password' => [
        new Assert\NotBlank(),
        new Assert\Length(['max' => 64]),
        new Assert\Type(['type' => 'string'])
    ],
    'agreed' => new Assert\Type(['type' => 'boolean'])
]);

$violations = $validator->validate($form, $constraint);

$errors = [];
if (0 !== count($violations)) {
    foreach ($violations as $violation) {
        $errors[] = $violation->getPropertyPath() . ' : ' . $violation->getMessage();
    }
} 

return $errors;


Kode mata tajam dalam PHP murni



$errors = [];

if (!preg_match('/^[A-Za-z]+\s[A-Za-z]+$/u', $form['name']))
    $errors['name'] = 'should consist of two words!';
if (!preg_match('/^[A-Za-z]+\s[A-Za-z]+$/u', $form['name_wrong']))
    $errors['name_wrong'] = 'should consist of two words!';
if (!preg_match('/^[a-zA-Z0-9-_]+$/', $form['login']))
    $errors['login'] = 'should contain only alphanumeric!';
if (!preg_match('/^[a-zA-Z0-9]-_+$/', $form['login_wrong']))
    $errors['login_wrong'] = 'should contain only alphanumeric!';

if (filter_var($form['email'], FILTER_VALIDATE_EMAIL) != $form['email'])
    $errors['email'] = 'provide correct email!';
if (filter_var($form['email_wrong'], FILTER_VALIDATE_EMAIL) != $form['email_wrong'])
    $errors['email_wrong'] = 'provide correct email!';

if (!is_string($form['password']) ||
    $form['password'] == '' ||
    strlen($form['password']) < 8 ||
    strlen($form['password']) > 64 
)
    $errors['password'] = 'provide correct password!';

if (!is_string($form['password_wrong']) ||
    $form['password_wrong'] == '' ||
    strlen($form['password_wrong']) < 8 ||
    strlen($form['password_wrong']) > 64 
)
    $errors['password_wrong'] = 'provide correct password!';

if (!preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/', $form['date']))
    $errors['date'] = 'provide correct date!';
if (!preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/', $form['date_wrong']))
    $errors['date_wrong'] = 'provide correct date!';

if (filter_var($form['ipv4'], FILTER_VALIDATE_IP) != $form['ipv4'])
    $errors['ipv4'] = 'provide correct ip4!';
if (filter_var($form['ipv4_wrong'], FILTER_VALIDATE_IP) != $form['ipv4_wrong'])
    $errors['ipv4_wrong'] = 'provide correct ip4!';

if (!preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $form['uuid']))
    $errors['uuid'] = 'provide correct uuid!';
if (!preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $form['uuid_wrong']))
    $errors['uuid_wrong'] = 'provide correct uuid!';

if (!isset($form['agreed']) || !is_bool($form['agreed']) || $form['agreed'] != true)
    $errors['agreed'] = 'you should agree with terms!';

return $errors;


Solusi berdasarkan salah satu pustaka Respect Validation yang paling populer



use Respect\Validation\Validator as v;
use Respect\Validation\Factory;

Factory::setDefaultInstance(
    (new Factory())
        ->withRuleNamespace('Validation')
        ->withExceptionNamespace('Validation')
);

$messages = [];

try {
    v::attribute('name', v::RespectRule())
        ->attribute('name_wrong', v::RespectRule())
        ->attribute('login', v::alnum('-_'))
        ->attribute('login_wrong', v::alnum('-_'))
        ->attribute('email', v::email())
        ->attribute('email_wrong', v::email())
        ->attribute('password', v::notEmpty()->stringType()->length(null, 64))
        ->attribute('password_wrong', v::notEmpty()->stringType()->length(null, 64))
        ->attribute('date', v::date())
        ->attribute('date_wrong', v::date())
        ->attribute('ipv4', v::ipv4())
        ->attribute('ipv4_wrong', v::ipv4())
        ->attribute('uuid', v::uuid())
        ->attribute('uuid_wrong', v::uuid())
        ->attribute('agreed', v::trueVal())
        ->assert((object) $form);
} catch (\Exception $ex) {
    $messages = $ex->getMessages();
}

return $messages;


Juga Dikenal Nama: Valitron



use Valitron\Validator;

Validator::addRule('uuid', function($field, $value) {
    return (bool) preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $value);
}, 'UUID should confirm RFC style!');

$rules = [
    'required'  => [ 'login', 'agreed' ],
    'regex'     => [ ['name', '/^[A-Za-z]+\s[A-Za-z]+$/'] ],
    'lengthMin' => [ [ 'password', '8'], [ 'password_wrong', '8'] ],
    'lengthMax' => [ [ 'password', '64'], [ 'password_wrong', '64'] ],
    'slug'      => [ 'login', 'login_wrong' ],
    'email'     => [ 'email', 'email_wrong' ],
    'date'      => [ 'date', 'date_wrong' ],
    'ipv4'      => [ 'ipv4', 'ipv4_wrong' ],
    'uuid'      => [ 'uuid', 'uuid_wrong' ],
    'accepted'  => 'agreed'
];

$validator = new Validator($form);
$validator->rules($rules);
$validator->rule('accepted', 'agreed')->message('You should set {field} value!');
$validator->validate();

return $validator->errors());


Sirius yang cantik




$validator = new \Sirius\Validation\Validator;

$validator
    ->add('name', 'required | \Validation\SiriusRule')
    ->add('login', 'required | alphanumhyphen', null, 'Only latin chars, underscores and dashes please.')
    ->add('email', 'required | email', null, 'Give correct email please.')
    ->add('password', 'required | maxlength(64)', null, 'Wrong password.')
    ->add('agreed', 'required | equal(true)', null, 'Where is your agreement?');

$validator->validate($form);

$errors = [];
foreach ($validator->getMessages() as $attribute => $messages) {
    foreach ($messages as $message) {
        $errors[] = $attribute . ' : '. $message->getTemplate();
    }
}

return $errors;


Dan inilah cara mereka memvalidasi di Laravel



use Illuminate\Validation\Factory as ValidatorFactory;
use Illuminate\Translation\Translator;
use Illuminate\Translation\ArrayLoader;
use Symfony\Component\Translation\MessageSelector;
use Illuminate\Support\Facades\Validator as FacadeValidator;

$rules = array(
    'name' => ['regex:/^[A-Za-z]+\s[A-Za-z]+$/u'],
    'name_wrong' => ['regex:/^[A-Za-z]+\s[A-Za-z]+$/u'],
    'login' => ['required', 'alpha_num'],
    'login_wrong' => ['required', 'alpha_num'],
    'email' => ['email'],
    'email_wrong' => ['email'],
    'password' => ['required', 'min:8', 'max:64'],
    'password_wrong' => ['required', 'min:8', 'max:64'],
    'date' => ['date'],
    'date_wrong' => ['date'],
    'ipv4' => ['ipv4'],
    'ipv4_wrong' => ['ipv4'],
    'uuid' => ['uuid'],
    'uuid_wrong' => ['uuid'],
    'agreed' => ['required', 'boolean']
);

$messages = [
    'name_wrong.regex' => 'Username is required.',
    'password_wrong.required' => 'Password is required.',
    'password_wrong.max' => 'Password must be no more than :max characters.',
    'email_wrong.email' => 'Email is required.',
    'login_wrong.required' => 'Login is required.',
    'login_wrong.alpha_num' => 'Login must consist of alfa numeric chars.',
    'agreed.required' => 'Confirm radio box required.',
);

$loader = new ArrayLoader();
$translator = new Translator($loader, 'en');
$validatorFactory = new ValidatorFactory($translator);

$validator = $validatorFactory->make($form, $rules, $messages);

return $validator->messages();


Validasi Rakit berlian tak terduga



$validator = new \Rakit\Validation\Validator;
$validator->addValidator('uuid', new \Validation\RakitRule);

$validation = $validator->make($form, [
    'name'           => 'regex:/^[A-Za-z]+\s[A-Za-z]+$/u',
    'name_wrong'     => 'regex:/^[A-Za-z]+\s[A-Za-z]+$/u',
    'email'          => 'email',
    'email_wrong'    => 'email',
    'password'       => 'required|min:8|max:64',
    'password_wrong' => 'required|min:8|max:64',
    'login'          => 'alpha_dash',
    'login_wrong'    => 'alpha_dash',
    'date'           => 'date:Y-m-d H:i:s',
    'date_wrong'     => 'date:Y-m-d H:i:s',
    'ipv4'           => 'ipv4',
    'ipv4_wrong'     => 'ipv4',
    'uuid'           => 'uuid',
    'uuid_wrong'     => 'uuid',
    'agreed'         => 'required|accepted'
]); 	

$validation->setMessages([
    'uuid'     => 'UUID should confirm RFC rules!',
    'required' => ':attribute is required!',
    // etc
]);

$validation->validate();

return $validation->errors()->toArray();


terus? Contoh kode manakah yang paling deskriptif, idiomatis, benar, dan umumnya β€œbenar”? Pilihan pribadi saya ada di dermaga di Comet: github.com/gotzmann/comet Akhirnya



, sedikit jajak pendapat untuk anak cucu.



All Articles