I have created a Quine relay involving PHP, Go, and Python, and I’m here to explain how it works.
This is the code for QuineRelay.php:
<?=eval($_='print "package main;import\42fmt\42;func main(){fmt.Print(\140print(r\47\47\47<?=eval(\44_=\47$_\47);\47\47\47)\140)}";');
Yes, it probably looks like total nonsense. I will explain it step by step.
Now, you can see many things like \42. In PHP, inside double quotes, these are treated as octal ASCII codes and converted into characters.
For example, a double quote is ASCII code 34, which is 42 in octal.
Therefore, \42 will be a double quote.
I have created a conversion table below:
| Octal | ASCII Code | Character |
|---|---|---|
| 42 | 34 | " (Double Quote) |
| 47 | 39 | ' (Single Quote) |
| 140 | 96 | Backtick |
(I couldn't put the actual backtick in the table without breaking the markdown 😅)
The advantage of using this octal notation is that these characters do not need to be escaped when they are included in Go or Python strings.
The difficult part of a Quine is how to handle characters like double quotes or single quotes that require escaping when they appear within a string, but by using octal notation, the need for escaping is eliminated.
Now, notice that the variable $_ is declared as an argument for the eval function at the beginning.
Let's look at the content of variable $_. Since $_ is enclosed in single quotes, the octal notation is treated literally as backslashes and numbers.
// inside $_
print "package main;import\42fmt\42;func main(){fmt.Print(\140print(r\47\47\47<?=eval(\44_=\47$_\47);\47\47\47)\140)}";
This code is then eval'ed. Since the string passed to print is enclosed in double quotes, the conversion from octal to ASCII occurs this time.
Also, $_ appears toward the end within the double quotes. In PHP, variable names inside double quotes are expanded with the value, so the second $_ will be expanded as the actual content of the variable.
The expansion of this $_ is the key trick to this Quine.
Running this PHP code outputs the following Go code:
package main;import"fmt";func main(){fmt.Print(`print(r'''<?=eval($_='print "package main;import\42fmt\42;func main(){fmt.Print(\140print(r\47\47\47<?=eval(\44_=\47$_\47);\47\47\47)\140)}";');''')`)}
Since escaping line breaks is difficult, I used semicolons to make it a one-liner of Go (When you write Go, you don't usually use semicolons at the end of statements, but Go compiler apparently adds them. Here I add semicolons manually to achieve the one-liner).
Also, by using backticks for the string, I can include single and double quotes within the string.
Running this Go code outputs the following Python code:
print(r'''<?=eval($_='print "package main;import\42fmt\42;func main(){fmt.Print(\140print(r\47\47\47<?=eval(\44_=\47$_\47);\47\47\47)\140)}";');''')
It is relatively straightforward, but by using ''', I can use single quotes within the string, and by using r''', I avoid the conversion from octal to ASCII.
Running this Python code brings us back to the original PHP.
<?=eval($_='print "package main;import\42fmt\42;func main(){fmt.Print(\140print(r\47\47\47<?=eval(\44_=\47$_\47);\47\47\47)\140)}";');
Summary
I thought a three-language Quine relay would be very difficult, but once I started writing it, it turned out to be simpler than expected.
I hope this article helps you read/write more quines 🙂
Top comments (0)