How to get the last segment of the path?

Asked

Viewed 318 times

3

URLs de exemplo:
content/edit
content/edit/
content/edit?q=
content/edit/?q=

I tried to make the code but it always fails when the url does not have "/" or "?" and if there is "/?" at the end. The code I made was:

.*\/([a-zA-Z0-9]*)[\/\?].*

That takes the value "Edit".

  • 2

    What are the expected results? In all the word edit shall be returned or in the latter the part ?q= should also be present at the return?

  • in vdd only the Edit and ignore the variables

  • So it’s not necessarily between the last occurrences of /, but always the last segment of path?

  • That’s it! But I just need the last word, in the Edit case, that could be any other.

  • 1

    It is that with each issue the question gets more confused. In a URL edit?q=teste, the last word would be teste, but what you need is edit, correct? If yes, use the expression last segment of the path, so as not to create any confusion.

  • You’re right, I made the changes

  • Put exactly like this your whole . htaccess, because multiple rewrites can conflict.

Show 2 more comments

4 answers

3

A very simple way, without using regular expression:

//Obtenha a URL sem as variáveis
$url = $_SERVER['REDIRECT_URL'];

//exploda 
$array_url = explode('/',$url);

//Caso a URL termine com /, a última posição do array estará em branco, então contorne isso
$array_url=array_filter($array_url);

//A última posição do array equivale à ultima palavra.
$palavra = array_pop($array_url);
  • Although the array part is good in response, however REDIRECT_URL can vary and depends a lot on the configuration of Apache, usually will exist on most servers, but in matters of fastgci and fpm this can be something that varies a lot. As I said, the answer is not bad, the problem is that the script is relying on a variable that can actually "vary" on different servers. The best thing would be to use something like PHP_SELF+parse_url(..., PHP_URL_PATH). Take it as a suggestion, you can run your tests to confirm.

2


The simplest solution is using PHP, as presented in other answers, but if you only want the regular expression to use next to the file .htaccess, see the solution below.

To answer this, we first need to understand the structure of a URI:

  foo://example.com:8042/over/there;param=value;p2;p3?name=ferret#nose
  \_/   \______________/\_________/ \_______________/ \_________/ \__/
   |           |            |              |              |         |
scheme     authority       path          params         query   fragment

We can realize that after the path the values of param, query and fragment. We then begin by analyzing only the path:

To get the last segment of path, we use regular expression:

\/?([a-zA-Z0-9_\-+]+)\/?$

That is, the value can start with a slider, followed by a non-zero sequence of letters, numbers or _, - and + (can freely change this part), followed or not by a bar, ending the value. In this way, the following Urls below will be properly analyzed:

edit
/edit
/edit/
/content/edit
/content/edit/

See working on Regex101.

Now, we must add to the expression the part that will analyze the possible existence of params in the URL. To simplify, as it is not of our interest to know what are the parameters of the path, let’s consider as parameter any string other than / that follows the character ;. Both the character and the sequence will be optional, then the regular expression becomes:

\/?([a-zA-Z0-9_\-+]+)\/?(?:\;[^\/]*)?$

So both the Urls above and below will work:

edit
/edit
/edit/
/content/edit
/content/edit/
/content/edit;param=foo
/content;param=foo/edit/

See working on Regex101.

The same logic will apply to the query URL, being defined as any string that follows the character ?. Thus the regular expression becomes:

\/?([a-zA-Z0-9_\-+]+)\/?(?:\;[^\/]*)?(?:\?.*)?$

So all the Urls below will work:

edit
/edit
/edit/
/content/edit
/content/edit/
/content/edit;param=foo
/content;param=foo/edit/
/content/edit?q=foo
/content/edit/?q=foo

See working on Regex101.

In addition, the Fragment URL, being defined as any string that follows the character #.

\/?([a-zA-Z0-9_\-+]+)\/?(?:\;[^\/]*)?(?:\?.*)?(?:\#.*)?$

Thus working for all possible URL variations:

edit
/edit
/edit/
/content/edit
/content/edit/
/content/edit;param=foo
/content;param=foo/edit/
/content/edit?q=foo
/content/edit/?q=foo
/content/edit#foo
/content/edit/#foo

In all, the only captured group will be edit.

See working on Regex101.

The same expression can be simplified to:

\/?([\w+-]+)\/?(?|\;[^\/]*|[?#].*)?$

Collaboration of Guilherme Lautert.

See working on Regex101.

  • 1

    You could reduce the regex, otherwise very good and well explained +1.

  • @Guilhermelautert what suggests?

  • 1

    This reduces the https://regex101.com/r/g2hcQo/2

  • @Guilhermelautert really became much simpler. Thank you.

1

I believe this regex solves your problem:

(\/\w+\/\w+)((\/?$)|(\?.+$))

I created a test in the link below:

https://regex101.com/r/b48kWg/1

The content you need is in group 1 (green)

  • What if I only have "content/Edit" or "content/Edit? q=123321&othersoparametro=432" without www and etc and wanted to take only the word Edit ?

  • No problem, because the rule is "end with". I added the www... because I believed it to be a complete URL, but it will work the same way.

1

Can use preg_split() to capture all values between bars and call array_reverse() to reverse the order of the elements, playing the latter as the first. preg_match() checks if the current elm starts with some letter otherwise moves on to the next element this deals with the case ?Q=abc

function ultimaParteURL($url){
    $segmentos = array_reverse(preg_split('#/#', $url , null, PREG_SPLIT_NO_EMPTY));
    foreach ($segmentos as $item){
        if(preg_match('#^[A-Z]#i', $item)) return $item; 
    }
}

echo ultimaParteURL('content/edit/?Q=abc') .'<br>';
echo ultimaParteURL('content/edit/') .'<br>';
echo ultimaParteURL('content/edit&abc=12015') .'<br>';

Example:

Array
(
    [0] => content
    [1] => edit?q=
)

After the call from array_reverse() flipped:

Array
(
    [0] => edit?q=
    [1] => content
)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.