0

Could someone tell me how I would do this. I have 3 strings.

$route = '/user/$1/profile/$2';
$path = '/user/profile/$1/$2';
$url = '/user/jason/profile/friends';

What I need to do is check to see if the url conforms to the route. I am trying to do this as follows.

$route_segments = explode('/', $route);
$url_segments = explode('/', $url);

$count = count($url_segments);
for($i=0; $i < $count; $i++) {
  if ($route_segments[$i] != $url_segments[$i] && ! preg_match('/\$[0-9]/', $route_segments[$i])) {
    return false;
  }
}

I assume the regex works, it's the first I have ever written by myself. :D

This is where I am stuck. How do I compare the following strings:

$route = '/user/$1/profile/$2';
$url = '/user/jason/profile/friends';

So I end up with:

array (
    '$1' => 'jason',
    '$2' => 'friends'
);

I assume that with this array I could then str_replace these values into the $path variable?

4 Answers 4

1
$route_segments = explode('/',$route);
$url_segments = explode('/',$url);
$combined_segments = array_combine($route_segments,$url_segments);

Untested and not sure how it reacts with unequal array lengths, but that's probably what you're looking for regarding an element-to-element match. Then you can pretty much iterate the array and look for $ and use the other value to replace it.

EDIT

/^\x24[0-9]+$/

Close on the RegEx except you need to "Escape" the $ in a regex because this is a flag for end of string (thus the \x24). The [0-9]+ is a match for 1+ number(s). The ^ means match to the beginning of the string, and, as explained, the $ means match to the end. This will insure it's always a dollar sign then a number.

(actually, netcoder has a nice solution)

Sign up to request clarification or add additional context in comments.

1 Comment

I like this solution, its simple and to the point. Thanks for the tip on the regex.
1

I did something similar in a small framework of my own.

My solution was to transform the template URL: /user/$1/profile/$2

into a regexp capable of parsing parameters: ^\/user\/([^/]*)/profile/([^/]*)\/$

I then check if the regexp matches or not.

You can have a look at my controller code if you need to.

2 Comments

The main selling point of my little application is simplicity. I feel that this would go against this principle. Its a nice solution though thanks.
I think you misunderstood my argument. I was not suggesting that you ask your user to input regexp instead of your more natural language. I was suggesting that you transform your natural language URL pattern to regexp at runtime in order to match current URL more easily.
1

You could do this:

$route = '/user/$1/profile/$2';
$path = '/user/profile/$1/$2';
$url = '/user/jason/profile/friends';

$regex_route = '#'.preg_replace('/\$[0-9]+/', '([^/]*)', $route).'#';
if (preg_match($regex_route, $url, $matches)) {
   $real_path = $path;
   for ($i=1; $i<count($matches); $i++) {
      $real_path = str_replace('$'.$i, $matches[$i], $real_path);
   }
   echo $real_path; // outputs /user/profile/jason/friends
} else {
   // route does not match
}

Comments

0

You could replace any occurrence of $n by a named group with the same number (?P<_n>[^/]+) and then use it as pattern for preg_match:

$route = '/user/$1/profile/$2';
$path = '/user/profile/$1/$2';
$url = '/user/jason/profile/friends';

$pattern = '~^' . preg_replace('/\\\\\$([1-9]\d*)/', '(?P<_$1>[^/]+)', preg_quote($route, '~')) . '$~';
if (preg_match($pattern, $url, $match)) {
    var_dump($match);
}

This prints in this case:

array(5) {
  [0]=>
  string(28) "/user/jason/profile/friends"
  ["_1"]=>
  string(5) "jason"
  [1]=>
  string(5) "jason"
  ["_2"]=>
  string(7) "friends"
  [2]=>
  string(7) "friends"
}

Using a regular expression allows you to use the wildcards at any position in the path and not just as a separate path segment (e.g. /~$1/ for /~jason/ would work too). And named subpatterns allows you to use an arbitrary order (e.g. /$2/$1/ works as well).

And for a quick fail you can additionally use the atomic grouping syntax (?>…).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.