I found myself starting to answer a question that I have answered many times , so I thought why not making a code snippet and just reference this.
This is a short code snippet only to demonstrate how this thing work (with apache and rewrite engine on) , in real life PHP code shouldn't be under the public_html / www folder in any case (with maybe only one exception a index.php that its main task is to include something (or instantiate a class) from the src folder)
Lets suppose that you have an example folder under the domain example.com , you have some urls
eg1: http://example.com/example?var=value (this in this approach is equivalent to http://example.com/example/?var=value)
eg2: http://example.com/example/threadName/topicName
and you want to get the ?var=value or threadName/topicName or what ever after the http://example.com/example/ part. This is a very common senario that I have seen in many variations.
So lets do it:
Under the example directory we have an .htaccess file
DirectoryIndex index.php
RewriteEngine On
RewriteCond %{ENV:URI} ^$
RewriteRule ^(.*)$ - [ENV=URI:$1]
RewriteCond %{ENV:BASE} ^$
RewriteCond %{ENV:URI}::%{REQUEST_URI} ^(.*)::(.*?)\1$
RewriteRule ^ - [ENV=BASE:%2]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule .* %{ENV:BASE}index.php [QSA,L]
And an index.php file :
<?php
error_reporting( E_ALL );
ini_set( 'display_errors' ,'1' );
// set UTF-8 encoding
mb_internal_encoding( "UTF-8" );
// eg1: lets suppose that your domain is http://example.com
// and that we (the .htaccess file and this index.php) is under the
// example directory
$protocol = StringUtils::beforeFirst( $_SERVER["SERVER_PROTOCOL"] ,"/" )
. ( empty( $_SERVER["HTTPS"] ) ? '' : ( $_SERVER["HTTPS"] == "on" )
? "s" : "" );
// The protocol part , eg1 > http
$httpHost = isset( $_SERVER["HTTP_HOST"] ) ? trim( $_SERVER["HTTP_HOST"]
,"/" ) : null;
// the host , eg1 > example.com
$phpSelf = $_SERVER["PHP_SELF"];
// the normal current url of the index.php
// , eg1 > http://example.com/example/index.php
$rootUrl = StringUtils::toLowerCase( $protocol ) . "://" . $httpHost .
StringUtils::beforeLast( $phpSelf ,"/" );
// The rootUrl (where the htaccess is) , eg1 > http://example.com/example
$fullRequestUri = StringUtils::toLowerCase( $protocol ) . "://" . $httpHost
. $_SERVER["REQUEST_URI"];
// The fullRequestedUrl (including the ? if is any or any other after
// slashes. eg1 > http://example.com/example/example/?var=value
// or eg1> http://example.com/example/action?var=value
// or anything
$afterRootUrl = StringUtils::afterFirst(
StringUtils::toLowerCase( $protocol ) . "://" . $httpHost
. $fullRequestUri , $rootUrl . "/" );
// The after root url , eg1 > action?var=value
// Now you have the after root Url and you can do what ever you like
// to it
echo $afterRootUrl;
/**
* StringUtils class contains static methods for common string
* operations
*
* @version THIS IS A MINIFIED VERSION having only the methods I need
* for this code snippet
*/
class StringUtils
{
/**
* Returns how many characters the string is
*
* @param <b>string $string</b>
* The string
* @return number
*/
public static function length($string)
{
return mb_strlen( $string );
}
/**
* Counts the occurrences of a string inside another string and returns
* the result
*
* @param <b>string $string</b>
* The string to be searched
* @param <b>string $search</b>
* The string to search for
* @param <b>boolean $caseSensitive
* :optional</b> Defines if will be
* case sensitive. By default true.
* @return number
*/
public static function count($string ,$search ,$caseSensitive = true)
{
return $caseSensitive ? mb_substr_count( $string ,$search )
: mb_substr_count(
self::toLowerCase( $string ) ,self::toLowerCase( $search ) );
}
/**
* Return the index of <b>the first occurance</b> of a part of a
* string to the string
*
* @param <b>string $string</b>
* The string to be searched
* @param <b>string $search
* string</b> The string to search for
* @param <b>boolean $caseSensitive
* :optional</b> Defines if will
* be case sensitive. By default true.
* @return number
*/
public static function firstIndexOf($string ,$search
,$caseSensitive = true)
{
return $caseSensitive ? mb_strpos( $string ,$search )
: mb_stripos( $string , $search );
}
/**
* Return the index of <b>the last occurance</b> of a part of a string
* to the string
*
* @param
* <b>$string string</b> The string to be searched
* @param
* <b>$search string</b> The string to search for
* @param
* <b>$caseSensitive boolean :optional</b> Defines if the search
* will be case sensitive. By default true.
* @return number
*/
public static function lastIndexOf($string ,$search
,$caseSensitive = true)
{
return $caseSensitive ? mb_strrpos( $string ,$search ) : mb_strripos(
$string ,$search );
}
/**
* Converts a string to lower case
*
* @param <b>string $string</b>
* The sting to be converted
* @return string
*/
public static function toLowerCase($string)
{
return mb_strtolower( $string );
}
/**
* Returns a part of the string from a character and for as many
* characters as provided
*
* @param
* <b>$string string</b> The string to retrieve the part from
* @param
* <b>$start string </b> The index of the first character
* (0 for the first one)
* @param
* <b>$length string</b> The length of the part the will be
* extracted from the string
* @return string
*/
public static function substring($string ,$start ,$length = null)
{
return ( $length === null ) ? ( mb_substr( $string ,$start ) )
: ( $length ==
0 ? "" : mb_substr( $string ,$start ,$length ) );
}
/**
* Returns the part of a string <b>before the first</b> occurrence of
* the string to search for.
* If the string doesn't contain the needle returns the string itself
*
* @param <b>string $string</b>
* The string to be searched
* @param <b>string $search</b>
* The string to search for
* @param <b>boolean $caseSensitive
* :optional</b> Defines if the search
* will be case sensitive. By default true.
* @return string
*/
public static function beforeFirst($string ,$search
,$caseSensitive = true)
{
return self::count( $string ,$search ,$caseSensitive ) === 0
? $string : self::substring($string
,0 ,self::firstIndexOf( $string ,$search ,$caseSensitive ) );
}
/**
* Returns the part of a string <b>before the last</b> occurrence of
* the string to search for.
* If the string doesn't contain the needle returns the string itself
*
* @param <b>string $string</b>
* The string to be searched
* @param <b>string $search</b>
* The string to search for
* @param
* <b>$caseSensitive boolean :optional</b> Defines if the
* search will be case sensitive. By default true.
* @return string
*/
public static function beforeLast($string ,$search ,$caseSensitive = true)
{
return self::count( $string ,$search ,$caseSensitive ) === 0 ?
$string : self::substring( $string
,0 ,self::lastIndexOf( $string ,$search ,$caseSensitive ) );
}
/**
* Returns the part of a string <b>after the first</b> occurrence of the
* string to search for.
* If the string doesn't contain the needle returns an empty string
*
* @param <b>string $string</b>
* The string to be searched
* @param <b>string $search</b>
* The string to search for
* @param <b>boolean $caseSensitive
* :optional</b> Defines if the search
* will be case sensitive. By default true.
* @return string
*/
public static function afterFirst($string ,$search ,$caseSensitive = true)
{
return self::count( $string ,$search ,$caseSensitive ) === 0 ? ""
: self::substring(
$string ,
self::firstIndexOf( $string ,$search ,$caseSensitive ) +
self::length( $search ) );
}
}
?>
And we are done , now you have the after root url in the $afterRootUrl variable and you can do what ever you like with it.