Closed (works as designed)
Project:
Drupal core
Version:
6.x-dev
Component:
comment.module
Priority:
Normal
Category:
Bug report
Assigned:
Reporter:
Created:
27 Feb 2008 at 22:45 UTC
Updated:
30 Mar 2010 at 11:53 UTC
Hi there,
It's not possible to modify form values in the validate handling of hook_comment(). The problem exists because the invoker of the hook (comment_validate()) does not declare its first parameter to be a reference. Easy fix.
The function docs for hook_comment('validate') read:
"validate": The user has just finished editing the comment and is trying to preview or submit it. This hook can be used to check or even modify the node. Errors should be set with form_set_error().
It states there that it can be used to "modify" the node.
The patch i've rolled adds the & operator to the first parameter of comment_validate().
--
Sammy Spets
Synerger
http://synerger.com
| Comment | File | Size | Author |
|---|---|---|---|
| comment.module.validate.ref_.200802280944.patch | 391 bytes | sammys |
Comments
Comment #1
sammys commentedswitching to CNR
Comment #2
Daitaka commentedAha, I knew I couldn't have been the only one noticing this. I hope this will get an official fix soon.
However, there's an other possible reason for this bug, and thus another possible fix: comment_form_validate() calls comment_validate() but does not store the return value.
Either references or return values must be used in order for the user validation to propagate through the system, but right now neither are used. Which one will get chosen is up to the devs to decide, of course.
Comment #3
Daitaka commentedOkay, I've tested implementing the reference, and it works.
HOWEVER...
It only works when posting comments. It doesn't work when previewing comments. And here's the reason why (comment.module line 1421):
This is the function that creates previews. First, $form_state['values'] is stored in $edit. Then, $form_state is passed to drupal_validate_form as a reference. If no errors occur, processing goes on... using $edit!!! Any changes made during validation are simply thrown out.
Obvious solution: move both the $edit and $node definitions to after the call to drupal_validate_form()
Comment #4
mot commentedThanks for all the input, your spend time etc. pp.. But first of all it should be referenced wether that function should validate (in this case, there is no need to change something) or filter (that is the proper verb for changing something) data.
Keep in mind that mixing the concepts of Validation and Filtering leads to serious security Issues which can destroy a webapplication in it's whole.
Therefore I can only strongly suggest that Validation Hooks should never be able to change data passed to them.
Since the main part of this Issue is about changing input data in a validation hook which is plain wrong, it must be closed.
Comment #5
jeff h commentedHmm, if we decide that validate operations should not be able to modify input data, then we can't just close this issue - the documentation at http://api.drupal.org/api/function/hook_comment/6 badly needs changing.
"validate": The user has just finished editing the comment and is trying to preview or submit it. This hook can be used to check or even modify the node. Errors should be set with form_set_error().I tend to agree that it's odd to modify data in a validate operation, but then which $op should the data be modified in? The docs don't say.
Jeff
Comment #6
mot commentedI think this is a pure misunderstanding. The Sentence: is there for giving a hint that you can modify the node data and to tell you the truth, you can. It is inside the Examples of the documentation page:
In this case, the nodes cache is "modified". Take care that "modify" itself stands inside QUOTES.
Since the patch changes a function head and uses bad design this way (passing variables by reference implies a lot so it is adviced to take much care here), I suggest that the ticket is closed until one of the core devs can say wether or not an API change is necessary.
Otherwise I suggest that the original poster provides more information about his/her motivation to apply the patch. Maybe there are better ways to achieve the same.
Comment #7
Daitaka commentedI will post my reasons for wanting this:
I am using Drupal to run an online roleplaying game. I want people to be able to roll dice in an easy way but without too much obvious ways to cheat.
So, the solution I chose is that the people write [roll]1d6[/roll] in their text, which then automagically turns into a random value between 1 and 6.
However, achieving this is tricky. After all, this random value may only be generated ONCE. It's impossible to play if the value keeps changing every time someone loads that particular node/comment.
The only solution to this that I see is to change the text itself. When someone presses 'Post' or 'Preview' on a text containing a [roll], the text itself must be modified, replacing the [roll] tag with a unique [rollid] tag (basically just a hash of some relevant values). This rollid is stored in the database along with the randomly generated result of the dice roll. Afterwards, the standard text filtering functionality is used to turn the [rollid] tag into a human readable text informing everyone of the roll and result.
But back to the problem at hand: the text of the post that is being made must be changed. It must be changed in such a way that every preview, every edit, every view of the text later on contains the modified version. It must be stored in the database in its modified form.
When it comes to nodes, this is not a problem:
These simple functions make sure that the text of every node gets sent to the diceroller_match function, which does some regex magic and other stuff and then returns the modified text, which then gets stored in the form again. Because $form_state is passed as a reference, the changes are final and global.
(Do note that this is done using the 'validate' functionality of nodes.)
But when it comes to comments, this simply isn't possible. The comment gets passed down as a copy, not a reference, and you can change all you want in the local values, it won't affect anything.
This has forced me to use the following hack to get the functionality I need:
The first piece of code is actually in my index.php, right after the drupal_bootstrap call... The function is in the module file, but it's still one ugly hack, totally bypassing the whole hook system for the very simple reason that the hook does not do what it promises: it does not give me the ability to modify the comment.
Comment #8
damiancugley commentedValidation should not change the contents of the form in any way visible to the user, because they expect to be able to edit the comment or node and see their text as they typed it. And for security reasons it is necessary to have HTML filtered on the way out of the database, so there is normally no reason to filter it on the way in.
Contradicting this, here are two use cases for changes during validation:
In the latter case, we have the problem that Word includes several kilobytes of hidden data in the HTML, but this becomes visible because some output filter or other escapes the comment opener that is supposed to hide it. Worse, some versions of Microsoft Word represent lists not as lists but as paragraphs with bullet characters at the start, and we wanted to normalize everything to straightforward HTML. After various unsuccessful attempts with doing it within TinyMCE or as a filter or a submit handler, our current version works by adding a validator that removes the Microsoft Word data islands from the HTML and replaces the appropriate P tags with UL or OL and LI. Note that if this works, the user sees no change (because they edit it in rich-text editor mode). So it does not break the user's expectations.
This works OK in most situations, but fails when previewing comments, because (as mentioned above) the $edit variable is a copy of the form values and is not munged when the comment is validated.
Comment #9
damiancugley commentedAlso, the above change to $edit does not allow changes during validation to be retained in the form in the case when the user has clicked the Preview button and not Post. This is because the preview is added during drupal_rebuild_form, and this uses a fresh copy of the submitted values.
Comment #10
jcisio commentedMy temporary solution is on $op='update', you can modify directly in the database. A poor design, but if you don't want to break the D6 API...
I don't know if this is changed in D7 (i.e. a $op='presave' like with node).
Edit: just find a new way to modify comment without doing the db_query directly.
Then modify your data after it is validated and before the default submit function takes place!
Comment #11
sunThis is the expected behavior. You should use hook_form_alter() to add a proper form validation handler.