Rewrite Rules in .htacess
RewriteEngine on
RewriteBase /
# Redirect Trailing Slashes.
RewriteRule ^(.*)/$ $1 [L,R=301]
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule (.+) /
DirectoryIndex index.php
The rule is simple. It simply sends the entire query to the file defined as directory index (document root / directory index). In the above case, the index.php file
With this you can manipulate the URL query as you like, without having to create new rules for each new parameter.
In index.php, just receive the query and make the appropriate treatments.
In this example, I have taken parts of a particular framework that I have developed for many years. The part that abstracted URI and GET and POST parameters, converted to a procedural style, without using classes, oop, etc. For beginners to understand and take advantage.
/*
Define a base da URL.
Caso queria executar num subfolder, basta especificar aqui.
Exemplo, http://localhost/pastateste/index.php
$href_base = '/pastateste/';
*/
$href_base = '/';
/*
Define o arquivo índice. Pode definir um arquivo diferente do definido em document root ou directory index seja u
Exemplo, http://localhost/pastateste/outro.php
$file_base = 'outro.php';
*/
$file_base = 'index.php';
$rs['path'] = null;
$rs['query'] = null;
$rs['post'] = null;
/*
Verifica em qual ambiente está sendo executado este script.
Tudo que começar com "cli", indica que está sob Command Line Interface.
*/
$cli_mode = ((substr(PHP_SAPI, 0, 3) == 'cli')? true : false);
$uri = (isset($_SERVER['REQUEST_URI'])? $_SERVER['REQUEST_URI'] : (isset($_SERVER['argv'][1])? $_SERVER['argv'][1] : ''));
$arr = parse_url($uri);
if (isset($arr['path']) && !empty($arr['path'])) {
$rs['path'] = $arr['path'];
unset($arr['path']);
/**
Checking for base path and remove it.
*/
if (strpos($rs['path'], $href_base) === 0) {
$rs['path'] = substr($rs['path'], strlen($href_base));
}
/**
Checking for file base path and remove it.
*/
if (strpos($rs['path'], $file_base) === 0) {
$rs['path'] = substr($rs['path'], strlen($file_base));
$rs['path'] = trim($rs['path'], '/');
}
/**
Convert the parameter to array.
*/
if (!empty($rs['path'])) {
$rs['path'] = explode('/', $rs['path']);
}
}
/**
Convert the URI query to array.
*/
if (isset($arr['query']) && !empty($arr['query'])) {
parse_str($arr['query'], $rs['query']);
}
/**
Get the POST array.
*/
if (isset($_POST) && !empty($_POST)) {
$rs['post'] = $_POST;
}
/*
Contém os dados extraídos da query uri
Exemplo: http://localhost/foo/bar
Retornará
array(0 => 'foo', 1 => 'bar')
*/
print_r($rs['path']);
/*
Contém os dados extraídos da variável global $_GET
Exemplo: http://localhost/?foo=1&bar=2
Retornará
array('foo' => 1, 'bar' => 2)
*/
print_r($rs['query']);
/*
Contém os dados extraídos da variável global $_GET
Exemplo:
<form action="http://localhost/" method="POST">
<input type="hidden" name="foo" value="1" />
<input type="hidden" name="bar" value="2" />
<input type="submit" value="send" />
</form>
Retornará
array('foo' => 1, 'bar' => 2)
*/
print_r($rs['post']);
In short, the result that interests you will be inside the $rs
array. Just manipulate this array as you wish.
Invoking the class and method retrieved from the URI
Taking the example of the question site/index.php?ato=conta'fazerlogin
.
I do not recommend doing it that way, using a single quote character as a separator.
In the example I posted, it would just work like this
http://site/conta/fazerlogin
Then this query data would be redeemed in $rs['path']
.
To call the class:
/*
Obviamente precisamos verificar se os parâmetros existem:
*/
if (
isset($rs['path'][0])
&& isset($rs['path'][1])
) {
$c = trim($rs['path'][0]);
$m = trim($rs['path'][1]);
} else {
/*
Isso aqui é para testes somente. Faça o tratamento adequado conforme o seu caso.
Recomendo que direcione para uma classe padrão.
*/
echo 'classe ou méotodo não informado'; exit;
}
if (
!empty($c)
&& !empty($m)
) {
if (class_exists($c)) {
/*
Aqui usamos o Reflection para poder instanciar um objeto caso não seja estático. Se for estático, será executado estaticamente.
*/
$reflection = new \ReflectionMethod($c, $m);
/*
Aqui também tomamos cuidado para checar se o método é publico.
O método deve ser definido como público para ser acessível.
*/
if ($reflection->isPublic()) {
if ($reflection->isStatic()) {
/*
Invoca de forma estática.
*/
$data = $c::$m();
} else {
/*
Invoca como instância.
*/
$c = new $c;
$data = $c->$m();
}
print_r($data);
} else {
/*
Isso aqui é para testes somente. Faça o tratamento adequado conforme o seu caso.
A decisão aqui depende de opinião pessoal. Avalie o que deseja fazer aqui pois pode-se aceitar um método inexistente ou negar a requisição. Isso dependerá do seu modelo de negócios.
Note que não foi necessário preocupar-se com method_exists(), pois a classe ReflectionMethod já faz esse trabalho.
*/
echo 'classe ou método vazios'; exit;
}
} else {
/*
Isso aqui é para testes somente. Faça o tratamento adequado conforme o seu caso.
Recomendo que direcione para uma classe que retorne um aviso de página inexistente ao usuário.
Aqui por exemplo, pode invocar uma classe que emita um http status 404 not found.
Claro que, se estiver trabalhando com design MVC, faça tudo dentro de sua respectiva camada.
*/
echo 'classe ou méotodo vazios'; exit;
}
} else {
/*
Isso aqui é para testes somente. Faça o tratamento adequado conforme o seu caso.
Recomendo que direcione para uma classe padrão.
*/
echo 'classe ou méotodo vazios'; exit;
}
class conta
{
public function fazerlogin()
{
return 'aqui retorna o for necessário';
}
}
Extra features of the script that abstracts the URI query parameters.
The script is compatible with command line (cli) executions
C:\pasta\onde\instalou\o\php\php.exe C:\www\site\index.php conta/fazerlogin
Fake URL Rewrite (false url rewrite).
http://site/index.php/conta/fazerlogin
Normal URL. (This part is not demonstrated in the scripts above.)
http://site/index.php/?p=conta/fazerlogin
Note
The above examples are purely didactic.
I tried to demonstrate very briefly how to abstract the URI query in a "universal" way, where we can also use the same routines in different environments.
For a more complete example, the answer would become 2 or 3 times more extensive. However, with the above examples we can see how such a simple task actually is quite complex.
The ideal thing is to put all this in OOP so that it reuses the routines and optimizes the executions.
To get a sense of how to further complicate, imagine business models where you need to attach specific parameters at the start or end of the query. An example in the real world is to add a parameter that identifies the language of the UI.
Example http://localhost/en/conta/fazerlogin
And at the same time also allow you to ignore the language parameter
Example http://localhost/conta/fazerlogin
When you do not find the parameter, the router would sign a default value and at the same time, it can not conflict with the order of the other parameters.