The #required flag has an interesting (errant) behavior when dealing with textareas. Take comments for example: Go to any Drupal site and post a comment (this issue will work also) with nothing but a carriage return in the description or comment body. Even though the field is required, a single return is considered enough content to slip past the 'Required' field. Stranger still, the content is trimmed before it is inserted into the database, resulting in a completely empty post even though the field is required.
I've been seeing this issue mostly with comments, we get 5-10 anonymous empty comments a day by bots. Would trimming the field value be a better solution than using empty()?
Index: /Users/nate/Sites/lullabot/v1/public_html/includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.174.2.3
diff -u -r1.174.2.3 form.inc
--- form.inc 29 Jan 2007 21:51:53 -0000 1.174.2.3
+++ form.inc 10 Feb 2007 05:24:34 -0000
@@ -526,10 +526,7 @@
/* Validate the current input */
if (!isset($elements['#validated']) || !$elements['#validated']) {
if (isset($elements['#needs_validation'])) {
- // An empty textfield returns '' so we use empty(). An empty checkbox
- // and a textfield could return '0' and empty('0') returns TRUE so we
- // need a special check for the '0' string.
- if ($elements['#required'] && empty($elements['#value']) && $elements['#value'] !== '0') {
+ if ($elements['#required'] && strlen(trim($elements['#value'])) == 0) {
form_error($elements, t('!name field is required.', array('!name' => $elements['#title'])));
}
Same patch also attached.
Comment | File | Size | Author |
---|---|---|---|
#60 | fix-trim-117748-60-5x.patch | 1.35 KB | pwolanin |
#41 | trim_required-117748-33-7x.patch | 1.3 KB | pwolanin |
#33 | trim_required-117748-33.patch | 1.31 KB | robloach |
#27 | required_trim-27.patch | 1.47 KB | robloach |
#23 | fix-trim-117748-23-6x.patch | 1.46 KB | pwolanin |
Comments
Comment #1
webchickThis seems very reasonable to me, except this problem also exists in HEAD and should be fixed there first. Also, the patch complains about unexpectedly ending. Here's a re-roll.
Now the only kind of weird thing is if I for example put in [space][space] as the title of a node, It will kick back and tell me "Title is required", but the [space][space] is still there, so the cursor appears more in the middle of the box -- I have to delete the two spaces in order to add my title. This does not happen, however, when I hit [return] in a comment body; there it puts the cursor right at the beginning of the textarea, as expected (so somewhere along the line it trimmed the input). We should standardize this behaviour.
Also, where did you see these things getting trimmed before they went in the db? We should remove that code if it's duplicate.
Comment #2
quicksketchThanks webchick. Not sure where things were getting trimmed before they went into the DB. I checked for string and regex replacements but couldn't find why this was taking place. Fortunately this patch (after you fixed it) mostly takes care of that problem. Now entering only returns or spaces into a required field will form_set_error on that field and leave the spaces or returns in place.
I like this approach more than actually trimming the value and making it empty again. Leaving the spaces in there but still throwing an error is inherently telling the user "spaces aren't enough for a title, dummy". Whereas if we trim the title back to an empty string then throw the error, the user will think "I put spaces in there didn't I?", thinking that might be enough. So in general we're avoiding modifying the user's input and instead just telling them it's not enough.
Unfortunately, in textareas if you enter a series of returns, every time you preview the post it looses another return. I'd like to figure that out before committing this patch.
Comment #3
PanchoHere is a rerolled patch. Now we need to figure out what seems to happen with returns in textareas (see #2)... I need to figure out how to test this, as CCK is broken right now.
Comment #4
PanchoRequired textareas are a rare thing in core. Forum posts with their required body are a good example to test.
If I require 10 (or something) words for any other content type, I'm testing a different validation than the required field.
Results of the testing: The "losing a return" problem is still present, but it is obviously not connected to this patch. It also arises, when a completely different validation routine throws an error or the form is finally saved to db. I also experienced this bug without this patch being applied. Therefore I filed a new ticket #216588.
As the bug we hit is not connected to this patch, I think the patch in #3 is rtbc.
I do consider this a usability bug, for Title fields it is even critical.
Comment #5
pwolanin CreditAttribution: pwolanin commentedcode looks good, though a code comment might be nice.
Works as advertised.
Comment #6
gábor hojtsyHm, added some short docs and committed with that.
Comment #7
webernet CreditAttribution: webernet commentedDuring Install:
notice: Array to string conversion in /includes/form.inc on line 670.
Comment #8
gábor hojtsyDoh, rolled this back. For reference, this was the patch I committed originally: http://cvs.drupal.org/viewvc.py/drupal/drupal/includes/form.inc?r1=1.264...
Comment #9
robloachWill it get the desired effect if we run a is_string on it? Might break something else, but worth attempting.
Comment #11
pwolanin CreditAttribution: pwolanin commentedgak, sorry about that - was focused on testing text fields. empty() does make sense for array elements, but causes its own problems.
how about something more like:
for any string (even an empty string) count() returns 1,
Comment #12
robloachThat made no sense. This will check if the value is actually a string, and then check if it's an empty string. This might give the desired result. Testing is definitely needed.
Comment #13
robloachNope...
Comment #14
pwolanin CreditAttribution: pwolanin commentedI don't know what webchick was posting, but I crossposted with both above.
@Rob Loach - I don't see that your code properly handles arrays - for example checkboxes that are required.
Comment #15
robloachThis is a bit better....
Comment #16
robloachIt seems like we should provide a switch statement to handle all required use cases (string, arrays, integers?).
Comment #17
PanchoRob Loach: Guess that's a good idea, as this is more transparent and thus also prevents future errors.
Comment #18
PanchoSomething like this would be cool:
but we don't have something like $elements['#datatype']. Good ideas?
Comment #19
pwolanin CreditAttribution: pwolanin commentedsee my comments above in #11- this last patch code is wrong since it fails to check arrays that may be empty
Comment #20
pwolanin CreditAttribution: pwolanin commented@Gabor - the rollback does not seem to have worked.
attached patch per the code in #11, seems to work for both checkboxes and textfields
Comment #21
Pancho#20 should work, but we better check twice...
I just split the if-expression in two, as it was hard to grasp. Also I updated documentation.
Comment #22
pwolanin CreditAttribution: pwolanin commented@Gabor - or - perhaps you rolled-back on 6.x and not HEAD?
Comment #23
pwolanin CreditAttribution: pwolanin commented@Panch - your docs are not correct: "Count() checks if the item (string, array, integer) contains anything."
Patches attached for HEAD and DRUPAL-6
Comment #24
PanchoAnother suggestion for the docs:
Also, I still prefer separate if-clauses for
if ($elements['#required'])
and the actual validation (see patch #21).Comment #25
gábor hojtsyYes, I rolled back on 6.x, I am not entitled to commit anything to HEAD. Once we figure out how to solve this, it needs to be ported to HEAD too (or if we don't figure out anything, HEAD needs to roll back the patch as well).
Comment #26
pwolanin CreditAttribution: pwolanin commented@Gabor - I think the code in #23 works well, so it's just a question of the code comments.
Comment #27
robloachThis has to be fixed before the release of Drupal 6.0 as all these warnings when submitting forms would drive most users away. So, I'm setting this to critical.
I've tested the code from #23 in both a checkbox and textfield situation and both seemed to work as desired. The textfield where I passed an empty string was denied, and the checkboxes that I didn't check a required value were denied. I tested this in admin/settings/blogapi and admin/settings/site-information.
In my opinion, the code comments from #23 are fine, but this might seem more helpful for someone reading through the code (see patch)....
Comment #28
PanchoWhich warnings? The erroneous patch has been rolled back, so we are in the previous state, at least in the D6 branch.
Demoting this to normal. If I misunderstood you, feel free to make this critical again.
Even if not critical, we should get this committed soon, both in the D6 branch and in HEAD. But no rushing in - this time it should be 100%.
Comment #29
PanchoComment #30
webernet CreditAttribution: webernet commentedDid a quick test of #23, and it doesn't appear to break anything.
Comment #31
Pancho#23 and #27 is essentially the same code. There are two differences:
This is nothing we can decide. Therefore it would be great if Gábor or Dries would take the decision and commit either of the two patches.
I mark this RTBC, as this is all we can do.
Comment #32
chx CreditAttribution: chx commentedI do *not* like the verbosity in #27. Thats code bloat in my eyes.
Comment #33
robloachComment #34
gábor hojtsyWhy do we only need to check for arrays and strings? Can someone shed a light on this?
Comment #35
pwolanin CreditAttribution: pwolanin commented@Gabor - data coming out of FAPI is always a string or an array. count(NULL) == 0, so that works. If you run trim() on a number or boolean, it's converted to a string, so that works too.
if someone really wants to return an object from a form(?!), they could implement the "countable" SPL interface. "This extension is available and compiled by default in PHP 5.":
http://us.php.net/manual/en/function.count.php
Comment #36
gábor hojtsypwolanin: thanks for the explanation. Committed #33 to Drupal 6. Still needs to be committed to 7.x.
Comment #37
pwolanin CreditAttribution: pwolanin commentedSo the comment could be clarified, maybe like:
+ // If the field is required, empty() cannot be used to check since
+ // the string '0' may be valid. count() gives the number of
+ // elements in an array or countable object, 0 for NULL, or 1.
+ // trim() removes white space, and converts to string.
Comment #38
pwolanin CreditAttribution: pwolanin commentedoops- cross posted
Comment #39
Senpai CreditAttribution: Senpai commentedThe error in #7 is still present during the installation of head. FYI
Comment #40
pwolanin CreditAttribution: pwolanin commented@Senpai - the bad patch still needs to be rolled back in HEAD and the good patch applied. This is only fixed in 6.x
Comment #41
pwolanin CreditAttribution: pwolanin commentedhere's a version of the patch from #33 that applies to HEAD.
Comment #42
robloachLooks good.
Comment #43
chx CreditAttribution: chx commentedUntil this is committed , HEAD will display a notice on install.
Comment #44
pwolanin CreditAttribution: pwolanin commentedbump - RTBC and causing errors in HEAD
Comment #45
pwolanin CreditAttribution: pwolanin commentedbump again...
Comment #46
Senpai CreditAttribution: Senpai commentedBump a third time...
Comment #47
vladimir.dolgopolov CreditAttribution: vladimir.dolgopolov commentedHere is the test for the issue.
Before #41 there were 31 passes, 2 fails and 2 exceptions.
After #41 there were 33 passes, 0 fails and 0 exceptions.
Comment #48
catchhttp://drupal.org/node/232763 was duplicate.
Also this is blocking progress on http://drupal.org/node/228594 since admin/user/user/create is broken
Comment #49
dries CreditAttribution: dries commentedI'm not a big fan of this patch. I think it's clumsy. Furthermore, I think we should be using drupal_strlen() instead of strlen(). Please verify. Thanks.
Comment #50
pwolanin CreditAttribution: pwolanin commented@Dries - strlen() should be fine (and much faster) since we just want a boolean answer of "characters or no characters".
Do you have suggestions? I think it's less clumsy than what we had before.
Comment #51
chx CreditAttribution: chx commentedClumsy...? Call PHP clumsy, then.
Comment #52
pwolanin CreditAttribution: pwolanin commented@Dries - this patch is already in D6, and fixes a critical bug. If you have suggestions for better code for D6 and or D7, can they be addressed after HEAD works again?
Comment #53
dries CreditAttribution: dries commentedOK, I've committed this to CVS HEAD to make HEAD work again. I'm marking this 'code needs work' as the test needs to be extracted into a simpletest test.
Comment #54
pwolanin CreditAttribution: pwolanin commented@Dries - thanks for getting the fix in, but I'm confused about what tests you are referring to?
Comment #55
catchpwolanin - did you see the test in #47
Comment #56
pwolanin CreditAttribution: pwolanin commentedoh, right, THAT test.
Making minor changes to the test and posting as a patch: http://drupal.org/node/231302
Comment #57
pwolanin CreditAttribution: pwolanin commentedhow about 5.x?
Comment #58
igorik CreditAttribution: igorik commentedYes, there is a little missunderstood which patch from all of them here is ok to apply to Drupal 5,
is it #23 - http://drupal.org/node/117748#comment-717485 ?
I have critical problem with empty nodes atomaticaly created when some user normal goes through site, he add no content...
so mabe this can be solution for it (http://drupal.org/node/236986)
thanks
Igorik
http://www.somvprahe.sk
Comment #59
pwolanin CreditAttribution: pwolanin commentednone of these patches work for 5.x, hence the status "to be ported"
Comment #60
pwolanin CreditAttribution: pwolanin commentedhere's an UNTESTED patch for 5.x
Comment #61
drummI do not think this is critical, it is only an edge case.
@igorik, maybe you should check with your problem users or see if a contributed module or somesuch is causing the problem.
Comment #62
pwolanin CreditAttribution: pwolanin commented@drumm - right, sorry, it was critical for HEAD since some forms were failing there due to the bad 1st patch that was committed.
Comment #63
janusman CreditAttribution: janusman commentedsubscribing
Comment #64
treksler CreditAttribution: treksler commentedApplied #60 to my Drupal 5.8 installation.
Doesn't appear to break anything and looks it is a very welcome bugfix that allows me to remove all the duplicate validation code in my module that is currently checking for empty values in required fields.
Comment #65
janusman CreditAttribution: janusman commentedDitto, it works here too =)
Comment #66
drummCommitted to 5.x.
Comment #67
Anonymous (not verified) CreditAttribution: Anonymous commentedAutomatically closed -- issue fixed for two weeks with no activity.
Comment #68
threexk CreditAttribution: threexk commentedThis change caused many of my required CCK radio button fields to give the following error when left unchosen at submission:
"An illegal choice has been detected. Please contact the site administrator."
The code-level problem was these fields had value Boolean false, and count() in the new line of code returns 1 for that. Oddly I was able to fix it on a per-field basis by editing and resaving the field in the CCK Manage Fields pages. This made the fields take on the empty string instead of Boolean false.