PHP - What's this code doing exactly? - php

I can't figure out how to log into my account here on Stackoverflow, I find it a little confusing. Anyway, I've asked a question here about a problem I'm having:
Other Question
I've since found an open source project that does exactly what I need done but the code is PHP and while I can understand most of it there are bits I don't get. I'll post it here with my comments through it and if someone can add extra details that would be appreciated.
public function productAttributeExists($attributesList, $currentProductAttribute = false)
{
$result = Db::getInstance()->ExecuteS('SELECT pac.`id_attribute`, pac.`id_product_attribute`
FROM `'._DB_PREFIX_.'product_attribute` pa
LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON (pac.`id_product_attribute` = pa.`id_product_attribute`)
WHERE pa.`id_product` = '.intval($this->id));
if (!$result OR empty($result))
return false;
$productAttributes = array();
foreach ($result AS $productAttribute)
$productAttributes[$productAttribute['id_product_attribute']][] = $productAttribute['id_attribute'];
foreach ($productAttributes AS $key => $productAttribute)
if (sizeof($productAttribute) == sizeof($attributesList))
{
$diff = false;
for ($i = 0; $diff == false AND isset($productAttribute[$i]); $i++)
if (!in_array($productAttribute[$i], $attributesList) OR $key == $currentProductAttribute)
$diff = true;
if (!$diff)
return true;
}
return false;
}
Ok turns out I can't comment this code in Stackoverflow without it all going to formatting hell. So my understanding is this:
1) Get the Data
2) If the dataset is empty return false
3) New array called productAttributes
4) Loop through the dataset and populate the array
5) Not sure what this last section is doing, the section beginning 'foreach' is unclear to me.
Any tips appreciated. Incidentally, C# is my preferred language and the one I understand best.

This function, as it is named, is only supposed to check if a particular attribute list of a product exists and is the same as the one provided in the first parameter.
The last part is confusing, but it's iterating through all the attributes to see if any of the retrieved attributes are the same as the ones provided.
in a loop iteration:
it first tries to see if the provided attribute list is the same length as the one coming from the database - if not, it just goes to the next attribute list in the for loop
if the length of the lists is the same, then it will go through each attribute in the attribute list and see if there's something different amongst any of the elements.
The function isn't very optimal, btw.

Related

I am trying to solve a PHP exercise but am unable to understand what's happening

First of all I'm very sorry for my irrelevant question title, as I did not know how to write it better.
To start with, I am a PHP beginner. I am solving some PHP exercise and I came upon a question I don't know where to start with:
function q3() {
// I am supposed to write stuff here and not change anything to get the question right.
}
function a3($admin = false) {
assertion_group("Question 3");
foreach ($GLOBALS as $k => $v) $$k = $v;
if ($admin) {
$file = q3("edsi.pem");
}
$key = #file_get_contents($file);
$key = substr($key, 0, 4);
assert($key == substr(file_get_contents(__FILE__), 0, 4));
return $key;
}
First of all, I understand what $GLOBALS does, but why assign the $$k to $v (so the $k value to the $v value)? And does $GLOBALS get the values within functions?
How can I set $admin = true? I believe through q3(), but I don't see how...
Next thing that confuses me most is: $file = q3("edsi.pem"). As my q3 function doesn't have any arguments, and that I'm not supposed to add one, how can I use that?!
Thank you all very much in advance for your answer. My apologies again for the very vague question...
EDIT:
With the help of #mario to better understand this whole mess, basically what I had to put in q3 was:
if ($info == 'edsi.pem') {
$info = __FILE__;
return $info;
}
plus add an argument for q3 (q3($info)) and add ?admin=true in the header...
Many thanks again!
First of all, I understand what $GLOBALS does, but why assign the $$k to $v (so the $k value to the $v value)? And does $GLOBALS get the values within functions?
What that foreach … $$k = $v; snippet does is basically extract($GLOBALS);
This isn't a very useful way to pass arguments around. Using global vars only makes sense if they have somewhat descriptive names, and if they're not misused as state flags between different code sections.
And no, globals aren't available in all functions right away. Read up on variable scope.
How can I set $admin = true? I believe through q3(), but I don't see how...
You are confusing the function names here (precisely because they aren't rather useful function names to begin with). You can pass the $admin parameter when calling a3() instead:
a3(true);
Next thing that confuses me most is: $file = q3("edsi.pem"). As my q3 function doesn't have any arguments, and that I'm not supposed to add one, how can I use that?!
The only way to get the argument in q3 is per func_get_arg().
And again really, unless this is an exercise about how not to write code or a tutorial about weird use cases, you shouldn't really bother further.

PHP compare subsequent array element to previous

So i'm having trouble getting a bit of code to work. Essentially what I want to do is:
in a foreach loop, if a given array value is set, compare that existing value to the current loop value, then set the existing value = current value (for the iteration) if the existing value is already greater than current val. Here is the code i'm working with:
if ($usedebayxml->ack == 'Success') {
foreach($usedebayxml->searchResult->item as $key => $value) {
if(isset($newarray[1]['TotalCost'])) {
if($newarray[1]['TotalCost'] > ((integer)$value->shippingInfo->shippingServiceCost + (integer)$value->sellingStatus->currentPrice)) {
$newarray[1]['Title'] = (string)$value->title ;
$newarray[1]['ShippingCost'] = (integer)$value->shippingInfo->shippingServiceCost;
$newarray[1]['Price'] = (integer)$value->sellingStatus->currentPrice;
$newarray[1]['Condition'] = 'New';
$newarray[1]['TotalCost'] = (integer)$value->shippingInfo->shippingServiceCost + (integer)$value->sellingStatus->currentPrice;
}
}
else
$newarray[1]['Title'] = (string)$value->title;
$newarray[1]['ShippingCost'] = (integer)$value->shippingInfo->shippingServiceCost;
$newarray[1]['Price'] = (integer)$value->sellingStatus->currentPrice;
$newarray[1]['Condition'] = 'Used';
$newarray[1]['TotalCost'] = (integer)$value->shippingInfo->shippingServiceCost + (integer)$value->sellingStatus->currentPrice;
}
}
With this code, what is returned is ultimately the values in the LAST key object in the xml file (im using simpleXML if that helps). In other words, i don't think the first if block (if isset) is being entered into, and the values are being set to whatever the values are for the current iteration. Can anyone see any flaw in my logic here? I've been stumped on this one for a while.
I am a supreme idiot. The logic here is fine, i was just missing a { for the opening else block. dur! After adding this, this bit of code works as intended :)
I'm surprised though that i wasn't throwing any errors without having this....I think that was probably throwing me off in determining why it wasn't working originally.

php use value as a variable name (for a key) from an array to unpack a resultset from Drupal

I will be reusing a Drupal db_query result set unpacking function many, many times in my code for a variety of different queries - I am using O-O and as such I want to reuse it and be as 'DRY' as possible.
Therefore I have tried to strip it down to the most generic functions so that as long as the $columns supplied match the columns used in the query and similarly in the $resultset, I can loop and assign values to keys, as is shown, and return a $rows[].
I've not yet come across the issue of trying to use a variable's value as a variable name (the $key), if it's just something I should avoid entirely, please say.
foreach($this->resultSet as $aRecord) {
$c = 0;
while (isset($this->columns[$c])) {
$value = $this->columns[$c];
$rows[$i] = array(
$key[$this->columns[$c]] => $aRecord->$value,
);
$c++;
}
$i++;
}
I've read through the following and am beginning to think this is just knowledge I'm missing in my PHP experience so far.
Can I use a generated variable name in PHP?
PHP use function return value as array
https://wiki.php.net/rfc/functionarraydereferencing
It felt wrong, and someone once told me that if you have to start writing complex functions in PHP you've probably missed an available function PHP already offers.. so true... thanks to (at the time of writing...) 'MrCode' for this suggestion.
$this->sql = "SELECT foo, bar FROM foobar";
$this->result = db_query($this->sql);
if ($this->result->rowCount() > 0) {
while ($row = $this->result->fetchAssoc()) {
$this->resultArray[] = $row;
}
}

PHP: If condition with explode within foreach loop

I am trying to get multiple value from user input from text field and want to explode or keep adding into if condition statement
Here is my code
foreach ($list['post'] as $item) {
if( ($item['single']['catid'] != 8) AND ($item['single']['catid'] != 4) ){
$this->list_post($item);
}
}
Now what exactly I am looking for is in if( ($item['single']['catid'] != 8) AND ($item['single']['catid'] != 4) ) I want allow user to add multiple category ID and each ID will add AND and further id code AND ($item['single']['catid'] != 4)
I never done this before and don't know either this is proper way to do or any other possible better way.
Thanks a lot
You should have some kind of an array of the category IDs you want to check for, for example:
$categories = array(8, 4);
Then you could use something like the in_array(needle, haystack) built-in function of PHP.
Your if condition would become like that one: if (!in_array($item['single']['catid'], $categories)) {.
You should be using the above, but I am going to give you an idea of how it works, so you can understand the principle for more complex issues:
function exists($target, $array) {
foreach ($array as $element) { // Go through each element in the array
if ($element == $target) { // Check to see if any element there is what you are searching for
return true; // Return true, that it does exist, and stop there.
} else {
// Just ignore it...
}
}
return false; // If you get here, it means nothing returned true, so it does not exist...
}
To be used as if (exists($item['single']['catid'], $categories)) {.
It wouldn't work if it was "inside" the if statement because you have to do some processing before evaluating if it exists or not. So you either could have done that before the if statement, and store the result in a variable, or use a function (which PHP provides).
Hopefully the concept will help you fir more complex problems...
Note: this assumes your input is in the form of an array, which you can build via various ways, if not provided as is directly.
Update:
The input you get via the input field is sent through form, to which you specify either POST or GET as a method. Assuming it is POST that you are using, this is how you'd get the input as a string as it was entered in the text field:
$categories_string = $_POST['the_name_field_in_the_input_tag'];
After that you have to understand it as a list of items, let's say separated by commas: 1,3,5,8. Then this is simply separating by commas. You can use explode($delimiter, $string). Like that:
$categories_array = explode(',', $_POST['categories']);
But you cannot trust the input, so you could get something like 1, 2, 3,5,6. The spaces will mess it up, because you will have spaces all around. To remove them you can use trim for example.
$categories = array(); // Create the array in which the processed input will go
foreach ($categories_array as $c) { // Go through the unprocessed one
$categories[] = trim($c) * 1; // Process it, and fill the result. The times one is just so that you get numbers in the end and not strings...
}
Then you can use it as shown earlier, but keep in mind that this is just an example, and you might not even need all these steps, and there are much more efficient ways to process this input (regular expressions for example). But the concern here is not sanitizing input, but keep in mind you will need to do that eventually.
Hope it's clear enough :)
You might be better off with in_array() for checking a value against a variable number of possibilities.
I'm not sure I understand your problem. You want user to be able to input different values, e.g.:
$string = "5, 6, 7, 8, 10";
Afterwards, you want to check if 'catid' is not in that array and if it isn't you want to run $this->list_post($item);
If so, then you should use something like this:
$values = explode(", ", $string); //make array from values
foreach ($list['post'] as $item) {
if (!in_array($item['single']['catid'], $values)) { //check whether catid is in array
$this->list_post($item); // execute whatever you want
}
}
Hope it helps.

Building a tree from transversing an array in PHP

How to build a tree from an array in PHP knowing the rules that need to be followed to build the tree?
I don't have any particular place in the code where I can find what's really wrong
Anyway, the problems are probably related with the passing by reference I'm repeatedly using.
I did not use recursion because speed is really really important here. From the rules that the input array has (I have full control over them), this is possible, and faster, without recursion.
How it works:
As you transverse the array, each element's ['start_order'] is a bigger number than the previous ['start_order'].Every time that the next element's ['start_order'] is bigger than this element's ['start_order'] and the next element's ['end_order'] is smaller than this element's ['end_order'], then that element is a child of this element. After that step, I must find all the children of that element (the one I just found that it it this element's child).
Here's my code.
<?php
ksort($treeArray);
$tree = array();
$stack = array();
reset($treeArray);
$currentParent = &$treeArray[key($treeArray)];
$tree[] = &$treeArray[key($treeArray)];
while(next($treeArray) !== false){
if(current($treeArray)['start_order'] <= $currentParent['end_order']){
if(current($treeArray)['end_order'] <= $currentParent['end_order']){
// There's a child of the previous
// push the new parent
$stack[] = $currentParent;
if(!isset($currentParent['children'])){
$currentParent['children'] = array();
}
$currentParent['children'][] = &$treeArray[key($treeArray)];
$currentParent = current($treeArray);
}else{
// Supposed not to happen. Log the problem.
}
}else /* if(current($treeArray)['start_order'] > $currentParent['end_order']) */{
// Pop the child here, there are no more children.
if(($popedElement = array_pop($stack)) === NULL){
$tree[] = $currentParent;
}else{
$popedElement['children'][] = &$treeArray[key($treeArray)];
$stack[] = $popedElement;
$currentParent = current($treeArray);
}
}
}
?>
Example:
The input array of this can be something that structurally looks like this:
[1][child1][child1child1][child2][child2child1][child2child2][child2child3][2][child2child1]
which resolves into this tree:
[1]
[child1]
[child1child1]
[child2]
[child2child1]
[child2child2]
[child2child3]
[2]
[child2child1]
And don't forget that this order maintains. [child2child3] never appears before [child2child2], [2] never appears before [1]. In this analogy, is almost like when dealing with XML.
Found the problem here. The problem is related on how I treat the pass-by-reference while trying to solve this problem.
Here's the solution:
$tree[] = &$treeArray[key($treeArray)];
$currentParent = &$treeArray[key($treeArray)];
next($treeArray);
while(current($treeArray) !== false){
if(current($treeArray)['start_order']['start_position'] <= $currentParent['end_order']['end_order']){
if(current($treeArray)['end_order']['end_order'] <= $currentParent['end_order']['end_order']){
// There's a child of the previous
// push the new parent
$stack[] = &$currentParent;
$currentParent['children'][] = &$treeArray[key($treeArray)];
$currentParent = &$treeArray[key($treeArray)];
}else{
// Supposed not to happen. Log the problem.
}
next($treeArray);
}else /* if(current($treeArray)['start_order']['start_position'] > $currentParent['end_order']['end_order']) */{
// Close previous element here. There are no more children.
if(end($stack) === false){
$currentParent = &$treeArray[key($treeArray)];
$tree[] = &$treeArray[key($treeArray)];
next($treeArray);
}else{
$currentParent = &$stack[key($stack)];
unset($stack[key($stack)]);
}
}
}
The main problem was actually the pass-by-reference which is different in PHP than it is in C.
To solve this problem, I'm unable to use both push or pop php functions:
The push because the $var[] operator is faster and using that function.
The pop, because its return is a copy of what I had pushed before instead of the actual element I had pushed.
Additionally, all variable assignments have to be explicitly made by reference (using the & character), so using current() for assignment is out of the question, instead I need to use the key() function like I did.
I also had a small but important bug that forced me to change the "while" instruction. It now contains current() instead of next(). That's only because after the pop of the stack I mustn't move to the next element. I need to do another iteration before I move to the next one. This solves the bad nesting generated when there are multiple tags closing in the same place.
Please note that this code is not optimized for speed.

Categories