This PHP exercise models a path rooted at / without touching the real filesystem. cd() appends a relative path, validates the allowed segment names, and removes name/.. pairs; the PHPUnit cases cover root handling, ordinary traversal, and attempts to escape above the root.
That distinction is important: this is lexical normalization, not a filesystem sandbox. It does not resolve symbolic links or prove that a later filesystem operation stays beneath a trusted directory. The implementation also accepts only ASCII letters as directory names, so its rules are intentionally narrower than normal POSIX path semantics.
<?php
declare ( strict_types = 1 );
namespace Task_1\Exceptions ;
use Exception ;
use Throwable ;
class IllegalNameException extends Exception
{
private const MESSAGE = 'Directory names consist only of English alphabet letters' ;
public function __construct ( string $message = "" , int $code = 0 , ?Throwable $previous = null )
{
$message = self :: MESSAGE . ': ' . $message ;
parent :: __construct ( $message , $code , $previous );
}
}
<?php
declare ( strict_types = 1 );
namespace Task_1\Exceptions ;
use Exception ;
use Throwable ;
class InvalidRootException extends Exception
{
private const MESSAGE = 'Root must be /' ;
public function __construct ( string $message = "" , int $code = 0 , ?Throwable $previous = null )
{
$message = self :: MESSAGE . ': ' . $message ;
parent :: __construct ( $message , $code , $previous );
}
}
<?php
declare ( strict_types = 1 );
namespace Task_1 ;
interface FilesystemAdapter
{
public function cd ( string $path ): void ;
public function getCurrentPath (): string ;
}
<?php
declare ( strict_types = 1 );
namespace Task_1 ;
use Task_1\Exceptions\IllegalNameException ;
use Task_1\Exceptions\InvalidRootException ;
class Path implements FilesystemAdapter
{
private string $currentPath ;
private string $nextPath ;
public function __construct ( string $path = '' )
{
$this -> cd ( $path );
}
/**
* Change the current path of the class.
*
* Normalize the path in order to remove the "traverse to parent directory" characters.
* Validates the given path for correctness (with basic regexes).
*
* @param string $path
* @return void
* @throws IllegalNameException
* @throws InvalidRootException
*/
public function cd ( string $path ): void
{
$this -> nextPath = $this -> getCurrentPath () . '/' . $this -> normalizeSlashes ( $path );
$this -> validateNextPath ();
$this -> normalizeNextPath ();
$this -> validateNormalizedPath ();
$this -> currentPath = $this -> nextPath ;
}
public function getCurrentPath (): string
{
return $this -> currentPath ?? '' ;
}
private function validateNextPath (): void
{
if ( $this -> nextPath === '/' ) {
return ;
}
if ( ! str_starts_with ( $this -> nextPath , '/' )) {
throw new InvalidRootException ( $this -> nextPath );
}
if ( preg_match ( '/^(\/([A-Za-z]+|\.\.))+\/?$/' , $this -> nextPath ) !== 1 ) {
throw new IllegalNameException ( $this -> nextPath );
}
}
private function validateNormalizedPath (): void
{
if ( $this -> nextPath === '/' ) {
return ;
}
if ( ! str_starts_with ( $this -> nextPath , '/' )) {
throw new InvalidRootException ( $this -> nextPath );
}
if ( preg_match ( '/^(\/[A-Za-z]+)+$/' , $this -> nextPath ) !== 1 ) {
throw new IllegalNameException ( $this -> nextPath );
}
}
private function normalizeNextPath (): void
{
$count = 0 ;
$this -> nextPath = preg_replace ( '/\/[A-Za-z]+\/\.\./' , '' , $this -> nextPath , 1 , $count );
if ( $this -> nextPath === '' ) {
$this -> nextPath = '/' ;
}
if ( $count !== 0 ) {
$this -> normalizeNextPath ();
}
}
private function normalizeSlashes ( string $path ): string
{
return ltrim ( rtrim ( $path , '/' ), '/' );
}
}
<?php
namespace Task_1 ;
use PHPUnit\Framework\TestCase ;
class PathTest extends TestCase
{
public function testGiven (): void
{
$path = new Path ( '/a/b/c/d' );
$path -> cd ( '../x' );
$this -> assertEquals ( '/a/b/c/x' , $path -> getCurrentPath ());
}
public function testRoot (): void
{
$path = new Path ();
$this -> assertEquals ( '/' , $path -> getCurrentPath ());
$path = new Path ( '' );
$this -> assertEquals ( '/' , $path -> getCurrentPath ());
$path = new Path ( '/' );
$this -> assertEquals ( '/' , $path -> getCurrentPath ());
}
public function testEscape (): void
{
$this -> expectException ( 'Task_1\Exceptions\IllegalNameException' );
new Path ( '/../../' );
}
public function testMultipleTraversals (): void
{
$path = new Path ( '/aa/bb/../cc/' );
$path -> cd ( '../xx/dd/' );
$this -> assertEquals ( '/aa/xx/dd' , $path -> getCurrentPath ());
}
}
ๆฅไปไธๆ - tgragnato.it - Tommaso Gragnato - Homepage
06-06-2026 - Tactical Macro Derisking - Systematic risk analysis and asset allocation ๐ฌ๐ง
12-08-2025 - Factor ETF Portfolio - Smart-beta investing the European way ๐ฌ๐ง
11-05-2025 - ัะตะผะฟะตัะฐ ะฝะฐ ะฑัะผะฐะณะต - ัะตะผะฟะตัะฝะฐั ะถะธะฒะพะฟะธัั - tempera on paper - tempera painting, tempera su carta - pittura a tempera, ็ดใซๆใใใใใณใใฉ - ใใณใใฉ็ป ๐ท๐บ
10-05-2025 - Allineamento Strategico - Grande parte del successo nella gestione di un buon team sta nella selezione. Scegli le persone giuste! ๐ฎ๐น
21-03-2025 - Open Source Day 2025 - For Who Loves Open Source ๐ฌ๐ง
23-02-2025 - Mitigations for the NoName057(16) DDoSia Project - Understanding the attack methodology and the source infrastructure to implement cost-effective mitigations ๐ฌ๐ง
19-02-2025 - HAProxy Stream Processing Offload Engine - Blind testing & Performance Benchmark ๐ฎ๐น
25-12-2024 - Code Chronicle - Advent of Code 2024 [Day 25] ๐ฌ๐ง
24-12-2024 - Crossed Wires - Advent of Code 2024 [Day 24] ๐ฌ๐ง
23-12-2024 - LAN Party - Advent of Code 2024 [Day 23] ๐ฌ๐ง
22-12-2024 - Monkey Market - Advent of Code 2024 [Day 22] ๐ฌ๐ง
21-12-2024 - Keypad Conundrum - Advent of Code 2024 [Day 21] ๐ฌ๐ง
20-12-2024 - Race Condition - Advent of Code 2024 [Day 20] ๐ฌ๐ง
19-12-2024 - Linen Layout - Advent of Code 2024 [Day 19] ๐ฌ๐ง
18-12-2024 - RAM Run - Advent of Code 2024 [Day 18] ๐ฌ๐ง
17-12-2024 - Chronospatial Computer - Advent of Code 2024 [Day 17] ๐ฌ๐ง
16-12-2024 - Reindeer Maze - Advent of Code 2024 [Day 16] ๐ฌ๐ง
15-12-2024 - Warehouse Woes - Advent of Code 2024 [Day 15] ๐ฌ๐ง
14-12-2024 - Restroom Redoubt - Advent of Code 2024 [Day 14] ๐ฌ๐ง
13-12-2024 - Claw Contraption - Advent of Code 2024 [Day 13] ๐ฌ๐ง
12-12-2024 - Garden Groups - Advent of Code 2024 [Day 12] ๐ฌ๐ง
11-12-2024 - Plutonian Pebbles - Advent of Code 2024 [Day 11] ๐ฌ๐ง
10-12-2024 - Hoof It - Advent of Code 2024 [Day 10] ๐ฌ๐ง
09-12-2024 - Disk Fragmenter - Advent of Code 2024 [Day 9] ๐ฌ๐ง
08-12-2024 - Resonant Collinearity - Advent of Code 2024 [Day 8] ๐ฌ๐ง
07-12-2024 - Bridge Repair - Advent of Code 2024 [Day 7] ๐ฌ๐ง
06-12-2024 - Guard Gallivant - Advent of Code 2024 [Day 6] ๐ฌ๐ง
05-12-2024 - Print Queue - Advent of Code 2024 [Day 5] ๐ฌ๐ง
04-12-2024 - Ceres Search - Advent of Code 2024 [Day 4] ๐ฌ๐ง
03-12-2024 - Mull It Over - Advent of Code 2024 [Day 3] ๐ฌ๐ง
02-12-2024 - Red-Nosed Reports - Advent of Code 2024 [Day 2] ๐ฌ๐ง
01-12-2024 - Historian Hysteria - Advent of Code 2024 [Day 1] ๐ฌ๐ง
31-10-2024 - USENIX SREcon24 Europe/Middle East/Africa - 29-31 Oct 2024 The Convention Centre Dublin ๐ฌ๐ง
20-10-2024 - The Innovation Paradox: Why Tech Revolutionaries Must Embrace Risk - The dichotomy that exists between genius and the solitude of failure ๐ฌ๐ง
08-09-2024 - US Covert Communications - Channels uncovered by the counter intelligence of Iran, Russia and China ๐ฌ๐ง
22-07-2024 - We Are Developers 2024 - 17-19 Jul 2024 Messe Berlin ๐ฌ๐ง
05-07-2024 - BPF HTTP Replay - Midpoint network interception for HTTP traffic mirroring ๐ฌ๐ง
14-05-2024 - DxDay 2024 (1st edition) - Bologna - Hotel Savoia Regency ๐ฌ๐ง
24-12-2023 - Never Tell Me The Odds - Advent of Code 2023 [Day 24] ๐ฌ๐ง
23-12-2023 - A Long Walk - Advent of Code 2023 [Day 23] ๐ฌ๐ง
22-12-2023 - Sand Slabs - Advent of Code 2023 [Day 22] ๐ฌ๐ง
21-12-2023 - Step Counter - Advent of Code 2023 [Day 21] ๐ฌ๐ง
20-12-2023 - Pulse Propagation - Advent of Code 2023 [Day 20] ๐ฌ๐ง
19-12-2023 - Aplenty - Advent of Code 2023 [Day 19] ๐ฌ๐ง
18-12-2023 - Lavaduct Lagoon - Advent of Code 2023 [Day 18] ๐ฌ๐ง
17-12-2023 - Clumsy Crucible - Advent of Code 2023 [Day 17] ๐ฌ๐ง
16-12-2023 - The Floor Will Be Lava - Advent of Code 2023 [Day 16] ๐ฌ๐ง
15-12-2023 - Lens Library - Advent of Code 2023 [Day 15] ๐ฌ๐ง
14-12-2023 - Parabolic Reflector Dish - Advent of Code 2023 [Day 14] ๐ฌ๐ง
13-12-2023 - Point Of Incidence - Advent of Code 2023 [Day 13] ๐ฌ๐ง
12-12-2023 - Hot Springs - Advent of Code 2023 [Day 12] ๐ฌ๐ง
11-12-2023 - Cosmic Expansion - Advent of Code 2023 [Day 11] ๐ฌ๐ง
10-12-2023 - Pipe Maze - Advent of Code 2023 [Day 10] ๐ฌ๐ง
09-12-2023 - Mirage Maintenance - Advent of Code 2023 [Day 9] ๐ฌ๐ง
08-12-2023 - Haunted Wasteland - Advent of Code 2023 [Day 8] ๐ฌ๐ง
07-12-2023 - Camel Cards - Advent of Code 2023 [Day 7] ๐ฌ๐ง
06-12-2023 - Wait For It - Advent of Code 2023 [Day 6] ๐ฌ๐ง
05-12-2023 - If You Give A Seed A Fertilizer - Advent of Code 2023 [Day 5] ๐ฌ๐ง
04-12-2023 - Scratchcards - Advent of Code 2023 [Day 4] ๐ฌ๐ง
03-12-2023 - Gear Ratios - Advent of Code 2023 [Day 3] ๐ฌ๐ง
02-12-2023 - Cube Conundrum - Advent of Code 2023 [Day 2] ๐ฌ๐ง
01-12-2023 - Trebuchet?! - Advent of Code 2023 [Day 1] ๐ฌ๐ง
20-09-2023 - EBMBTreeBench - a naive measurement tool for ebmb trees ๐ฌ๐ง
20-08-2023 - Topton N5105 e Kingnovy J6413 - Due schede efficienti e potenti, con un mucchio di porte ๐ฎ๐น
04-06-2023 - Fondamenti SEO con Cloudflare - Una guida completa su come Cloudflare puรฒ migliorare la SEO del tuo sito web ๐ฎ๐น
26-03-2023 - Browser's "memory management" - A common memory leak in JS engines ๐ฌ๐ง
12-03-2023 - ะะธะบัะพ ะะธะฝะธะฐัััะฐ / Micro Miniatura - ะขัะฐะฝะทะธััะพัะฝัะต ะฃัะธะปะธัะตะปะธ / Amplificatori e Transistor ๐ท๐บ
07-12-2022 - Application Programming Interface - We followed your API documentation to the letter! ๐ฎ๐น
03-10-2022 - Apple Silicon Decompilation - When you wish you didn't know how to use a decompiler ๐ณ๏ธ
06-09-2022 - ๋ถ์๋ณ ์ฌ์ฉ์์ฉ์ฒด๊ณ / Red Star Operating System - pilsung ์ํธํ ์๊ณ ๋ฆฌ์ฆ / pilsung encryption algorithm ๐ฌ๐ง
17-04-2022 - Enriching HAProxy Logs with GeoIP and Elasticsearch - A Go ingestion sketch that parses HAProxy records, adds GeoIP and ASN data, then indexes events ๐ฌ๐ง
13-12-2020 - Estimating Service Coverage with the Haversine Formula - A PHP example that ranks shoppers by straight-line distance from nearby locations ๐ฌ๐ง
20-09-2020 - A Personal Suricata Policy Snapshot - Historical network-policy and signature rules, with the assumptions and operational risks made explicit ๐ฌ๐ง
27-08-2020 - Geiger Counter - A nuclear side project ๐ณ๏ธ
28-12-2019 - Grizzly Steppe - Samples from Russian cyber operations ๐ฌ๐ง
03-11-2019 - A RAID6 Recovery Attempt with mdadm - An archived Go experiment for testing candidate disk orders, with important data-preservation caveats ๐ฌ๐ง
21-04-2019 - A Go Job Queue, a Misnamed Stack, and a Race - A small producer-consumer example that exposes locking and ticker-lifecycle mistakes ๐ฌ๐ง
18-11-2018 - An OpenSSL Default TLS Policy Fragment - A historical system-default configuration for protocol versions, cipher suites, and TLS options ๐ฌ๐ง
13-07-2018 - Traffic Analysis - Exfiltrating (meta)data while minimising lateral movements ๐ฌ๐ง
01-07-2018 - D-Link botnet - Extracting binaries from a botnet of compromised NAS devices ๐ฌ๐ง
17-06-2018 - Notes on Searching for ROP Gadgets in a JavaScript Buffer - An incomplete research fragment for scanning a byte buffer with partial gadget signatures ๐ฌ๐ง
10-05-2018 - FASTGate-RCE - Abusing DNS to exploit a command injection and obtain root ๐ฌ๐ง
18-03-2018 - An Intentionally Vulnerable TCP Server - A small socket-programming lab showing how unsafe input handling becomes a memory-safety problem ๐ฌ๐ง
12-11-2017 - PerlใงMaildirใmboxๅฝขๅผใซใพใจใใ - reformailใพใใฏformailใไฝฟใฃใฆMaildirใฎใกใใปใผใธใไธใคใฎใกใผใซใใใฏในใซๅคๆใใๆงๅผในใฏใชใใ ๐ฏ๐ต
14-05-2017 - D-Link DNS-323 toolchain - An in-depth guide for DNS-323 hacking with patches, binaries, and helpful resources ๐ฌ๐ง
23-03-2017 - macOS firmware integrity check - Looking how Apple's security features are implemented across architectures ๐ฌ๐ง
05-02-2017 - An Incomplete jQuery Experiment with Video Blobs - A CoffeeScript sketch for fetching a video as a Blob and creating an object URL ๐ฌ๐ง
18-09-2016 - Dumping Legacy Paradox Databases with Python - A small Python 2 batch exporter for inspecting Paradox database files ๐ฌ๐ง
22-05-2016 - Extracting Tracks from BIN/CUE CD Images - An archived Linux-oriented bin2iso program for converting raw CD tracks to ISO and WAV files ๐ฌ๐ง
17-04-2016 - Rubyใง้่คใใกใคใซใๆคๅบใใ - SHA-256ใไฝฟใฃใ้่คใใกใคใซๆคๅบในใฏใชใใใจใๅ้คๅใซ็ขบ่ชใในใๅฎ่ฃ
ไธใฎๆณจๆ็น ๐ฏ๐ต
20-03-2016 - Building aMule in a Disposable Vagrant VM - An archived Debian and VirtualBox recipe for configuring and compiling aMule from a mounted source tree ๐ฌ๐ง
24-01-2016 - Sketching Simplex Data-Transfer Protocols in C - A small sequence of sender and receiver examples, useful for discussing acknowledgements and incomplete state handling ๐ฌ๐ง
20-12-2015 - Installing APKs on Multiple Android Devices with ADB - A small JavaFX and Ant tool for installing selected APK files across connected Android devices ๐ฌ๐ง
08-11-2015 - A One-Click FFmpeg Converter for ownCloud - A historical ownCloud app for converting stored media, and the shell-safety lessons in its implementation ๐ฌ๐ง
13-09-2015 - RubyใงTCPใใผใใธใฎๆฅ็ถใ็ขบ่ชใใ - TCPSocketใจใฟใคใ ใขใฆใใไฝฟใฃใใๅฐใใชTCPๆฅ็ถใใงใใฏ ๐ฏ๐ต
19-07-2015 - Rendering a Run-Length Encoded Pixel Pattern - A tiny Python script that expands monochrome pixel runs into a text image ๐ฌ๐ง
24-06-2015 - Generatore di sudoku in coffeescript - Permutazioni, rimozione validazione e backtracking ๐ฎ๐น
12-04-2015 - A Minimal File Copier with POSIX System Calls - A small C example using open, read, write, and creat, with an important short-write caveat ๐ฌ๐ง