Tahhan Posted September 29, 2017 Share Posted September 29, 2017 I have followed a youtube playlist to build a simple MVC framework based on PHP, here is a link to the playlist I have followed. and here is an image of my application structure image I have connected the application to a MySql database, everything is working fine, but now I am trying to do friendly URLs. Currently, my URLs look like the following: mywebsite.com/public/home/property This is fine as this link is for a static page, but I want the same for dynamic URLs, for example: Current URL: mywebsite.com/public/home/property?id=10 to URL: mywebsite.com/public/home/property/id/10 I have tried a lot of methods in htaccss but the data is not pulled from the database once the URL is re-written and I get only an empty page. current .htaccess code (the one that is located in the public folder): Options -MultiViews RewriteEngine On RewriteBase /public RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.+)$ index.php?url=$1 [QSA,L] I have tried a lot of methods and rules but non have worked. I am not sure if the details I provided are clear enough, I am little confused as I combined a lot of tutorials together to create this app. App.php code: <?php class App{ protected $controller = 'home'; protected $method = 'index'; protected $params = []; public function __construct(){ $url = $this->parseUrl(); if(file_exists('../app/controllers/' . $url[0] . '.php')){ $this->controller = $url[0]; unset($url[0]); } require_once '../app/controllers/' .$this->controller. '.php'; $this->controller = new $this->controller; if(isset($url[1])){ if(method_exists($this->controller, $url[1])){ $this->method = $url[1]; unset($url[1]); } } $this->params = $url ? array_values($url) : []; call_user_func_array([$this->controller, $this->method], $this->params); } public function parseUrl(){ if(isset($_GET['url'])){ return $url = explode('/', filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL)); echo $url; } } } ?> controller.php code: <?php class Controller{ public function model($model){ require_once '../app/models/' . $model . '.php'; return new $model(); } public function view($view, $data = []){ require_once '../app/views/' . $view . '.php'; } } ?> controllers code: <?php class home extends Controller{ public function index(){ $this->view('home/index'); } public function listings(){ $this->view('home/listings'); } public function property(){ $this->view('home/property'); } } ?> code for the page that should show data from mysql database: <?php include "includes/head.php"; ?> <?php $property = Property::find_id($_GET['id']); ?> <section id="sub-main"></section> <section id="sub-list"> <div class="container"> <div class="row"> <div class="col-xs-12 col-sm-6"> <div id="listingCarousel" class="carousel slide" data-ride="carousel"> <div class="carousel-inner" role="listbox"> <div class="item active"> <img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=585%C3%97380&w=585&h=380" alt=""> </div> <div class="item"> <img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=585%C3%97380&w=585&h=380" alt=""> </div> <div class="item"> <img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=585%C3%97380&w=585&h=380" alt=""> </div> </div> </div> </div> <div class="col-xs-12 col-sm-6"> <h1><?php echo $property->property_name; ?></h1> <ul class="list-inline"> <li><i class="fa fa-map-signs" aria-hidden="true"></i> <b></b> <?php echo $property->city; ?></li> </ul> </div> </div> <hr> <div id="map"></div> </div> </section> <?php include "includes/subscribe.php"; ?> <?php include "includes/footer.php"; ?> The project is online, I can give full access if someone interested in helping me solve this issue. Quote Link to comment Share on other sites More sharing options...
requinix Posted September 30, 2017 Share Posted September 30, 2017 That was a long post so I'm just going to cover it from top to bottom. > Current URL: mywebsite.com/public/home/property?id=10 Are you sure you want "public" in there? By the looks of it you should have public as the web root - you can still reference files outside it but this way the website won't try to offer application files (eg, /app/init.php) when it shouldn't. Remove /public from the places that use it, like the entire RewriteBase line in your .htaccess. Naturally that means you can get rid of /app/.htaccess too. > RewriteRule ^(.+)$ index.php?url=$1 [QSA,L] Fine so far. I assume index.php (or /app/init.php?) ends up doing new App();Having a new object automatically run code isn't the best design, but it isn't something to worry about right now. > if(file_exists('../app/controllers/' . $url[0] . '.php')){ 1. Doing relative file paths is very dangerous. In your situation index.php or init.php should create something (I suggest a constant) that gives an absolute path to the root of the entire application: the directory that has app/ and public/. As in define("APP_ROOT", dirname(__DIR__)); // if run from /public/index.php or /app/init.phpThen if(file_exists(APP_ROOT . '/app/controllers/' . $url[0] . '.php')){2. Are you sure $url contains what you think it does? Dump it out. 3. Before you translate $url to a file path you need to make sure it's safe to do so: $url could be maliciously created (since it comes from the URL) in a way to trick your code into running files it shouldn't. Since the first part maps to a class name, you can verify it only contains valid class name characters*. > include "includes/head.php"; Same comment from before about relative paths. You could define another constant for the path to the includes/ directory, or include $_SERVER["DOCUMENT_ROOT"] /* which is now public/ */ . "/includes/head.php"; * Class names in PHP can have more than just letters, but in your application that doesn't look like it will be the case for the controllers. So restricting it to letters should be fine. Quote Link to comment Share on other sites More sharing options...
Tahhan Posted September 30, 2017 Author Share Posted September 30, 2017 Thanks for the reply, I really appreciate it from you, pardon me please as I am not an advanced PHP user, especially when it comes to OOP and MVC, I have tried to do what you wrote me. but still having the same issue. I just want to know how to pass the variable which is id in the URL, without showing the "?" and "=" sign, I would really appreciate it if you help with this, as I have been trying for more than 3 days and couldn't achieve anything. Quote Link to comment Share on other sites More sharing options...
requinix Posted October 1, 2017 Share Posted October 1, 2017 You're already doing the hard part of it: the RewriteRule stuff. The rest is you making creating the right URLs in your links - that doesn't happen automatically. 1 Quote Link to comment Share on other sites More sharing options...
Gandalf64 Posted October 1, 2017 Share Posted October 1, 2017 That for me was the hardest part in writing clean URLS and I don't know why? I would have this in my .htaccess file RewriteRule ^(index|about|blog|calendar|contact|edit|login|order)$ $1.php [NC,L] RewriteRule ^edit/(\d+)$ edit.php?id=$1 [NC,L] but forget I had to do this echo '<a class="edit" href="edit/' . $this->row->id . '">Edit</a>'; I would spend days trying to get it work and finally a light bulb turned on, but until I did figure it out it was like I was myself. Quote Link to comment Share on other sites More sharing options...
Tahhan Posted October 2, 2017 Author Share Posted October 2, 2017 I had this issue in the past, I even hired an advanced PHP developer to solve it, and then it turned out that I was forgetting to implement it in the a tag. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.