0

First of all thank you for taking your time takling this difficult topic.

Goal:

My URL structure is like facebook/twitter: site.com/Username

To let the user set the username, I need to check if a path of a route matches a username.

Possibilities & problems:

If somebody is interested, the possible solutions I came up with:

1.) Using getRouteCollection()

Problem: This method shouldn't be used because it rebuilds the route cache and kills performance (see https://github.com/symfony/symfony-docs/issues/6710)

2.) Using a blacklist as RegExp in the User (for Username) Entity to blacklist all sites like "settings", "about", "login", "register"...

* @Assert\Regex(pattern="/^(?!register)(?!login)...

Problem: This is nearly guaranteed to explode because sometimes a URL is forgotten to add into this RegExp

3.) Using CURL to check if the site.com/username results in a 404

Problem: This seems to be a "hack" for me and unprofessional.

Question:

Whats the professional, secure way of checking if a route doesn't already exists, so that the username can be set and is guaranteed to be "free" (via absolute path like site.com/Username and no other route is in the way)?

By example something like $app->hasURL('/username')

emovere
  • 152
  • 1
  • 13
  • 1
    I thinking you are over thinking the problem. Routes are matched in the order they are defined so as long as you define /register,/login etc before /{username} then all will be well. – Cerad Aug 24 '17 at 22:28

1 Answers1

2

Add: use \Symfony\Component\RoutingException\ResourceNotFoundException;

Then, where $router is the routing service, you can attempt to match the url to a route. If it doesn't match anything it will throw an exception, but if you have a default catch-all route it will always match something so you would need to just detect if it matches the catch-all instead:

$routeIsAvailable = false;

try {
    $route = $router->match( '/' . $username );

    // If you are using a catch-all route to load profiles
    if ( $route[ '_route' ] === 'name_of_catch_all_route' )
        $routeIsAvailable = true;

} catch ( ResourceNotFoundException ) {

    // If the url didn't match any route at all
    $routeIsAvailable = true;
}

Make sure that you validate $username first so that it doesn't have any characters like ? or /. You can also urlencode it, but you probably don't want your user's profile urls to have encoded characters in them, so it's better to just restrict the valid usernames.

Paul
  • 139,544
  • 27
  • 275
  • 264