Comparing string - woes in PHP - php

I want to allow the user to enter a coupon number in order to get a discount. After the coupon number is entered and submitted, the page reloads withe a tick showing that they have entered a correct amount.
The way I'm trying to do this is displaying the tick if the coupon amount is not £0.00. But the string comparison doesn't seem to work, since it always thinks that it is not £0.00. The code is as follows. The function coupon_amount() returns the coupon amount. coupon_amount() returns "£0.00" (including the pound sign)
<?php $coup_amount = coupon_amount(); ?>
<?php $zero_amount = "£0.00"; ?>
<?php if(strcmp($coup_amount, $zero_amount)== 0) { ?>
<?php echo 'Enter coupon code if applicable:' ?>
<input type='text' class='couponinput' name='coupon_num' id='coupon_num' value='coupons_name' />
<input type='submit' class='update-button' value='submitcoupon' />
<?php } else { ?>
<?php echo 'Thanks.' ?><input type='text' disabled='disabled' class='couponinput' name='coupon_num' id='coupon_num' value='coupons_name' />
<div class='tick'></div>
<?php } ?>
Am I doing something wrong with the comparison?
I followed Oscar's suggestion below, and here is the output. Seems to be an encoding problem. And the pound sign is not appearing properly for the zero_amount.
coup_amount: (£0.00) zero_amount: (�0.00)
coup_len:10 zero_len:5
strcmp: -1
coup_ascii: 38 zero_ascii:163

You should really be storing/working with the discount values as numbers, this would make the comparison much easier.

Have you tried printing out all the values?
<?php $coup_amount = coupon_amount(); ?>
<?php $zero_amount = "£0.00"; ?>
//print'em out
<pre>
<?php
echo "coup_amount: ($coup_amount) zero_amount: ($zero_amount) \n";
echo "coup_len:".strlen($coup_amount)." zero_len:".strlen($zero_amount)."\n";
echo "strcmp: ".strcmp($coup_amount, $zero_amount)."\n";
echo "coup_ascii: ".ord($coup_amount[0])." zero_ascii:".ord($zero_amount[0]);
?>
</pre>
Amendment
So yes, now that we can see the output from this, it seems like the coup-string is an UTF16 (10 bytes long) and the other is something else (5 bytes long).
(Preaching follows.) When dealing with money you should really take extra care to make sure numbers are handled correctly. We've just seen that strings are subject to encoding, and like others have pointed out, floats are subject to fractional errors. Your best bet is probably to try and express it in 1/100s using an integer, and to express the currency in a separate variable. (Preaching over.)
But I'm guessing the coupon_amount-function is used everywhere and you can't change it. Then you might wanna look into converting the two strings so that the are in the same format. Take a look at iconv.

<?php if(strcmp($coup_amount, $zero_amount)== 0) { ?>
Seems very unreadable compared to:
<?php if(coupon_amount() == 0) { ?>
If coupon_amount() returned the actual value, not the formatted string representation.
Are you able to change the coupon_amount() function to get rid of the pound symbol? the php function money_format is good for adding whatever the users currency symbol is to a string for displaying on the page (or which ever symbol you set the locale to)
In the future you will find yourself having to remove the pound symbol first before you do any arithmetic on the return value from coupon_amount()

There are a lot of things that seem insignificant to user, but may break string comparison
coupon_amount() may insert some spaces somewhere in returned value
coupon_amount() may return variable number of zeros
coupon_amount() may use comma instead of dot (depending on locale)
coupon_amount() may encode pound sign using some HTML entity
Said that, it is much better to compare numeric values, and then format number as currency.

the strcmp call seems ok, my bet is on the coupon_amount function.

The absurd lengths I had to go to to get this working :) .. I changed the first if statment to:
if((ord($coup_amount[0])==38) && (ord($coup_amount[1])==35)
&& (ord($coup_amount[2])==49) && (ord($coup_amount[3])==54)
&& (ord($coup_amount[4])==51) && (ord($coup_amount[5])==59)
&& (ord($coup_amount[6])==48) && (ord($coup_amount[7])==46)
&& (ord($coup_amount[8])==48) && (ord($coup_amount[9])==48)
&& (ord($coup_amount[10])==0))

have you triend comparing it without a pound sign?..
like this
substr($coup_amount, 1) == "0.00";
i see you're having problem when retrieving the pound sign so i think it is best to try this.

Related

How to count integer values stored in a variable using php?

I am developing a web form which have a field 'marks' where user can put marks... I want to force the user to input only marks less then 4 digits. Here is function for this purpose but it is not working...
Function validate($marks)
If(strlen($marks)<=4 && !filter_var($marks, FILTER_VALIDATE_INT)
)
Return false;
Else
Return true ;
This can be achieved using only HTML5 input options (PHP is unnecessary for this application).
If your input is type="number" you can use min=-9999 max=9999 to limit the number to 4 digits.
If your input is type="text" you can use maxlength=4 to limit to 4 characters.
Here is a list of input types and options that might help: https://www.w3schools.com/tags/tag_input.asp
Use the maxlength attribute of the input tag.
e.g.
<input type='text' maxlength='4' name='marks' />
Depending on how you want to implement this, you can use javascript too, which will allow you to display some dynamic warning info when it is less than 4 digits.
If you want to do it with php you can do it like this if the data type is an integer or a float:
if ($marks <= 9999.99) {
//do something
}
If it is a string representation of numbers, you can do it like this:
if (strlen($marks) <= 4) {
// do something
}

Incorrect calculation using decimals in php

I have some arrays, holding the numbers for a multiplication quiz. Here are some examples:
if($level==8){
$first=array(13,14,16,17,18,19);
$second=array(9,10,11,12,13,14,15,16,17,18,19);}
if($level==9){
$first=array(23,19,46,87,98,39);
$second=array(19,10,111,112,139,178,145,166,167,185,192);}
if($level>9){
$first=array(2.3,1.9,4.6,8.7,9.8,3.9);
$second=array(1.9,10,11.1,11.2,13.9,17.8,14.5,16.6,16.7,18.5,19.2);}
These numbers are used to calculate some answers that are placed on a button and the user has to click on the correct answer.
// the correct answer
$b=rand(0,5);
$c=rand(0,10);
$f=$first[$b];
$s=$second[$c];
$d=$f*$s;
// wrong answer no. 1
$w1a=rand(0,5);
$w1b=rand(0,10);
$w1c=$first[$w1a];
$w1d=$second[$w1b];
$w1e=$w1c*$w1d;
if ($w1e==$d){
wronganswer1();
}
// wrong answer no. 2
$w2a=rand(0,5);
$w2b=rand(0,10);
$w2c=$first[$w2a];
$w2d=$second[$w2b];
$w2e=$w2c*$w2d;
if ($w2e==$d){
wronganswer2();
}
There is a check on the receiving page of the POSTing to see if the user has indeed got the correct answer:
$b=$_POST["b"];
$c=$_POST["c"];
$subby=$_POST["sub"];
$d=$c * $b;
$score=$_SESSION["score"];
?>
</head>
<body>
<?php
if ($subby==$d){
echo "<script>correct.play()</script>";}
else{
echo "<script>wrong.play()</script>";
}
?>
<?php
if ($subby==$d) {
echo "Well done!";
$_SESSION["score"]=$_SESSION["score"]+1;
echo "<h3>The button you pressed said: ".$subby;
echo "</h3><br><h2>";
echo $b."x".$c."=".$subby;
echo "</h2><br>";
echo "<h3>Your streak is worth ".$_SESSION["score"];
}
else {
echo "<h1>No!<br>";
$_SESSION["score"]=0;
echo $b."x".$c."=".$d;
echo "<br>";
echo "Your streak has been reset to 0!</h1>";
}
Now, when I have whole numbers: no problem. But the decimals are causing a problem. My code is telling the player that a correct calculation is wrong!
I've spent some time echoing out simple decimal multiplications and the output is correct (so no truncating of decimals or anything like that)...
Why the inaccuracy?
I'm guessing that you are comparing floating point numbers in the same way as integers.
It can't possibly work because of the nature of floating point numbers.
You can't check equality of floating point values, but you can ask if their absolute difference is within a tolerance that you specify. Here's pseudo code to show what I mean:
float x = 1.1;
float y = 1.2;
float tolerance = 1.0e-3;
if (abs(x-y) <= tolerance) { // abs() is an absolute value function
print "within tolerance"
} else {
print "not within tolerance"
}
In the end I managed to get the desired result by casting my 'comparator' to a string (see top line of code):
if ($subby==(string)$d) {
echo "Well done!";
$_SESSION["score"]=$_SESSION["score"]+1;
echo "<h3>The button you pressed said: ".$subby;
echo "</h3><br><h2>";
echo $b."x".$c."=".$subby;
echo "</h2><br>";
echo "<h3>Your streak is worth ".$_SESSION["score"];
Thanks for the help of all who led me to the conclusion/knowledge that 'you can't compare floating values'.

PHP unserialize : everything works fine except one entry

I'm trying to unserialize some data stored in mysql.
Everything is okay except ONE field that can't be displayed.
The data :
a:4:{
s:7:"prénom";s:6:"Johnny";
s:3:"nom";s:5:"Rocky";
s:12:"NOT WORKING";s:2:"on";
s:7:"opt in2";s:2:"on";
}
that I'm calling with
<?php $mydata = $result['data'];
$mydata = unserialize($mydata);
echo $mydata['prénom'];
echo $mydata['nom'];
echo $mydata['NOT WORKING'];
echo $mydata['opt in2'];
?>
"prénom", "nom" and "opt in2" are correctly displayed, but "NOT WORKING" isn't (nothing is displayed).
What is interesting in the latter is that the number before the string do not match the number of letters, you can see it's written 12 while the string has 11 letters (space included). I tried to change it to 11 but it screws everything.
What is even more fun is that all the values (including "NOT WORKING" can still be properly displayed with something like :
<?php foreach($result['data'] as $fieldName => $fieldValue){?>
<?php echo esc_html(strip_tags(wp_kses_stripslashes(ucwords($fieldName)))); ?>
<?php echo esc_html(strip_tags(wp_kses_stripslashes(ucwords($fieldValue)))); ?>
Can someone explain me what is happening ? I can't see any logic in here.
Thanks a lot !

php validation concept

First of all, I don't want to use any framework but I am looking for a good way to use whitelist validation. I am going to apply it on all the user input I receive, I need validation for XSS protection and I also want to apply different formats for example:
Example 1 XSS.
<input type="text" name="test" value="<script>alert('test');</script" />
Example 2 Date.
<input type="text" name="test" value="31-05-2012" />
Example 3 Time.
<input type="text" name="test" value="15:00" />
Example 4 Max length.
<input type="text" name="test" value="short description" />
Example 5 Min length.
<input type="text" name="test" value="min description" />
Example 6 Alphabetic and default symbols only
<input type="text" name="test" value="hello world. This is à ö text input :P :) :S :$ =D !! ??" />
Example 7 Numeric only
<input type="text" name="test" value="1234567890" />
My idea is to build a clientside and server site validation, if the user gets passed through the clientside validation (jQuery) they will get marked as hacker, since it is impossible for default users to pass through the clientside validation.
My question is: What would be the best way to apply client+serverside validation to prevent XSS and apply regular expressions on fields. Are there any lightweight PHP libraries for validation?
I have looked at:
ctype_alpha
preg_match
But I am not quit sure what would be the best one to use, and ctype_alpha is not allowing default symbols etc.
Any advises? Examples? Thanks for your time and reading, and sorry for the hectic question.
It seems you just need some basic validation, not "whitelist" one.
the idea is quite simple.
Create a server-side validation. with ctype_alpha, preg_match and such. (I hope that your question is not about teaching you these functions from scratch).
Create cleint-side validation if you want, by making AJAX calls to the very same validation routines you've used for the (1).
Of course, you have to use both anyway.
Marking users as a hackers seems not the best idea. What you gonna do with marked users?
I've had a similar problem and ended up writing my own "Input-Datatype" classes. This might be a bit excessive if you only use them for validating input though. But you could build validation functions that use a mix of PHP functions such as preg_match, is_numeric, strtotime etc...
An example for date validation would be:
public function validate(&$value) {
$date = strtotime($value);
if($date === false){
//Error no valid date
}else{
if(isset($this->maxDate)){
if($date>strtotime($this->maxDate)){ //maxDate being the maximal date allowed
//Error max date exceeded
}
}
if(isset($this->minDate)){
if($date<strtotime($this->minDate)){ //minDate being the minimal date allowed
//Error date too low
}
}
$value = strftime($this->format,$date); //format being the format in which the date should be saved
}
Another example for validating text could be:
public function validate(&$value) {
if (isset($value) && $value != "") {
if(isset($this->maxLength)&&$this->maxLength!= ""){ //maxLength being the maximal number of characters
if (strlen($value) > $this->maxLength) {
//Error max length exceeded
}
}
} else {
if (!$this->allowNull) { //allowNull being a boolean: true if text can be empty
//Error value is empty
}
}
if(isset($this->regex)&&$this->regex!= ""){ //regex can be any regular expression, e.g: /[A-Za-z]/ for letters only
if(!preg_match($this->regex, $value)){
//Error value does not match expression
}
}
}
As far as XSS goes, make sure you use prepared statements when interacting with a database and use htmlentities when displaying user inputted data.
Hope this helps.
Some time ago, i've written a lightweight-validation class. Maybe you can use it.
For example:
$oValidator = new Validator();
$oValidator->setLanguage('en');
$oValidator->isValid('short description', 'max_length[4]');
echo $oValidator->getLastErrorMessage();
//The input can not exceed 4 characters in length.
$oValidator->isValid('min description', 'min_length[5]');
$oValidator->isValid('hello world. This is à ö text input :P :) :S :$ =D !! ??', 'min_length[5]');
$oValidator->isValid('1234567890', 'digits');
Rule definition:
/**
* #ErrorMessage[lang=de] Die Eingabe muss mindestens %d Zeichen lang sein.
* #ErrorMessage[lang=en] The input must be at least %d characters in length.
*/
public function check_min_length($mValue, $aParams)
{
return (strlen($mValue) >= $aParams[0]);
}
Example:
http://sklueh.de/2013/01/lightweight-php-validator-neue-version/
github:
https://github.com/sklueh/Lightweight-PHP-Validator

strtolower($a)==strtolower($b)!=match?

OK, i have a function that compares values and returns the results, regardless of case, ie: Interfacility Transfer = INTERFACILITY TRANSFER here is the function:
function fncResult ($expVal, $actVal)
{
$negNulls=array("-5","-10","-15","-20","-25");
if (!in_array($expVal, $negNulls))
{
if(strtolower($expVal)==strtolower($actVal))
{
echo "
<td class='match' title='The values match.'>Match</td>
</tr>";
}
else
{
echo "
<td class='notMatch' title='The values do not match.'>Not Match<br />No Match</td>
</tr>";
}
}
else
{
echo "
<td class='null' title='The value in the XML was a negative null.'>Negative Null</td>
</tr>";
}
}
It works about 99% of the time except when it comes to this:
//--Type of service requested
echo "
<tr>
<td>E02_04</td>
<td>Type of Service Requested</td>
<td>36. <Nature of Call></td>
<td>$fldServReq</td>
<td>".fncGrabNemsis("E02_04",$fldServReq,$local)."</td>
<td>".fncIsSet($CZ_E02_04[1])."</td>";
fncResult(fncGrabNemsis("E02_04",$fldServReq,$local),fncIsSet($CZ_E02_04[1]));
Although it looks more complicated, it really is just a strtolower($expVal)==strtolower($actVal), comparison. When I echo the values being compared, I get: "interfacility transfer" and "interfacility transfer" and "No Match"... WTF? Could it be because the first value is coming from a XML (UTF-8) and the second is from a DB (?) I have no idea what to do and am incredibly frustrated since this a simple task. Thanks for any help!
Is there any trailing whitespace on your strings? Perhaps nesting a trim() along with a strtolower() would clear that up? If you're looking at this in HTML output, take a look at the source and make sure there's not an HTML entity in there messing it up (i.e. "interfacility transfer" and "interfacility transfer" are not the same, but may look the same rendered in HTML).
The final option is to "upgrade" to the mb_strtolower and see if it is an encoding issue.
Print out the bytes of expval and actval (with urlencode, for example). There are a lot of different characters that look exactly the same (for example, normal space and non-breaking space, or c, es and roman 100).

Categories