I'm evaluating using JSON Schema for validating form data.
I can use it to validate my form data when you click submit using AJV and then check it again on the server using a PHP implementation of JSON Schema.
That part sounds great, but I'm trying to figure out how I would use it for real-time validations -- i.e., validation as you're filling out the form/typing.
Specifically, I can run the entire validator on every keystroke, but it seems expensive to validate the whole form when only one input has changed. In particular, any AJAX-based validations (such as a username uniqueness check) would fire too frequently.
Has anyone used JsonSchema for this purpose? Is it feasible? How would I fine-tune AJV or another JsonSchema implementation to only run the validators that are necessary on input?
Integrating this with the client will depend heavily on what you're using on the client side. I'm working on a project using this with dynamically created forms in Angular 2+ and AJV and it is working really well.
It will also depend on how much of JSON Schema you're using. For example, I want my forms to be able to use $data references so that validity of one input can depend on the value of other inputs. This basically means I have to validate on any change in the form since there's not an effective way to tell what value is the target of a $data reference.
Also, if there's any potential for your model data to change outside of the user interacting with the form (e.g., new data being pulled from the server from other users, etc.) it is much more resilient to validate the schema and model in its entirety.
In general even on my more complicated forms with up to 30-40 input values ajv takes less than 10ms to validate the entire form including a function of my own to match ajv's errors to my inputs for display. So I wouldn't worry about the performance hit.
Edit: As for the async validators adding a debounce of some sort will depend on what you're using client side, but shouldn't be too hard and AJV's documentation is really complete.
Edit: Here's the loop I have the errors go through to match them and clean them up a little (most of AJV's errors are user readable, but a few like pattern matching need some help rather than spitting out a regex at the user):
errs.forEach((err) => {
// Is this a value that is being matched to another input?
if (err.dataPath === dataPath && err.keyword === 'const' && err.schema.$data) {
return messages.push('Does not match')
}
// Don't show regex to people.
else if (err.dataPath === dataPath && err.keyword === 'pattern') {
return messages.push('Not valid format')
}
// Is the keyword 'required' and the parentPath is a match and the property is matched to err.params.missingProperty
else if (err.keyword === 'required' && err.dataPath === parentPath && err.params.missingProperty === propertyName) {
return messages.push('Required')
}
// Is the dataPath a match and no other special criteria apply
else if (err.dataPath === dataPath) {
// Cap first letter
return messages.push(err.message.charAt(0).toUpperCase() + err.message.slice(1))
}
})
Related
Hello Devs I am a fresher and I am currently working on a task. In that I have used 3 forms inside single form so I can validate the object of objects but when I try to validate them in nested manner the only the first form was validating. Can anyone give me some advices to solve this problem ? And this above pic is the code I have used to validate the nested forms but only 1st form is validating.
I agree with the comments that say you should not submit a picture of text, and you need to supply a minimal reproducible example. Without that, a specific error can't be pinpointed.
However, here is some general feedback. One issue is that deeply nested code is not clean code. In my opinion you should divide the logic into smaller chunks and write it in a more linear structure to make it easier to troubleshoot. You could have computed properties like this:
bankDetailsValid(){
// bank details validation here
},
employeeDetailsValid(){
// employee details validation here
},
# more specific validation can be in more computed properties
allFieldsValid(){
// return this.bankDetailsValid && this.employeeDetailsValid # can add
// whatever checks are needed here to determine if the form as a
// whole can be submitted
},
errorMessage() {
if (!this.bankDetailsValid) {
return "Bank details error"
}
if (!this.employeeDetailsValid){
return "Employee details error"
}
# more error messages would go in if-statements here. Then you would return a default error:
return ""
}
Also keep in mind that "formValidation" suggests that your function is doing more than one thing, because it is both determining if the form is valid AND determining what the error message is. That's overly complex, so it leads to dirty code. The code will be easier to read and debug if one function does one thing.
newbie with Javascript. I have a javascript function that is checking user input. The html document has two forms. I call validateForm(document.forms[0]) with the first form as an argument. Then in my function I rename the argument to TheForm. (e.g. validateForm(theForm).) The fields contain integers. In validateForm I simply want to check equality for two form fields like this:
if(theForm.Field1.value == theForm.Field2.value)
{
//do something
}
Pretty simple eh? I have tried
theForm.Field[x].value.toString, theForm.Field[x].toString.Trim, theForm.Field[x].
Also tried to assign vars for both fields and test. Viewing the contents in Visual Studio I can see where the fields are exactly the same, and hence, the boolean check should fire.
I have a database that cannot accept non 8-bit chars, and if the user adds a Euro symbol throughout the form the whole thing collapses.
It's a very, very big form and I don't really want to add lines of code everywhere to run a simple replace function - but I can't find any method online to search through a whole form pre-submit, is this possible?
Failing that what's the best way to restrict certain character inputs globally in my web form?
Running ASP.NET MVC4 using lots of jQuery.
Really not enough info to answer this as best as possible. But I will give it a go. You wouldn't add lines of code everywhere. I assume you are aggregating the form data before submission, at that point you would strip the euro symbol. Assume it is an object..
var formObj = {firstName : "aspiring€", lastName : "programmer€", comment : "I really like euro symbols!!€€€!!" }
$.each(formObj, function( key, value ) {
formObj[key] = formObj[key].replace(/€/g, '');
});
console.log(formObj);
2 possible options
A. Your could create a custom model binder that strips the invalid characters before the model is bound. Refer this example for a custom model binder that removes white space from posted values. The advantage is that you can register it in global.asax.cs and your model properties will not contain invalid characters on post back. The disadvantage is that if ModelState is not valid and you return the view, then the user sees the modified text, which might be confusing (what happened to what I entered?)
B. Create an attribute that inherits from RegularExpressionAttribute and apply it to all relevant properties
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class MyAttribute : RegularExpressionAttribute
{
public MyAttribute() : base(#"^[^\u20AC]+$")
{
// Add default error message
ErrorMessage = "The value cannot contain the euro symbol";
}
}
and register it in Global.asax.cs
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MyAttribute), typeof(RegularExpressionAttributeAdapter));
The advantage is that it gives both client side and server validation. The disadvantage is that you need to remember to add it to all properties
I want to avoid the occurrence of an %sign in the e-mail adress.
So the user does not add additional headers to the e-mail.
However I am totally overwhelmed with regex and cannot find the solution.
So far I have
/[%]+/
But in my whole code this does validate an e-mail adress like test#example.com% as true.
This was due to Firefox and Chrome having an internal e-mail check whan specifying type="email" for the input!!!
function validateEmail(sEmail) {
var filter = /^[a-z0-9]+([-._][a-z0-9]+)*#([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,4}$/;
filter2 = /^(?=.{1,64}#.{4,64}$)(?=.{6,100}$).*/;
filter3 = /[%]+/
if (filter.test(sEmail) && filter2.test(sEmail) && !filter3.test(sEmail)) {
return true;
} else {
return false;
}
}
Btw. since I am totally unable to write this myself so far, I found two solutions, which I am not sure which one is better.
The upper one (1) or 2:
/^([\w-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/
What do you think?
You shouldn't be using regular expressions to prevent against injection. Instead use a prepared sql statement:
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
I wouldn't use regex unless you fully understand what a valid email address is. Instead, you should parameterize all values so that even if malicious code is inserted, it'll just treat it as a string. See OWASP:
https://www.owasp.org/index.php/Query_Parameterization_Cheat_Sheet
I see that you changed the question. You're actually interested in fixing PHP email header injection. This is considerably more complex than simply filtering out a single character in email addresses. You need to check to see if hackers/bots are trying to inject multipart/form data (especially newline/carriage returns which delimit header from body of a multipart message), manipulate form and session variables, and filter names and other fields (which shouldn't contain special characters).
Email address filtering just isn't sufficient to prevent attacks. The machine itself needs to be properly configured as well. Follow this guide to do what you can to secure against php injection (includes examples for filtering out newlines and for software configuration): http://static.askapache.com/pdf/xss-csrl-injection.pdf
A custom validator has properties called ClientValidationFunction and ControlToValidate. The function is like this:
function MyValidationFunction(source,args) {
if(args.Value==......)
}
I know that here 'source' is the ControlToValidate. But I can't understand what the type of the args.Value is. What does it take as a Value. When the controltovalidate is a textbox I know it's the text of that textbox but what is it if the control is a user control. So my question is what is the Value to validate and can we change it?
Apparently, for client-side validation, the Value property of the rendered HTML control is used, which makes sense, for example, for TextBox controls, which are rendered as a simple <input type="text"> (and whose value property contains the content of the text box). If a (custom) control consists of multiple HTML controls, client-side validation is not feasible, according to the following Knowledge Base article:
How to extend a Web Form control to work with the validation controls by using Visual Basic .NET or Visual Basic 2005:
NOTE: This article demonstrates how to extend the Calendar control for server-side validation only. For client-side validation to occur, the validation controls hook up to the corresponding HTML control's Value property. Because many HTML controls are used to build the Calendar control, no single HTML control contains the selected value for the Calendar control. Thus, client-side validation is not appropriate for the Calendar control.
By the way, for server-side validation, you can use the ValidationProperty attribute to specify which property is used for validation.
EDIT: According to this SO question, if you output an <input type="hidden"> as the first control of your user control, this will be used for client-side validation. This might be a useful workaround, if you are comfortable with storing your actual control value in there.
Ref: ASP.NET Validation in Depth
Two parameters are passed into your client function, corresponding to
the parameters that are passed to the server function. The first is
the client validator element, and the second is the equivalent of the
arguments on the server. It has two properties, the Value, which
contains the input to be validated and IsValid, which you can update
to indicate validity.
function CheckEven(source, args) {
var val = parseInt(args.Value, 10);
if (isNaN(val)) {
args.IsValid = false;
}
else {
args.IsValid = ((val % 2) == 0);
}
}
You can not change value, it is readonly. check erverValidateEventArgs.Value Property
and Using the CustomValidator Control