Pregunta

I am using mod_rewrite to create canonical links. So far, I've used RewriteRule to successfully meet every test case. The code below definitely works, and could be adequate. However, I know that these rewrites can be taxing, so I want to make them as efficient as possible. Where can this be made more efficient? What makes a rewrite less efficient or inefficient?

There are 3 different areas of the website: national, state, and schools. Each area's main page is a hub for the whole area. E.g., "state" provides a list of all 50 states.

State Area:

  • url.com/state/ produces a list of all 50 states (r=state) for the default year
  • url.com/state/GA/ produces a list for GA (r=GA) for the default year
  • url.com/state/2011 produces a list of all 50 states (r=state) for 2011 (class=2011)
  • url.com/state/GA/2011 produces a list for GA (r=GA) for 2011 (class=2011)

National Area:

  • url.com/national/ produces a national listing (r=national) for the default year
  • url.com/national/jobs/ produces a national listing (r=national) of jobs (show=jobs) for the default year
  • url.com/national/2011 produces a national listing (r=national) for 2011 (class=2011)
  • url.com/national/jobs/2011 produces a national listing (r=national) of jobs (show=jobs) for 2011 (class=2011)

School Area:

Does virtually the same thing as the national list, but has one further sub variable.

<IfModule mod_rewrite.c>
RewriteEngine on 
# Rewrite user URLs 
RewriteRule ^state/?$ index.php?r=state [L,NC]
RewriteRule ^state/([0-9]+)/?$ index.php?r=state&class=$1 [L,NC]
RewriteRule ^state/([A-Za-z]+)/?$ index.php?r=$1 [L,NC]
RewriteRule ^state/([A-Za-z]+)/([0-9]+)/?$ index.php?r=$1&class=$2 [L,NC]
RewriteRule ^national/?$ index.php?r=national [L,NC]
RewriteRule ^national/([0-9]+)/?$ index.php?r=national&class=$1 [L,NC]
RewriteRule ^national/([A-Za-z]+)/?$ index.php?r=national&show=$1 [L,NC]
RewriteRule ^national/([A-Za-z]+)/([0-9]+)/?$ index.php?r=national&show=$1&class=$2 [L,NC]
RewriteRule ^schools/?$ index.php?r=schools [L,NC]
RewriteRule ^schools/([0-9]+)/?$ index.php?r=schools&class=$1 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/?$ index.php?school=$1 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([0-9]+)/?$ index.php?school=$1&class=$2 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([A-Za-z]+)/?$ index.php?school=$1&show=$2 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([A-Za-z]+)/([0-9]+)/?$ index.php?school=$1&show=$2&class=$3 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([A-Za-z]+)/([A-Za-z]+)/?$ index.php?school=$1&show=$2&sub=$3 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([A-Za-z]+)/([A-Za-z]+)/([0-9]+)/?$ index.php?school=$1&show=$2&sub=$3&class=$4 [L,NC]
</IfModule>

Thanks in advance. If additional details would be helpful, I will update/reply.

¿Fue útil?

Solución

Any sort of optimization will require a "blank" check in your php scripts, because paths that aren't there will still have a $_GET[''] variable associated with it, just that it'll be blank.

As far as the "state" and "national" URLs go, there's pretty much only one thing you can do, combine these two rules:

RewriteRule ^state/([A-Za-z]+)/?$ index.php?r=$1 [L,NC]
RewriteRule ^state/([A-Za-z]+)/([0-9]+)/?$ index.php?r=$1&class=$2 [L,NC]

by making the "class" optional (but there will still be a "class" parameter, it'll just be blank):

RewriteRule ^state/([A-Za-z]+)(?:/([0-9]+)|)/?$ index.php?r=$1&class=$2 [L,NC]

Same with the national:

RewriteRule ^national/([A-Za-z]+)/?$ index.php?r=national&show=$1 [L,NC]
RewriteRule ^national/([A-Za-z]+)/([0-9]+)/?$ index.php?r=national&show=$1&class=$2 [L,NC]

gets combined into:

RewriteRule ^national/([A-Za-z]+)(?:/([0-9]+)|)/?$ index.php?r=national&show=$1&class=$2 [L,NC]

But the school stuff is a little more complex. You can combine some of them, like:

RewriteRule ^schools/([A-Za-z-]+)/?$ index.php?school=$1 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([A-Za-z]+)/?$ index.php?school=$1&show=$2 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([A-Za-z]+)/([A-Za-z]+)/?$ index.php?school=$1&show=$2&sub=$3 [L,NC]

can be combined into just a single:

RewriteRule ^schools/([A-Za-z-]+)(?:/([A-Za-z]+)|)(?:/([A-Za-z]+)|)/?$ index.php?school=$1&show=$2&sub=$3 [L,NC]

while the

RewriteRule ^schools/([0-9]+)/?$ index.php?r=schools&class=$1 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([0-9]+)/?$ index.php?school=$1&class=$2 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([A-Za-z]+)/([0-9]+)/?$ index.php?school=$1&show=$2&class=$3 [L,NC]
RewriteRule ^schools/([A-Za-z-]+)/([A-Za-z]+)/([A-Za-z]+)/([0-9]+)/?$ index.php?school=$1&show=$2&sub=$3&class=$4 [L,NC]

can be combined into a single:

RewriteRule ^schools/([A-Za-z-]+)(?:/([A-Za-z]+)|)(?:/([A-Za-z]+)|)/([0-9]+)/?$ index.php?school=$1&show=$2&sub=$3&class=$4 [L,NC]

Otros consejos

You can create a big regex for each 3 pages, but you'll have to test it if that actually makes things faster or slower. If Apache has to apply more regex before it can serve a page, it will be slower, but if it has to apply a complex regex to the url, that might be slower than applying several simple regexes to the same url. Mod_rewrite is definitelly faster for url-rewriting than most programming languages are, mostly because to rewrite an url, you don't need to load any interpreter/compiler.

If you are able to use the END flag instead of the L flag, this speeds up rewriting a bit, because unlike the L flag, the END flag will stop rewriting completely, not just this 'round' of rewriting. It is however not available on old versions of Apache.

However, you are redirecting all your requests to index.php, so having a rule like:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ /index.php [L]

Then check $_SERVER['REQUEST_URI'], for example like this:

$boom = explode( '/', $_SERVER['REQUEST_URI'] );
#var_dump( $boom ); //Something like Array( '', 'state', '2011' );
if( isset( $boom[1] ) ) {
  if( $boom[1] == 'state' ) {
    if( isset( $boom[3] ) ) {
      $r = $boom[2];
      $class = $boom[3];
    } else if( isset( $boom[2] ) && intval( $boom[2], 10 ) == $boom[2] ) {
      $r = 'state';
      $class = $boom[2];
    } else if( isset( $boom[2] ) ) {
      $r = $boom[2];
    } else {
      $r = 'state';
    }
  } else if( $boom[1] == 'schools' ) {
    echo 'a';
  }
} else {
  header( '404: What the heck is this?!' );
  //No, don't use this header... 
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top