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).
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 have several ways to write a phone number :
+5511999999999
55999999999
11999999999
999999999
is there any library or logic way to compare phone numbers in PHP?
Interesting question.
In order to compare two strings (as phone number or email for example) you have to be sure to have them written in similar format.
I suggest to perform validation of the entry of your forms when you get the phone numbers from the user. This way will allow you to compare strings that have the same template. for example: Country code: [+XXX] Area Code: [(XXX)] Phone Number: [XXX-XXXX]
The user should write something like +44(887)345-5532 (for UK PHONE).
If you have file or list with some phones that you would like to compare, you have to come up with a criteria for Country code, area code and actual phone number in order to compare them with no mistakes.
When this is done you can split the string and compare each element.
There are many open source methods of doing such validation. Try and use ZEND FRAMEWORK, or CAKE PHP, CODE IGNITER or some similar framework and see how to do it there.
Hope that helps.
An interesting approach to the problem could be considering a percentage of similarity. For this case you could use similar_text. I built a function thtat takes an array of phone numbers and compares them to one number like this:
function similarPhone($search, $phones, $acceptablePercentage)
{
foreach ($phones as $phone) {
similar_text($search, $phone, $percentage);
if ($percentage >= $acceptablePercentage) {
return true;
}
}
return false;
}
So I use an acceptable percentage of 80% to compare.
I have written a function to generate a random string of 7 alphanumeric characters which I am then inserting in a mysql database.
Here is the code :
function getRandomID(){
$tmp ="";
$characters=array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9");
for($i=0;$i<7;$i++)
$tmp.=$characters[rand(0,count($characters)-1)];
return $tmp;
}
I am not checking for duplicates atm because I anticipate there will be no more than 1000 entries in the database and I've calculated that this function can return (35)^7 = 64,339,296,875 possible values.
I am testing it out locally as well as on a live server.
The problem is just in the last hour , this function generated duplicate values twice.
I came upon 3 entries in the database all of which had the same random string.
I do not know what could have caused this as I tried numerous times afterwards and the problem wasn't reproducible.
Does anybody have any idea what could be going on here?
Many thanks in advance
Designing your code with the mindset of "meh, that's not going to happen" is a very risky game, just do it properly once so you don't have to get back to your code multiple times to quick-fix minor things like these.
Do the duplicate check and you'll be solid.
You can create a function like
function stringExists($string)
{
...
return $boolValue;
}
And you can easily create a while loop that generates a new string while an old one has been generated.
$duplicate = true;
while($duplicate)
{
$newString = getRandomId();
$duplicate = !stringExists($string);
}
// Work with the newest string that is not a duplicate.
If you really want to get into it
You can then take a look at the documentation for rand if you want to find out what might be causing your problem. Besides, 3 entries doesn't mean anything if we don't know how many total entries there are. Also sometimes "random" function are not as random as one might think, sometimes random functions in some programming languages are always usable but require some sort of an initiation before they become "truly" random.
The time of the inserts might also be a part of the problem, there are plenty of threads on the internet, like this one on stackoverflow, that have some interesting points that can affect your "random"ness.
Whether it's true or not, not which has been pointed out in the comment, you can be pretty sure to find an answer to your question in related threads and topics.
Short answer: Don't think about it and do a duplicate check, it's easy.
Note that you should, of-course, make your ID be a UNIQUE constraint in the database to begin with.
Random != unique. Collisions happen. Check that the value is unique before you insert into the database, and/or put an integrity contstraint in your DB to enforce uniqueness.
If you're using a very old version of PHP [eg. pre-4.2] you have to seed the random number generator with srand().
Aside from #2, it's probably not your getRandomID() function but something else in your code that's re-using previous values.
If you need to enrer unique data in the DB, you may use PHP function uniqid(). (http://ca3.php.net/uniqid)
The function generates more-less random string based on current microseconds. So in theory it is unique.
But still, its always good to check before insert. Or at least put UNIQUE index on the field.
You could do something like this:
function randomString($length, $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
$string = "";
$charsLength = strlen($chars);
for ($i = 0; $i < intval($length); $i++) {
$string .= $chars[rand(0, $charsLength - 1)];
}
return $string;
}
The function above will generate a random string in the given length from the given characters. This makes it a little bit more flexible, than your implementation, if you need to use it in amother context later.
Then you could do a check like this:
$id = null;
do {
$id = randomString(7);
} while (!isUnique($id));
// do your insert here. You need to write your isUnique, so that it checks if
// the given string is unique or not.
I need to restrict phone numbers with patterns like:
0123456789,
1111111111,
2222222222,
3333333333,
4444444444,
etc.
I am trying to do it in PHP.
So far i came up with creating an array and searching in it to restrict that mobile no.
Is there any better way to do the same?
Maybe a regex or maybe in javascript.
If you don't want to keep updating a long array of numbers to check against like you mention yourself you basically want to do pattern detection / pattern recognition.
This can be everything from trivial to very complicated depending on your previous knowledge.
A small start can be found here... But there are tons of very thick books on the subject ;)
http://en.wikipedia.org/wiki/Pattern_recognition
So the "easiest" way is probably to use an array look up. The downside is that you must know every single number you wish to blacklist beforehand. A middle way would be to have an array of regexps of invalid formats that you check against instead of having the actual numbers in the array.
So you could have regexps covering things like
Numbers to short
Numbers to long
Numbers with only the same digits
etc
Depending on available systems and geographical location it might actually be possible to do some kind of look up against some known database of numbers. But that could lead to false positives for unlisted numbers.
For a global, dynamic, working system keeping a look up array and doing look ups against databases could both prove to become very hard to handle since the number of known data sources to keep working support for might grow to large to handle.
If you need to block specific phone numbers, you could do this:
$numberToTest = [...]; // this is your user input number to test
$notAllowed = array(
'0123456789',
'1111111111',
'2222222222',
// and so on
);
if(in_array($numberToTest, $notAllowed)) {
// NOT VALID
}
else {
// VALID
}
to match all numbers like 1111111111, 2222222222, etc you could do this:
if(preg_match('/^(\d)\1{9}$/', $numberToTest)) {
// NOT VALID
}
else {
// VALID
}
Javascript with regexp. isRestricted is set to true when the number is in restricted list:
var number = "0123456789";
var isRestricted = number.match( /0123456789|1111111111|2222222222|3333333333|4444444444/g ) != null;
I'm sure regexps works with PHP pretty much the same way using preg_match.
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)