diff --git a/config.json b/config.json
index c452b416..15c5ce3f 100644
--- a/config.json
+++ b/config.json
@@ -1180,6 +1180,14 @@
         "prerequisites": [],
         "difficulty": 5
       },
+      {
+        "slug": "secret-handshake",
+        "name": "Secret Handshake",
+        "uuid": "c0721b15-5bfb-4a2e-92d3-b2e32c096810",
+        "practices": [],
+        "prerequisites": [],
+        "difficulty": 4
+      },
       {
         "slug": "circular-buffer",
         "name": "Circular Buffer",
diff --git a/exercises/practice/secret-handshake/.docs/instructions.md b/exercises/practice/secret-handshake/.docs/instructions.md
new file mode 100644
index 00000000..d2120b9b
--- /dev/null
+++ b/exercises/practice/secret-handshake/.docs/instructions.md
@@ -0,0 +1,48 @@
+# Instructions
+
+Your task is to convert a number between 1 and 31 to a sequence of actions in the secret handshake.
+
+The sequence of actions is chosen by looking at the rightmost five digits of the number once it's been converted to binary.
+Start at the right-most digit and move left.
+
+The actions for each number place are:
+
+```plaintext
+00001 = wink
+00010 = double blink
+00100 = close your eyes
+01000 = jump
+10000 = Reverse the order of the operations in the secret handshake.
+```
+
+Let's use the number `9` as an example:
+
+- 9 in binary is `1001`.
+- The digit that is farthest to the right is 1, so the first action is `wink`.
+- Going left, the next digit is 0, so there is no double-blink.
+- Going left again, the next digit is 0, so you leave your eyes open.
+- Going left again, the next digit is 1, so you jump.
+
+That was the last digit, so the final code is:
+
+```plaintext
+wink, jump
+```
+
+Given the number 26, which is `11010` in binary, we get the following actions:
+
+- double blink
+- jump
+- reverse actions
+
+The secret handshake for 26 is therefore:
+
+```plaintext
+jump, double blink
+```
+
+~~~~exercism/note
+If you aren't sure what binary is or how it works, check out [this binary tutorial][intro-to-binary].
+
+[intro-to-binary]: https://medium.com/basecs/bits-bytes-building-with-binary-13cb4289aafa
+~~~~
diff --git a/exercises/practice/secret-handshake/.docs/introduction.md b/exercises/practice/secret-handshake/.docs/introduction.md
new file mode 100644
index 00000000..176b92e8
--- /dev/null
+++ b/exercises/practice/secret-handshake/.docs/introduction.md
@@ -0,0 +1,7 @@
+# Introduction
+
+You are starting a secret coding club with some friends and friends-of-friends.
+Not everyone knows each other, so you and your friends have decided to create a secret handshake that you can use to recognize that someone is a member.
+You don't want anyone who isn't in the know to be able to crack the code.
+
+You've designed the code so that one person says a number between 1 and 31, and the other person turns it into a series of actions.
diff --git a/exercises/practice/secret-handshake/.meta/config.json b/exercises/practice/secret-handshake/.meta/config.json
new file mode 100644
index 00000000..a826a7d3
--- /dev/null
+++ b/exercises/practice/secret-handshake/.meta/config.json
@@ -0,0 +1,19 @@
+{
+  "authors": [
+    "tomasnorre"
+  ],
+  "files": {
+    "solution": [
+      "SecretHandshake.php"
+    ],
+    "test": [
+      "SecretHandshakeTest.php"
+    ],
+    "example": [
+      ".meta/example.php"
+    ]
+  },
+  "blurb": "Given a decimal number, convert it to the appropriate sequence of events for a secret handshake.",
+  "source": "Bert, in Mary Poppins",
+  "source_url": "https://www.imdb.com/title/tt0058331/quotes/?item=qt0437047"
+}
diff --git a/exercises/practice/secret-handshake/.meta/example.php b/exercises/practice/secret-handshake/.meta/example.php
new file mode 100644
index 00000000..322679b7
--- /dev/null
+++ b/exercises/practice/secret-handshake/.meta/example.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+class SecretHandshake
+{
+    public function commands(int $handshake): array
+    {
+        $handshakeCommands = ['wink', 'double blink', 'close your eyes', 'jump'];
+        $shakeWith = [];
+
+        for ($i = 0; $i < 4; $i++) {
+            if ($handshake & (2 ** $i)) {
+                $shakeWith[] = $handshakeCommands[$i];
+            }
+        }
+
+        if ($handshake & (2 ** 4)) {
+            $shakeWith = array_reverse($shakeWith);
+        }
+
+        return $shakeWith;
+    }
+}
diff --git a/exercises/practice/secret-handshake/.meta/tests.toml b/exercises/practice/secret-handshake/.meta/tests.toml
new file mode 100644
index 00000000..f318e528
--- /dev/null
+++ b/exercises/practice/secret-handshake/.meta/tests.toml
@@ -0,0 +1,43 @@
+# This is an auto-generated file.
+#
+# Regenerating this file via `configlet sync` will:
+# - Recreate every `description` key/value pair
+# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
+# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
+# - Preserve any other key/value pair
+#
+# As user-added comments (using the # character) will be removed when this file
+# is regenerated, comments can be added via a `comment` key.
+
+[b8496fbd-6778-468c-8054-648d03c4bb23]
+description = "wink for 1"
+
+[83ec6c58-81a9-4fd1-bfaf-0160514fc0e3]
+description = "double blink for 10"
+
+[0e20e466-3519-4134-8082-5639d85fef71]
+description = "close your eyes for 100"
+
+[b339ddbb-88b7-4b7d-9b19-4134030d9ac0]
+description = "jump for 1000"
+
+[40499fb4-e60c-43d7-8b98-0de3ca44e0eb]
+description = "combine two actions"
+
+[9730cdd5-ef27-494b-afd3-5c91ad6c3d9d]
+description = "reverse two actions"
+
+[0b828205-51ca-45cd-90d5-f2506013f25f]
+description = "reversing one action gives the same action"
+
+[9949e2ac-6c9c-4330-b685-2089ab28b05f]
+description = "reversing no actions still gives no actions"
+
+[23fdca98-676b-4848-970d-cfed7be39f81]
+description = "all possible actions"
+
+[ae8fe006-d910-4d6f-be00-54b7c3799e79]
+description = "reverse all possible actions"
+
+[3d36da37-b31f-4cdb-a396-d93a2ee1c4a5]
+description = "do nothing for zero"
diff --git a/exercises/practice/secret-handshake/SecretHandshake.php b/exercises/practice/secret-handshake/SecretHandshake.php
new file mode 100644
index 00000000..67ef675a
--- /dev/null
+++ b/exercises/practice/secret-handshake/SecretHandshake.php
@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * By adding type hints and enabling strict type checking, code can become
+ * easier to read, self-documenting and reduce the number of potential bugs.
+ * By default, type declarations are non-strict, which means they will attempt
+ * to change the original type to match the type specified by the
+ * type-declaration.
+ *
+ * In other words, if you pass a string to a function requiring a float,
+ * it will attempt to convert the string value to a float.
+ *
+ * To enable strict mode, a single declare directive must be placed at the top
+ * of the file.
+ * This means that the strictness of typing is configured on a per-file basis.
+ * This directive not only affects the type declarations of parameters, but also
+ * a function's return type.
+ *
+ * For more info review the Concept on strict type checking in the PHP track
+ * <link>.
+ *
+ * To disable strict typing, comment out the directive below.
+ */
+
+declare(strict_types=1);
+
+class SecretHandshake
+{
+    public function commands(int $handshake): array
+    {
+        throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__));
+    }
+}
diff --git a/exercises/practice/secret-handshake/SecretHandshakeTest.php b/exercises/practice/secret-handshake/SecretHandshakeTest.php
new file mode 100644
index 00000000..91b32c8c
--- /dev/null
+++ b/exercises/practice/secret-handshake/SecretHandshakeTest.php
@@ -0,0 +1,112 @@
+<?php
+
+declare(strict_types=1);
+
+class SecretHandshakeTest extends PHPUnit\Framework\TestCase
+{
+    private SecretHandshake $secretHandshake;
+
+    public static function setUpBeforeClass(): void
+    {
+        require_once 'SecretHandshake.php';
+    }
+
+    public function setUp(): void
+    {
+        $this->secretHandshake = new SecretHandshake();
+    }
+
+    /**
+     * uuid: b8496fbd-6778-468c-8054-648d03c4bb23
+     */
+    public function testWinkForOne(): void
+    {
+        $this->assertEquals(['wink'], $this->secretHandshake->commands(1));
+    }
+
+    /**
+     * uuid: 83ec6c58-81a9-4fd1-bfaf-0160514fc0e3
+     */
+    public function testDoubleBlinkForTen(): void
+    {
+        $this->assertEquals(['double blink'], $this->secretHandshake->commands(0b0_0010));
+    }
+
+    /**
+     * uuid: 0e20e466-3519-4134-8082-5639d85fef71
+     */
+    public function testCloseYourEyesForHundred(): void
+    {
+        $this->assertEquals(['close your eyes'], $this->secretHandshake->commands(0b100));
+    }
+
+    /**
+     * uuid: b339ddbb-88b7-4b7d-9b19-4134030d9ac0
+     */
+    public function testJumpForThousand(): void
+    {
+        $this->assertEquals(['jump'], $this->secretHandshake->commands(8));
+    }
+
+    /**
+     * uuid: 40499fb4-e60c-43d7-8b98-0de3ca44e0eb
+     */
+    public function testCombineTwoActions(): void
+    {
+        $this->assertEquals(['wink', 'double blink'], $this->secretHandshake->commands(3));
+    }
+
+    /**
+     * uuid: 9730cdd5-ef27-494b-afd3-5c91ad6c3d9d
+     */
+    public function testReverseTwoActions(): void
+    {
+        $this->assertEquals(['double blink', 'wink'], $this->secretHandshake->commands(0b10011));
+    }
+
+    /**
+     * uuid: 0b828205-51ca-45cd-90d5-f2506013f25f
+     */
+    public function testReversingOneActionGivesTheSameAction(): void
+    {
+        $this->assertEquals(['jump'], $this->secretHandshake->commands(24));
+    }
+
+    /**
+     * uuid: 9949e2ac-6c9c-4330-b685-2089ab28b05f
+     */
+    public function testReversingNoActionsStillGivesNoActions(): void
+    {
+        $this->assertEquals([], $this->secretHandshake->commands(16));
+    }
+
+    /**
+     * uuid: 23fdca98-676b-4848-970d-cfed7be39f81
+     */
+    public function testAllPossibleActions(): void
+    {
+        $this->assertEquals(
+            ['wink', 'double blink', 'close your eyes', 'jump'],
+            $this->secretHandshake->commands(15)
+        );
+    }
+
+    /**
+     * uuid: ae8fe006-d910-4d6f-be00-54b7c3799e79
+     */
+    public function testReverseAllPossibleActions(): void
+    {
+        $this->assertEquals(
+            ['jump', 'close your eyes', 'double blink', 'wink'],
+            $this->secretHandshake->commands(31)
+        );
+    }
+
+    /**
+     * uuid: 3d36da37-b31f-4cdb-a396-d93a2ee1c4a5
+     */
+    public function testDoNothingForZero(): void
+    {
+        $this->assertEquals([], $this->secretHandshake->commands(0b0));
+    }
+}