Finding nearest value in array from user-input - php

I have a CSV of GDP figures, both nominal and PPP. The structure is Country,Nominal,PPP.
Example:
Islamic Republic of Afghanistan,560.673,998.466
Albania,"3,616.10","7,381.00"
Algeria,"4,477.80","7,103.61"
Users enter in a nominal GDP value. What I'm trying to figure out is how to use that value to find the nearest nominal GDP value in an array constructed from the CSV file. Once I find the nominal value, I'm wanting to print the country and the PPP value.
I haven't scripted anything in quite some time, so I can't get my head around how to go about doing this.

// $input_gdp is entered by user
// $my_data is an array from the csv
$closest = -1;
$closest_diff = false;
foreach($my_data as $key=>$row) {
// $row[0] - Country
// $row[1] - Nominal
// $row[2] - PPP
if($closest_diff === false) {
$closest = $key;
$closest_diff = abs($row[1] - $input_gdp);
} else {
$current_diff = abs($row[1] - $input_gdp);
if($current_diff < $closest_diff) {
$closest = $key;
$closest_diff = $current_diff;
}
}
}
if($closest > -1) {
echo 'The closest is ' . $my_data[$closest][0] . ' with a PPP of ' . $my_data[$closest][2] . '.';
} else {
echo 'None were found.';
}

Related

Universal Mobile number validation pattern in PHP

Here is My working Code, if you got a better one post below.
Took me hours to build.
Number can be between (4-15) Universal Standard.
Might contain '+' at the beginning and '-' is allowed once with allowed format like ('1+123,12+123,+1-123,+12-123).
Rest all spaces and '-' and '+' will be replaced by blank and a proper Number will be returned.
public function validateMobileNumber($mobile){
$mobile = str_replace(' ','',$mobile);//remove all the blank spaces i.e +1-123456342234
//now let's do it for mobile numbers
if(preg_match('/^([0-9,\\-,+,]){4,15}$/', $mobile)){//pratially valid number
$mobile = rtrim($mobile, "+");
$mobile = trim($mobile, "-");
//removing multiple '-'
$mobile_arr = explode('-',$mobile);//elplode a number like +1-123 456-342-234
$sub1 = $mobile_arr[0];//+1
if(strlen($sub1) != strlen($mobile)){ // condition where 12345678 valid nos is detected
$check_plus = explode('+',$sub1); //logic to detect number starts with +1-123.. or +12-123.. or 1-123.. or 12-123...
if($check_plus[0] == ''){ // occurs when we get +1...
if(strlen($sub1) == 2 || strlen($sub1) == 3){//valid digits like +1-123, +12-123
unset($mobile_arr[0]);
} else {
//invlid number
return array('status'=>'error','message'=>'Number must be in +1-123.. or +12-123.. or 1-123.. or 12-123... format');
}
} else {
if(strlen($sub1) == 1 || strlen($sub1) == 2){//valid digits like 1-123, 12-123
unset($mobile_arr[0]);
} else {
//invlid number
return array('status'=>'error','message'=>'Number must be in 1-123.. or 12-123.. or +1-123.. or +12-123... format');
}
}
$mobile = $sub1 .'-'.implode('',$mobile_arr);//+1-123 456342234
}
//removing '-' ends
//removing '+'
$mobile_arr = explode('+',$mobile);//explode a number like +1-123 456+342-234
if($mobile_arr[0]!='') {
if (strlen($mobile_arr[0]) != strlen($mobile)){ //number might be 1-123 456+342-234+
return array('status'=>'error','message'=>'Number must have "+" at the start ');
}
} else {
if($mobile_arr[2]!=''){//when we have more than one +
$sub1 = $mobile_arr[1];
unset($mobile_arr[1]);
$mobile = '+'.$sub1.implode('',$mobile_arr);//+1-123 456342234
}
}
return array('status'=>'success','data'=>$mobile);
} else {
return array('status'=>'error','message'=>'Invalid Mobile Number.');
}
//Validate Mobile number logic ends
}

Return value of an array for each item in a list

I'm still quite new to writing functions and PHP so please excuse me if this is easy. Let me provide a little background...
I have built an e-commerce site using MarketPress by WPMUDev and trying to write a function that will show the stock remaining depending on the product variation selected.
In MarketPress, if you have more than one variation of a product, e.g. Shirt (Blue/Black/White) then you specify the one product with three variations. On the single product page, you have a drop down box for each variant.
The code I have so far will find the stock level of the initial product only and not the variants. Please see below:
function mp_product_stock_sc( $atts ){
global $post;
$product_id = $post->ID;
$stock = get_post_meta($product_id, 'mp_inventory', true);
$high_st = 1;
//return 'Default Stock: ' . $stock[0];
if ($stock[0] <= $high_st AND $stock[0] > 0 ) {
//return 'Hurry! We only have ' . $stock[0] . ' in stock!';
return 'Hurry! Only one left in stock!';
} elseif ($stock[0] == 0) {
return '';
} else {
return 'In Stock';
}
return 'Stock: ' . $stock[0];
}
add_shortcode( 'mp_product_stock', 'mp_product_stock_sc' );
I know that the function is selecting the first variant in $stock[0] because the [0] is explicitly defined. By manually writing [1] it would select the next variant and so on.
What I need to do is, on the product variation drop down list, for each variant to have next to it the stock, e.g:
Shirt (Blue) - In Stock
Shirt (Black) - Hurry only 1 left!
Shirt (White) - In Stock
I know where to put the code, just not how to return the value.
Any advice greatly appreciated. There's probably a much better way of writing this too...
Thanks!
Edit: Adding below the code where the drop down is generated.
//create select list if more than one variation
if (is_array($meta["mp_price"]) && count($meta["mp_price"]) > 1 && empty($meta["mp_file"])) {
$variation_select = '<select class="mp_product_variations" name="variation">';
foreach ($meta["mp_price"] as $key => $value) {
$disabled = (in_array($key, $no_inventory)) ? ' disabled="disabled"' : '';
$variation_select .= '<option value="' . $key . '"' . $disabled . '>' . esc_html($meta["mp_var_name"][$key]) . ' - ';
if ($meta["mp_is_sale"] && $meta["mp_sale_price"][$key]) {
$variation_select .= $mp->format_currency('', $meta["mp_sale_price"][$key]);
} else {
$variation_select .= $mp->format_currency('', $value);
}
$variation_select .= "</option>\n";
}
$variation_select .= "</select> \n";
} else {
$button .= '<input type="hidden" name="variation" value="0" />';
}
This answer is based on the fact that you have an item code that you can feed into the method:
EDIT: I added a Randomizer method that will do two things. 1) You can set it to return a random number to check that the $calltoaction if statement is working (set the second variable in Randomizer to true instead of false) and 2) It will check that your number is numeric and return it back if it is. If not numeric, it will return 'err' which means it's not a number.
class StockCheck
{
public static function Fetch($itemcode, $high_st = 1)
{
// Check your stock on this item code (I pressume this is what it's doing.
// If not, this is what it should to do.)
$stock = get_post_meta($itemcode, 'mp_inventory', true);
// Assign number. If randomizer set to true, it will just generate a random num
// to test the if statement below. Change to false to return true number
$_inStock = self::Randomizer($stock[0],false);
if($_inStock !== 'err') {
if($_inStock !== 0) {
// If stock is less than or equal to 10
if($_inStock <= 10)
$calltoaction = 'Hurry! Only '.$_inStock.' Left in Stock!';
// If stock is greater than 10 but less than or equal to 20
elseif($_inStock > 10 && $_inStock <= 20)
$calltoaction = 'Only a Few Left. Going fast!';
// Anthing else is just in stock
else
$calltoaction = 'In Stock';
}
// If zero, out of stock.
else
$calltoaction = 'Out of Stock, Sorry!';
}
return (isset($calltoaction))? $calltoaction:'Error: Stock value not numeric';
}
protected static function Randomizer($value = 0, $randomizer = false)
{
// If set to true, it will just generate a random number for testing purposes
$defVal = ($randomizer == true)? rand(0,30):$value;
// If $defVal is not a numeric, return "err"
return (is_numeric($defVal) || $defVal == 0)? $defVal:'err';
}
}
if(is_array($meta["mp_price"]) && count($meta["mp_price"]) > 1 && empty($meta["mp_file"])) {
$variation_select = '<select class="mp_product_variations" name="variation">';
foreach ($meta["mp_price"] as $key => $value) {
$disabled = (in_array($key, $no_inventory)) ? ' disabled="disabled"' : '';
$variation_select .= '<option value="' . $key . '"' . $disabled . '>' . esc_html($meta["mp_var_name"][$key]) . ' - ';
$variation_select .= ($meta["mp_is_sale"] && $meta["mp_sale_price"][$key])? $mp->format_currency('', $meta["mp_sale_price"][$key]): $mp->format_currency('', $value);
// This is where you would feed your item code...
$variation_select .= StockCheck::Fetch($meta["mp_itemcode"],1);
$variation_select .= "</option>\n";
}
$variation_select .= "</select> \n";
}
else
$button .= '<input type="hidden" name="variation" value="0" />';

Finding all points contouring the overlapping squares

The setup:
a. 2D surface
b. points (with x, y coordinates) which when connected form squares.
c. I found an algorithm that finds the intersection points of those squares so assume we have them as well.
The question is: how do I get points that contour the squares.
I've included an image for better understanding.
I was looking into http://en.wikipedia.org/wiki/Convex_hull_algorithms but it seems like they all skip those intersections (the 90' angles).
I am writing this in php but i'd love to even see a pseudo code if at all possible.
<?php
//WARNING! we assume coords as non-polar. for this to work on large-scale, you need to convert polar into decard coords.
//Can be done outside this script.
//Points sample:
$points_raw=json_decode('{"1":[[41.014357690351,-73.73715475406],[41.029170309649,-73.73715475406],[41.014357690351,-73.75644124594],[41.029178309649,-73.73721675406],[41.014365690351,-73.75650324594],[41.031554690351,-73.73806375406],[41.046091309649,-73.78489424594],[41.014688690351,-73.78819424594],[41.012691690351,-73.75993275406],[41.012691690351,-73.77921924594],[41.015809690351,-73.75893475406],[41.053689309649,-73.76006575406],[41.053689309649,-73.77935224594],[41.050793309649,-73.78376624594],[41.043862309649,-73.79638424594],[41.029049690351,-73.79638424594],[41.019350690351,-73.79608224594],[41.033268690351,-73.73637875406],[41.048081309649,-73.73637875406],[41.048081309649,-73.75566524594],[41.014365690351,-73.75644124594],[41.029170309649,-73.73721675406],[41.018165690351,-73.75650324594],[41.029178309649,-73.74662775406],[41.031554690351,-73.74662775406],[41.033268690351,-73.73806375406],[41.043862309649,-73.78489424594],[41.019350690351,-73.78819424594],[41.015809690351,-73.75993275406],[41.014688690351,-73.77921924594],[41.018165690351,-73.75893475406],[41.047266309649,-73.76006575406],[41.050793309649,-73.77935224594],[41.046091309649,-73.78376624594],[41.029049690351,-73.79608224594],[41.047266309649,-73.75566524594]]}',1);
//BEGIN HERE:
$points=$points_raw[1];
function to_round($val)
{
//here we can try conversion from polar to decard. not sure if will work
//no conversion for now, but just rounding for comparsion
return round($val*1000000000000);
}
function sort_points_array($a, $b, $which)
{
$da=to_round($a[$which]);
$db=to_round($b[$which]);
if ($da == $db) {
return 0;
}
return ($da < $db) ? -1 : 1;
}
function sort_by_0($a, $b)
{
return sort_points_array($a, $b, 0);
}
function sort_by_1($a, $b)
{
return sort_points_array($a, $b, 1);
}
//BEGIN OF UNOPTIMIZED SORT
//sort by columns from left to right (does not have to be left/right on the map)
//but we will try :) 0 -> Y, 1 -> X
//sort by X, so lower X will be on top of array.
//and each point in those columns will be also sorted from top to bottom by their Y
usort($points,"sort_by_1");
//then foreach to split array by "columns";
$column_counter=0;
$point_columns=array();
$point_columns[$column_counter][]=$points[0];
foreach($points as $n_point=>$p_coords)
{
if($n_point>0)
{
if(to_round($p_coords[1]) > to_round($point_columns[$column_counter][1][1]))
$column_counter++;
$point_columns[$column_counter][]=$p_coords;
}
}
//now sort each column
$sorted_point_columns=array();
foreach($point_columns as $pcn => $p_column)
{
usort($p_column,"sort_by_0");
$sorted_point_columns[$pcn]=$p_column;
}
//SAME TO MAKE sorted_point_rows
usort($points,"sort_by_0");
$row_counter=0;
$point_rows=array();
$point_rows[$row_counter][]=$points[0];
foreach($points as $n_point=>$p_coords)
{
if($n_point>0)
{
if(to_round($p_coords[0]) > to_round($point_rows[$row_counter][0][0]))
$row_counter++;
$point_rows[$row_counter][]=$p_coords;
}
}
$sorted_point_rows=array();
foreach($point_rows as $prn => $p_row)
{
usort($p_row,"sort_by_1");
$sorted_point_rows[$prn]=$p_row;
}
// END OF UNOPTIMIZED SORT
//output array
$final_points_poly=array();
//clearly first point will be from 1st row;
//and we will go to the RIGHT in current row to find next point
$final_points_poly[0]=$sorted_point_rows[0][0];
//and let the magic begin:
$finished=false;
$last_point_index=0;
$points_total=count($points);
$pos_x=0; //pos by columns
$pos_y=0; //pos by rows
$relative_X=0; //relative X position in current ROW;
$relative_Y=0; //relative Y position in current COLUMN;
$rule=1; // right / down = 1, left / up = -1
//detect if we go by X or Y
$going_Y=false;
$finished=false;
while(!$finished)
{
if($going_Y)
{
$relative_Y+=$rule;
$last_point_index+=1;
$cur_p=$sorted_point_columns[$pos_x][$relative_Y];
$final_points_poly[$last_point_index]=$cur_p;
$going_Y = !$going_Y;
//search for pos_y:
foreach($sorted_point_rows as $cur_y => $row)
{
if(to_round($row[0][0]) == to_round($cur_p[0]))
{
$pos_y=$cur_y;
//search for relative_X
foreach($row as $cur_rel_x => $check_point)
{
if(to_round($check_point[1]) == to_round($cur_p[1]))
{
$relative_X=$cur_rel_x;
$rule = ($relative_X % 2 == 0 ? 1 : -1);
break 2;
}
//error_check 1
if($cur_rel_x == count($row)-1)
echo "error with calculating relative_X! check your data!\n";
}
}
//error_check 2
if($cur_y == count($sorted_point_rows)-1)
echo "error with calculating pos_y! check your data!\n";
}
}
else
{
$relative_X+=$rule;
$last_point_index+=1;
$cur_p=$sorted_point_rows[$pos_y][$relative_X];
$final_points_poly[$last_point_index]=$cur_p;
$going_Y = !$going_Y;
//search for pos_x:
foreach($sorted_point_columns as $cur_x => $column)
{
if(to_round($column[0][1]) == to_round($cur_p[1]))
{
$pos_x=$cur_x;
//search for relative_Y
foreach($column as $cur_rel_y => $check_point)
{
if(to_round($check_point[0]) == to_round($cur_p[0]))
{
$relative_Y=$cur_rel_y;
$rule = ($relative_Y % 2 == 0 ? 1 : -1);
break 2;
}
//error_check 1
if($cur_rel_y == count($column)-1)
echo "error with calculating relative_Y! check your data!\n";
}
}
//error_check 2
if($cur_x == count($sorted_point_columns)-1)
echo "error with calculating pos_x! check your data!\n";
}
}
if($last_point_index == $points_total-1)
{
$finished=true;
}
}
echo "all points:\n";
print_r($final_points_poly);
/*
//generate markers for google mapping
$out = "var bbs=[];var markers=[];";
$out .= "var pinI = new google.maps.MarkerImage('http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|ADDE63');";
$out .= "var pinI2 = new google.maps.MarkerImage('http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|FF8C00');";
$out .= "var pinI3 = new google.maps.MarkerImage('http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|990099');";
$out .= "bbs.push(new google.maps.Polyline({ ";
$out .= "path: [";
foreach($final_points_poly as $m){
$out .= "new google.maps.LatLng(".join(",",$m)."),";
}
$out .= "],";
$out .= "strokeColor: 'black', strokeOpacity: 0.4, strokeWeight: 1 }));";
$f = fopen("bbs.js",'w');
fwrite($f,$out);
fclose($f);
*/
?>

How do I retrieve house number in magento street value via soap?

I have magento, and I'm posting a request via the soap v2 api to get the address of an order.
With that I get the following object which contains the street name + housenumber(God knows why these fields are not seperate...)
$shipping_address->street = "4th avenue 108";
Now what I want is to have the housenumber 108.
How do I get this house number without getting the 4?
(if someone has a more reliable function/piece of code than the one I post below, please feel free to post it.)
What you basically have to do is check for the first number occurence with a space in front of it.
This way you minimse the risk of fetching the wrong number:
// Code by Michael Dibbets
// shared under creative commons Attribution 3.0 Unported (CC BY 3.0 http://creativecommons.org/licenses/by/3.0/ )
$value = "4th street26";
$spl = str_split($value);
$pos = 0;
$location = 0;
// simple loop to find the first character with space + integer
foreach($spl as $char)
{
if(is_numeric($char) && $spl[$pos-1]==' ')
{
$location = $pos;
break;
}
$pos++;
}
// If we didn't encounter the space + integer combination
if(!$location)
{
// is the last character an integer? Assume that the last numbers are house numbers
if(is_numeric($spl[count($spl)-1]))
{
for($c=count($spl)-1;$c>0;$c--)
{
if(is_numeric($spl[$c]))
{
continue;
}
else
{
$location = $c+1;
break;
}
}
}
}
if($location)
{
$street = substr($value,0,$location);
$number = substr($value,$location);
}
else
{
$street = $value;
$number = null;
}
// echoing the results. The number should appear after the dash.
echo $street . ' - ' . $number;

PHP MeCard Decoder or MeCard to VCard Converter

I'm working on a QR code parser and I'm wondering if anyone knows of a MeCard library, or code that converts a MeCard to a VCard. If not, is there an official specification doc for MeCard out there? I know NTT DoCoMo created it, but I can't find any kind of RFC on it.
From http://code.google.com/p/zxing/wiki/BarcodeContents, I found a link to DoCoMo's specification for MeCard, at http://www.nttdocomo.co.jp/english/service/developer/make/content/barcode/function/application/addressbook/index.html. It is pretty dirt simple and converting it to a VCard with a function call should be pretty trivial.
== EDIT ==
I wrote a little conversion function. Just in case anyone in the future wants the code, it is below:
private function MeCardtoVCard($mecard_text)
{
// Useful References:
// http://www.nttdocomo.co.jp/english/service/developer/make/content/barcode/function/application/addressbook/index.html
// http://code.google.com/p/zxing/wiki/BarcodeContents
// http://en.wikipedia.org/wiki/VCard
// https://theqrplace.wordpress.com/2011/05/02/qr-code-tech-info-mecard-format/
$vcard = '';
if (stripos($mecard_text, "mecard") === 0)
{
$mecard_text = str_replace("\n", "", $mecard_text); // Strip out newlines
$mecard_text = substr($mecard_text,7); // Strip off the MECARD: header
$lines = explode(";", $mecard_text);
if (count($lines) > 0)
{
// Using Version 2.1 because it is the most commonly supported.
$vcard = "BEGIN:VCARD\nVERSION:3.0\n";
foreach($lines as $l)
{
$line_elements = explode(":",$l);
if (count($line_elements) > 1)
{
// Must split into two parts. Not sure how DoCoMo escapes
// data that actually contains a ":", so for now we are presuming
// that the first token is the property name and all other elements
// are the value
$property = $line_elements[0];
$value = implode(":", array_slice($line_elements,1));
if ($property != '' && $value != '')
{
if ($property == 'N')
{
// MeCards only support first and last name.
$tmp = explode(",",$value);
if (count ($tmp) == 1)
{
$vcard .= "N:;" . $tmp[0] . "\n";
}
else
{
$vcard .= "N:" . implode(";",explode(",",$value)) . "\n";
}
}
if ($property == 'TEL')
{
// MeCard does not use card types, so we will presume all of them are type CELL
$vcard .= "TEL:" . $value . "\n";
}
if ($property == 'ADR')
{
// MeCard: "The fields divided by commas (,) denote PO box, room number, house number, city, prefecture, zip code and country, in order."
// VCard: "...post office box; the extended address; the street address; the locality (e.g., city); the region (e.g., state or province); the postal code; the country name" See http://www.ietf.org/rfc/rfc2426.txt 3.2.1
$vcard .= "ADR:" . implode(";",explode(",",$value)) . "\n";
}
if (in_array($property, array('NOTE', 'BDAY', 'URL', 'NICKNAME')))
{
$vcard .= $property . ':' . $value . "\n";
}
}
}
}
$vcard .= "END:VCARD\n";
return $vcard;
}
else
{
return false;
}
}
return false;
}

Categories