public function parse($filename) { if (!file_exists($filename)) { throw new \Exception('File not found "' . $filename . '"'); } $tokens = $this->lexer->lex(file_get_contents($filename)); $current_node = [static::T_ROOT]; $current_node_level = 0; /** @var Node|null $node */ $node = null; $nodes = []; /** @var Rewrite|null $rewrite */ $rewrite = null; $variable_key = $variable_value = null; $config = new Collection([]); foreach ($tokens as $token) { $line_context = " (" . $filename . "#" . $token[1] . ")"; switch ($token[0]) { /** Nodes */ case static::T_NODE_OPEN: if (!in_array($current_node[$current_node_level], [static::T_ROOT]) && in_array($token[3][1], ['VirtualHost', 'Directory'])) { throw new SyntaxErrorException('Syntax error, expected T_ROOT given [Node: ' . $token[3][1] . '] ' . $this->get_constant_name($current_node[$current_node_level]) . ' ' . $line_context); } if (!in_array($current_node[$current_node_level], [static::T_NODE_OPEN]) && in_array($token[3][1], ['IfModule'])) { throw new SyntaxErrorException('Syntax error, expected T_NODE_OPEN given [Node: ' . $token[3][1] . '] ' . $this->get_constant_name($current_node[$current_node_level]) . ' ' . $line_context); } switch ($token[3][1]) { case 'VirtualHost': $node = new VirtualHost($token['3']['2']); break; case 'Directory': $node = new Directory($token['3']['2']); break; case 'IfModule': if (empty($node) || !$node instanceof Node) { throw new SyntaxErrorException('No current node defined ' . $line_context); } $nodes[$current_node_level] = $node; $current_node_level++; $node = new IfModule($token['3']['2']); break; } $current_node[$current_node_level] = static::T_NODE_OPEN; break; case static::T_NODE_CLOSE: if ($current_node_level > 0) { $current_node_level--; $nodes[$current_node_level]->children[] = $node; $node = $nodes[$current_node_level]; unset($nodes[$current_node_level]); } else { if (!in_array($current_node[$current_node_level], [static::T_NODE_OPEN])) { throw new SyntaxErrorException('Syntax error, expected T_NODE_OPEN given ' . $this->get_constant_name($current_node[$current_node_level]) . $line_context); } $config[] = $node; $current_node[$current_node_level] = static::T_ROOT; unset($node); } break; case static::T_VARIABLE: if (!in_array($current_node[$current_node_level], [static::T_NODE_OPEN])) { throw new SyntaxErrorException('Syntax error, expected T_NODE_OPEN given ' . $this->get_constant_name($current_node[$current_node_level]) . $line_context); } $variable_key = trim($token[3][1]); $variable_value = trim($token[3][2]); $current_node[$current_node_level] = static::T_VARIABLE; break; case static::T_CONTINUE_VARIABLE: if (!in_array($current_node[$current_node_level], [static::T_VARIABLE])) { throw new SyntaxErrorException('Syntax error, expected T_VARIABLE given ' . $this->get_constant_name($current_node[$current_node_level]) . $line_context); } if ($variable_key === null || $variable_value === null) { throw new SyntaxErrorException('Syntax error, no variable key or value found ' . $line_context); } $variable_value .= ' ' . trim($token[3][1]); break; case static::T_LINEBREAK: switch ($current_node[$current_node_level]) { case static::T_VARIABLE: if ($variable_key === null || $variable_value === null) { throw new SyntaxErrorException('Syntax error, no variable key or value found ' . $line_context); } if ($node === null) { throw new SyntaxErrorException('No node defined ' . $line_context); } if (in_array($variable_key, ['RewriteCond', 'RewriteRule'])) { $rewrite || ($rewrite = new Rewrite()); switch ($variable_key) { case 'RewriteCond': $rewrite->conditions[] = $variable_value; break; case 'RewriteRule': $rewrite->rules[] = $variable_value; if (preg_match('/,?L\\]$/', $variable_value)) { $node['Rewrite'] = $rewrite; $rewrite = null; } break; } } else { if ($rewrite !== null) { $node['Rewrite'] = $rewrite; $rewrite = null; } $node[$variable_key] = $variable_value; } $variable_key = $variable_value = null; $current_node[$current_node_level] = static::T_NODE_OPEN; break; } break; } } if ($current_node[0] != static::T_ROOT) { $line_context = " (" . $filename . "#EOF)"; throw new SyntaxErrorException('Syntax error, expected T_ROOT given ' . $this->get_constant_name($current_node[0]) . $line_context); } return $config; }