All answers to returntrue.win with explanations

Feb 15, 2018 · 2567 words · 13 minute read php

UPDATE Wednesday 30 May, 2018: Added answers to questions 12 through 16

A few days ago this website returntrue.win started to appear in my Twitter feed. It’s a website with a simple concept of supplying you with a PHP function and asks what value you should supply to that function to have it return true.

Additionally, the website shows the shortest answer given so far for each question, so there is an additional challenge to not only find a value that works, but also the shortest value that works. The point is not to pass a nice value, but to pass any value that works, all hacks allowed, and throwing an E_NOTICE is fine, as long as the final return value is true.

So let’s dive in.

Question 1

<?php

function foo($x)
{
    return $x;
}

This function will simply return any value you pass to it, also known as the identity function. So the first answer that comes to mind here is true. Entering that works, but will give you a score of 4 (since true is 4 characters) and the shortest answer to date is 2. So what consist of 2 characters and evaluates to true? The answer is !0. Basically ! will take the negated boolean value of its argument, and since the boolean value of 0 is false, the negation of 0 is true, and there is the shortest answer.

TL;DR !0

Question 2

<?php

function foo($x)
{
    return $x('gehr') === 'true';
}

Okay, so we need to pass it a function, that given gehr will return true. The most naive function that does this is function(){return'true';}. That passes but has a score of 25 while the best score to date is 9.

Since the string function(){} has 12 characters already we can exclude any answer with anonymous functions. Back to basics, what things are callable in PHP? Well, looking at the manual page on callables there are anonymous functions, invokable classes, arrays consisting of class instances/names and strings containing the name of a function. But if anonymous functions are too long, invokable classes will definitely be too long, and so will arrays referring to classes (especially because we would need to define a class first). So we are left with strings containing the name of a function.

So the question now becomes “Which built-in PHP function returns true given the input gehr?“. The answer can be found in the very basics of cryptography, namely a function that takes each character that and rotates it 13 places in the alphabet. The nice property of that function is that if you rotate it 13 places again you get the original string back. The PHP function for this is str_rot13, which indeed has 9 characters and is the shortest answer. This will emit an E_NOTICE, but as I said in the intro of this post, that’s okay.

TL;DR str_rot13

Question 3

<?php

function foo($x)
{
    return ($x >= 1) && ($x <= 1) && ($x !== 1);
}

Here we need to pass a value that, when evaluated as a number (due to non-strict comparisons), is greater than or equal to 1 and also less than or equal to one, and it must not be the integer 1.

Breaking this down, “greater than or equal to 1” and “less than or equal to one” can only be true at the same time if the value is exactly 1, since a value cannot be both bigger than 1 and smaller than 1 at the same time. Not even in PHP. So the question becomes, “What evaluates to 1 when treated as a number, but not the integer 1?”. First thing that comes to mind is true. Entering that shows that it’s correct, but has a score of 4, while the best score is 2. To get a score of 2 we can re-use our answer to question 1, !0. Alternatively 1., which will be interpreted as the float 1 also works.

TL;DR !0

Question 4

<?php

function foo($x)
{
    $a = 0;
    switch ($a) {
        case $x:
            return true;
        case 0:
            return false;
    }
    return false;
}

Not really sure why this one is in here, as it’s pretty trivial. What value must $x have to be equal to 0? Well, 0, duh.

TL;DR 0

Question 5

<?php

function foo($x)
{
    return strlen($x) === 4;
}

So here the question is “Which input has length of 4?”. A trivial answer would be ‘blah’, and that passes but has a score of 4, whole the shortest score is 1. Which is a rather weird. So we have to find a single character that has a length of 4.

Until you recall that strlen is blissfully unaware of character encoding (you’d need mb_strlen for that) and will return the number of bytes in the character you pass. So armed with this knowledge, the question becomes “What character consists of 4 bytes?” and the answer can be found in the 4 byte utf8 characters, for example this nice hamburger emoji: 🍔

TL;DR 🍔

Question 6

<?php

function foo($x)
{
    return $x === $x();
}

Hold on, what? We need a value that when invoked returns itself… How on earth do we do that? An anonymous function cannot return a reference to itself as far as I know, and there is no built-in PHP function that returns a reference to itself as far as I know, so that would leave an invokable class. That could work: new class{function __invoke(){return $this;}}. Yes, that does work, but the score is 45 and the lowest score is 22. At this point I was stumped for several hours until I couldn’t take it anymore and went to Google for answers.

I ended up finding the answer in this gist in a comment from Kacper Rowiński and was like “What? What on earth does this even do!?”. So is the answer they give is ($x=session_id)($x).$x. There is no way I can see what this does without breaking it down. So let’s break it down :)

The first part ($x=session_id) is assigning the string session_id to $x (while emitting an E_NOTICE, but that’s fine). What you then need to know is that an assignment returns the value that was assigned, so now that $x is set to “session_id” and we encounter ($x) PHP will interpret the string session_id as a function name and call it with argument $x, so basically it’s calling session_id('session_id'). This returns an empty string, since no session id was set in this request yet. Then we concatenate $x to that empty string (the last .$x bit) and end up with the string session_id. Okay, so ($x=session_id)($x).$x resolves to session_id and we pass the string session_id to our foo function.

What happens then is that PHP will call session_id again (the $x() part in the foo() function) and that will return session_id we set in it while evaluating ($x=session_id)($x).$x, so $x() returns session_id, and $x was already the string session_id so $x is indeed equal to $x() here. Wow.

UPDATE: Ramon de la Fuente pointer out on Twitter that you can actually create an anonymous function that returns a reference to itself: $x=function()use(&$x){return$x;}. Nice! :)

TL;DR ($x=session_id)($x).$x

Question 7

<?php

function foo(stdClass $x)
{
    $x = (array) $x;
    return $x[0];
}

Here we need to supply an instance of stdClass that when cast to an array has true in index 0. There are two ways (that I know of) to create a stdClass. First is to instantiate it explicitly, i.e., new stdClass() and the other one is casting an array to an object, i.e., (object)[]. The first way doesn’t seem plausible here, as we would still need a way to get a true value in that stdClass and we can’t do that in a parameter, so that leaves the second way, casting an array to an object. So the first attempt would be (object)[true], and indeed, that passes!

But is has a score of 14, and the best score so far is 12, so we need to shave of two characters. That trick we know from earlier questions, just use !0 instead of true. So the final answer is (object)[!0].

TL;DR (object)[!0]

Question 8

<?php

class Bar {}

function foo(Bar $x)
{
    return get_class($x) != 'Bar';
}

So we need to pass a value that is an instance of Bar, whose class name is not Bar. At first glance that seems to contradict itself, but once you realise that the type hint will also accept any class that extends Bar it’s actually rather simple: new class extends Bar{}. And that is also the shortest answer given so far with a score of 23.

TL;DR new class extends Bar{}

Question 9

<?php

function foo($x)
{
    $y = $x + 1;
    return ++$x != $y;
}

This one seems impossible at first. A value that when you add one is not the same as the value when you add one. For any given integer this will not succeed, so we need to look at another value.

The answer lies in the manual page on incrementing where it states “PHP follows Perl’s convention when dealing with arithmetic operations on character variables and not C’s. For example, in PHP and Perl $a = ‘Z’; $a++; turns $a into ‘AA’, while in C a = ‘Z’; a++; turns a into ‘[’ (ASCII value of ‘Z’ is 90, ASCII value of ‘[’ is 91).“. So basically what is says it that ++ applied to a will result in b (the next character in the ASCII table)! So the answer is a (without string quotes, which will trigger an E_NOTICE, but is valid and the shortest answer possible).

TL;DR a

Question 10

<?php

class Bar
{
    private $a;

    public function __construct($a)
    {
        $this->a = (bool) $a;
    }

    public function a()
    {
        return $this->a;
    }
}

function foo(callable $x)
{
    $object = new Bar(false);
    $x($object);
    return $object->a();
}

What we need to do here is make our callable modify $object in such a way that the private variable $a, which defaults to false, will become true.

My first instinct would be to use reflection, but since we can only pass one parameter that’s not really an option.

Then we can resort to a nasty trick that PHP doesn’t mind when you call a constructor on instantiated object: function($x){$x->__construct(1);} (we can pass 1 because the constructor casts to an boolean).

That passes, but has a score of 33 while the best score so far is 27. I couldn’t come up with the solution, but my colleague Daan van Renterghem came up with function(&$x){$x=new Bar(1);} which has a score of 29. It basically changes the variable $object to point to a new instance of Bar where $a is true. That was the best score yesterday, but it seems it can be even shorter.

Then I realized you can use new $x to create a new Bar when $x is an instance of Bar, so then you get function(&$x){$x=new $x(1);}. This also works and has a score of 28, still one higher than the best score. So I made a lucky guess that PHP will be able to separate new and $x when you remove the space and it somehow does :| So the final answer, for score 27, is function(&$x){$x=new$x(1);}. Not really sure why this works but it does. Probably the PHP tokenizer encounters the $ after new and will start a new token even though the space before the $ is missing.

TL;DR function(&$x){$x=new$x(1);}

Question 11

<?php

function foo(array $x)
{
    return $x[0] === null;
}

Here we need to pass an array which 0th element is null. The first attempt would be [null], but that has score 6 and the lowest possible score is 2, so it must be shorter. Of course, in an empty array, every index you request will issue an E_NOTICE (which we don’t care about in the context of this site) and return null, so the shortest answer is simply an empty array, [].

TL;DR []

Question 12

<?php

function foo($x)
{
    return $x[123456] !== null
        && $x[123456] === $x[123457];
}

The best score so far is 1, so the easiest answer to check is a, which in fact works! The reason this works is apperantly that any index of an undefined constant is empty string, i.e., var_dump(NON_EXISTENT_CONSTANT[123456]) outputs string(0) "". So indeed that is not equal to NULL, but "" is equal to "", so that works.

TL;DR a

Question 13

<?php

class Test
{
    private $foo = true;
}

function foo($x)
{
    $o = (array) new Test;
    return $o[$x];
}

Here you really need to know how PHP casts private properties of objects to an array. Var_dumping a new Test will show you it has a property Testfoo, but when you try to access it it will say there is no such property. The trick is there is two null bytes (hex 0x00) in the string that aren’t visible on screen, one before the class name and one before the property name, so it becomes "\0Test\0foo". Note you cannot omit the double quotes here because then it’s not a valid string.

TL;DR "\0Test\0foo"

Question 14

<?php

function foo($x)
{
    return is_object($x) && is_object($x());
}

So here we need to pass an object, that when invoked also return an object. One solution would be what’s stated above, the suggestion from Ramon de la Fuente: $x=function()use(&$x){return$x;}. And that works, but has a score of 32, while the best absolute score is 18. What also works is function(){return function(){};}, also with a score of 32. Another solution would be new class{function __invoke(){return$this;}}, but that has an worse score of 44.

After trying for a while (I even looped get_declared_classes to see of any of the builtin classes has an __invoke method, but none of them do) I went to google, but that wasn’t helping either. So even though I have several answers, they are not the shortest, and I haven’t the foggest where to look anymore.

So I just posted this post, and Taco van den Broek gave me the answer on Twitter. It is function(){yield;}, which indeed has a score of 18. And it’s correct because anonymous functions are represented by the Closure class in PHP, and yield returns a Generator class. Thanks again Taco :)

TL;DR function(){yield;}

Question 15

<?php

function foo($value)
{
    return $value != $value;
}

I’ve actually had this question before, so I already know the answer, which is NAN - Not a Number (same as Javascripts NaN). I’ve never actually encountered this in real life PHP applications, but it’s there, and it’s the only value that’s not equal to itself. Even if you use ===.

TL;DR NAN

Question 16

<?php

function foo($x)
{
    // This level is slightly different than level 12
    // the comparison is != instead of !== ;)
    return $x[123456] != null
        && $x[123456] === $x[123457];
}

Here you have you know how the array syntax works. What you normally see is arrays like [1=>1,2=>2,3=>3], but actually when you’ve specified a numeric key and then continue with an element without a key it will the take the key you’ve specified and add 1. So the array I just is exactly the same as [1=>1,2,3]. Once you realise that you quickly realise that the answer is [123456=>1,1], which is actually [123456=>1,123457=>1], and that returns true for this function.

TL;DR [123456=>1,1]

comments powered by Disqus