Recipe Calculator - php

I am creating a website that stores recipes. I am wanting to make a recipe scaler-where you can enter the desired servings, and the script will convert the recipe ingredients to match it. I can change the amount easy enough, but I'm trying to figure out how to convert units. Now I know I can go and put in 1500 if/then statements, but I'm trying to make it a bit simpler. :)
I was looking at a site called Tasty Kitchen. They POST the servings via AJAX to this file (http://tastykitchen.com/recipes/wp-admin/admin-ajax.php), and that file returns the ingredients. Then they display them on the page. Go to http://tastykitchen.com/recipes/breads/plain-bagels/ for an example.
I would REALLY appreciate any help I can get.
Thanks!

My suggestion would be to store a single serve in your database, then simply multiply out how many people you want to feed on the page.
So, if your user has selected they want to make the meal for 4 people, you keep a variable (session, cookie, whatever) - lets call it $peeps for this example - when you output the data you do soemthing like this:
Echo "This will make $peeps portions:";
Echo "Ingredients:<br>";
Echo ($peeps*Ingredient1Quantity)." - ".$ingredient1Name."<br>";
Echo ($peeps*Ingredient2Quantity)." - ".$ingredient2Name."<br>";
and so on.
If you want your site to also convert from imperial to metric, you can do it easily enough with a simple function.
If you store all your data in metric in the database (or Imperial, but all the same type) you can output it easily enough by converting it in a similar manner to the user based on their preference:
// Assumes a function that converts to Imperial from Metric called convertToImperial()
Echo "This will make $peeps portions:";v
Echo "Ingredients:<br>";
Echo convertToImperial($peeps*Ingredient1Quantity)." - ".$ingredient1Name."<br>";
Echo convertToImperial($peeps*Ingredient2Quantity)." - ".$ingredient2Name."<br>";
Edit: If you store everything in the database in Metric, you can then have a function return the data to you in the best Imperial measurement.
// For example, input is passed as
// $qty=30 (ml)
// $serves is passed as 3 (ie, three people)
// $type is passed as liquid.
function convertToImperial($qty, $serves, $type)
{
// Metric to Imperial will need a $type passed (Liquid, Weight, Other).
// You can use a switch statement to pass between the different types.
switch ($type)
{
case "Liquid":
// Assumes 5ml is a teaspoon
// Assumes 15ml is a tablespoon
// Assumes 250ml is a cup.
$CalMeasure=$qty*$serves; // Now at 90ml.
// Here you can now choose to either pick the best match
// ie, measurement with least remainder/exact measure
// which in this case would be 6 tablespoons
// or
// switch measurement types after a certain quantity is reached.
if ($CalMeasure>125) // Half a cup
{
return (round($CalMeasure/250,2)." cups");
}
elseif ($CalMeasure>15) // tablespoons
{
return (round($CalMeasure/15,2)." Tablespoons");
}
else
{
return (round($CalMeasure/5,2)." Teaspoons");
}
break;
case "Weight":
// Similar approach to Weights, Convert Grams to Pounds and the like.
return $WeightMeasured;
break;
default: // assumes Other (pinches, sprinkles etc
// Similar approach again.
break;
}

#Caleb - Fluffeh is right on here with his strategy in regards to storing everything in one type of measurement and then having a series of functions to convert them to others. I built a web application https://Gredio.com that does recipe scaling among other things and was able to produce very flexible reports in this way. One additional difficulty is around liquid measures versus weight. Large scale food production is always done by weight, but the small guys sometimes misunderstand the difference. Doing liquid to weight conversions programmatically can be complex as you need to know the liquids weight which will vary greatly (think honey versus water...)

Related

Does a string contain any of a list of substrings in PHP?

I am adding a feature to an application that allows authorised oil rig personnel to submit weather reports (for use by our pilots when planning flights) to our system via email. The tricky part is that we want to match these reports to a particular oil platform, but the personnel (and their email accounts) can move between rigs.
We already have a list of waypoints that each have an "aliases" field. Basically if the email subject contains something in the aliases field, we should match the email to that waypoint.
The subject could be "Weather report 10 April # 1100 Rig A for you as requested"
The aliases for that waypoint would be something like
"RRA RPA Rig A RigA"
Keep in mind there is a similar list of aliases for all the other waypoints we have.
Is there a better way of matching than iterating through each word of each alias and checking if it's a substring of the email subject? Because that sounds like a n^2 sort of problem.
The alternative is for us to put a restriction and tell the operators they have to put the rig name at the start or end of the subject.
This sounds more like an algorithms question than a PHP question specifically. Take a look at What is the fastest substring search algorithm?
Well you can transform this into something like an O(n log n) algorithm, but it depends on the implementation specifics of stripos():
define('RIG_ID_1', 123);
define('RIG_ID_2', 456);
function get_rig_id($email_subject) {
$alias_map = [
'RRA' => RIG_ID_1,
'RPA' => RIG_ID_1,
'Rig A' => RIG_ID_1,
'RigA' => RIG_ID_1,
// ...
];
foreach(array_keys($alias_map) as $rig_substr) {
if(stripos($email_subject, $rig_substr) !== false) {
return $alias_map[$rig_substr];
}
}
return null;
}
Here each substring is examined by stripos() exactly once. Probably a better solution is to compose these strings into a series of regexes. Internally, the regex engine is able to scan text very efficiently, typically scanning each character only one time:
ex.:
<?php
define('RIG_ID_1', 123);
define('RIG_ID_2', 456);
function get_rig_id($email_subject) {
$alias_map = [
'/RRA|RPA|Rig\\sA|RigA/i' => RIG_ID_1,
'/RRB|RPB|Rig\\sB|RigB/i' => RIG_ID_2,
// ...
];
foreach(array_keys($alias_map) as $rig_regex) {
if(preg_match($rig_regex, $email_subject)) {
return $alias_map[$rig_regex];
}
}
return null;
}
For your purposes the practical solution is very much dependent upon how many rigs you've got an how many substrings per rig. I suspect that unless you're dealing with tens of thousands of rigs or unless performance is a critical aspect of this application, a naive O(n^2) solution would probably suffice. (Remember that premature optimization is the root of all evil!) A simple benchmark would bear this out.
An even-better solution -- and potentially faster -- would be to set up an elasticsearch instance, but once again that may be too much effort to go to when a naive approach would suffice in a fraction of the implementation time.

PHP pagination with Couchbase gets very slow at high page numbers

I've build a PHP based webapp with pagination. I've made both a Couchbase and a Postgres version. I had to abandon N1QL because it had terrible performance (maybe I'll make another question for that). So I migrated the project from N1QL to views. I noticed that, while at low page number (e.g. 1, 10, 50 with 48 records per page) performance was better than postgres (0.07s vs 0.11s), but at a high page number (e.g. 4000 -> 1.5 seconds and 16000 -> 5 seconds) performance is very bad. I use skip + limit for pagination with native CB library.
Any ideas?
PHP:
public static function findByPage($recordsPerPage, $page) {
$query = CouchbaseViewQuery::from("dev_".static::COLLECTION_NAME, "get_".static::COLLECTION_NAME."")->reduce(false)->skip($recordsPerPage*($page-1))->limit($recordsPerPage)->custom(array("full_set"=> "true"));
$data = DB::getDB()->query($query, null, true);
// var_dump($data);
$objects = array();
foreach($data["rows"] as $row) {
$objects[] = static::find($row["key"]);
}
return $objects;
}
One of the views (they are pretty much all the same):
function (doc, meta) {
if(doc.collection == "green_area") {
emit(doc._id, null);
}
}
This is a known limitation with views. The issue is that there is no way to know how far through the view index record 4000 is. When you request records 4000-4004, the view-engine doesn't have to generate just 5 records, it has to generate 4000 that it immediately discards and then hands you the next 5. Due to the nature of views and having to scatter-gather from multiple nodes to produce a single result this can be extremely expensive as you have observed. For this reason it is discouraged to use the 'skip' option
Instead it is recommended that you use the 'range' option. The way this works is to initially specify the range as open (ie. such that it would include all records), an example of this would be from \u00 to \u0fff (The full range of unicode characters) and to return e.g. 10 records. You would then remember what the 10th record was and specify that as the start of your range for the next page). For instance if your 10th record was 'beer' then you would specify the range from 'beer' to \u0fff. Now this would include beer as the 1st result, there are two ways to resolve this. The first is to request 11 results and ignore the first. The second way to resolve this would be to specify the range as 'beer\u00' to \u0fff which starts at the first possible record after 'beer'.
This Couchbase blog post goes into more details: http://blog.couchbase.com/pagination-couchbase
It's worth noting that N1QL will generally have the same problem of not being able to guess where the nth record will be in the index and will not necessarily be the answer to your problem.

how to compare 2 phone numbers PHP

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.

Restrict Phone numbers with pattern like 0123456789, 8888888888, 9999999999, etc

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.

Divide amount by characters present in string, found via regex

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).

Categories