React JSフロントエンドコンポーネントを含むフォームがあります。コンポーネントは必要な情報を収集します。Reactコンポーネントは、非表示のフォームフィールド。
ユーザーがコンポーネントを介して必要なデータの入力をバイパスできないようにするには、次の要件を満たす必要があります。
私はこのようにフォームをレンダリングしようとしました:
_ public function buildForm(array $form, FormStateInterface $form_state) {
$form = [];
$form['selected_values'] = [
'#type' => 'hidden',
];
$form['actions'] = [
'#type' => 'actions',
'#weight' => 100,
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
'#button_type' => 'primary',
'#disabled' => TRUE, // Controlled by JS on the frontend
];
return $form;
}
_
そしてJavaScriptでは、次のようなonValueChange()
イベントコールバックがあります。
_function onValueChange(value) {
if (value.trim() === '') {
$(submitButton).prop('disabled', true);
}
else {
$(submitButton)
.prop('disabled', false)
.removeClass('is-disabled');
}
}
_
私も試しました:
_ public function buildForm(array $form, FormStateInterface $form_state) {
$form = [];
$selected_values = form_state->getValue('selected_values');
$form['selected_values'] = [
'#type' => 'hidden',
];
$form['actions'] = [
'#type' => 'actions',
'#weight' => 100,
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
'#button_type' => 'primary',
'#disabled' => !empty($selected_values),
];
return $form;
}
_
これらのアプローチはどちらも同じ問題を示しています。「送信」をクリックしてもフォームは送信されません。フォームを再構築するようです。 2番目の方法では、フォームのレンダリング中、選択された入力値は常に空のように見えます。 afterフォームが構築されるまで、フォームの状態に適用されません。
必要な値を要求しながら、「送信」ボタンが無効になっていることを確認するにはどうすればよいですか?
DrupalフォームAPIにボタンが入力を期待していないことを伝えるため、送信ボタンで#disabled
を使用することは間違った解決策です。つまり、Drupalボタンがまったく存在しないかのように動作します。したがって、送信ボタンをクリックしても効果はありません。通常、巧妙なユーザーが単にバックエンドロジックを無効にするだけなので、セキュリティの観点からこれはすべて意味があります。開発者ツールを使用して、無効または読み取り専用のフォーム要素を強制的に有効にします。
代わりに、解決策は2つあります。
'#required' => TRUE
としてマークすると、ユーザーがDev Toolsに細心の注意を払っていてもフォームをバイパスすることができなくなります。実際には次のようになります。
public function buildForm(array $form, FormStateInterface $form_state) {
$form = [];
$form['selected_values'] = [
// Though this field is hidden, it's required. So, the title is still
// shown if/when the field is ever NULL during submission.
'#title' => $this->t('File selection'),
'#type' => 'hidden',
'#required' => TRUE,
];
$form['actions'] = [
'#type' => 'actions',
'#weight' => 100,
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
'#button_type' => 'primary',
'#attributes' => [
// This button is programmatically enabled/disabled via JS on the
// frontend.
'disabled' => 'disabled',
];
return $form;
}
ボタンを有効にするためのフロントエンドロジックは変わりません。ここでの違いは、ボタンはバックエンドフォームで無効になるのではなく、レンダリングされたHTMLでのみ無効になることです。さらに、狡猾なユーザーがHTML DOM要素のdisabled
属性を削除してボタンを有効にすると、次のような検証エラーが発生します。
ファイル選択フィールドは必須です。
それとは別に、2番目のアプローチが入力値に基づいて「送信」ボタンを有効/無効にできない理由は、Drupalが入力値を処理する前に最初にフォームを作成して、入力を処理するためにどのフォーム要素を呼び出す必要があるか。したがって、フォームビルダーが呼び出された時点では、フォーム状態値にはまだ何もありません。仮説的には、$form_state->getUserInput()
を介して生の入力を取得できる可能性があります次に、それに基づいてボタンを有効にするかどうかを制御しますが、このアプローチはセキュリティに影響を与える可能性があります。