Absolute URL from base folder with rewrite - php

I have a project running local on WampServer. It's an MVC-like structure; it rewrites the URL to index.php?url=$1. Full .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
When I want to send the user to another page using PHP location: <location> it doesn't do this properly because of the rewriting (all-though I am technically always in index.php).
For example if I am on http://localhost/project_name/controller/method/ and this controller's constructor or method tries to send me to:
header('location: another_controller/method'); sends me to
http://localhost/project_name/controller/method/another_controller/method/
header('location: /another_controller/method'); sends me to
http://localhost/another_controller/method/
But I want it to send me like this:
header('location: /another_controller/method'); sends me to
http://localhost/project_name/another_controller/method/
Now the only solution I have found is:
define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');
But this isn't perfect either because it causes me to have to change this defined constant BASE_URL whenever the domain or folder name changes. I could also create a method in my BaseController that creates absolute URLs, but this method would basically just prepend BASE_URL too.
Note: The same problem doesn't arise with HTML's src and href attributes, which can use relative paths (without project_name folder in path). I don't understand why however. Because if the header location causes the browser to append the the relative-URL to the current location, why doesn't it have the same behavior when looking for .css or .js files.
So... this raises a couple of questions for me:
Would I have this problem if I had virtual hosts?
What is the best way to solve this problem?
Is is best to just have the full absolute URL?
Why do HTML's src and href attributes not share this behavior?

Now the only solution I have found is:
define('BASE_URL','http://localhost/project_name');
header('location: '.BASE_URL.'/another_controller/method/');
But this isn't perfect either because it causes me to have to change
this defined constant BASE_URL whenever the domain or folder name
changes.
You shouldn't need to change the defined constant. These values can be found dynamically.
Example:
if ($_SERVER['DOCUMENT_ROOT'] == dirname($_SERVER['SCRIPT_FILENAME'])) {
define('BASE_PATH', '/');
} else {
define('BASE_PATH', dirname($_SERVER['SCRIPT_NAME']) . '/');
}
$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
define('BASE_URL', $protocol . $_SERVER['SERVER_NAME'] . BASE_PATH);
Additionally, rather than worrying about whether to specify an absolute URL or a path, you can wrap the redirect into a function which can handle both:
function redirect($path = null) {
if (isset($path)) {
if (filter_var($path, FILTER_VALIDATE_URL)) {
header('Location: ' . $path);
} else {
header('Location: ' . BASE_URL . $path);
}
} else {
header('Location: ' . BASE_URL);
}
exit;
}
Finally, as #HarshSanghani mentioned in the comments, the base path in your .htaccess file should match the base path in your code. So if BASE_PATH (based on the example above) outputs /project_name/, then your .htaccess should accommodate it:
RewriteBase /project_name/

To answer your questions:
It depends on how your virtual hosts would be configured.
You could simply generate your BASE_URL dynamically: $baseUrl = dirname($_SERVER['SCRIPT_NAME']);. This way you won't have to change any code if your folder or domain changes.
You don't need the domain part.
The html src and href are interpreted by your browser which takes into account the page's <base> tag. All paths on a page with a <base> tag get changed accordingly by your browser.
The HTTP headers you send from your server (for redirect) have nothing to do with the html page you send and are therefore not updated.

You're going to have this problem if you have your project set up in a subdirectory. Using virtual hosts would be a way round the issue if you wanted to set them up at say, project_name.localhost.
In my projects I use an environment variable to load a different config file for development, staging or production. In this I set a $baseUri somehow.
It's best practice to use the absolute urls (including the domain) for both the solution of this problem and for SEO. In terms of functionality you don't need the domain part.
The src and href tags generally work the same way, but as Andreas mentioned they could be affected by the base tag.

You should specify RewriteBase in your htaccess file. Use relative paths in your links and you need nothing more.
RewriteBase /project_name/
RewriteEngine on
RewriteCond $1 !\.(gif|jpe?g|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]

Related

Extract URL slug using PHP. Building a URL shortener

I'm building a URL shortening web app using PHP. I am able to generate shorter URLs successfully. But I'm not able to redirect the users when they visit the shortened URL.
If the user enters https://example.com/aBc1X, I'd like to capture the aBc1X. I'll then query the database to find the original URL and then redirect.
My question is, how can I extract the aBc1X from the above URL?
P.S. I'll use either Apache or Nginx.
Two things to do for you.
First you have to redirect all traffic to one file which will be your router file. You can do this by placing a few rules in .htaccess file. I will put there some generic rules to start with (this one come from Wordpress):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^redirect\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /redirect.php [L]
</IfModule>
They tell that everywhere url points to which isn't file or directory will run file redirect.php. You may want to tweak that settings to your needs.
Then in redirect.php you can capture url by looking inside $_SERVER['REQUEST_URI'].
For url http://example.com/any-url-i-want you would have
$_SERVER['REQUEST_URI'] == '/any-url-i-want.
Now the only thing you need is to find the url in database, and do a redirect.
I guess you can handle string operations at this point, either by using parse_url, regular expressions, or simple string cutting.
You want to use;
$_SERVER['REQUEST_URI'];
That will return what you're looking for.
You can see the documentation here
To parse the url
$url = "https://example.com/aBc1X";
$path = ltrim(parse_url($url, PHP_URL_PATH), '/');
Then $path will be aBc1X as desired. Note that any query following a ? will be omitted in this solution. For more details have a look at the documentation of the parse_url function.

.htaccess rewrite to access php include in subfolder

I have this URL that give me two main parameters, folder and page, and som other tahat can variable to be present or not:
http://www.domain.com/adm/master.php?f=folder&p=page&otherparam1=somthing&otherparm2=somthing&otherparm3=somthing[...]
in my master.php-file I include a php-file based on these parameters:
$folder = $_GET['f'];
$page = $_GET['p'];
if(empty($page)) {
$page = 'dashboard';
}
$path = $folder.'/'.$page;
include_once 'pages/'.$path.'.php?otherparm1=somthing&otherparm2=somthing&otherparm3=somthing[...]';
The otherparam is to be multiple parameters given i the URL.
I want to rewrtite the URL to show somthing like this:
www.domain.com/adm/folder/page/somthing/somthing/somthing[...]
I have searched the web, but not been able to find a solution.
If you want to do it with simple .htacces then you can use following .htacces code:
RewriteEngine on
RewriteCond $1 !^(index\.php|css|favicon.ico|fonts|images|js|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]
Basically what this code do is overwrite your request to your domain (ex: localhost/mysite), instead accessing folder or file it will access your index.php. Except for index.php, favoicon.ico, robots.txt files and css,fonts,image and js folder or what you define in second line on my code above.
Try this in your Root/.htaccess
RewriteEngine On
RewriteRule ^adm/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /adm/master.php?f=$1&p=$2&otherparam1=$3&otherparm2=$4&otherparm3=$5 [NC,L]
$1 ,$2,$3... contains whateve value was matched in regex capture groups "([^/]+)".
This will rewrite
example.com/adm/folder/page/foo/bar/foobar
to
example.com/adm/master.php?f=folder&p=page&otherparam1=foo&otherparm2=bar&otherparm3=foobar
without changing the url in browser address bar.

PHP File request from url directory

This is probably a very easy question. Anyway how do you use variables from a url without requests. For example:
www.mysite.com/get.php/id/123
Then the page retrieves id 123 from a database.
How is this done? Thanks in advance!
UPDATE
If i have the following structure:
support/
sys/
issue/
issue.php
.htaccess
home.php
etc.....
With .htaccess file containing:
RewriteEngine On
RewriteRule ^/issue/(.*)$ /issue/issue.php?id=$1 [L]
Why do I have to type:
http://www.mysite.com/support/sys/issue/issue/1234
In order to load a file? When I want to type
http://www.mysite.com/support/sys/issue/1234
also, how do I then retrieve the id once the file loads?
Problem
This is a very basic/common problem which stems from the fact that your .htaccess rule is rewriting a url which contains a directory which actually exists...
File structure
>support
>sys
>issue
issue.php
.htaccess
(I.e. the directory issue and the .htaccess file are in the same directory: sys)
Rewrite Issues
Then:
RewriteEngine ON
RewriteRule ^issue/(.*)/*$ issue/issue.php?id=$1 [L]
# Note the added /* before $. In case people try to access your url with a trailing slash
Will not work. This is because (Note: -> = redirects to):
http://www.mysite.com/support/sys/issue/1234
-> http://www.mysite.com/support/sys/issue/issue.php?id=1234
-> http://www.mysite.com/support/sys/issue/issue.php?id=issue.php
Example/Test
Try it with var_dump($_GET) and the following URLs:
http://mysite.com/support/sys/issue/1234
http://mysite.com/support/sys/issue/issue.php
Output will always be:
array(1) { ["id"]=> string(9) "issue.php" }
Solution
You have three main options:
Add a condition that real files aren't redirected
Only rewrite numbers e.g. rewrite issue/123 but not issue/abc
Do both
Method 1
RewriteEngine ON
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^issue/(.*)/*$ issue/issue.php?id=$1 [L]
Method 2
RewriteEngine ON
RewriteRule ^issue/(\d*)/*$ issue/issue.php?id=$1 [L]
Method 3
RewriteEngine ON
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^issue/(\d*)/*$ issue/issue.php?id=$1 [L]
Retrieving the ID
This is the simple part...
$issueid = $_GET['id'];
In your .htaccess you should add:
RewriteEngine On
RewriteRule ^id/([^/]*)$ /get.php/?id=$1 [L]
Also like previous posters mentioned, make sure you have your mod_rewrite activated.
You have to use a file called .htaccess, do a search on Google and you'll find a lot of examples how to accomplish that.
You will need mod_rewrite (or the equivalent on your platform) to rewrite /get.php/id/123 to /get.php?id=123.
I tried and tried the .htaccess method but to no avail. So I attempted a PHP solution and came up with this.
issue.php
<?php
if (strpos($_SERVER['REQUEST_URI'], 'issue.php') !== FALSE){
$url = split('issue.php/', $_SERVER['REQUEST_URI']);
}elseif (strpos($_SERVER['REQUEST_URI'], 'issue') !== FALSE){
$url = split('issue/', $_SERVER['REQUEST_URI']);
}else{
exit("URI REQUESET ERROR");
}
$id = $url[1];
if(preg_match('/[^0-9]/i', $id)) {
exit("Invalid ID");
}
?>
What you're looking for is the PATH_INFO $_SERVER variable.
From http://php.net/manual/en/reserved.variables.server.php:
'PATH_INFO'
Contains any client-provided pathname information trailing the actual
script filename but preceding the query string, if available. For
instance, if the current script was accessed via the URL
http://www.example.com/php/path_info.php/some/stuff?foo=bar, then
$_SERVER['PATH_INFO'] would contain /some/stuff.
explode() it and work on its parts.
EDIT: Use rewrite rules to map the users' request URLs to your internal structure and/or hide the script name. But not to convert the PATH_INFO to a GET query, that's totally unnecessary! Just do a explode('/',$_SERVER['PATH_INFO']) and you're there!
Also, seeing your own answer, you don't need any preg_mathes. If your database only contains numeric ids, giving it a non-numeric one will simply be rejected. If for some reason you still need to check if a string var has a numeric value, consider is_numeric().
Keep it simple. Don't reinvent the wheel!
Just wondering why no answer has mentioned you about use of RewriteBase
As per Apache manual:
The RewriteBase directive specifies the URL prefix to be used for
per-directory (htaccess) RewriteRule directives that substitute a
relative path.
Using RewriteBase in your /support/sys/issue/.htaccess, code will be simply:
RewriteEngine On
RewriteBase /support/sys/issue/
RewriteRule ^([0-9+)/?$ issue.php?id=$1 [L,QSA]
Then insde your issue.php you can do:
$id = $_GET['id'];
to retrieve your id from URL.

How can I remove file extension from a website address?

I am designing a website. I want my website address to look like the following image:
I don't want my website to look like http://something.example/profile.php.
I want the .php extension to be removed in the address bar when someone opens my website. In other words, I want my website to be like: http://something.example/profile
As a second example, you can look at the Stack Overflow website address itself.
How can I get this done?
Just add an .htaccess file to the root folder of your site (for example, /home/domains/domain.example/htdocs/) with the following content:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
More about how this works in these pages: mod_rewrite guide (introduction, using it), reference documentation
First, verify that the mod_rewrite module is installed. Then, be careful to understand how it works, many people get it backwards.
You don't hide URLs or extensions. What you do is create a NEW URL that directs to the old one, for example
The URL to put on your web site will be yoursite.example/play?m=asdf
or better yet
yoursite.example/asdf
Even though the directory asdf doesn't exist. Then with mod_rewrite installed you put this in .htaccess. Basically it says, if the requested URL is NOT a file and is NOT a directory, direct it to my script:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /play.php [L]
Almost done - now you just have to write some stuff into your PHP script to parse out the new URL. You want to do this so that the OLD ones work too - what you do is maintain a system by which the variable is always exactly the same OR create a database table that correlates the "SEO friendly URL" with the product id. An example might be
/Some-Cool-Video (which equals product ID asdf)
The advantage to this? Search engines will index the keywords "Some Cool Video." asdf? Who's going to search for that?
I can't give you specifics of how to program this, but take the query string, strip off the end
yoursite.example/Some-Cool-Video
turns into "asdf"
Then set the m variable to m=asdf.
So both URLs will still go to the same product
yoursite.example/play.php?m=asdf
yoursite.example/Some-Cool-Video
mod_rewrite can do lots of other important stuff too, Google for it and get it activated on your server (it's probably already installed.)
You have different choices.
One on them is creating a folder named "profile" and rename your "profile.php" to "default.php" and put it into "profile" folder.
and you can give orders to this page in this way:
Old page: http://something.example/profile.php?id=a&abc=1
New page: http://something.example/profile/?id=a&abc=1
If you are not satisfied leave a comment for complicated methods.
Here is a simple PHP way that I use.
If a page is requested with the .php extension then a new request is made without the .php extension. The .php extension is then no longer shown in the browser's address field.
I came up with this solution because none of the many .htaccess suggestions worked for me and it was quicker to implement this in PHP than trying to find out why the .htaccess did not work on my server.
Put this at the beginning of each PHP file (preferrably before anything else):
include_once('scripts.php');
strip_php_extension();
Then put these functions in the file 'scripts.php':
//==== Strip .php extension from requested URI
function strip_php_extension()
{
$uri = $_SERVER['REQUEST_URI'];
$ext = substr(strrchr($uri, '.'), 1);
if ($ext == 'php')
{
$url = substr($uri, 0, strrpos($uri, '.'));
redirect($url);
}
}
//==== Redirect. Try PHP header redirect, then Java, then http redirect
function redirect($url)
{
if (!headers_sent())
{
/* If headers not yet sent => do php redirect */
header('Location: '.$url);
exit;
}
else
{
/* If headers already sent => do javaScript redirect */
echo '<script type="text/javascript">';
echo 'window.location.href="'.$url.'";';
echo '</script>';
/* If javaScript is disabled => do html redirect */
echo '<noscript>';
echo '<meta http-equiv="refresh" content="0; url='.$url.'" />';
echo '</noscript>';
exit;
}
}
Obviously you still need to have setup Apache to redirect any request without extension to the file with the extension.
The above solution simply checks if the requested URI has an extension, if it does it requests the URI without the extension. Then Apache does the redirect to the file with the extension, but only the requested URI (without the extension) is shown in the browser's address field.
The advantage is that all your "href" links in your code can still have the full filename, i.e. including the .php extension.
The problem with creating a directory and keeping index.php in it is that
your links with menu will stop functioning
There will be way too many directories. For eg, there will be a seperate directory for each and every question here on stackoverflow
The solutions are
1. MOD REWRITE (as suggested above)
2. use a php code to dynamically include other files in index file. Read a bit more abt it here http://inobscuro.com/tutorials/read/16/
Actually, the simplest way to manipulate this is to
Open a new folder on your server, e.g. "Data"
Put index.php (or index.html) in it
And then the URL www.yoursite.example/data will read that index.php file. If you want to take it further, open a subfolder (e.g. "List") in it, put another index.php in that folder and you can have www.yoursite.example/data/list run that PHP file.
This way you can have full control over this, very useful for SEO.
same as Igor but should work without line 2:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
Tony, your script is ok, but if you have 100 files? Need add this code in all these :
include_once('scripts.php');
strip_php_extension();
I think you include a menu in each php file (probably your menu is showed in all your web pages), so you can add these 2 lines of code only in your menu file. This work for me :D
Remove a file extension through .htaccess:
Original URL: http://ravinderrathore.herobo.com/contact.php
.htaccess rule to remove .php, .html, etc. file extensions from URLs:
RewriteRule ^(.*)$ $1.php
After Rewriting: http://ravinderrathore.herobo.com/contact
RewriteEngine on
RewriteCond %{THE_REQUEST} ^(.+)\.php([#?][^\ ]*)?\ HTTP/
RewriteRule ^index(.*)?$ index.php$1 [L,QSA]
RewriteRule ^login_success(/)?$ login_success.php [L,QSA]
RewriteRule ^contact(/)?$ contact.php [L,QSA]
just nearly the same with the first answer about, but some more advantage.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
Just add up if you have a other file-extension in your sites
For those who are still looking for a simple answer to this; You can remove your file extension by using .htaccessbut this solution is just saving the day maybe even not. Because when user copies the URL from address bar or tries to reload or even coming back from history, your standart Apache Router will not be able to realize what are you looking for and throw you a 404 Error. You need a dedicated Router for this purpose to make your app understand what does the URL actually means by saying something Server and File System has no idea about.
I leave here my solution for this. This is tested and used many times for my clients and for my projects too. It supports multi language and language detection too. Read Readme file is recommended. It also provides you a good structure to have a tidy project with differenciated language files (you can even have different designs for each language) and separated css,js and phpfiles even more like images or whatever you have.
Cr8Router - Simple PHP Router

In PHP, how can I get any string after the domain to be a php variable? Ex: me.com/FOO, me.com/VAR3

so my index.php can be this:
<?php
$restOfURL = ''; //idk how to get this
print $restOfURL; //this should print 'FOO', 'VAR3', or any string after the domain.
?>
You want to use,
<?php
$restOfURL = $_SERVER['REQUEST_URI'];
// If you want to remove the slash at the beginning you can use ltrim()
$restOfURL = ltrim($restOfURL, "/");
?>
You can find more of the predefined server variables in the PHP documentation.
Update
Based on your comment to the question, I guess you're using something like mod_rewrite to rewrite the FOO, etc and route everything to just one file (index.php). In that case I would expect the rest of the URL to already be passed to the index.php file. However, if not, you can use mod_rewrite to pass the rest of the URL as a GET variable, and then just use that GET variable in your index.php file.
So if you enable mod_rewrite and then add something like this to your .htaccess file,
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]
Then the rest of the URL will be available to you in your index.php file from the $_GET['url'] variable.
Reading $_SERVER['REQUEST_URI'], as everybody has pointed out, can tell you what the URL looks like, but it doesn't really work the way you want it unless you have a way to point requests for me.com/VALUE1 and me.com/VALUE2 to the script that will do the processing. (Otherwise your server will return a 404 error unless you have a script for each value you want, in which case the script already knows the value...)
Assuming you're using apache, you want to use mod_rewrite. You'll have to install and enable the module and then add some directives to your .htaccess, httpd.conf or virtual host config. This allows you make a request for me.com/XXX map internally to me.com/index.php?var=XXX, so you can read the value from $_GET['var'].
$var = ltrim( $_SERVER['REQUEST_URI'], '/' )
http://www.php.net/manual/en/reserved.variables.server.php
Just by looking at the examples, i think you are looking for the apache mod_rewrite.
You can apply a RewriteRule via an htaccess file, for example:
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^([\w]+)$ /checkin.php?string=$1 [L]
For example this url http://foo.com/aka2 will be process by checkin.php script and will have "aka2" passed as $_GET['string'].
Make no mistake, the URL will still be visible in the browser as http://foo.com/aka2 but the server will actually process http://foo.com/checkin.php?string=aka
mod_rewrite documentation
$_SERVER['REQUEST_URI']
Why bother with all the fancy mod_rewrite/query_string business? There's already $_SERVER['PATH_INFO'] available for just such data.

Categories