// GetCheck won't work like we want for checks.
// Fetch the value in either one of the two following case:
- // - we have a valid token (form got posted or GET forged by the user)
+ // - we have a valid submit attempt (form was just submitted, or a GET URL forged by the user)
// - checkbox name has a value (false or true), ie is not null
- if ( $request->getCheck( 'wpEditToken' ) || $request->getVal( $this->mName ) !== null ) {
+ if ( $this->isSubmitAttempt( $request ) || $request->getVal( $this->mName ) !== null ) {
return $invert
? !$request->getBool( $this->mName )
: $request->getBool( $this->mName );
* @return array
*/
function loadDataFromRequest( $request ) {
- if ( $this->mParent->getMethod() == 'post' ) {
- if ( $request->wasPosted() ) {
- // Checkboxes are not added to the request arrays if they're not checked,
- // so it's perfectly possible for there not to be an entry at all
- return $request->getArray( $this->mName, [] );
- } else {
- // That's ok, the user has not yet submitted the form, so show the defaults
- return $this->getDefault();
- }
- } else {
- // This is the impossible case: if we look at $_GET and see no data for our
- // field, is it because the user has not yet submitted the form, or that they
- // have submitted it with all the options unchecked. We will have to assume the
- // latter, which basically means that you can't specify 'positive' defaults
- // for GET forms.
+ if ( $this->isSubmitAttempt( $request ) ) {
+ // Checkboxes are just not added to the request arrays if they're not checked,
+ // so it's perfectly possible for there not to be an entry at all
return $request->getArray( $this->mName, [] );
+ } else {
+ // That's ok, the user has not yet submitted the form, so show the defaults
+ return $this->getDefault();
}
}
protected $mSubmitText;
protected $mSubmitTooltip;
+ protected $mFormIdentifier;
protected $mTitle;
protected $mMethod = 'post';
protected $mWasSubmitted = false;
}
# Load data from the request.
- $this->loadData();
+ if (
+ $this->mFormIdentifier === null ||
+ $this->getRequest()->getVal( 'wpFormIdentifier' ) === $this->mFormIdentifier
+ ) {
+ $this->loadData();
+ } else {
+ $this->mFieldData = [];
+ }
return $this;
}
public function tryAuthorizedSubmit() {
$result = false;
- $submit = false;
+ $identOkay = false;
+ if ( $this->mFormIdentifier === null ) {
+ $identOkay = true;
+ } else {
+ $identOkay = $this->getRequest()->getVal( 'wpFormIdentifier' ) === $this->mFormIdentifier;
+ }
+
+ $tokenOkay = false;
if ( $this->getMethod() !== 'post' ) {
- $submit = true; // no session check needed
+ $tokenOkay = true; // no session check needed
} elseif ( $this->getRequest()->wasPosted() ) {
$editToken = $this->getRequest()->getVal( 'wpEditToken' );
if ( $this->getUser()->isLoggedIn() || $editToken !== null ) {
// Session tokens for logged-out users have no security value.
// However, if the user gave one, check it in order to give a nice
// "session expired" error instead of "permission denied" or such.
- $submit = $this->getUser()->matchEditToken( $editToken, $this->mTokenSalt );
+ $tokenOkay = $this->getUser()->matchEditToken( $editToken, $this->mTokenSalt );
} else {
- $submit = true;
+ $tokenOkay = true;
}
}
- if ( $submit ) {
+ if ( $tokenOkay && $identOkay ) {
$this->mWasSubmitted = true;
$result = $this->trySubmit();
}
*/
public function getHiddenFields() {
$html = '';
+ if ( $this->mFormIdentifier !== null ) {
+ $html .= Html::hidden(
+ 'wpFormIdentifier',
+ $this->mFormIdentifier
+ ) . "\n";
+ }
if ( $this->getMethod() === 'post' ) {
$html .= Html::hidden(
'wpEditToken',
return $this;
}
+ /**
+ * Set an internal identifier for this form. It will be submitted as a hidden form field, allowing
+ * HTMLForm to determine whether the form was submitted (or merely viewed). Setting this serves
+ * two purposes:
+ *
+ * - If you use two or more forms on one page, it allows HTMLForm to identify which of the forms
+ * was submitted, and not attempt to validate the other ones.
+ * - If you use checkbox or multiselect fields inside a form using the GET method, it allows
+ * HTMLForm to distinguish between the initial page view and a form submission with all
+ * checkboxes or select options unchecked.
+ *
+ * @since 1.28
+ * @param string $ident
+ * @return $this
+ */
+ public function setFormIdentifier( $ident ) {
+ $this->mFormIdentifier = $ident;
+
+ return $this;
+ }
+
/**
* Stop a default submit button being shown for this form. This implies that an
* alternate submit method must be provided manually.
$this->mShowEmptyLabels = $show;
}
+ /**
+ * Can we assume that the request is an attempt to submit a HTMLForm, as opposed to an attempt to
+ * just view it? This can't normally be distinguished for e.g. checkboxes.
+ *
+ * Returns true if the request has a field for a CSRF token (wpEditToken) or a form identifier
+ * (wpFormIdentifier).
+ *
+ * @param WebRequest $request
+ * @return boolean
+ */
+ protected function isSubmitAttempt( WebRequest $request ) {
+ return $request->getCheck( 'wpEditToken' ) || $request->getCheck( 'wpFormIdentifier' );
+ }
+
/**
* Get the value that this input has been set to from a posted form,
* or the input's default value if it has not been set.
* @return string
*/
function loadDataFromRequest( $request ) {
- if ( $this->mParent->getMethod() == 'post' ) {
- if ( $request->wasPosted() ) {
- # Checkboxes are just not added to the request arrays if they're not checked,
- # so it's perfectly possible for there not to be an entry at all
- return $request->getArray( $this->mName, [] );
- } else {
- # That's ok, the user has not yet submitted the form, so show the defaults
- return $this->getDefault();
- }
- } else {
- # This is the impossible case: if we look at $_GET and see no data for our
- # field, is it because the user has not yet submitted the form, or that they
- # have submitted it with all the options unchecked? We will have to assume the
- # latter, which basically means that you can't specify 'positive' defaults
- # for GET forms.
- # @todo FIXME...
+ if ( $this->isSubmitAttempt( $request ) ) {
+ // Checkboxes are just not added to the request arrays if they're not checked,
+ // so it's perfectly possible for there not to be an entry at all
return $request->getArray( $this->mName, [] );
+ } else {
+ // That's ok, the user has not yet submitted the form, so show the defaults
+ return $this->getDefault();
}
}