entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

2votos

[PHP] ¿Cuál es la mejor forma de crear un Router MVC?

Hola, actualmente mi router.php consiste en parsear la ruta desde el constructor y separar el controlador, método y argumentos en variables. Luego llamo directamente a los archivos y métodos respectivamente, pero he visto que es una forma vulnerable a ataques y tampoco funciona para lo que necesito.

Mi planteamiento para el router era el siguiente:
1.- Creo un método para añadir las rutas a un array:

$router->add('/account/signup', array('controller' => 'account', 'action' => 'signup'); 
$router->add('/account/signin', array('controller' => 'account', 'action' => 'signin');

2.- Al acceder a la aplicación en el constructor parseo la ruta actual y guardo el nombre del controlador, el método y los argumentos en una variable.

3.- Llamo a otro método que comprueba si existe el controlador en el array, si existe incluye el controlador y llama al método.

El problema es que necesito que se pueda acceder al perfil de usuario de este modo http://www.pagina.com/usuario y no se muy bien como hacer eso.

¿Quizás añadiendo otra ruta al final con /* y si no ha coincidido con ninguna de las rutas anteriores que llame a ese controlador?

$router->add('/*', array('controller' => 'profile', 'action' => 'index');  

Estoy bastante liado porque veo bastantes opciones pero ninguna que me resuelva el problema del nombre de usuario en la url sin que sea un controlador

1 Respuesta

2votos

Leonardo-Tadei Puntos227010

Hola @Zenok,

sin ver la lógica del ruteador, no es simple proponerte soluciones, pero viendo la interfaz que usás para agregar las rutas, algo como esto debería funcionarte para este escenario:

$router->add('/usuario', array('controller' => 'profile', 'action' => 'index');

La llamada con /* no parece útil, porque debería matchear con cualquier cosa, y no solo con el perfil.

El funcionamiento de esto depende de cómo parseas las rutas, pero sin ver ese código, solo podemos suponer...

A priori este mecanismo no es vulnerable, ya que al definir todas las rutas, si se pone un URL inexistente debería ir a un default o a un "no existe". La otra cosa neceasria para la seguridad es que cada script valide que el usuario sea válido, y no solo por ser invocado asumas que es un usuario logueado.

La otra forma de hacer esto es no hacerlo y usar HTACCESS para que sea el servidor quien escriba las rutas dependiendo de la petición. Es un mecanismo bueno, pero a veces es dificil de depurar el código porque las invocaciones a los script pasan a estar en manos de otro software.

Saludos!

1voto

Zenok comentado

Gracias por tu respuesta Leonardo, creo que no me he explicado muy bien. Culpa mía, te explico:

Estoy intentando hacer mi propio framework para ejercicios prácticos, la cuestión es que no sé muy bien como hacer lo que te comento; que además de poder especificar rutas hacia un controlador específico, si la ruta a la que estoy llamando es un nombre de perfil de usuario (Por ejemplo http://www.pagina.com/zenok) Que llame al controlador profile.php pasando el nombre como argumento y no trate de buscar un controlador llamado "zenok". Si lo hago del modo en el que lo tengo ahora, buscaría en el array la ruta /zenok pensando que es el nombre del controlador y no es así.

El código que tengo ahora mismo es el siguiente:


class Router {

    public $routes = array();

    public $__CONTROLLER = 'index';
    public $__METHOD = 'index';
    public $__ARGUMENTS = array();

    public function __construct()
    {
        if(isset($_GET['url']))
        {
            $this->url = filter_input(INPUT_GET, 'url', FILTER_SANITIZE_URL);
            $this->url = explode('/', $this->url);

            $this->__CONTROLLER = array_shift($this->url);
            $this->__METHOD = array_shift($this->url);
            $this->__ARGUMENTS = $this->url;
        }
    }

    public function add($route, $controller)
    {
        $this->routes = array_merge($this->routes, array($route => $controller));
    }

    public function handle()
    {
        //AQUÍ LLAMARÍA A LA FUNCIÓN PARA COMPROBAR SI EXISTE EL CONTROLADOR EN EL ARRAY, SI EXISTE LLAMARÍA AL CONTROLADOR Y A SU RESPECTIVO MÉTODO.
    }

    public function getController()
    {
        return $this->__CONTROLLER;
    }

    public function getMethod()       
    {
        return $this->__METHOD;
    }

    public function getArguments()
    {
        return $this->__ARGUMENTS;
    }
}

Con eso lo que hago es lo que te comentaba, defino las rutas con su respectivo controlador y al acceder a una URL separo el nombre del controlador, método y argumentos. Luego simplemente es cuestión de comprobar si existe ese controlador en el array y llamarlo, pero el problema que tengo es lo que te comento, ¿Qué puedo hacer cuando en la ruta el lugar donde va el nombre del controlador, no es un controlador, si no un argumento?

Gracias de nuevo, espero que se entienda ahora

1voto

Leonardo-Tadei comentado

@Zenok,

con esa estructura no podrás hacer concordar http://www.pagina.com/zenok con un contralodar como decís, pero no por un problema del código, sino porque tomar /zenok como parámetro de por ejemplo /profile te impediría tener contenido en la raíz del sitio, y es de esperar que cuando alguien va a http://www.pagina.com/ vea la portada.

Tu problema es que querés que la raíz del sitio tenga dos funcionalidades...

Podrías implementar esto después del ruteo, por ejemplo haciendo que la portada /, en caso de ercibir un parámetro como "zenok", redirija a su vez a otra página o cargue vía un include() algún contenido diferente, pero si hacés esto, la raíz del sitio no puede tener otras funciones.

Es por esto que verás que los perfiles siempre están en algo como sitio.com/users/zenok o sitio.com/profile/zenok, es decir, es /users o /profile quien reciben el parámetro.

Te sugiero que leas un poco sobre HTACCESS y su concordancia de patrones para inspirarte en soluciones posibles sobre esta cuestión: aunque no las uses, te servirá para ver como analizar URLs.

Saludos!

1voto

Zenok comentado

Hola @Leonardo-Tadei, de nuevo gracias por tu respuesta.

Exactamente ese era el problema. La cuestión es que no sé como lo harán los sitios web como Twitter, Twitch y plataformas similares para además de tener sus rutas, tener canales de usuarios o perfiles de ese modo. Imagino que será porque está programado con otros lenguajes.

Muchas gracias Leornardo, será cuestión de como dices, utilizar la ruta /profile/zenok

1voto

Leonardo-Tadei comentado

Yo no creo que sea cuestión del lenguaje a usar: lo que yo haría en un escenario como twitter es rutear todo a /usuarios/nombre excepto las rutas con contenido propio, que en comparación son muy pocas.

Es decir, la regla es que todo vaya como parámetro de /usuarios, salvo algunas pocas cosas.

Sería invertir el enfoque de tu código: si no está definido en el router, va a /usuarios con su paŕametro, si está definido, va a esa ruta específica. Si lo pensás, es "nada más" que invertir los patrones de concordancia...

Por otra parte, no sabemos si Twitter tiene los usuarios en la raíz o si lo que estamos viendo es una regla de reescritura, o si es que tiene un "index" que consulta en una DB y hace el include del código según el parámetro.

Saludos!

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta