Rewrite URL in .htaccess just cause 404 error - php

I'm trying to learn how to rewrite URL in the .htaccess file. I have read some tutorials, but despite that I write as in the example code, nothing happens for me! I'm wondering what I'm doing wrong here? I get a 404-code when I'm trying the code below.
RewriteEngine On
RewriteRule /byggnader/1/ /?p=byggnad&id=1
This is just a test and I wonder if /byggnader/ must be an existing file or just a name in the URL. I'm using a page controler design. So URL /?p=byggnad&id=1 will open the PSelectedBuilding.php file inside the index.php file.
I preciate some feedback to be able to continue.
EDIT: Since it's not working despite the help below, I also add the code from the index.php file that handle the requests. Perhaps that could give a clue why!?
<?php
session_start();
// Allow only access to pagecontrollers through frontcontroller
$indexIsVisited = TRUE;
require_once('config.php');
// pagecontrol
$page = isset($_GET['p']) ? $_GET['p'] : 'start';
switch($page) {
case 'start': require_once('PIndex.php'); break;
case 'karta': require_once('PMap.php'); break;
case 'byggnader': require_once('PBuildings.php'); break;
case 'tips': require_once('PTips.php'); break;
case 'visa-byggnad': require_once('PHandleSessions.php'); break;
case 'byggnad': require_once('PSelectedBuilding.php'); break;
case 'visa': require_once('PSelectedBuilding.php'); break;
case 'visa2': require_once('PHandleSessions.php'); break;
default: require_once('PIndex.php'); break;
}
require_once("CreatePage.php"); // Call file that creates the page
?>
EDIT 2:
This works fine, but not when I'm using requests for some of the pages:
RewriteEngine On
RewriteRule bilder-byggnader-kopenhamn /?p=byggnader
RewriteRule karta-byggnader-kopenhamn /?p=karta
RewriteRule start /?p=start
RewriteRule tips /?p=tips

Remove leading slash from your rule. .htaccess is per directory directive and Apache strips the current directory path (thus leading slash) from RewriteRule URI pattern.
RewriteEngine On
RewriteRule ^byggnader/1/?$ /?p=byggnad&id=1 [L]

Try this one:
RewriteEngine On
RewriteCond %{QUERY_STRING} p=(\w+)&id=(\d+)
RewriteRule ^index.php /%1/%2? [R=301, L]
The RewriteCond mathches the Query String (as per your wish) extracting two variables which you can reuse to build your redirection target in the rewrite rule directive. The final question mark tells Apache not to reappend existing QS. R=301 says that the redirection is permanent, L that this is the last rule to be processed.
You may have to play with the index.php part since you never put the REQUEST_URI part in your question.

Related

Understanding the front controller with PHP

I'm very new with PHP, and I've managed to create a really rough CMS. At the moment, it's using many different pages and includes.
However, if possible I'd like to use a controller rather than having lots of pages (I've already got article.php/admin.php).
As an example, I'm trying to convert to something like this:
switch ( 'admin' ) {
case 'home':
include 'view/home.php';
break;
case 'admin':
include 'view/admin.php';
break;
case 'article':
include 'view/article.php';
break;
default:
echo 'default';
break;
}
This would be used with $_GET['page'], so the admin URL looks like: http://cms.dev/?page=admin
However, what happens if I need to go to a subdirectory of admin? For example, if these were hardcoded pages, I would go admin/new-post.php. Is there an equivalent I could get, using the $_GET method?
Sorry if this has not been explained well. Let me know and I will try and edit it. I've used a smorgsaboard of tutorials so I'm not 100% on any of this.
You can have forward slashes in your $_GET['page'] variable, so https://cms.dev/?page=admin/new-post.php should work fine.
Alternatively you can put this into your .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L,QSA]
And then get it from the REQUEST_URI:
$uri = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);

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.

Using SERVER['REQUEST_URI'] and GET in controlling the website flow

I have a small website. It's .htaccess file is like this:
RewriteEngine On
RewriteBase /site/
RewriteRule ^(.+)$ index.php [QSA,L]
So it redirects all the URLs to 'index.php'. I can get the requested URL and act accordingly :
$uri = $_SERVER['REQUEST_URI'];
switch($uri)
{
case 'index':
LoadIndex();
break;
case 'about':
LoadAbout();
break;
case 'Posts':
LoadPosts();
break;
default:
LoadNotFound();
}
Say I want to use $_GET[] in Index page. That changes the URL, so it fails to load the page.
How can I do that? How can I route my site without affecting $_GET[] variables in URLs?
$_SERVER[REQUEST_URI] will be /index.php and not index. $_SERVER[REQUEST_URI] also includes the QUERY_STRING. So, it might be /index.php?var1=abc&var2=def.
If you need only the URI path, try PHP_SELF or SCRIPT_NAME. But keep in mind, that these will be /index.php too, including / and .php.
$uri = $_SERVER['PHP_SELF'];
switch($uri)
{
case '/index.php':
LoadIndex();
break;
...
}
You don't need QSA in your RewriteRule. From RewriteRule Directive
Modifying the Query String
By default, the query string is passed through unchanged.
This means, the $_GET variable is available in your PHP script as before.

Rewrite rules for php urls

I've tried to find an answer for a question i had in my mind, but it seems to I can't find it.
How is it possible to make some php urls with "?" and "=" to /
Example one (1):
example.com/user.php?profile=example
to:
example.com/user/profile/example
Example two (2):
example.com/forum.php?thread=example-in-an-example
to:
example.com/forum/thread/example-in-an-example
Like a code that takes the second "/" (slash) as a "?" and the third and the rest as a "=" so i can freely use it instead of making a new one for each page...
LIKE: /forum (or any others) is like the page itself
AND: /thread (or any others) is like the $_GET
AND: /example-in-an-example (or any others) is like the value to the $_GET
EXTRA:
here is a code from Jeroen:
RewriteRule ^(.*)/(.*)/(.*)/$ $1.php?$2=$3 [L]
Problem one (1): when going to like: "example.com/forum" or "example.com/user" its giving a 404 error
Problem two (2): When using links like "example.com/forum/thread/test-thread/reply/2" it gives 404 error, (supose to loop with "&" and "=" after making the 1st real one so its enable to use more than one $_GET)
Add this to your .htaccess file:
RewriteEngine On
RewriteRule ^user/profile/(.*)/$ user.php?profile=$1 [L]
RewriteRule ^forum/thread/(.*)/$ /forum.php?thread=$1 [L]
Or a more generic version...
RewriteEngine On
RewriteRule ^(.*)/(.*)/(.*)/$ $1.php?$2=$3 [L]
Make sure Apache's mod rewrite is enabled!
If you have full access to the application and you can modify the code, I can submit you some trick I usually use for my REST utilities.
Put AllowOverride All inside your apache configuration to enable .htaccess file.
Assure to LoadModule your mod_rewrite module too.
Create a .htaccess file into your web server document root (your application path) and put this stuff inside:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
Create a file called index.php and put this inside, this will be your controller:
<?
// echo "REQUEST_URI: " . $_SERVER['REQUEST_URI'] . "</br>\n";
$controller = explode("/", $_SERVER['REQUEST_URI']);
//print_r($controller);
$resource = $controller[1];
$operation = $controller[2];
$operation_value = $controller[3];
echo "Requested resource: $resource, opetation: $operation, value: $operation_value<br>\n";
switch($resource) {
case 'user':
echo "User requested\n";
//require_once("user.php");
break;
case 'forum':
echo "Forum requested\n";
//require_once("forum.php");
break;
/* add any other resource */
default:
echo "Requested page was not found.\n";
break;
}
?>
When the user call http://example.com/user/profile/ZeroXitreo the page will be renderer as:
Requested resource: user, opetation: profile, value: ZeroXitreo
User requested
When the user call http://example.com/forum/thread/example-in-an-example the page will be:
Requested resource: forum, opetation: thread, value: example-in-an-example
Forum requested
Read the PHP code of the controller, I think it's quite self explaining.

How do I restructure the htaccess to allow for the home page?

Ok so I have a site that has tons of pages and I want to create a php file fore each one...this works great..here is what i have, code wise
Here is my htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L]
here is my index.php file
$parts = explode('/', $_REQUEST['url']);
switch ($parts[count($parts) - 1]) {
case 'restaurant':
include "pages/restaurant.php";
break;
case 'retail':
include "pages/retail.php";
break;
.......
.......
}
this works great and if i visit the url http://someurl.com/restaurant the proper file in pages/restaurant.php pulls up. The only problem is the home page http://someurl.com when i visit it i get a:
Forbidden
You don't have permission to access /structure on this server.
Is there a way to fix this in the .htaccess to address this issue and should i create a file maybe called home.php in the pages folder or should i just put the content of the home page in the index file in an else condition...any ideas
You forgot to specify a default switch case?
switch ($parts[count($parts) - 1]) {
case 'restaurant':
include "pages/restaurant.php";
break;
case 'retail':
include "pages/retail.php";
break;
default:
include "pages/default_page.php";
break;
.......
.......
}
1. Use this rule somewhere before existing rules:
RewriteRule ^$ index.php?url=home [L]
2. Create pages/home.php
3. Add this to your switch statement:
case 'home':
include "pages/home.php";
break;
P.S. I do not recommend using default: to handle home page. default: should be used to handle 404 page / unknown pages ONLY.
Do you have a default statement in that switch? My bet is you don't.
DirectoryIndex index.php
Do you have this code in your httpd.conf or .htaccess?
It seems like your default file is not index.php

Categories