Awkward comparison of functions in PHP - php

So I've got this snippet:
function compare1($s1, $s2)
{
return $s1===$s2;
}
function compare2($s1, $s2)
{
return !strcmp($s1, $s2);
}
function challenge($s1, $s2) //Objective: return TRUE
{
return compare1($s1, $s2) ^ compare2($s1, $s2);
}
What's requested from me is to supply/append/assign values to the $s1 and $s2 variables so as for the last function to return TRUE.
I've tried nearly everything I could think of, like $s1='1' and $s2=1 which does return TRUE:
var_dump(compare1('1', 1) ^ compare2('1', 1)); //output: int 1
Creator of the challenge told me that I shouldn't or rather can't assign integer values to the variables but issue is that no boolean variations worked. Here is the website I'm talking about so as you can see if you could possibly come up with a solution: http://securitytraps.no-ip.org/challs/strcmp/
Thanks in advance :)

How about
$s1= null;
$s2 = "";
This does not work on the tool provided but works from the command line.
also
$s1 = "";
$s2 = false;

Ok so the first give away is that the site is a security trap site so they are looking to show you vulnerabilities in PHP. So while the other answers are valid they don't work when being passed over the internet.
To solve the challenge you actually have to modify the HTML on the page and turn one of the keys into an array like: <input name="s2[]" value="s2" /> and then submit the form. When that happens the strcmp will compare $_POST['s1'] (string) with $_POST['s2'] (array) causing PHP to evaluate the strcmp as true!

Related

php recursive function in class

This function works fine outside of a class. Ie simply define the function and call it. Yet when I add it to a class it no longer works - any help is greatly appreciated:
public function recursive_array_search($needle,$haystack) {
foreach($haystack as $key=>$value) {
$current_key=$key;
if($needle===$value || (is_array($value) && $this->recursive_array_search($needle,$value) !== false)) {
return $current_key;
}
}
return false;
}
obviously the $this is removed when not in a class.
Edit:
The error I an getting when using it in a class is:
Invalid argument supplied for foreach()
app\components\GenFun::recursive_array_search('9377907', 9378390)
My sole expectation from the function is that it returns any key (ie identifies that the needle exists in the haystack) - I actually dont care about the actual index.
To be perfectly honest, "it no longer works" isn't a helpful metric by which to assist you in debugging your problem. Nor is "it works fine", since that doesn't tell us your definition of what works means to you. More precisely, these statements don't tell us what you expected the code to do that it's not doing, or what the code is doing that you did not expect.
To me this code is doing exactly what you've told it to do and the result of both a function as well as a class method (using the same code) are identical... See the working 3v4l pastebin here.
However, my guess is that your expectations may be different from what this code actually does. Specifically, this function will return at the very first match of the $needle in the $haystack. Such that the following array, returns 0 (_that is with a needle of 'foo').
$haystack = ['foo', ['foo', 'bar']];
It will also return only the key of the outer-most array in the $haystack. Meaning, the following array returns 0 as the key. Even though the actual match is in $haystack[0][1][2]
$haystack = [['bar',['quix','baz','foo'],'baz'],'quix'];
So depending on what you expected (the inner-most key, or the outer-most key), you may believe this function doesn't work.
So you'll need to clarify exactly what you want the code to do and provide some reproducible example of what didn't work (and that includes the data used or arguments provided to the function).
EDIT:
Hey, I'm glad you figured it out. Here are just a few suggestions to maybe help you refactor this code slightly as well...
So since you're looking for the existence of the needle in any part of the array and don't actually care about the key, you may want to make your intent more obvious in the logic.
So for example, always return a boolean (true on success and false on failure) rather than return false on failure and the key on success. This makes checking the function's result easier and clearer from the caller's perspective. Also, consider naming the function to describe it's intent more clearly (for example: in_array_recursive rather than recursive_array_search since we're not actually intent on searching the array for something, but proving that something is actually in the array). Finally, consider avoiding multiple return points in the same function as this makes debugging harder.
So a cleaner way to write the same code might be something like this:
public function in_array_recursive($needle, $haystack, $strict = false) {
$result = false;
foreach($haystack as $value) {
if(!is_array($value)) {
$result = $strict ? $needle === $value : $needle == $value;
} else {
$result = $this->in_array_recursive($needle, $value, $strict);
}
if ($result) {
break;
}
}
return $result;
}
Now the caller simply does...
$arr = ['bar',['foo']];
if (in_array_recursive('foo', $arr)) {
/* 'foo' is in $arr! */
} else {
/* 'foo' is not in $arr... */
}
Making the code more readable and easier to debug. Notice you also don't have to use exact match if you wanted to add an optional argument for $strict at the end of the function there and also be more inline with in_array.
So the reason this was not working was due to the method by which I was defining $needle.
In my old code it would be input as an integer and in my new code it was a string. The === operator then obviously denied it as being the same. This is why you don't work at 2am :)

How to check if variable was passed by reference in PHP

Straightforward:
I want to write some code which tells if a variable was passed by reference or not.
For example:
<?php
function isReference($variable) {
//return TRUE if &$something was passed
//return FALSE if $something was passed
}
$text = 'Anything';
$a = isReference(&$text); //return TRUE
$b = isReference($test); //return FALSE
?>
For those who are curious - why do I need it?
Firstly I do not like to leave problems unsolved.
Secondly, I am currently enhancing by skills by writing an extension to mysqli, which would prepare statements similar to how PDO does. If anybody knows the difference between bindParam and bindValue in PDO, they know that it's a workaround of this question. I can just make two functions, but I wonder if it's possible with one.
Thanks in advance.
Here's a way to do it without using the debug_zval_dump function:
function isReference($variable) {
$variable = array($variable);
$arg = func_get_arg(0);
$isRef = isset($arg[0]) && $arg === array($variable[0]);
$variable = $variable[0];
return $isRef;
}
Note: there is only a single case when this will not work:
$text = array(&$text); // although i don't see why such a structure could be used
isReference($text); // will wrongly return false
Obviously you can bypass this limitation by using a random unique key (instead of 0).
You can use debug_zval_dump to dump a string representation of an internal zend value to output:
function isRef(&$val) {
ob_start();
debug_zval_dump(&$val);
$ret = ob_get_clean();
preg_match('~refcount\((\d+)\)~', $ret, $matches);
return $matches[1] - 4;
}
$var1 = 'Var1';
$var2 = &$var1; // passed by ref
if(isRef($var2)) echo 'Passed by ref';
But be aware of PHP - 5.4.
Simply checking for the default value seems to work fine in my tests. Obviously it wont work if $t is already set to 'x' but you could change the default value to something totally unlikely to workaround this:
function test(&$t='x'){
if($t!='x') $t = 2;
}
test(); echo $t; //outputs: null
test($t); echo $t; //outputs: 2

Why doesn't my code to test an email address against a specific domain work?

I wanted to allow only specific email domain. Actually I did it. What i wanted to ask why my first code did not work at all.
I am just trying to learn PHP so that the question may seem silly, sorry for that.
Here is my code:
function check_email_address($email) {
$checkmail = print_r (explode("#",$email));
$container = $checkmail[1];
if(strcmp($container, "gmail.com")) {
return true;
}else {
return false;
}
}
Check out the documentation for strcmp() , it will return 0 of the two strings are the same, so that's the check you want to be doing. Also, you're using print_r() when you shouldn't be, as mentioned by the other answerers.
Anyway, here's how I would have done the function - it's much simpler and uses only one line of code:
function check_email_address($email) {
return (strtolower(strstr($email, '#')) == 'gmail.com');
}
It uses the strstr() function and the strtolower() function to get the domain name and change it to lower case, and then it checks if it is gmail.com or not. It then returns the result of that comparison.
It's because you're using print_r. It doesn't do what you seem to expect from it at all. Remove it:
$checkmail = explode("#", $email);
You can find the docs about print_r here:
http://php.net/print_r
Besides that, you can just use the following (it's much shorter):
$parts = explode("#", $email);
return (strcmp($parts[1], "gmail.com") == 0);
The following row doesn't work as you think it does:
$checkmail = print_r (explode("#",$email));
This means that you're trying to assign the return value from print_r() into $checkmail, but it doesn't actually return anything (if you don't supply the second, optional parameter with the value true).
Even then, it would've gotten a string containing the array structure, and your $container would have taken the value r, as it's the second letter in Array.
Bottom line: if your row would've been without the call to print_r(), it would've been working as planned (as long as you made sure to compare the strcmp() versus 0, as it means that the strings are identical).
Edit:
Interesting enough, I just realized that this could be achieved with the use of substr() too:
<?php
//Did we find #gmail.com at the end?
if( strtolower(substr($email, -10)) == '#gmail.com' ) {
//Do something since it's an gmail.com-address
} else {
//Error handling here
}
?>
You want:
if(strcmp($container, "gmail.com")==0)
instead of
if(strcmp($container, "gmail.com"))
Oh! And no inlined print_r() of course.
Even better:
return strcmp($container, "gmail.com")==0;
No need for the print_r; explode returns a list. And in terms of style (at least, my style) no need to assign the Nth element of that list to another variable unless you intend to use it a lot elsewhere. Thus,
$c = explode('#',$mail);
if(strcmp($c[1],'gmail.com') == 0) return true;
return false;

Strange PHP string error

This is a very very weird bug that happens randomly. So I will try to explain this as best as I can. I'm trying to diminish the code substantially to pinpoint the problem without having to reference a framework, nor deal with 500 lines of code outside of the framework - so I will try and come back and update this question when I do. OK, so here we go.
So basically say I'm taking a string in a function and preg_replace like so:
$table = '/something';
print $table;
$table = preg_replace("#^(/)#",'prefix_',$table);
print $table;
The output will look something like
...
/something - prefix_something
/something - prefix_something
/something - /something
You have an error in you sql query... blah blah somewhere around SELECT * FROM /something
What happens is that after rolling through the code, this simply stops working and the sql errors out. What's more strange is that if I start commenting out code outside the function it then works. I put that code back in, it breaks.
I tried recoding this by substr($var,0,1) and var_dumping the variable. After a few rounds it returns a bool(false) value even though $var is in fact a string. It's very very strange. Has anybody run into this before? Is this a PHP bug? It's looking like it to me.
-- EDIT --
Example:
foreach ( $user as $id => $user ) {
get_data("/table_name","*", "user_id = '$id'");
}
#in the function $_table_ holds "/table_name"
$_table_ = trim($_table_);
$tmp = explode(',', $_table_);
$tables = array();
foreach ($tmp as $c => $n) {
$n = trim($n);
$a = substr($n, 0, 1);
$b = substr($n, 1);
if ($a == false) {
var_dump($n);
$a = substr($n, 0, 1);
var_dump($b);
var_dump($a);
}
if ($a == '/') { etc...
Output:
string(11) "/table_name" string(10) "table_name" bool(false)
If I switch to the original preg_replace functionality, it simply does not preg_replace and the same thing happens "/table_name" is return rather then "prefix_table_name" and this happens randomly. Meaning it will work on the string it broke on if I comment code out outside of the function that is seemingly unrelated.
--- SOLUTION ----
I found out that it has to do with string to array conversion in another function that caused this strange error.
Basically a function was expecting a null or array() value and instead a number was passed. We have notices turned off, so I turned them on and started fixing all the notices and warnings and that's how I found this strange bug. Now exactly what the inner workings are that created the problem is unknown to me. However I can define the symptom as a string assignment problem that would occur at some other place in the code which we caught when it wouldn't reassign the $table variable with the new preg_replace value which is detailed above. Now you know. The function looks something similar to this:
function format_something($one, $two, $three = array()){
if ($three['something'] == 'Y') {
/** etc... */
}
...
format_something('one','two',3);
After a while in a loop this type of conversion started having problems randomly in the code.
substr doesn't always return a string. If it can't find the substring, it returns false.
Return Values
Returns the extracted part of string, or FALSE on failure or an empty string.
You should test for this condition and var_dump the string you are searching to see what it contains in such cases.

Using reference to nonexistent value sets variable to NULL?

When passing a non-existent value by reference, PHP creates the value and sets it to NULL. I noticed it when memory increases were occurring while checking empty values in some functions. Take the following function:
function v(&$v,$d=NULL){return isset($v)?$v:$d;}
$bar = v($foo, $default);
This would be shorthand for:
if(isset($foo))
{
$bar = $foo;
}
else
{
$bar = $default;
}
However, when passing non-existent variables PHP creates them. In the case of variables - they are removed as soon as the method/function ends - but for checking super global arrays like $_GET or $_POST the array element is never removed causing extra memory usage.
$request_with = v($_SERVER['HTTP_X_REQUESTED_WITH']);
Can anyone explain why this happens and if it is a PHP todo fix or a feature for some other crazy use of values?
XeonCross' function v is a shorthand for the often used:
$val= isset($arr['elm']) ? $arr['elm'] : 'default'
to avoid the dreaded 'Undefined index: elm' notice. A nice helper function would be:
function ifset(&$v1, $v2 = null) {
return isset($v1) ? $v1 : $v2;
}
as Xeoncross suggested, so you could write the much nicer
$val = ifset($arr['elm'],'default')
however, this has a lot of interesting (?) quirks in our beloved "language" that we call PHP:
inside the function ifset, $v1 seems UNSET, so it correctly returns the value $v2 and you might conclude that ifset works ok. But afterwards $arr['elm'] is silently set to NULL. So consider the following:
function wtf(&$v) {
if (isset($v))
echo "It is set";
else
echo "It is NOT set";
}
$p=[];
wtf($p['notexist']); => It is NOT set
$p; => [ 'notexist' => NULL ]
But this is another delusion, as the isset() function returns false for NULL values as well:
$x=NULL;
isset($x) => false... huh??
Did we expect this? well.. it is in the documentation, so this is by design as well. Welcome to the wonderful world of php.
The reason you have the memory leak, is because you're telling it to.
When you ask for a reference parameter, PHP will provide you with one. When you are calling a function with an unset variable, PHP will set the variable and then pass the reference to that new variable. When you call it with a superglobal, it creates the missing index. That's because you told it to.
However, I must ask why specifically do you need variable references? 99.9% of the time you don't really need them. I suspect that it'll work just fine to do:
function v($v, $d = null) { return isset($v) ? $v : $d; }
Or, if you really must use references (which you can't get around your original problem with), you should also return a reference:
function &v(&$v, $d = null) {
if (isset($v)) {
return $v;
}
return $d;
}
Otherwise it's pointless to take a reference and not return one...

Categories