public static function getRelativePath(string $from, string $to): string
    {
        $from = self::getUnixStylePath($from);
        $to = self::getUnixStylePath($to);
        if (is_dir($from)) {
            $from = self::getNormalizedPath($from);
        }
        if (is_dir($to)) {
            $to = self::getNormalizedPath($to);
        }

        $from = explode('/', $from);
        $to = explode('/', $to);
        $relativePath = $to;

        foreach ($from as $depth => $directory) {
            // find first non-matching dir
            if ($directory === $to[$depth]) {
                // ignore this directory
                array_shift($relativePath);
            } else {
                // get number of remaining dirs to $from
                $remaining = count($from) - $depth;
                if ($remaining > 1) {
                    // add traversals up to first matching dir
                    $padLength = (count($relativePath) + $remaining - 1) * -1;
                    $relativePath = array_pad($relativePath, $padLength, '..');
                    break;
                }
                $relativePath[0] = './' . $relativePath[0];
            }
        }
        return implode('/', $relativePath);
    }