So I have a form with 2 text inputs.
One is price and the other is quantity.
Before saving the form there are some checks that act as safeguard against tampered user input and SQL injection.
so one of them is:
if(strval(floatval($quantity)) === $quantity && strval(floatval($price)) === price) {
$errors = false;
}
The problem with this check is that if we have $price = "47.80" for example
floatval() gives us 47.8 and then strval() gives us "47.8" which does not equal to "47.80"
So the check fails and we get an error.
I would like to know if you can think of a way to go around this without changing the logic too much.
You can use the filter extension:
$price = filter_var($price, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
It removes everything that is not a digit or a period.
If the number has to have two decimal points then you have to somehow enforce that. You can either not allow numbers without two decimal points or you can fix the input yourself. Something like this should do:
$price= number_format($price, 2, '.', null);
Related
My api requires all data related to subscription costs be in the correct format before being committed to the DB as customers will be charged the amount. The following rules apply.
Must be numeric with no currency symbols. Validating using is_string($data['cost'])
Cannot be a negative amount. Validating using $data['cost'] < 0
Must have two decimal places, even when the amount has no cents ($100.00).
What would be the best way to go about validating requirement #3?
Decided to go with something pretty straight forward. If a decimal is present in the cost, check how many places to the right. Otherwise commit to DB.
$amount = explode('.', $data['cost']);
if(isset($amount[1]) && strlen($amount[1]) > 2) {
// response
}
Use number_format(). The advantage is that no matter what you get (not enough 0s or too many 0s) it will save it in the correct format
number_format("1000000",2) // 1,000,000.00
Edit: To use this for validation,
$num = $data['cost'];
$check = number_format($num,2);
if ($num == $check) return true;
I'm trying to implement a simple captcha into a form I'm building but I've run up against an issue I can't seem to sort out by myself.
I'm using simple code to generate a random number like so ....
$randomnr = rand(1000, 9999);
$_SESSION['randomnr2'] = md5($randomnr);
.... and then some more code to generate an image of the random number and display it on the page. I'm against it for validity like this ....
if (strlen($captcha) !== ($_SESSION['randomnr2'])) {
$error['captcha'] = "CAPTCHA error. Please try again";
}
How do I go about checking the value that's been input into the captcha input field against the random number that's stored in the session randomnr2?
I'm not sure why you are checking the length of the string against an md5 hash of the string here, but assuming $captcha is the number from the user, you can just do this:
if(md5($captcha) !== $_SESSION['randomnr2']) {
$error['captcha'] = "CAPTCHA error. Please try again";
}
PHP will auto-convert anything to a string (if it can) for strlen(), so
echo strlen(42);
echo strlen('42');
will both output '2', even though the first one's an integer. To compare the submitted value to the store value, it's as simple as
if ($_SESSION['randomnr2'] === (int)$captcha) {
... it matched ...
}
You'll want to cast the submitted value to an int again, as anything in the PHP $_GET/POST arrays is internally treated as a string.
<div id='captcha_to_show' style='border:1px solid silver;'>gobldeygook</div>
<input name='captcha' id='captcha'>
...
attached via scriptmonkey...
$('document').ready(function(){
$('#captcha').val($('#captcha_to_show').html());
});
look into a open-source captcha script. your implementation is going to require sending that captcha across the page in a way that it's value can be seen by whatever is pulling the page, and that person/bot/whatever can fill in the validating field accordingly, so you actually have zero protection. that is why captchas either use convoluted images that are hard to impossible to read with a script, or semantic questions better understood by humans in context than bots, such as ['What would you say the sum of one and 3 are?' === 4]. and yes, the more simple image captcha's with the set fonts, spacing and size can be hacked with a sort of pixel-pattern dictionary attack.
I recently was told there is FILTER_VALIDATE_INT which is great by the way.
My question is in terms of taking an integer value from the website whether it maybe from user or generated from the web application, and passed via query string.
The value (integer) may be displayed or used in mysql query.
I am trying to structure the best possible security method for this.
With that in mind, is it safe to simply use
$myNum = (int)$_GET['num'];
Or
if (filter_var($_GET['num'], FILTER_VALIDATE_INT)) $myNum = $_GET['num'];
Also, please explain what is the difference between using (int) and FILTER_VALIDATE_INT
The difference is that a cast to int will always get you an int, which may or may not be the original value. E.g. (int)'foobar' results in the int 0. This makes it safe for most SQL purposes, but has nothing to do with the original value, and you won't even know it.
filter_var with FILTER_VALIDATE_INT tells you whether the value is an int, based on which you can make the decision to use it in an SQL query or display an error message to the user.
<input type="text" name="param"></input>
$price = filter_input(INPUT_POST, 'param', FILTER_VALIDATE_INT);
if ($price !== false) {
print " a number."; //works when value is number
}
if(is_int($_POST['param'])){
print "is number."; //don't works when value is number
}
Please try test with when value is number .
I put a check in a script that makes sure a total is correct. What it does is looks at the total as it is stored in the database and then using other variables, calculates what the total should be.
If these two values - the stored total and the calculated total - are not equal, it's a problem so I want it to send an email alert.
Here's the snippet of the code I use to do this:
$storedTotal = $row['total']; # Pulls from a varchar field in the database
$calculatedTotal = $subtotal + $tax + $shipping - $deduct;
# Make sure the stored total equals what it should (the calculated total)
if($storedTotal != $calculatedTotal) {
# Send an alert
mail("admin#domain.com","Total check fail","Stored total:$storedTotal \n\n Calculated total:$calculatedTotal \n\n");
}
It seems very simple, however, I repeatedly get emails from it that looks like this:
Stored total:23.40
Calculated total:23.40
As you can see, the two values appear the same.
Can anyone see any reason why they're not showing as equal? I'm not using a strict equality check so it shouldn't be getting tripped up on types.
It's most likely a floating point comparison error - there are probably some very insignificant digits which the default float -> string conversion routines think aren't worth printing but which are significant enough to cause the comparison to fail. You'll find dozens of similar questions on StackOverflow.
As these appear to be currency amounts, just check that they're within a tenth of a minor unit of each other:
$is_equal = (abs($val1 - $val) < 0.001);
Try converting and rounding before you compare them:
$storedTotal = round(floatval($storedTotal), 2);
$calculatedTotal = round(floatval($calculatedTotal), 2);
if ($storedTotal != calculatedTotal) {
...
I had the same problem - my simple data-consistency sanity checks were failing as a result. I used Alnitak's solution to implement this simple function:
function not_equals($val1, $val2)
{
return (abs($val1 - $val2) > 0.001);
}
Now my tests pass but I'm very unhappy. A programming language where 6.60 does not equal 6.60??? What else will PHP do to me? I want to go back to C++!
There must be something else that you are missing and we aren't seeing. Probably something related to the size of floats.
Because.
$test = "24.50";
$test2 = 24.50;
var_dump($test == $test2); // bool(true)
Suggestions for an updated title are welcome, as I'm having trouble easily quantifying what I'm trying to do.
This is a web-based form with PHP doing the calculations, though this question probably has an algorithmic or language agnostic answer.
Essentially, there is an Amount field and a Charge Code field.
The Charge code entered represents a short-hand for several 'agents' to whom the Amount is divided by. Most cases are single letters, however there are a couple cases where this varies, and gives a bit of trouble.
Basically, A = AgentType1, J = AgentType2, L = AgentType3, and as paperwork and user requirements would have it, "A2" is also a valid replacement for "J".
So an amount of 50 and a Charge Code of "AJ" would result in the Amount being divided by 2 (two agents) and dispersed accordingly. The same for a string like "AA2".
I have currently set up process (that works) that goes like this:
Divide = 0;
RegEx check for AgentType1 in Charge Code:
Divide++;
Set This-AgentType-Gets-Return;
RegEx check for AgentType2 in Charge Code:
Devide++;
Set This-AgentType-Gets-Return;
... etc ...
Then I divide the Amount by the "Divide" amount, and the result gets divvied up to each AgentType present in the Charge Code.
I know there must be an easier/simpler way to implement this, but it's not coming to me at the moment.
Is there a way to quickly derive the number of AgentTypes involved in the Charge Code, and which they are?
I would probably just do something simple like this:
$valid_codes = array('A', 'J', 'L');
// deal with the special A2 case first, to get it out of the string
// this code could be generalized if more special cases need to be handled
if (stripos($charge_code, 'A2') !== FALSE)
{
$found['J'] = true;
str_ireplace('A2', '', $charge_code);
}
foreach ($valid_codes as $code)
{
if (stripos($charge_code, $code) !== FALSE) // if the code was in the string
{
$found[$code] = true;
}
}
Now you can get the number you need to divide amount by with count($found), and the codes you need to divide between with array_keys($found).
Can you change the charge code field to an array of fields? Something like:
<input type="hidden" name="agent[]" value="A" />
for all your agents would let you do:
$divide = count($_POST["agent"]);
foreach($_POST["agent"] as $agent) {
$sum = $_POST["amount"] / $divide;
//do other stuff
}
Couldn't you match the string by something like this regex
^([A-Z]\d*)*$
and then work through the generated match list? The divisor would just be the length of this list (perhaps after removing duplicates).
For mapping symbols to Agents (why AgentTypes?), you could use a simple associative list, or a hashmap (I don't know what kind of constructs are easiest available in PHP).