I currently run a site where I want to give people the ability to make their own URLs. For example, here is my URL:
http://www.hikingsanfrancisco.com/hiker_community/hiker_public_profile.php?community_member_id=2
You see, it is named just by id, which is uninteresting and also bad for SEO (not that it matters here).
Ideally I want my site members to also have their names in the URL. How is that typically done? So in my case, it would be something like:
http://www.hikingsanfrancisco.com/alex-genadinik and have the id hidden.
Is that possible? Any advice would be appreciated!
Thanks,
Alex
you need router, see https://stackoverflow.com/questions/115629/simplest-php-routing-framework
Generally this is accomplished via the use of an htaccess file on a server with mod_rewrite (most Linux servers). An example might be like:
Options -Indexes
RewriteEngine On
RewriteRule ^([0-9a-zA-Z\-]+)$ $1.php
RewriteRule ^/(alex[\-]genadinik)$ /hiker_community/hiker_public_profile.php? community_member_name=$1
This implies that your hiker_public_profile.php script will need to accept "alex-genadinik" as $_GET variable "community_member_name," and then query the database via the name instead of the ID.
So you'd take the above code, save it in a file called ".htaccess," and then upload it to the root directory of your website. Learning regular expressions is recommended.
Code Igniter is a great MVC framework which provides configuration derived routes, which can easily be configured to send all requests through a common controller, where content can be dynamically pulled from a database and rendered.
Here is an example of a basic routing rule, which excludes request for users, students, and lessons, but routes all other request to a common content controller.
So if you request http://mydomain.com/hiking-and-camping-info, the url would be parsed, and hiking-and-camping-info would be looked up in the database and the related content pulled down.
Routing configuration:
$route['^(?!lessons|students|users|content).*'] = 'content';
and the content controller then grabs the url segment and finds the matching content and loads it:
class Content extends Controller {
function __construct() {
parent::Controller();
$this->load->model('Content_model', 'content');
}
function index() {
$content_url = $this->uri->segment(1);
$data['content'] = $this->content->get_content_by_name($content_url);
$this->load->view('content', $data);
}
}
Related
Hi I'm currenly playing around with PHP MVC programming, and was wondering if anyone has made some sort of "routing" with a database?
I have a "page" table that looks like this: http://i.imgur.com/xS1OvjW.png
Currently all routes are hardcoded, and I thought it must be possible to do with a database..
But not only do I want to get the page and show it, I also need to be able to send parameters with it.
Example:
As shown in my page table, I have a "test" url. If i type http://demo.com/test/ I would get "rerouted" to use the "home" controller and "Index" method. But I also need to be able to type http://demo.com/test/id/40 and id/40 will be sent as params to the controller/method.
If this isn't a good thing to do, or if anyone got a better soloution please let me know! :)
Regards,
Frederik
This definitely depends on the server you're using, but since you're a PHP MVC noobie I'll reference apache in this example, and hope it's what you have for the sake of the examples.
First, you'll need your webserver configured to know that it has to send all traffic through your base page (usually index.php). Now that page would do some other stuff (call bootstrap, etc) but for the sake of argument we'll say that all it does right away is look at the request from the page, compare it to the DB, and complete the request if it can.
In that case, it will be helpful to have the request info from the server passed in to the index.php page. To do this, you'll want to configure apache with an .htaccess file similar to:
DirectoryIndex index.php
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ public/?path=$1 [L,QSA]
This tells it to use index.php for all requests that aren't specific files or directories, and to pass the full url path through to index.php as a $_GET var.
Next, in index.php, you'll want to check the path you were passed against DB of paths. Here's a really simple example to show:
<?php
// Obviously use your database and some string parsing here to match correctly
// I generally explode the path on '/' to break it into controller, action, etc.
if ($_GET['path'] == "user/account") {
// Then you call the controller that matches the first part of the route
// The action that matches the second part of your route
// And pass the request along so you can access anything else
call UserController::accountAction($_REQUEST);
} else if ($_GET['path'] == "user/resetpassword") {
call UserController::resetPasswordAction($_REQUEST);
}
From there, you should be in the right place and have everything you need. That Controller/Action URL format is a fairly common one for how easily it lets us do this.
Hope the answer helped!
i want to build a website with different views, but a stable header and footer - no problem so far. But i dont like the kind of urls i got at the moment with the php GET method.
My site at the moment works like this (what istn working properly):
$_page = $_GET['p'];
if ($_page == "city-sitemap"){ include "views/city-sitemap-view.php"; }
if ($_page == "place"){ include "views/place-view.php"; }
else { include "views/index-view.php";}
this isnt a very sweet solution but i dont know a other for now. I tried to use a mvc framework but failed dramatically. So everytime i add a link i use for example this "index.php?p=place" - not very nice.
The including of the views isn very smart as well? is there a better way?
I would like to use something like the rewriteEngine that the new url is like a folder.
Can you help me to find a better solution?
Thanks a lot
Page including
For the page inclusion, you can use a simple array to dynamically allocate your page to a specific name. As so:
$pages = array('city-sitemap'=>'views/city-sitemap-view.php',
'place'=>'views/place-view.php',
)
if(array_key_exists($_GET['p'], $pages){
include $pages[$_GET['p']];
}else{
include 'views/error.php';
}
This array should be added in a general configuration file. With this configuration if you want to display your city-sitemap-view.php view, you will have to write this url: http://www.domain.com/index.php?p=city-sitemap
Url rewriting
It is possible to rewrite an URL with a .htaccess file. Here is an example of code you would can to write in your .htaccess file.
RewriteEngine On
RewriteRule ^(.*)$ index.php?p=$1 [L,QSA]
An url that looks like this:
http://www.domain.com/index.php?p=city-sitemap
will be converted to this one:
http://www.domain.com/city-sitemap
There is something called the front controller that you should look into. You can write a very simple one yourself. It works in conjunction with URL rewriting. If for example your url looks like this:
/mypage.html
the url rewriter will reroute the request to index.php .
Index.php will then look at the URL and do somehting like this:
1) break the page out into string, ignoring .html extention
preg_match("\/(.*?)\.html", $_REQUEST['URI'], $matches);
$pageClass = $matches[1];
//$pageClass = "mypage"
2) look for and load a class named "Mypage.php"
$controller = new $pageClass();
3) call the run method on the page class, passing it all the request parameters
$request = new Request($_REQUEST);
$controller->run($request);
you can then do all the page specific stuff inside your controller class that is specific to the page.
At each simple step along the way, you will find you want to do more and more things like authentication, filtering, tracking, etc. You will get end up developing a front controller that is specific to your needs, as well as a base Controller class that does a bunch of standard stuff that all your controllers have in common.
As per my comment, i really think you should consider the framework i linked, (it is very logical) or any other micro framework, but if you really wish to do this yourself then you can handle your includes like so:
<?php //index.php
$requested_page=isset($_GET['p'])?$_GET['p']:'home';
//maybe have this included from pages.php for organization
$pages=array(
'home'=>'home_content.php',
'about'=>'about_content.php',
'contact'=>'contact_content.php'
);
include "views/header.php";
if(array_key_exists($requested_page, $pages)){
include "views/".$pages[$requested_page];
}else{
header('HTTP/1.0 404 Not Found');
include "views/error404.php";
}
include "views/footer.php";
This keeps your pages in a single array, and protects against arbitrary inclusion vulnerabilities.
For nicers urls, see The other users .htaccess rewrite rules
For a "classic" website, one would create a /foldername/index.php for every web page. With WordPress, however, this is not the case. For example, if a page was created with WordPress whose URI was http://myblog.org/some_page, you would not find the folder www/myblog.org/some_page in your web host's FTP.
My question then, is, How can I serve up pages located at http://[MY_WEBSITE].com/[page_name] for any arbitrary page_name, without creating a new folder for every page_name?
One method would be to use the page_name as parameter to a common file and use that to serve the contents of the required page.
That behaviour is handled (in an Apache server) by a .htaccess file, wherein rewrite rules are defined. Rewrite rules basically capture incoming traffic and directs those requests to a file on the server (typically a single page which will act as a router).
The router is then responsible for taking the input URI (usually via $_SERVER["REQUEST_URI"] in PHP) and working out what to do with it, and ultimately what the output will be for that request.
As for a decent router, you could look at klein.php. Also, a brief example:
# htaccess file
RewriteEngine On
RewriteRule ^[^\.]+$ index.php
And the index.php:
$route = $_SERVER["REQUEST_URI"];
if($route === '/home')
{
echo 'This is the homepage';
}
You tell your server to rewrite the URL. Most servers do it in their own way, so to find out how to do it look at your server's documentation.
Wordpress uses templates that make use of the require() function and a foreach loop commonly called "The Loop" to retreive content.
Different pages are called using different templates. If you want to know exactly how this logic is calculated, look into this.
I want to make a small web application, and I'm not sure how to go about this.
What I want to do is send every request to the right controller. Kind of how CodeIgniter does it.
So if user asks for domain.com/video/details
I want my bootstrap (index?) file to send him to the "Video" controller class and call the "details" method in that class.
If the user asks for domain.com/profile/edit I want to send him to the "Profile" controller class and call the "edit" method in that class.
Can someone explain how I should do this? I have some experience using MVC frameworks, but have never "written" something with MVC myself.
Thanks!
Edit: I understand now how the url points to the right Controller, but I don't see where the object instance of the Controller is made, to call the right method?
You need to re-route your requests. Using apache, this can be done using mod_rewrite.
For example, add a .htaccess file to your public base directory and add the following:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?rt=$1 [L,QSA]
This will redirect users trying to access
/profile/edit
to
index.php?rt=profile/edit
In index.php, you can access the $_GET['rt'] to determine which controller and action has been requested.
Use mod-rewrite (.htaccess) to
rewrite the url from
www.example.com/taco to
www.example.com/index.php?taco/
in index.php, grab the first URL
parameter key, use that to route to
the correct url. As it will look
like "taco/"
You may want to add / to the front
and back if it doesn't exist. As
this will normalize the urls and
make life easier
If you want to preserve the ability
to have traditional query strings.
Inspect the URL directly and take
the query string portion. break that
on ?, which will leave you with the
routing info in key 0 and the rest
in key 1. split that on &, then
split each of those on = and set the
first to the key and the second to
the value of an array. Replace $_GET
with that array.
Example:
$path = explode("?", $_SERVER["QUERY_STRING"],2);
$url = $path[0];
if(substr($url,0,1) != "/")
{
$url = "/".$url;
}
if(substr($url,-1,1) != "/")
{
$url = $url."/";
}
unset($_GET);
foreach(explode("&", $path[1]) as $pair)
{
$get = explode("=", $pair, 2);
$_GET[$get[0]] = $get[1];
}
// Define the Query String Path
define("QS_PATH", $url);
Depending on what you want to do or how much work you want to do, another option versus writing your own MVC is to use Zend Framework. It does exactly what you're asking for and more. You still need to configure URL rewriting as mentioned in the other answers, but it quick and easy.
Even if you're not interested in Zend Framework, the following link can help you configure your rewrite rules: http://framework.zend.com/wiki/display/ZFDEV/Configuring%2BYour%2BURL%2BRewriter
In Zend framework, using the MVC, if A user surf explicitly to http://base/url/index.php instead of just http://base/url, The system thinks the real base url is http://base/url/index.php/ and according to that calculates all the URLs in the system.
So, if I have a controller XXX and action YYY The link will be
http://base/url/index.php/XXX/YYY which is of course wrong.
I am currently solving this by adding a line at index.php:
$_SERVER["REQUEST_URI"]=str_replace('index.php','',$_SERVER["REQUEST_URI"]);
I am wondering if there is a built-in way in ZF to solve this.
You can do it with ZF by using Zend_Controller_Router_Route_Static (phew!), example:
Read the manual page linked above, there are some pretty good examples to be found.
$route = new Zend_Controller_Router_Route_Static(
'index.php',
array('controller' => 'index', 'action' => 'index')
);
$router->addRoute('index', $route);
Can't say I totally disagree with your approach. That said, others may well point out 5000 or so disadvantages. Good luck with that.
Well it really depends on how you want to solve this. As you know the Zend Frameworks build on the front controller pattern, where each request that does not explicitly reference a file in the /public directory is redirected to index.php. So you could basically solve this in a number of ways:
Edit the .htaccess file (or server configuration directive) to rewrite the request to the desired request:
RewriteRule (.*index.php) /error/forbidden?req=$1 // Rewrite to the forbidden action of the error controller.
RewriteRule index.php /index // Rewrite the request to the main controller and action
Add a static route in your bootstrapper as suggested by karim79.
Use mod_rewrite. Something like this should do it:
RewriteRule ^index.php/(.*)$ /$1 [r=301,L]
I don't think you should use a route to do this.
It's kind of a generic problem which shouldn't be solved by this way.
You better should have to do it in your .htaccess, which will offer you a better & easier way to redirect the user to where you want, like to an error page, or to the index.
Here is the documentation page for the mod_rewrite
I've never faced this problem using Zend Framework. just do not link to index.php file. that's it. and when your are giving your application's address to users, just tell them to go to http://base/url/
when the user enters http://base/url/ her request URI is base/url and your .htaccess file routs the request to index.php, but the request IS base/url. you do not need to remove 'index.php' from the request. because it is not there.
when you are trying to generate URLs for links and forms and ..., use the built-in url() view helper to generate your links. like this:
// in some view script
<a href="<?php
echo $this->url( array('controller'=>'targetController','action'=>'targetAction') );
?>" >click</a>
do not worry about the link. Zend will generate a URL for you.
The way I look at this is that if I have a website powered by PHP and a user goes to http://site/index.aspx then I would send a 404.
Even though index.php does exist in theory, it's not a valid URL in my application so I would send a 404 in this case too.