Using preg_match to detect special characters not working - php

I'm trying to stop users from being able to put any characters in the username box apart from a-z(A-Z), 0-9 and spaces. Here's the HTML to start off with:
<form action='register.php' method='post'>
<div class="field-wrap">
<label>
Username<span class="req">*</span>
</label>
<input type="text" name="username" required autocomplete="nope" />
</div>
<div class="field-wrap">
<label>
Email Address<span class="req">*</span>
</label>
<input type="email" name="email" required autocomplete="nope" />
</div>
<div class="field-wrap">
<label>
Set A Password<span class="req">*</span>
</label>
<input type="password" name="password" required autocomplete="nope" />
</div>
<button type="submit" class="button button-block" />
REGISTER</button>
</form>
Pretty self explanatory, right?
Here's the PHP on register.php:
$username = $_POST['username'];
$password = $_POST['password'];
if(preg_match('/[^a-zA-Z0-9[:space:]]+$/', $username)){
//pass
}
else{
$message = "Your username may only contain letters, numbers and spaces";
$_SESSION['error'] = $message;
header("Location:auth.php");
}
// do all the other stuff like add user to database etc
header("Location:index.php");
When I try to create a user with a username such as "test##!?*^'/"()", the preg_match function doesn't work. Instead of redirecting back to the login/register page (auth.php), it adds the user to the database and redirects me to the homepage (index.php).
I have also tried /^[a-z0-9 .-]+$/i for the parameters in preg_match but that doesn't work either.
Just a side note, I'm not using this for security reasons, I use stripslashes and mysql_real_escape_string AFTER the preg_match.
Any ideas, or a better way to only allow a-z(A-Z), 0-9 and spaces? I have been trying to solve this for hours now and to no avail. Thanks!

Use this preg_match code to only allow Letters (including uppercase), Numbers, and Spaces:
$Passed = 0;
$username = $_POST['username'];
$password = $_POST['password'];
if(!preg_match("/[^a-z0-9 ]/i", $username)){
$Passed = 1;
//stop header location here.
}
else{
$message = "Your username may only contain letters, numbers and spaces";
$_SESSION['error'] = $message;
header("Location:auth.php");
}
if ($Passed == 0){
header("Location:index.php");
}

About your original question:
This regular expression doesn't work properly due to caret (^) position:
/[^a-zA-Z0-9[:space:]]+$/
↑
In this position, caret negate following pattern inside square brackets. In fact, your pattern search for any not a-zA-Z0-9....
To match a string with only alphanumeric characters and spaces you have to move the caret at start of pattern. In this position the caret means “start of string”:
/^[a-zA-Z0-9[:space:]]+$/
↑
But you can also simplify your pattern, and replace [:space:] with a real blank space ([:space:] and \s match also newline, tab, etc...1). Try this regular expression:
/^[A-z0-9 ]+$/
Your script still not working:
The solution is die().
If the string doesn't match the pattern, you execute this code:
$message = "Your username may only contain letters, numbers and spaces";
$_SESSION['error'] = $message;
header("Location:auth.php");
Sending headers doesn't interrupt the script, so the remaining code is executed and the last sent header (Location:index.php) is loaded.
Force script termination after sending header:
header("Location:auth.php");
die();
1 From PHP documentation: “The "whitespace" characters are HT (9), LF (10), FF (12), CR (13), and space (32). However, if locale-specific matching is happening, characters with code points in the range 128-255 may also be considered as whitespace characters, for instance, NBSP (A0).”

Change your regex to:
/^[\d\w\s]+?$/
You can easy test with http://regexr.com/

Solved this now thanks to Ghulam... his logic was great although the code he wrote was wrong so I've updated it.
Also updated my answer with fusion3k's die(); approach just to make sure the code is completely finished.
$username = $_POST['username'];
$password = $_POST['password'];
$passed = 0;
if(preg_match("/^[A-Za-z0-9 ]+?$/", $username)){
//pass
$passed = 1;
}
if($passed == 0){
$message = "Your username may only contain letters, numbers and spaces";
$_SESSION['error'] = $message;
header("Location:auth.php");
die();
}
if($passed == 1){
//add user to database
header("Location:index.php");
}
We set $passed as 0 to begin with.
If $username only contains letters a-z(A-Z), 0-9 and spaces then we set $passed to 1 as it has passed the preg_match check.
If $username contains any other characters apart from these, (#, %, ^ etc) then we leave the $passed variable as 0.
If $passed is 0 then the username is invalid, so return the user to the register/login page (auth.php) and give them an error message.
If $passed is 1 then the username is valid so we can add the user to the database and return them to the homepage.
die(); is used to make sure the code stops reading/running after the header redirect has been sent. The page might redirect but the user could still be added to the database!

This is a good example for a short security tutorial.
The original code presented by OP allows access if $username does not contains characters from list, at least one of them:
if(preg_match('/[^a-zA-Z0-9[:space:]]+$/', $username)){
//pass
}
The updated code posted here is doing the job:
if(preg_match("/^[A-Za-z0-9 ]+?$/", $username)){
//pass
$passed = 1;
}
However, correctly is to refuse access if $username contains ANY characters outside from the allowed set:
if(!preg_match("/[^A-Za-z0-9 ]/", $username)){
//allows access
$passed = 1;
} else {
//refuse access
$passed = 0;
}
This will cover and refuse anything outside from the allowed character set.
The caret sign "^", usually is a metacharacter that assert start of subject (or line, in multiline mode), like in /^(A sentence).*$/, but when used in a character class, like [^abc] it means "NOT the characters inside the brackets" (reference).

Related

How to stop user from entering only space in input PHP?

I am creating a social site and in the registration code someone can enter only spaces in the input fields.
I don't want them to enter any spaces in the fields except for the password one.
I have tried a bunch of things, empty, trim, htmlentities !trim and some more I forgot. None of them worked. Some of them gave the first name the value of 1.
What am I missing?
Below is a list of things I have tried (not at the same time).
$first_name = trim(strip_tags(filter_var($_POST['first_name'], FILTER_SANITIZE_STRING)));
str_replace(' ', ' ', $first_name);
if (empty($first_name)) {
echo "Fill in first name to sign up";
}
if (!ctype_alnum($first_name)) {
echo "Invalid first name, it only may contain letters or digits";
}
$first_name = $_POST['first_name'] ?? '';
if (empty($first_name)) {
echo "Fill in first name to sign up";
}
if (!ctype_alnum($first_name)) {
echo "Invalid first name, it only may contain letters or digits";
}
$first_name = htmlentities(trim(strip_tags(filter_var($_POST['first_name'], FILTER_SANITIZE_STRING)));
if (empty($first_name)) {
echo "Fill in first name to sign up";
}
if (!ctype_alnum($first_name)) {
echo "Invalid first name, it only may contain letters or digits";
}
Use regular expressions. The following checks it to be at least 5 symbols and contain just letters and digits;
$firstName = trim($_POST['first_name']);
if (!preg_match("/^[a-zA-Z0-9]{5,}$/", $firstName)){
echo 'Invalid';
}
More information on preg_match() can be found here.
Hey i have simple solution regarding your question try one
If you want to submit only text and whitespace than use this one
<input type="text" name="Name" required pattern="[a-zA-Z ]+" >
If you want to submit number and whitespace than use this one
<input type="text" name="Name" required pattern="[0-9 ]+" >
If you want to insert text not whitespace than use this one
<input type="text" name="Name" required pattern="[a-zA-Z]+" >
Use any line according to your requirements no extra line of code or condition simple and secure

PHP Trim function not removing whitespaces

I'm doing some tests with learning purpose. I have a PHP script in which I used some functions to see how they work:
First I used isset to make sure a var exist
Then empty to make sure if a var has some value
Finally I used trim to remove whitespaces
After some testing I realized that trim function is not working properly.
For example I can still write whitespaceCHARwhitespace, then I used strlen function and I get a 3 as a result. What's wrong with my script?
Btw I would like to know how acceptable is this form validation I would like to avoid some sqlinjection.
Thanks in advance.
<span><?php echo $msg;?></span>
<form method="POST">
<label for="name" class="white-headers">NAME</label>
<input type="text" name="name" id="name" class="form-control">
<label for="last_name" class="white-headers">LAST NAME</label>
<input type="text" name="last_name" id="last_name" class="form-control">
<input type="submit" class="btn btn-success" name="submit">
</form>
$msg="";
if(isset($_POST["submit"])){
$name = $_POST["name"];
$last_name = $_POST["last_name"];
if(!empty(trim($name)) && !empty(trim($last_name))){
$name_len=strlen($name);
$last_name_len=strlen($name);
$msg="<div class='alert alert-success'>
both fields are set and have some value name =".$name." with ".$name_len." chars and last_name =".$last_name."
with ".$last_name_len. "chars</div>";
}
else{
$msg="<div class='alert alert-danger'>
both fields are set but one or both are empty name =".$name." and last_name =".$last_name."</div>";
}
}
The only times you're using trim there are when you check whether or not there's anything left after you trim the variables:
if(!empty(trim($name)) && !empty(trim($last_name))) {
That doesn't affect $name and $last_name.
trim returns a string with the whitespace removed, but it doesn't change the value of the variable given as an argument. If you want those to be trimmed for later use in your code, you need to set them to their trimmed values, like $name = trim($name), etc.
In your case, you could probably trim them when you set them from $_POST initially.
$name = trim($_POST["name"]);
$last_name = trim($_POST["last_name"]);
Then you can check if there's anything left more simply:
if ($name && $last_name) {
empty isn't necessary because you know they're set, and zero-length strings evaluate to false.
As specified in the documentation, trim only removes whitespaces at the beginning or at the end of a string. Whitespaces in the middle are not affected (using _ to mark a whitespace):
__string will become string
string__ will become string
s_t_r_i_n_g will remain s_t_r_i_n_g
Plus, as pointed in Don't Panic's answer, you are checking the strings after the trim, not its return value.
About the form validation: if you want to clean your inputs before using them in your application, simply trimming them isn't enough. There are many ways to sanitize inputs, every framework offers some options, but since you specifically spoke of sqlinjections, my suggestion is to start by reading PHP's mysqli.real_escape_string

Invalid if Special Character is entered

I currently have this code below which validates username length only. If none entered it will show error message, if less than 3 characters entered show error message. I want to add an if/else statement that if the user enters special characters like !##$%^&*()+=/? etc... the only special character is allowed is underscore (_) and hypen (-)... Help me how.
thanks
here's the code i have:
<?php
$serror="";
if (isset($_POST['submit'])) {
$username=$_POST['username'];
$lengt = strlen($username);
if($lengt == 0){
$serror=" Please enter account username ";
}
else{
if($lengt < 3 ){
$serror=" Please enter valid account username ";
}
}
if($serror==""){
ob_start();
echo "Success";
header("Location:progress.php?username=$username");
exit;
ob_end_flush();
}
else{}
}
?>
use preg_match() function
$yourString = "blahblah";
if (preg_match('/^[A-Za-z0-9_-]*$/', $yourString)) {
#your string is good
}
remeber preg_match() returns boolean
Your php script works after the user submits the form. From your tags in the question I assume you can use javascript. With Javascript you catch these errors before the form is submitted.
So, your html input field would fire a script and you can use the onkeypress event to see the value of the keystroke.
The submit button would also have a javascript event to look for min string length, else give warning and not submit form.
As others already pointed out, you should use regular expressions for this.
Try with the following if-statement (allows a-z, numbers, underscores and hyphens). It also checks that the length is at least 3 characters:
if (!preg_match("/^([\w\-]{3,})$/", $username)) {
$error = "Not enough chars or there are invalid ones".
}
Read more about preg_match() here

PHP - Validating a registration form

How do I validate the first name to only contain a-z characters using php. I have the following at the moment:
if (empty($myFirstName)) {
echo "<p>Please enter your first name!</p>";
else if(!preg_match("/^[a-zA-Z]$/", $myFirstName)){
echo "Your first name can only contain letters!";
}
Here's a working code :
if (empty($myFirstName)) {
echo "<p>Please enter your first name!</p>";}
else if(preg_match("/[^a-zA-Z]/", $myFirstName)){
echo "Your first name can only contain letters!";
}
I did a little modification to the regex : I added a ^ in the group, and removed the anchors.
As a result, your regex will match any character which is not a letter, and display the error message if there is a match.
I strongly advice you to validate user input at least on server side, and on client side if you want to.
For an email validation, the html filter works on client side.
On server side, you can use pre-set PHP filters :
if(filter_var($email, FILTER_VALIDATE_EMAIL)){
echo "email OK";
}
FYI, there is a regexp matching emails according to the RFC2822 standards :
[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
May be you can use
if(! ctype_alpha($myFirstName) )
{
//check for alphabetic inputs only
echo "Your first name can only contain letters!";
}
Php manual
Your if is incorrect.
!preg_match("/^[a-zA-Z]$/", $myFirstName)
will only hold true if $myFirstName is not a single alpha character
to ensure that $myFirstName is not any number of alpha characters, try
!preg_match("/^[a-zA-Z]*$/", $myFirstName)

Allow only capital and small letters

I would like to accept only small and capital letters from the user.
I tried the below code, it echoes the invalid character message but doesn't work. I mean it doesn't check. It just displays the message. Any help?
<form action="" method="post">
<input type="text" name="fname">
<input type="submit" value="Send" name="submit">
</form>
Update: this is what I have to check and insert the name to database. if numbers found in the name reject the name by displaying the error message else if the name contains only letters insert it into database. That's all I want to acheive.
<?php
if ( isset( $_POST['submit'] ) ) {
$fname = $_POST["fname"];
if(!preg_match ('/^([a-zA-Z]+)$/', $fname)){
echo "Invalid characters";
}
if (empty($fname)) {
echo '<span> First name is required</span>';
}
else{
$mysqli = new mysqli("localhost", "root", "", "test");
$stmt = $mysqli->prepare("INSERT INTO test (firstname) VALUES (?)");
$stmt->bind_param("s", $fname);
$stmt->execute();
$stmt->close();
$mysqli->close();
}
}
?>
If you just want to check you could use ctype_alpha() but you said you want to ACCEPT only letters so if you choose to accept the input you could:
$fname=preg_replace('/[^a-z]/i','',$fname);
better after the check
if(!isset($_POST['fname']) || !ctype_alpha($_POST['fname'])){
// can i haz alpha letters only?
}
(reference)
There are several issues with the code, and the one you are stuck with is probably that you have the form and its processing in the same PHP file. That’s possible, but it requires a different approach. For a starter, it’s probably better to separate them.
What happens with the code posted is that the PHP processor tries to process the form data when no form has been submitted, without even checking for the presence of the data. Now $fname is undefined, so the test always fails.
The test is wrong, too. Now it only checks whether $fname contains at least one letter. For example, if(!preg_match ('/^[a-zA-Z]+$/', $fname)) would test that $fname consists of one or more Ascii letters and nothing else.
use this , this is giving me correct answer
if(!preg_match ('/^([a-zA-Z]+)$/', $fname)){
echo "Invalid characters";
}
else{
echo "correct";
}
The general idea of checking for characters that don't match the [a-zA-Z] pattern is a good one.
However, the "not" part of your if condition is in the wrong place if you want this to work. What you've got now just makes sure that any single character in fname is an upper- or lower-case Latin letter.
You want to push the "not" part of the logic into the pattern:
if (preg_match('/[^a-zA-Z]/', $fname)) {
This checks if any character in fname is not a Latin letter, which is what you're trying to do.
Edit: Your new update has a different test that also works (it appears to be from sourcecode's updated answer, but you've got several tests from the different answers here that will work equally well). But, your updated post makes it clear that your problem isn't really with the pattern for testing the name.
Your code looks like this:
if (/* invalid fname */) {
echo "Invalid characters";
}
if (/* empty fname */) {
echo '<span> First name is required</span>';
}
else {
/* insert into database */
}
That else clause only depends on the the if that comes immediately before it: the check whether fname is empty. In other words, regardless of the result of your check against the characters of fname, you insert it into the database whenever it's not empty.
One easy way to fix this is to just change your second if to an elseif. This will chain all three conditionals together, so the final else block will only occur if both of the earlier conditionals that print error messages weren't triggered.
if (/* empty fname */) {
echo 'First name is required.';
}
elseif (/* invalid fname */) {
echo 'Invalid characters';
}
else {
/* insert into database */
}

Categories