PHP Performing Calculations with Multidim Array - php

I've currently have a multidim array with a planet and it's relative gravity value.
([0][0] = planet and [0][1] = relative gravity).
On my page I have a form where the user submits the weight of an item and the planet they wish to see it's weight on. What I'm trying to do is take the weight the user entered and multiply it by the relative gravity of the specific planet they chose.
My initial attempts have been to use something like this:
<?php
$file = fopen("PLANET.txt", "r");
$planets = array();
while(!feof($file)) {
$line = fgets($file);
$value = explode(" ", $line);
array_push($planets, $value);
}
if(isset($_POST['weight']) && isset($_POST['planet'])) {
while($x=0;x<count($planets);x++) {
if($_POST['planet'] == $planets[x][0]) {
$final_weight = $_POST['weight'] * $planets[x][1];
}
}
}
?>
However it does not seem to be working... I am brand new to PHP and I could be making a dumb mistake but I can't seem to find it, any help would be much appreciated.
EDIT:
Ok here is what I have now and it seems to be working, thank you guys very much. Feel so dumb for making those mistakes!
for($x=0;$x<count($planets);$x++) {
if($_POST['planet'] == $planets[$x][0]) {
$final_weight = $_POST['weight'] * $planets[$x][1];
}
}

Your while loop should look like that (note the additional $ signs):
while($x=0;$x<count($planets);x++) {
if($_POST['planet'] == $planets[$x][0]) {
$final_weight = $_POST['weight'] * $planets[$x][1];
}
}
EDIT: The above is complete nonsense. No idea what got into me. It should of course be:
for($x=0;$x<count($planets);x++) {
if($_POST['planet'] == $planets[$x][0]) {
$final_weight = $_POST['weight'] * $planets[$x][1];
}
}

Related

PHP foreach loop messes up my in_array function

I've written a script that checks bulk input of names received via a textarea and omits all values that are already in the database. It works if you enter just one repeated name. If you enter two or more, it will filter out the first repeated name, treat the rest as unique names and insert them in the database. I can't figure out why.
Firstly, this is an array that is built in another part of the script. It's generated from a database query:
Array
(
[0] => john
[1] => peter
[2] => max
[3] => jake
)
This array is referred to as $onlyHandles. Then this is the script:
if((isset($_POST['extract']) && !empty($_POST['extract']))){
$handles = trim($_POST['extract']);
$handles = explode("\n", $handles);
if(count($handles)>200){
echo 'error';
exit(1);
}
foreach($handles as $handle) {
$handleRep = strtolower(str_replace('#','',$handle));
$handleClean = str_replace(str_split('\\/:*?&"<>=+-#%$|'), ' ', $handleRep, $count);
if ($count > 0) {
echo 'error';
exit(1);
}
else{
if (in_array($handleClean, $onlyHandles)){
$delmessage .= "<p>".$handleClean." is already in your list.</p>";
}
else{
$sqlIns = "INSERT INTO...blah blah blah)";
$resultIns = mysql_query($sqlIns);
$resInsArr[] = array($resultIns);
}
}
}
$countresIns = count($resInsArr);
if ($countresIns > 0){
$delmessage .= "<p>User(s) added to list succesfully!</p>" ;
}
}
Now, if you enter "john" in the textarea, it will shout that the name already exists. If you enter "john" and "max" it will omit john and add max.
Any help would be greatly appreciated.
P.S. regarding the query format, I know, I know, thanks!
I would like to give U some idea about how to achieve it:
Replace the first line:
if((isset($_POST['extract']) && !empty($_POST['extract']))){
through
if((!empty($_POST['extract']))){
because !empty already guives U the guaranty that it isset
I am suspescting some special chars in play
U could also use the power of Regular Expression to replace the unneeded chars
in replacing:
Line 12: $handleClean = str_replace(str_split('\\/:*?&"<>=+-#%$|'), ' ', $handleRep, $count);
Through:
$handleClean = preg_replace("/\[\/:\*?&\"<>=\+-#%\$\|\]*/", ' ', $handleRep, $count);
In Ur For-Loop, what about refactoring the following lines:
line 2: $handles = trim($_POST['extract']);
through (trim is not necessary hier)
$handles = $_POST['extract'];
AND
line 11: $handleRep = strtolower(str_replace('#','',$handle));
through
$handleRep = trim(strtolower(str_replace('#','',$handle)));
Hey ;-),
U should also add some print_r(...) to debug each step
thanks #Ulrich Tevi Horus that made my code a bit cleaner but didn't solve the mysteriously disappearing users.
#shulard, you should post this as an answer to get the upvote. array_diff was indeed the best solution.
Here's the final code. Needs some tidying up but it's good enough to go on my server for testing.
//this is the current contents of the list:
$onlyHandles = array();
foreach ($organizedArray as $key2 => $val2) {
$onlyHandles[] = $val2['name'];
}
echo "<br>begin onlyhandles<br>";
print_r($onlyHandles);
echo "<br>end onlyhandles<br>";
//finish preparation for display
//if names submitted for the list list
if(!empty($_POST['extract'])){
$handles = trim($_POST['extract']);
$handles = explode("\n", $handles); //this is now an array
echo "<br>begin handles<br>";
print_r($handles);
echo "<br>end handles<br>";
//$countInput = count($handles);
if($countInput>200){
echo '<p style="color:red;">Please Enter fewer than 200 names!</p>';
exit(1);
}
else{
$handleFinal = array();
foreach($handles as $handle) {
//$handleRep = strtolower(str_replace('#','',$handle));
$handleRep = trim(strtolower(str_replace('#','',$handle)));
$handleClean = str_replace(str_split('\\/:*?&"<>=+ -#%$|'), 'p', $handleRep, $count);
//$handleClean = preg_replace("/\[\/:\*?&\"<>=\+-#%\$\|\s+\]*/", ' ', $handleRep, $count);
echo "handleClean: ".$handleClean."<br>";
if ($count > 0) {
echo '<p style="color:red;">Your input contained special characters.</p>';
exit(1);
}
else{
$handleFinal[] = $handleClean;
}
}//end foreach
}//finish checking count input number
echo "<br>begin handleFinal<br>";
print_r($handleFinal);
echo "<br>end handleFinal<br>";
$countFinal = count($handleFinal);
echo "<br>countfinal is ".$countFinal."<br>";
//check if this user is already in the list
$handleDiffs = array_diff($handleFinal,$onlyHandles);
echo "<br>begin handlediffs<br>";
print_r($handleDiffs);
echo "<br>end handlediffs<br>";
foreach($handleDiffs as $handleDiff) {
$sqlIns = "blah blah blah";
$resultIns = mysql_query($sqlIns);
$resInsArr[] = array($resultIns);
}
$countresIns = count($resInsArr);
if ($countresIns > 0){
$delmessage .= "<p>User(s) added to the list succesfully!</p>" ;
}
}
I post my comment answer as a real answer :)
You must trim your $handle variable too because it's possible to have some spaces around it...
Then about your problem, I don't understand it. Your code seems "clean", maybe you should consider set the strict flag to true see function definition here.

Trouble reading huge CSV file with php fgetcsv - understanding memory consumption

Good morning,
I´m actually going through some hard lessons while trying to handle huge csv files up to 4GB.
Goal is to search some items in a csv file (Amazon datafeed) by a given browsenode and also by some given item id´s (ASIN). To get a mix of existing items (in my database) plus some additional new itmes since from time to time items disapear on the marketplace. I also filter the title of the items because there are many items using the same.
I have been reading here lots af tips and finally decided to use php´s fgetcsv() and thought this function will not exhaust memory, since it reads the file line by line.
But no matter what I try I´m always running out of memory.
I can not understand why my code uses so much memory.
I set the memory limit to 4096MB, time limit is 0. Server has 64 GB Ram and two SSD hardisks.
May someone please check out my piece of code and explain how it is possible that im running out of memory and more important how memory is used?
private function performSearchByASINs()
{
$found = 0;
$needed = 0;
$minimum = 84;
if(is_array($this->searchASINs) && !empty($this->searchASINs))
{
$needed = count($this->searchASINs);
}
if($this->searchFeed == NULL || $this->searchFeed == '')
{
return false;
}
$csv = fopen($this->searchFeed, 'r');
if($csv)
{
$l = 0;
$title_array = array();
while(($line = fgetcsv($csv, 0, ',', '"')) !== false)
{
$header = array();
if(trim($line[6]) != '')
{
if($l == 0)
{
$header = $line;
}
else
{
$asin = $line[0];
$title = $this->prepTitleDesc($line[6]);
if(is_array($this->searchASINs)
&& !empty($this->searchASINs)
&& in_array($asin, $this->searchASINs)) //search for existing items to get them updated
{
$add = true;
if(in_array($title, $title_array))
{
$add = false;
}
if($add === true)
{
$this->itemsByASIN[$asin] = new stdClass();
foreach($header as $k => $key)
{
if(isset($line[$k]))
{
$this->itemsByASIN[$asin]->$key = trim(strip_tags($line[$k], '<br><br/><ul><li>'));
}
}
$title_array[] = $title;
$found++;
}
}
if(($line[20] == $this->bnid || $line[21] == $this->bnid)
&& count($this->itemsByKey) < $minimum
&& !isset($this->itemsByASIN[$asin])) // searching for new items
{
$add = true;
if(in_array($title, $title_array))
{
$add = false;
}
if($add === true)
{
$this->itemsByKey[$asin] = new stdClass();
foreach($header as $k => $key)
{
if(isset($line[$k]))
{
$this->itemsByKey[$asin]->$key = trim(strip_tags($line[$k], '<br><br/><ul><li>'));
}
}
$title_array[] = $title;
$found++;
}
}
}
$l++;
if($l > 200000 || $found == $minimum)
{
break;
}
}
}
fclose($csv);
}
}
I know my answer is a bit late but I had a similar problem with fgets() and things based on fgets() like SplFileObject->current() function. In my case it was on a windows system when trying to read a +800MB file. I think fgets() doesn't free the memory of the previous line in a loop. So every line that was read stayed in memory and let to a fatal out of memory error. I fixed it using fread($lineLength) instead but it is a bit trickier since you must supply the length.
It is very hard to manage large data using array without encountering timeout issue. Instead why not parse this datafeed to a database table and do the heavy lifting from there.
Have you tried this? SplFileObject::fgetcsv
<?php
$file = new SplFileObject("data.csv");
while (!$file->eof()) {
//your code here
}
?>
You are running out of memory because you use variables, and you are never doing an unset(); and use too many nested foreach. You could shrink that code in more functions
A solution should be, use a real Database instead.

PHP remove duplicate instances of dates in an array

I've tried various permutations of array_unique, and have searched other generic questions here on removing duplicate values from an array, but I can't quite set upon the answer I need. I have an array being passed of dates and values, and only want to view the DATE value once per date.
I'm using this for a Google chart and only want the date labels to show up once for each date. And I don't want to remove it entirely, because I want to be able to plot it on the chart.
So, an example array being passed:
["June 4",30],["June 4",35],["June 5",46],["June 5",38.33],["June 5",12]
And how I want it:
["June 4",30],["",35],["June 5",46],["",38.33],["",12]
Ideas?
Since you're using the data to feed into a google chart, I'm assuming that you know exactly what you need as far as output data. There's already some suggestions above for better ways to structure the data, but that probably won't work directly for a google chart.
How about this?
$data = [["June 4",30],["June 4",35],["June 5",46],["June 5",38.33],["June 5",12]];
$found = array();
foreach ($data as $i => $x) {
if (in_array($x[0], $found)) {
$data[$i][0] = '';
} else {
$found[] = $x[0];
}
}
print_r($data);
Basically, it's just building a list of dates that it's already seen. We loop through the data, and check if we've seen the date... if we have, we clear it from the data, otherwise we save it to the list so it'll be cleared next time.
Here's an alternate solution that only checks for duplicate dates that are consecutive, unlike the first solution that will remove all duplicates. This is probably closer to what you need for charting:
$data = [["June 4",30],["June 4",35],["June 5",46],["June 5",38.33],["June 5",12]];
$last = '';
foreach ($data as $i => $x) {
if ($x[0] == $last) {
$data[$i][0] = '';
} else {
$last = $x[0];
}
}
print_r($data);
In this case, we're just keeping track of the last date we've seen... and if our new date matches that, we clear it.
This is a possible solution for your problem, though I would recommend a re-construction as Patashu & Nikola R stated.
$untrimmed = [["June 4",30],["June 4",35],["June 5",46],["June 5",38.33],["June 5",12]];
$trimmed = stripDates($untrimmed);
function stripDates($dates) {
foreach( $dates as $key=>$date ) {
if ($key>0) {
if ($date[0] === $dates[$key-1][0]) {
$dates[$key][0] = "";
} else if($dates[$key-1][0] === "") {
for ($i = $key-1; $i > -1; $i--) {
if ($date[0] === $dates[$i][0]) $dates[$key][0] = "";
if ($dates[$key] != "") break;
}
}
}
}
return $dates;
}
// Note: This would require dates to be added chronically
//Output: ["June 4",30],["",35],["June 5",46],["",38.33],["",12]
I would recommend something like this:
$unconstructed = [["June 4",30],["June 4",35],["June 5",46],["June 5",38.33],["June 5",12]];
$constructed = constructAssoc($unconstructed);
function constructAssoc($dates) {
$constructed = array();
foreach( $dates as $index=>$date ) {
if (!array_key_exists($date[0], $constructed)) {
$constructed[$date[0]] = array("index"=>$index, "value"=>$date[1]);
} else {
array_push($constructed[$date[0], ["index"=>$index,"value"=>$date[1]]);
}
}
return $constructed;
}
//Output: ["June 4"=> [["index"=>0, "value"=>30], ["index"=>1, "value"=>35]], "June 5"=>[["index"=>2, "value"=>46], ["index"=>3, "value"=>38.33], ["index"=>4, "value"=>12]]]
Note: Added index in recommended solution if a more accurate re-construction is needed.

Scraping Keyword Suggestions from Google

I'm currently working to scrape keyword suggestion from Google. This is the script I'm working with:
<?php
function text_between($start,$end,$string) {
if ($start != '') {$temp = explode($start,$string,2);} else {$temp = array('',$string);}
$temp = explode($end,$temp[1],2);
return $temp[0];
}
function gsscrape($keyword) {
$keyword=str_replace(" ","+",$keyword);
global $kw;
$data=file_get_contents('http://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl=en-US&q='.$keyword);
$data=explode('[',$data,3);
$data=explode('],[',$data[2]);
foreach($data as $temp) {
$kw[]= text_between('"','"',$temp);
}
}
#simple to use, just use yourscriptname.php?keywords
if ($_SERVER['QUERY_STRING']!='') {
gsscrape($_SERVER['QUERY_STRING']);
foreach ($kw as $keyword) {
gsscrape($keyword);
}
//sorted and duplicates removed
sort(array_unique($kw));
#all results echoed with break
foreach ($kw as $keywords) {
echo $keywords. "<br />";
}
}
?>
When accessing directly through the URL Google will give me this response for the keyword money:
["money",["moneygram","money network","money mutual","money trees lyrics","moneyball","moneypak","money","money converter","money order","money2india"]]
However, for some reason when I test it on my website, it's just showing this:
moneygram
moneygram
What needs to be changed so that it displayed each of the keywords like this?
moneygram, money network, money mutual, money trees lyrics, moneyball, moneypak, money, money converter, money order, money2india
This is valid JSON, use json_decode and you are done!
var_dump(json_decode('["money",["moneygram","money network","money mutual","money trees lyrics","moneyball","moneypak","money","money converter","money order","money2india"]]'));
edit - complete example;
<?php
function getKeywordSuggestionsFromGoogle($keyword) {
$keywords = array();
$data = file_get_contents('http://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl=en-US&q='.urlencode($keyword));
if (($data = json_decode($data, true)) !== null) {
$keywords = $data[1];
}
return $keywords;
}
var_dump(getKeywordSuggestionsFromGoogle('money'));
To get the data as an array use this:
function gsscrape($keyword) {
return json_decode(utf8_decode(file_get_contents('http://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl=en-US&q='.urlencode($keyword))),true);
}

Multi-dimensional array search to preserve parent

TL;DR
I have this data: var_export and print_r.
And I need to narrow it down to: http://pastebin.com/EqwgpgAP ($data['Stock Information:'][0][0]);
How would one achieve it? (dynamically)
I'm working with vTiger 5.4.0 CRM and am looking to implement a function that would return a particular field information based on search criteria.
Well, vTiger is pretty weakly written system, looks and feels old, everything comes out from hundreds of tables with multiple joins (that's actually not that bad) etc., but job is job.
The need arose from getting usageunit picklist from Products module, Stock Information block.
Since there is no such function as getField();, I am looking forward to filter it out from Blocks, that is actually gathering the information about fields also.
getBlocks(); then calls something close to getFields();, that again something close to getValues(); and so on.
So...
$focus = new $currentModule(); // Products
$displayView = getView($focus->mode);
$productsBlocks = getBlocks($currentModule, $displayView, $focus->mode, $focus->column_fields); // in theory, $focus->column_fields should/could be narrowed down to my specific field, but vTiger doesn't work that way
echo "<pre>"; print_r($productsBlocks); echo "</pre>"; // = http://pastebin.com/3iTDUUgw (huge dump)
As you can see, the array under the key [Stock Information:], that actually comes out from translations (yada, yada...), under [0][0] contains information for usageunit.
Now, I was trying to array_filter(); the data out from there, but only thing I've managed to get is $productsBlocks stripped down to only contain [Stock Information:] with all the data:
$getUsageUnit = function($value) use (&$getUsageUnit) {
if(is_array($value)) return array_filter($value, $getUsageUnit);
if($value == 'usageunit') return true;
};
$productsUsageUnit = array_filter($productsBlocks, $getUsageUnit);
echo "<pre>"; print_r($productsUsageUnit); echo "</pre>"; // = http://pastebin.com/LU6VRC4h (not that huge of a dump)
And, the result I'm looking forward to is http://pastebin.com/EqwgpgAP, that I've manually got by print_r($productsUsageUnit['Stock Information:'][0][0]);.
How do I achieve this? (dynamically...)
function helper($data, $query) {
$result = array();
$search = function ($data, &$stack) use(&$search, $query) {
foreach ($data as $entry) {
if (is_array($entry) && $search($entry, $stack) || $entry === $query) {
$stack[] = $entry;
return true;
}
}
return false;
};
foreach ($data as $sub) {
$parentStack = array();
if ($search($sub, $parentStack)) {
$result[] = $parentStack[sizeof($parentStack) - 2];
}
}
return $result;
}
$node = helper($data, 'usageunit');
print_r($node);

Categories